blob: f023ee1a6b7f60d73b901777f0572a753d7e5209 [file] [log] [blame]
Joe Onorato1754d742016-11-21 17:51:35 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Yi Jin4e843102018-02-14 15:36:18 -080016#define DEBUG false
Yi Jinb592e3b2018-02-01 15:17:04 -080017#include "Log.h"
Joe Onorato1754d742016-11-21 17:51:35 -080018
19#include "report_directory.h"
20
Joe Onorato1754d742016-11-21 17:51:35 -080021#include <private/android_filesystem_config.h>
22#include <utils/String8.h>
23
Joe Onorato1754d742016-11-21 17:51:35 -080024#include <dirent.h>
25#include <libgen.h>
Yi Jinb592e3b2018-02-01 15:17:04 -080026#include <sys/stat.h>
27#include <sys/types.h>
Joe Onorato1754d742016-11-21 17:51:35 -080028#include <unistd.h>
29
30#include <vector>
31
32using namespace android;
33using namespace std;
34
Yi Jinb592e3b2018-02-01 15:17:04 -080035status_t create_directory(const char* directory) {
Joe Onorato1754d742016-11-21 17:51:35 -080036 struct stat st;
37 status_t err = NO_ERROR;
38 char* dir = strdup(directory);
39
40 // Skip first slash
41 char* d = dir + 1;
42
43 // Create directories, assigning them to the system user
44 bool last = false;
45 while (!last) {
46 d = strchr(d, '/');
47 if (d != NULL) {
48 *d = '\0';
49 } else {
50 last = true;
51 }
52 if (stat(dir, &st) == 0) {
53 if (!S_ISDIR(st.st_mode)) {
54 err = ALREADY_EXISTS;
55 goto done;
56 }
57 } else {
Yi Jin4bab3a12018-01-10 16:50:59 -080058 ALOGE("No such directory %s, something wrong.", dir);
59 err = -1;
60 goto done;
Joe Onorato1754d742016-11-21 17:51:35 -080061 }
62 if (!last) {
63 *d++ = '/';
64 }
65 }
66
67 // Ensure that the final directory is owned by the system with 0770. If it isn't
68 // we won't write into it.
69 if (stat(directory, &st) != 0) {
70 ALOGE("No incident reports today. Can't stat: %s", directory);
71 err = -errno;
72 goto done;
73 }
74 if ((st.st_mode & 0777) != 0770) {
Yi Jinb592e3b2018-02-01 15:17:04 -080075 ALOGE("No incident reports today. Mode is %0o on report directory %s", st.st_mode,
76 directory);
Joe Onorato1754d742016-11-21 17:51:35 -080077 err = BAD_VALUE;
78 goto done;
79 }
Yi Jin4bab3a12018-01-10 16:50:59 -080080 if (st.st_uid != AID_INCIDENTD || st.st_gid != AID_INCIDENTD) {
Joe Onorato1754d742016-11-21 17:51:35 -080081 ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s",
Yi Jinb592e3b2018-02-01 15:17:04 -080082 st.st_uid, st.st_gid, directory);
Joe Onorato1754d742016-11-21 17:51:35 -080083 err = BAD_VALUE;
84 goto done;
85 }
86
87done:
88 free(dir);
89 return err;
90}
91
Yi Jinb592e3b2018-02-01 15:17:04 -080092static bool stat_mtime_cmp(const pair<String8, struct stat>& a,
93 const pair<String8, struct stat>& b) {
Joe Onorato1754d742016-11-21 17:51:35 -080094 return a.second.st_mtime < b.second.st_mtime;
95}
96
Yi Jinb592e3b2018-02-01 15:17:04 -080097void clean_directory(const char* directory, off_t maxSize, size_t maxCount) {
Joe Onorato1754d742016-11-21 17:51:35 -080098 DIR* dir;
99 struct dirent* entry;
100 struct stat st;
101
Yi Jinb592e3b2018-02-01 15:17:04 -0800102 vector<pair<String8, struct stat>> files;
Joe Onorato1754d742016-11-21 17:51:35 -0800103
104 if ((dir = opendir(directory)) == NULL) {
105 ALOGE("Couldn't open incident directory: %s", directory);
106 return;
107 }
108
Yi Jinadd11e92017-07-30 16:10:07 -0700109 String8 dirbase(directory);
110 if (directory[dirbase.size() - 1] != '/') dirbase += "/";
Joe Onorato1754d742016-11-21 17:51:35 -0800111
112 off_t totalSize = 0;
113 size_t totalCount = 0;
114
115 // Enumerate, count and add up size
116 while ((entry = readdir(dir)) != NULL) {
117 if (entry->d_name[0] == '.') {
118 continue;
119 }
120 String8 filename = dirbase + entry->d_name;
121 if (stat(filename.string(), &st) != 0) {
122 ALOGE("Unable to stat file %s", filename.string());
123 continue;
124 }
125 if (!S_ISREG(st.st_mode)) {
126 continue;
127 }
Yi Jinb592e3b2018-02-01 15:17:04 -0800128 files.push_back(pair<String8, struct stat>(filename, st));
Joe Onorato1754d742016-11-21 17:51:35 -0800129
130 totalSize += st.st_size;
131 totalCount++;
132 }
133
134 closedir(dir);
135
136 // Count or size is less than max, then we're done.
137 if (totalSize < maxSize && totalCount < maxCount) {
138 return;
139 }
140
141 // Oldest files first.
142 sort(files.begin(), files.end(), stat_mtime_cmp);
143
144 // Remove files until we're under our limits.
Yi Jinb592e3b2018-02-01 15:17:04 -0800145 for (vector<pair<String8, struct stat>>::iterator it = files.begin();
146 it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
Joe Onorato1754d742016-11-21 17:51:35 -0800147 remove(it->first.string());
148 totalSize -= it->second.st_size;
149 totalCount--;
150 }
151}