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