1512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <errno.h> 2512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <libgen.h> 3512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <stdio.h> 4512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <stdlib.h> 5512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <string.h> 6512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <sys/stat.h> 7512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <sys/statfs.h> 8512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <unistd.h> 9512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <dirent.h> 10512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include <ctype.h> 11512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 12512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker#include "applypatch.h" 13512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 14512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongkerstatic int EliminateOpenFiles(char** files, int file_count) { 15512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker DIR* d; 16512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker struct dirent* de; 17512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker d = opendir("/proc"); 18512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (d == NULL) { 19512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("error opening /proc: %s\n", strerror(errno)); 20512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return -1; 21512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 22512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker while ((de = readdir(d)) != 0) { 23512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker int i; 24512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i); 25512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (de->d_name[i]) continue; 26512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 27512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // de->d_name[i] is numeric 28512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 29512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker char path[FILENAME_MAX]; 30512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcpy(path, "/proc/"); 31512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcat(path, de->d_name); 32512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcat(path, "/fd/"); 33512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 34512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker DIR* fdd; 35512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker struct dirent* fdde; 36512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker fdd = opendir(path); 37512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (fdd == NULL) { 38512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("error opening %s: %s\n", path, strerror(errno)); 39512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker continue; 40512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 41512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker while ((fdde = readdir(fdd)) != 0) { 42512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker char fd_path[FILENAME_MAX]; 43512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker char link[FILENAME_MAX]; 44512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcpy(fd_path, path); 45512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcat(fd_path, fdde->d_name); 46512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 47512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker int count; 48512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker count = readlink(fd_path, link, sizeof(link)-1); 49512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (count >= 0) { 50512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker link[count] = '\0'; 51512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 52512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // This is inefficient, but it should only matter if there are 53512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // lots of files in /cache, and lots of them are open (neither 54512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // of which should be true, especially in recovery). 55512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (strncmp(link, "/cache/", 7) == 0) { 56512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker int j; 57512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker for (j = 0; j < file_count; ++j) { 58512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (files[j] && strcmp(files[j], link) == 0) { 59512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("%s is open by %s\n", link, de->d_name); 60512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker free(files[j]); 61512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker files[j] = NULL; 62512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 63512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 64512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 65512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 66512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 67512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker closedir(fdd); 68512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 69512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker closedir(d); 70512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 71512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return 0; 72512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker} 73512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 74512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongkerint FindExpendableFiles(char*** names, int* entries) { 75512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker DIR* d; 76512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker struct dirent* de; 77512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker int size = 32; 78512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker *entries = 0; 79512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker *names = malloc(size * sizeof(char*)); 80512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 81512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker char path[FILENAME_MAX]; 82512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 83512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // We're allowed to delete unopened regular files in any of these 84512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // directories. 85512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker const char* dirs[2] = {"/cache", "/cache/recovery/otatest"}; 86512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 87512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker unsigned int i; 88512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker for (i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) { 89512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker d = opendir(dirs[i]); 90512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (d == NULL) { 91512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("error opening %s: %s\n", dirs[i], strerror(errno)); 92512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker continue; 93512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 94512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 95512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // Look for regular files in the directory (not in any subdirectories). 96512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker while ((de = readdir(d)) != 0) { 97512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcpy(path, dirs[i]); 98512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcat(path, "/"); 99512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker strcat(path, de->d_name); 100512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 101512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // We can't delete CACHE_TEMP_SOURCE; if it's there we might have 102512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // restarted during installation and could be depending on it to 103512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // be there. 104512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue; 105512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 106512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker struct stat st; 107512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { 108512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (*entries >= size) { 109512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker size *= 2; 110512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker *names = realloc(*names, size * sizeof(char*)); 111512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 112512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker (*names)[(*entries)++] = strdup(path); 113512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 114512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 115512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 116512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker closedir(d); 117512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 118512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 119512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("%d regular files in deletable directories\n", *entries); 120512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 121512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (EliminateOpenFiles(*names, *entries) < 0) { 122512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return -1; 123512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 124512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 125512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return 0; 126512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker} 127512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 128512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongkerint MakeFreeSpaceOnCache(size_t bytes_needed) { 129512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker size_t free_now = FreeSpaceForFile("/cache"); 130512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("%ld bytes free on /cache (%ld needed)\n", 131512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker (long)free_now, (long)bytes_needed); 132512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 133512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (free_now >= bytes_needed) { 134512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return 0; 135512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 136512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 137512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker char** names; 138512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker int entries; 139512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 140512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (FindExpendableFiles(&names, &entries) < 0) { 141512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return -1; 142512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 143512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 144512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (entries == 0) { 145512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // nothing we can delete to free up space! 146512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("no files can be deleted to free space on /cache\n"); 147512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return -1; 148512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 149512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 150512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // We could try to be smarter about which files to delete: the 151512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // biggest ones? the smallest ones that will free up enough space? 152512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // the oldest? the newest? 153512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // 154512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker // Instead, we'll be dumb. 155512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 156512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker int i; 157512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker for (i = 0; i < entries && free_now < bytes_needed; ++i) { 158512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker if (names[i]) { 159512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker unlink(names[i]); 160512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker free_now = FreeSpaceForFile("/cache"); 161512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker printf("deleted %s; now %ld bytes free\n", names[i], (long)free_now); 162512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker free(names[i]); 163512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 164512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 165512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 166512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker for (; i < entries; ++i) { 167512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker free(names[i]); 168512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker } 169512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker free(names); 170512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker 171512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker return (free_now >= bytes_needed) ? 0 : -1; 172512536a54a1a211a9f582e76cbf12850dc7d5466Doug Zongker} 173