blob: 5c2ad2dceefa32adc5c91607c04a338fca0dc024 [file] [log] [blame]
Mike Lockwood94afecf2012-10-24 10:45:23 -07001/*
2** Copyright 2008, The Android Open Source Project
3**
Dave Allisond9370732014-01-30 14:19:23 -08004** 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
Mike Lockwood94afecf2012-10-24 10:45:23 -07007**
Dave Allisond9370732014-01-30 14:19:23 -08008** http://www.apache.org/licenses/LICENSE-2.0
Mike Lockwood94afecf2012-10-24 10:45:23 -07009**
Dave Allisond9370732014-01-30 14:19:23 -080010** 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
Mike Lockwood94afecf2012-10-24 10:45:23 -070014** limitations under the License.
15*/
16
Andreas Gampe02d0de52015-11-11 20:43:16 -080017#include "utils.h"
Mike Lockwood94afecf2012-10-24 10:45:23 -070018
Andreas Gampe02d0de52015-11-11 20:43:16 -080019#include <errno.h>
20#include <fcntl.h>
21#include <stdlib.h>
22#include <sys/stat.h>
23#include <sys/wait.h>
24
25#if defined(__APPLE__)
26#include <sys/mount.h>
27#else
28#include <sys/statfs.h>
29#endif
30
Elliott Hughese4ec9eb2015-12-04 15:39:32 -080031#include <android-base/logging.h>
Andreas Gampe02d0de52015-11-11 20:43:16 -080032#include <android-base/stringprintf.h>
33#include <cutils/fs.h>
34#include <cutils/log.h>
35#include <private/android_filesystem_config.h>
Jeff Sharkeyc03de092015-04-07 18:14:05 -070036
Andreas Gampe02d0de52015-11-11 20:43:16 -080037#include "globals.h" // extern variables.
38
39#ifndef LOG_TAG
40#define LOG_TAG "installd"
41#endif
Mike Lockwood94afecf2012-10-24 10:45:23 -070042#define CACHE_NOISY(x) //x
43
Jeff Sharkeyc03de092015-04-07 18:14:05 -070044using android::base::StringPrintf;
Mike Lockwood94afecf2012-10-24 10:45:23 -070045
Andreas Gampe02d0de52015-11-11 20:43:16 -080046namespace android {
47namespace installd {
48
Jeff Sharkeyc03de092015-04-07 18:14:05 -070049/**
50 * Check that given string is valid filename, and that it attempts no
51 * parent or child directory traversal.
52 */
53static bool is_valid_filename(const std::string& name) {
54 if (name.empty() || (name == ".") || (name == "..")
55 || (name.find('/') != std::string::npos)) {
56 return false;
57 } else {
58 return true;
59 }
Mike Lockwood94afecf2012-10-24 10:45:23 -070060}
61
Calin Juravle6a1648e2016-02-01 12:12:16 +000062static void check_package_name(const char* package_name) {
63 CHECK(is_valid_filename(package_name));
64 CHECK(is_valid_package_name(package_name) == 0);
65}
66
Mike Lockwood94afecf2012-10-24 10:45:23 -070067/**
Jeff Sharkeyd7921182015-04-30 15:58:19 -070068 * Create the path name where package app contents should be stored for
69 * the given volume UUID and package name. An empty UUID is assumed to
70 * be internal storage.
71 */
72std::string create_data_app_package_path(const char* volume_uuid,
73 const char* package_name) {
Calin Juravle6a1648e2016-02-01 12:12:16 +000074 check_package_name(package_name);
Jeff Sharkeyd7921182015-04-30 15:58:19 -070075 return StringPrintf("%s/%s",
76 create_data_app_path(volume_uuid).c_str(), package_name);
77}
78
79/**
Jeff Sharkeyc03de092015-04-07 18:14:05 -070080 * Create the path name where package data should be stored for the given
81 * volume UUID, package name, and user ID. An empty UUID is assumed to be
82 * internal storage.
Mike Lockwood94afecf2012-10-24 10:45:23 -070083 */
Jeff Sharkey2f720f72016-04-10 20:51:40 -060084std::string create_data_user_ce_package_path(const char* volume_uuid,
Jeff Sharkeyd7921182015-04-30 15:58:19 -070085 userid_t user, const char* package_name) {
Calin Juravle6a1648e2016-02-01 12:12:16 +000086 check_package_name(package_name);
Jeff Sharkeyd7921182015-04-30 15:58:19 -070087 return StringPrintf("%s/%s",
Jeff Sharkey2f720f72016-04-10 20:51:40 -060088 create_data_user_ce_path(volume_uuid, user).c_str(), package_name);
89}
90
91std::string create_data_user_ce_package_path(const char* volume_uuid, userid_t user,
92 const char* package_name, ino_t ce_data_inode) {
93 // For testing purposes, rely on the inode when defined; this could be
94 // optimized to use access() in the future.
95 auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name);
96 if (ce_data_inode != 0) {
97 auto user_path = create_data_user_ce_path(volume_uuid, user);
98 DIR* dir = opendir(user_path.c_str());
99 if (dir == nullptr) {
100 PLOG(ERROR) << "Failed to opendir " << user_path;
101 return fallback;
102 }
103
104 struct dirent* ent;
105 while ((ent = readdir(dir))) {
106 if (ent->d_ino == ce_data_inode) {
Jeff Sharkey1d992f92016-04-13 13:45:47 -0600107 auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
108 if (resolved != fallback) {
109 LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
110 << " instead of " << fallback;
111 }
Jeff Sharkey2f720f72016-04-10 20:51:40 -0600112 closedir(dir);
Jeff Sharkey1d992f92016-04-13 13:45:47 -0600113 return resolved;
Jeff Sharkey2f720f72016-04-10 20:51:40 -0600114 }
115 }
Jeff Sharkey1d992f92016-04-13 13:45:47 -0600116 LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
Jeff Sharkey2f720f72016-04-10 20:51:40 -0600117 closedir(dir);
118 return fallback;
119 } else {
120 return fallback;
121 }
Jeff Sharkeyc03de092015-04-07 18:14:05 -0700122}
Mike Lockwood94afecf2012-10-24 10:45:23 -0700123
Jeff Sharkey63ec2d62015-11-09 13:10:36 -0800124std::string create_data_user_de_package_path(const char* volume_uuid,
125 userid_t user, const char* package_name) {
Calin Juravle6a1648e2016-02-01 12:12:16 +0000126 check_package_name(package_name);
Jeff Sharkey63ec2d62015-11-09 13:10:36 -0800127 return StringPrintf("%s/%s",
128 create_data_user_de_path(volume_uuid, user).c_str(), package_name);
129}
130
Jeff Sharkeyc03de092015-04-07 18:14:05 -0700131int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
132 const char *postfix, userid_t userid) {
133 if (is_valid_package_name(pkgname) != 0) {
134 path[0] = '\0';
Mike Lockwood94afecf2012-10-24 10:45:23 -0700135 return -1;
136 }
137
Jeff Sharkey2f720f72016-04-10 20:51:40 -0600138 std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
Jeff Sharkeyc03de092015-04-07 18:14:05 -0700139 const char* tmp = _tmp.c_str();
140 if (strlen(tmp) >= PKG_PATH_MAX) {
141 path[0] = '\0';
142 return -1;
143 } else {
144 strcpy(path, tmp);
145 return 0;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700146 }
Mike Lockwood94afecf2012-10-24 10:45:23 -0700147}
148
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700149std::string create_data_path(const char* volume_uuid) {
150 if (volume_uuid == nullptr) {
151 return "/data";
152 } else {
153 CHECK(is_valid_filename(volume_uuid));
154 return StringPrintf("/mnt/expand/%s", volume_uuid);
155 }
156}
157
Mike Lockwood94afecf2012-10-24 10:45:23 -0700158/**
Jeff Sharkeyd7921182015-04-30 15:58:19 -0700159 * Create the path name for app data.
160 */
161std::string create_data_app_path(const char* volume_uuid) {
162 return StringPrintf("%s/app", create_data_path(volume_uuid).c_str());
163}
164
165/**
Jeff Sharkeyabe4fe52013-07-10 16:55:46 -0700166 * Create the path name for user data for a certain userid.
Mike Lockwood94afecf2012-10-24 10:45:23 -0700167 */
Jeff Sharkey2f720f72016-04-10 20:51:40 -0600168std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700169 std::string data(create_data_path(volume_uuid));
170 if (volume_uuid == nullptr) {
171 if (userid == 0) {
172 return StringPrintf("%s/data", data.c_str());
173 } else {
174 return StringPrintf("%s/user/%u", data.c_str(), userid);
175 }
Mike Lockwood94afecf2012-10-24 10:45:23 -0700176 } else {
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700177 return StringPrintf("%s/user/%u", data.c_str(), userid);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700178 }
Mike Lockwood94afecf2012-10-24 10:45:23 -0700179}
180
181/**
Jeff Sharkey63ec2d62015-11-09 13:10:36 -0800182 * Create the path name for device encrypted user data for a certain userid.
183 */
184std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) {
185 std::string data(create_data_path(volume_uuid));
186 return StringPrintf("%s/user_de/%u", data.c_str(), userid);
187}
188
189/**
Jeff Sharkeyabe4fe52013-07-10 16:55:46 -0700190 * Create the path name for media for a certain userid.
Mike Lockwood94afecf2012-10-24 10:45:23 -0700191 */
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700192std::string create_data_media_path(const char* volume_uuid, userid_t userid) {
193 return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700194}
195
Calin Juravle6a1648e2016-02-01 12:12:16 +0000196std::string create_data_user_profiles_path(userid_t userid) {
197 return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
198}
199
200std::string create_data_user_profile_package_path(userid_t user, const char* package_name) {
201 check_package_name(package_name);
202 return StringPrintf("%s/%s",create_data_user_profiles_path(user).c_str(), package_name);
203}
204
205std::string create_data_ref_profile_package_path(const char* package_name) {
206 check_package_name(package_name);
207 return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name);
208}
209
Jeff Sharkeye3637242015-04-08 20:56:42 -0700210std::vector<userid_t> get_known_users(const char* volume_uuid) {
211 std::vector<userid_t> users;
212
213 // We always have an owner
214 users.push_back(0);
215
216 std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
217 DIR* dir = opendir(path.c_str());
218 if (dir == NULL) {
219 // Unable to discover other users, but at least return owner
220 PLOG(ERROR) << "Failed to opendir " << path;
221 return users;
222 }
223
224 struct dirent* ent;
225 while ((ent = readdir(dir))) {
226 if (ent->d_type != DT_DIR) {
227 continue;
228 }
229
230 char* end;
231 userid_t user = strtol(ent->d_name, &end, 10);
232 if (*end == '\0' && user != 0) {
233 LOG(DEBUG) << "Found valid user " << user;
234 users.push_back(user);
235 }
236 }
237 closedir(dir);
238
239 return users;
240}
241
Robin Lee095c7632014-04-25 15:05:19 +0100242/**
243 * Create the path name for config for a certain userid.
244 * Returns 0 on success, and -1 on failure.
245 */
246int create_user_config_path(char path[PATH_MAX], userid_t userid) {
247 if (snprintf(path, PATH_MAX, "%s%d", "/data/misc/user/", userid) > PATH_MAX) {
248 return -1;
249 }
250 return 0;
251}
252
Mike Lockwood94afecf2012-10-24 10:45:23 -0700253int create_move_path(char path[PKG_PATH_MAX],
254 const char* pkgname,
255 const char* leaf,
Andreas Gampe02d0de52015-11-11 20:43:16 -0800256 userid_t userid ATTRIBUTE_UNUSED)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700257{
258 if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
259 >= PKG_PATH_MAX) {
260 return -1;
261 }
262
263 sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
264 return 0;
265}
266
267/**
268 * Checks whether the package name is valid. Returns -1 on error and
269 * 0 on success.
270 */
271int is_valid_package_name(const char* pkgname) {
272 const char *x = pkgname;
273 int alpha = -1;
274
Jeff Sharkeyc03de092015-04-07 18:14:05 -0700275 if (strlen(pkgname) > PKG_NAME_MAX) {
276 return -1;
277 }
278
Mike Lockwood94afecf2012-10-24 10:45:23 -0700279 while (*x) {
280 if (isalnum(*x) || (*x == '_')) {
281 /* alphanumeric or underscore are fine */
282 } else if (*x == '.') {
283 if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) {
284 /* periods must not be first, last, or doubled */
285 ALOGE("invalid package name '%s'\n", pkgname);
286 return -1;
287 }
288 } else if (*x == '-') {
289 /* Suffix -X is fine to let versioning of packages.
290 But whatever follows should be alphanumeric.*/
291 alpha = 1;
292 } else {
293 /* anything not A-Z, a-z, 0-9, _, or . is invalid */
294 ALOGE("invalid package name '%s'\n", pkgname);
295 return -1;
296 }
297
298 x++;
299 }
300
301 if (alpha == 1) {
302 // Skip current character
303 x++;
304 while (*x) {
305 if (!isalnum(*x)) {
306 ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
307 return -1;
308 }
309 x++;
310 }
311 }
312
313 return 0;
314}
315
Narayan Kamath3aee2c52014-06-10 13:16:47 +0100316static int _delete_dir_contents(DIR *d,
317 int (*exclusion_predicate)(const char *name, const int is_dir))
Mike Lockwood94afecf2012-10-24 10:45:23 -0700318{
319 int result = 0;
320 struct dirent *de;
321 int dfd;
322
323 dfd = dirfd(d);
324
325 if (dfd < 0) return -1;
326
327 while ((de = readdir(d))) {
328 const char *name = de->d_name;
329
Narayan Kamath3aee2c52014-06-10 13:16:47 +0100330 /* check using the exclusion predicate, if provided */
331 if (exclusion_predicate && exclusion_predicate(name, (de->d_type == DT_DIR))) {
332 continue;
333 }
Mike Lockwood94afecf2012-10-24 10:45:23 -0700334
335 if (de->d_type == DT_DIR) {
Chih-Hung Hsieh99d9fb12014-09-11 14:44:46 -0700336 int subfd;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700337 DIR *subdir;
338
339 /* always skip "." and ".." */
340 if (name[0] == '.') {
341 if (name[1] == 0) continue;
342 if ((name[1] == '.') && (name[2] == 0)) continue;
343 }
344
Nick Kralevich8b7acac2015-08-10 13:43:00 -0700345 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700346 if (subfd < 0) {
347 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
348 result = -1;
349 continue;
350 }
351 subdir = fdopendir(subfd);
352 if (subdir == NULL) {
353 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
354 close(subfd);
355 result = -1;
356 continue;
357 }
Narayan Kamath3aee2c52014-06-10 13:16:47 +0100358 if (_delete_dir_contents(subdir, exclusion_predicate)) {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700359 result = -1;
360 }
361 closedir(subdir);
362 if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
363 ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
364 result = -1;
365 }
366 } else {
367 if (unlinkat(dfd, name, 0) < 0) {
368 ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
369 result = -1;
370 }
371 }
372 }
373
374 return result;
375}
376
Calin Juravleb06f98a2016-03-28 15:11:01 +0100377int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
378 return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing);
Jeff Sharkeyebf728f2015-11-18 14:15:17 -0700379}
380
Calin Juravleb06f98a2016-03-28 15:11:01 +0100381int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
382 return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing);
Jeff Sharkeyebf728f2015-11-18 14:15:17 -0700383}
384
Mike Lockwood94afecf2012-10-24 10:45:23 -0700385int delete_dir_contents(const char *pathname,
386 int also_delete_dir,
Calin Juravleb06f98a2016-03-28 15:11:01 +0100387 int (*exclusion_predicate)(const char*, const int),
388 bool ignore_if_missing)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700389{
390 int res = 0;
391 DIR *d;
392
393 d = opendir(pathname);
394 if (d == NULL) {
Calin Juravleb06f98a2016-03-28 15:11:01 +0100395 if (ignore_if_missing && (errno == ENOENT)) {
396 return 0;
397 }
Mike Lockwood94afecf2012-10-24 10:45:23 -0700398 ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno));
399 return -errno;
400 }
Narayan Kamath3aee2c52014-06-10 13:16:47 +0100401 res = _delete_dir_contents(d, exclusion_predicate);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700402 closedir(d);
403 if (also_delete_dir) {
404 if (rmdir(pathname)) {
405 ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno));
406 res = -1;
407 }
408 }
409 return res;
410}
411
412int delete_dir_contents_fd(int dfd, const char *name)
413{
414 int fd, res;
415 DIR *d;
416
Nick Kralevich8b7acac2015-08-10 13:43:00 -0700417 fd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700418 if (fd < 0) {
419 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
420 return -1;
421 }
422 d = fdopendir(fd);
423 if (d == NULL) {
424 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
425 close(fd);
426 return -1;
427 }
428 res = _delete_dir_contents(d, 0);
429 closedir(d);
430 return res;
431}
432
Robin Lee60fd3fe2014-10-07 16:55:02 +0100433static int _copy_owner_permissions(int srcfd, int dstfd)
434{
435 struct stat st;
436 if (fstat(srcfd, &st) != 0) {
437 return -1;
438 }
439 if (fchmod(dstfd, st.st_mode) != 0) {
440 return -1;
441 }
442 return 0;
443}
444
445static int _copy_dir_files(int sdfd, int ddfd, uid_t owner, gid_t group)
446{
447 int result = 0;
448 if (_copy_owner_permissions(sdfd, ddfd) != 0) {
449 ALOGE("_copy_dir_files failed to copy dir permissions\n");
450 }
451 if (fchown(ddfd, owner, group) != 0) {
452 ALOGE("_copy_dir_files failed to change dir owner\n");
453 }
454
455 DIR *ds = fdopendir(sdfd);
456 if (ds == NULL) {
457 ALOGE("Couldn't fdopendir: %s\n", strerror(errno));
458 return -1;
459 }
460 struct dirent *de;
461 while ((de = readdir(ds))) {
462 if (de->d_type != DT_REG) {
463 continue;
464 }
465
466 const char *name = de->d_name;
467 int fsfd = openat(sdfd, name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
468 int fdfd = openat(ddfd, name, O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_CREAT, 0600);
469 if (fsfd == -1 || fdfd == -1) {
470 ALOGW("Couldn't copy %s: %s\n", name, strerror(errno));
471 } else {
472 if (_copy_owner_permissions(fsfd, fdfd) != 0) {
473 ALOGE("Failed to change file permissions\n");
474 }
475 if (fchown(fdfd, owner, group) != 0) {
476 ALOGE("Failed to change file owner\n");
477 }
478
479 char buf[8192];
480 ssize_t size;
481 while ((size = read(fsfd, buf, sizeof(buf))) > 0) {
482 write(fdfd, buf, size);
483 }
484 if (size < 0) {
485 ALOGW("Couldn't copy %s: %s\n", name, strerror(errno));
486 result = -1;
487 }
488 }
489 close(fdfd);
490 close(fsfd);
491 }
492
493 return result;
494}
495
496int copy_dir_files(const char *srcname,
497 const char *dstname,
498 uid_t owner,
499 uid_t group)
500{
501 int res = 0;
502 DIR *ds = NULL;
503 DIR *dd = NULL;
504
505 ds = opendir(srcname);
506 if (ds == NULL) {
507 ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno));
508 return -errno;
509 }
510
511 mkdir(dstname, 0600);
512 dd = opendir(dstname);
513 if (dd == NULL) {
514 ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno));
515 closedir(ds);
516 return -errno;
517 }
518
519 int sdfd = dirfd(ds);
520 int ddfd = dirfd(dd);
521 if (sdfd != -1 && ddfd != -1) {
522 res = _copy_dir_files(sdfd, ddfd, owner, group);
523 } else {
524 res = -errno;
525 }
526 closedir(dd);
527 closedir(ds);
528 return res;
529}
530
Mike Lockwood94afecf2012-10-24 10:45:23 -0700531int lookup_media_dir(char basepath[PATH_MAX], const char *dir)
532{
533 DIR *d;
534 struct dirent *de;
535 struct stat s;
536 char* dirpos = basepath + strlen(basepath);
537
538 if ((*(dirpos-1)) != '/') {
539 *dirpos = '/';
540 dirpos++;
541 }
542
543 CACHE_NOISY(ALOGI("Looking up %s in %s\n", dir, basepath));
544 // Verify the path won't extend beyond our buffer, to avoid
545 // repeated checking later.
546 if ((dirpos-basepath+strlen(dir)) >= (PATH_MAX-1)) {
547 ALOGW("Path exceeds limit: %s%s", basepath, dir);
548 return -1;
549 }
550
551 // First, can we find this directory with the case that is given?
552 strcpy(dirpos, dir);
553 if (stat(basepath, &s) >= 0) {
554 CACHE_NOISY(ALOGI("Found direct: %s\n", basepath));
555 return 0;
556 }
557
558 // Not found with that case... search through all entries to find
559 // one that matches regardless of case.
560 *dirpos = 0;
561
562 d = opendir(basepath);
563 if (d == NULL) {
564 return -1;
565 }
566
567 while ((de = readdir(d))) {
568 if (strcasecmp(de->d_name, dir) == 0) {
569 strcpy(dirpos, de->d_name);
570 closedir(d);
571 CACHE_NOISY(ALOGI("Found search: %s\n", basepath));
572 return 0;
573 }
574 }
575
576 ALOGW("Couldn't find %s in %s", dir, basepath);
577 closedir(d);
578 return -1;
579}
580
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700581int64_t data_disk_free(const std::string& data_path)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700582{
583 struct statfs sfs;
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700584 if (statfs(data_path.c_str(), &sfs) == 0) {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700585 return sfs.f_bavail * sfs.f_bsize;
586 } else {
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700587 PLOG(ERROR) << "Couldn't statfs " << data_path;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700588 return -1;
589 }
590}
591
592cache_t* start_cache_collection()
593{
594 cache_t* cache = (cache_t*)calloc(1, sizeof(cache_t));
595 return cache;
596}
597
598#define CACHE_BLOCK_SIZE (512*1024)
599
600static void* _cache_malloc(cache_t* cache, size_t len)
601{
602 len = (len+3)&~3;
603 if (len > (CACHE_BLOCK_SIZE/2)) {
604 // It doesn't make sense to try to put this allocation into one
605 // of our blocks, because it is so big. Instead, make a new dedicated
606 // block for it.
607 int8_t* res = (int8_t*)malloc(len+sizeof(void*));
608 if (res == NULL) {
609 return NULL;
610 }
611 CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %d", res, len));
612 // Link it into our list of blocks, not disrupting the current one.
613 if (cache->memBlocks == NULL) {
614 *(void**)res = NULL;
615 cache->memBlocks = res;
616 } else {
617 *(void**)res = *(void**)cache->memBlocks;
618 *(void**)cache->memBlocks = res;
619 }
620 return res + sizeof(void*);
621 }
622 int8_t* res = cache->curMemBlockAvail;
623 int8_t* nextPos = res + len;
624 if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) {
Jeff Sharkey19803802015-04-07 12:44:51 -0700625 int8_t* newBlock = (int8_t*) malloc(CACHE_BLOCK_SIZE);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700626 if (newBlock == NULL) {
627 return NULL;
628 }
629 CACHE_NOISY(ALOGI("Allocated new cache mem block: %p", newBlock));
630 *(void**)newBlock = cache->memBlocks;
631 cache->memBlocks = newBlock;
632 res = cache->curMemBlockAvail = newBlock + sizeof(void*);
633 cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE;
634 nextPos = res + len;
635 }
636 CACHE_NOISY(ALOGI("cache_malloc: ret %p size %d, block=%p, nextPos=%p",
637 res, len, cache->memBlocks, nextPos));
638 cache->curMemBlockAvail = nextPos;
639 return res;
640}
641
642static void* _cache_realloc(cache_t* cache, void* cur, size_t origLen, size_t len)
643{
644 // This isn't really a realloc, but it is good enough for our purposes here.
645 void* alloc = _cache_malloc(cache, len);
646 if (alloc != NULL && cur != NULL) {
647 memcpy(alloc, cur, origLen < len ? origLen : len);
648 }
649 return alloc;
650}
651
652static void _inc_num_cache_collected(cache_t* cache)
653{
654 cache->numCollected++;
655 if ((cache->numCollected%20000) == 0) {
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700656 ALOGI("Collected cache so far: %zd directories, %zd files",
Mike Lockwood94afecf2012-10-24 10:45:23 -0700657 cache->numDirs, cache->numFiles);
658 }
659}
660
661static cache_dir_t* _add_cache_dir_t(cache_t* cache, cache_dir_t* parent, const char *name)
662{
663 size_t nameLen = strlen(name);
664 cache_dir_t* dir = (cache_dir_t*)_cache_malloc(cache, sizeof(cache_dir_t)+nameLen+1);
665 if (dir != NULL) {
666 dir->parent = parent;
667 dir->childCount = 0;
668 dir->hiddenCount = 0;
669 dir->deleted = 0;
670 strcpy(dir->name, name);
671 if (cache->numDirs >= cache->availDirs) {
672 size_t newAvail = cache->availDirs < 1000 ? 1000 : cache->availDirs*2;
673 cache_dir_t** newDirs = (cache_dir_t**)_cache_realloc(cache, cache->dirs,
674 cache->availDirs*sizeof(cache_dir_t*), newAvail*sizeof(cache_dir_t*));
675 if (newDirs == NULL) {
676 ALOGE("Failure growing cache dirs array for %s\n", name);
677 return NULL;
678 }
679 cache->availDirs = newAvail;
680 cache->dirs = newDirs;
681 }
682 cache->dirs[cache->numDirs] = dir;
683 cache->numDirs++;
684 if (parent != NULL) {
685 parent->childCount++;
686 }
687 _inc_num_cache_collected(cache);
688 } else {
689 ALOGE("Failure allocating cache_dir_t for %s\n", name);
690 }
691 return dir;
692}
693
694static cache_file_t* _add_cache_file_t(cache_t* cache, cache_dir_t* dir, time_t modTime,
695 const char *name)
696{
697 size_t nameLen = strlen(name);
698 cache_file_t* file = (cache_file_t*)_cache_malloc(cache, sizeof(cache_file_t)+nameLen+1);
699 if (file != NULL) {
700 file->dir = dir;
701 file->modTime = modTime;
702 strcpy(file->name, name);
703 if (cache->numFiles >= cache->availFiles) {
704 size_t newAvail = cache->availFiles < 1000 ? 1000 : cache->availFiles*2;
705 cache_file_t** newFiles = (cache_file_t**)_cache_realloc(cache, cache->files,
706 cache->availFiles*sizeof(cache_file_t*), newAvail*sizeof(cache_file_t*));
707 if (newFiles == NULL) {
708 ALOGE("Failure growing cache file array for %s\n", name);
709 return NULL;
710 }
711 cache->availFiles = newAvail;
712 cache->files = newFiles;
713 }
714 CACHE_NOISY(ALOGI("Setting file %p at position %d in array %p", file,
715 cache->numFiles, cache->files));
716 cache->files[cache->numFiles] = file;
717 cache->numFiles++;
718 dir->childCount++;
719 _inc_num_cache_collected(cache);
720 } else {
721 ALOGE("Failure allocating cache_file_t for %s\n", name);
722 }
723 return file;
724}
725
726static int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName,
727 DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen)
728{
729 struct dirent *de;
730 cache_dir_t* cacheDir = NULL;
731 int dfd;
732
733 CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s",
734 parentDir, dirName, dir, pathBase));
735
736 dfd = dirfd(dir);
737
738 if (dfd < 0) return 0;
739
740 // Sub-directories always get added to the data structure, so if they
741 // are empty we will know about them to delete them later.
742 cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
743
744 while ((de = readdir(dir))) {
745 const char *name = de->d_name;
746
747 if (de->d_type == DT_DIR) {
748 int subfd;
749 DIR *subdir;
750
751 /* always skip "." and ".." */
752 if (name[0] == '.') {
753 if (name[1] == 0) continue;
754 if ((name[1] == '.') && (name[2] == 0)) continue;
755 }
756
Nick Kralevich8b7acac2015-08-10 13:43:00 -0700757 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700758 if (subfd < 0) {
759 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
760 continue;
761 }
762 subdir = fdopendir(subfd);
763 if (subdir == NULL) {
764 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
765 close(subfd);
766 continue;
767 }
768 if (cacheDir == NULL) {
769 cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
770 }
771 if (cacheDir != NULL) {
772 // Update pathBase for the new path... this may change dirName
773 // if that is also pointing to the path, but we are done with it
774 // now.
775 size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
776 CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase));
777 if (finallen < pathAvailLen) {
778 _add_cache_files(cache, cacheDir, name, subdir, pathBase,
779 pathPos+finallen, pathAvailLen-finallen);
780 } else {
781 // Whoops, the final path is too long! We'll just delete
782 // this directory.
783 ALOGW("Cache dir %s truncated in path %s; deleting dir\n",
784 name, pathBase);
785 _delete_dir_contents(subdir, NULL);
786 if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
787 ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
788 }
789 }
790 }
791 closedir(subdir);
792 } else if (de->d_type == DT_REG) {
793 // Skip files that start with '.'; they will be deleted if
794 // their entire directory is deleted. This allows for metadata
795 // like ".nomedia" to remain in the directory until the entire
796 // directory is deleted.
797 if (cacheDir == NULL) {
798 cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
799 }
800 if (name[0] == '.') {
801 cacheDir->hiddenCount++;
802 continue;
803 }
804 if (cacheDir != NULL) {
805 // Build final full path for file... this may change dirName
806 // if that is also pointing to the path, but we are done with it
807 // now.
808 size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
809 CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase));
810 if (finallen < pathAvailLen) {
811 struct stat s;
812 if (stat(pathBase, &s) >= 0) {
813 _add_cache_file_t(cache, cacheDir, s.st_mtime, name);
814 } else {
815 ALOGW("Unable to stat cache file %s; deleting\n", pathBase);
816 if (unlink(pathBase) < 0) {
817 ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno));
818 }
819 }
820 } else {
821 // Whoops, the final path is too long! We'll just delete
822 // this file.
823 ALOGW("Cache file %s truncated in path %s; deleting\n",
824 name, pathBase);
825 if (unlinkat(dfd, name, 0) < 0) {
826 *pathPos = 0;
827 ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase,
828 strerror(errno));
829 }
830 }
831 }
832 } else {
833 cacheDir->hiddenCount++;
834 }
835 }
836 return 0;
837}
838
839void add_cache_files(cache_t* cache, const char *basepath, const char *cachedir)
840{
841 DIR *d;
842 struct dirent *de;
843 char dirname[PATH_MAX];
844
845 CACHE_NOISY(ALOGI("add_cache_files: base=%s cachedir=%s\n", basepath, cachedir));
846
847 d = opendir(basepath);
848 if (d == NULL) {
849 return;
850 }
851
852 while ((de = readdir(d))) {
853 if (de->d_type == DT_DIR) {
854 DIR* subdir;
855 const char *name = de->d_name;
856 char* pathpos;
857
858 /* always skip "." and ".." */
859 if (name[0] == '.') {
860 if (name[1] == 0) continue;
861 if ((name[1] == '.') && (name[2] == 0)) continue;
862 }
863
864 strcpy(dirname, basepath);
865 pathpos = dirname + strlen(dirname);
866 if ((*(pathpos-1)) != '/') {
867 *pathpos = '/';
868 pathpos++;
869 *pathpos = 0;
870 }
871 if (cachedir != NULL) {
872 snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s/%s", name, cachedir);
873 } else {
874 snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s", name);
875 }
876 CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname));
877 subdir = opendir(dirname);
878 if (subdir != NULL) {
879 size_t dirnameLen = strlen(dirname);
880 _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname+dirnameLen,
881 PATH_MAX - dirnameLen);
882 closedir(subdir);
883 }
884 }
885 }
886
887 closedir(d);
888}
889
890static char *create_dir_path(char path[PATH_MAX], cache_dir_t* dir)
891{
892 char *pos = path;
893 if (dir->parent != NULL) {
894 pos = create_dir_path(path, dir->parent);
895 }
896 // Note that we don't need to worry about going beyond the buffer,
897 // since when we were constructing the cache entries our maximum
898 // buffer size for full paths was PATH_MAX.
899 strcpy(pos, dir->name);
900 pos += strlen(pos);
901 *pos = '/';
902 pos++;
903 *pos = 0;
904 return pos;
905}
906
907static void delete_cache_dir(char path[PATH_MAX], cache_dir_t* dir)
908{
909 if (dir->parent != NULL) {
910 create_dir_path(path, dir);
911 ALOGI("DEL DIR %s\n", path);
912 if (dir->hiddenCount <= 0) {
913 if (rmdir(path)) {
914 ALOGE("Couldn't rmdir %s: %s\n", path, strerror(errno));
915 return;
916 }
917 } else {
918 // The directory contains hidden files so we need to delete
919 // them along with the directory itself.
920 if (delete_dir_contents(path, 1, NULL)) {
921 return;
922 }
923 }
924 dir->parent->childCount--;
925 dir->deleted = 1;
926 if (dir->parent->childCount <= 0) {
927 delete_cache_dir(path, dir->parent);
928 }
929 } else if (dir->hiddenCount > 0) {
930 // This is a root directory, but it has hidden files. Get rid of
931 // all of those files, but not the directory itself.
932 create_dir_path(path, dir);
933 ALOGI("DEL CONTENTS %s\n", path);
934 delete_dir_contents(path, 0, NULL);
935 }
936}
937
938static int cache_modtime_sort(const void *lhsP, const void *rhsP)
939{
940 const cache_file_t *lhs = *(const cache_file_t**)lhsP;
941 const cache_file_t *rhs = *(const cache_file_t**)rhsP;
942 return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0);
943}
944
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700945void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700946{
947 size_t i;
948 int skip = 0;
949 char path[PATH_MAX];
950
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700951 ALOGI("Collected cache files: %zd directories, %zd files",
Mike Lockwood94afecf2012-10-24 10:45:23 -0700952 cache->numDirs, cache->numFiles);
953
954 CACHE_NOISY(ALOGI("Sorting files..."));
955 qsort(cache->files, cache->numFiles, sizeof(cache_file_t*),
956 cache_modtime_sort);
957
958 CACHE_NOISY(ALOGI("Cleaning empty directories..."));
959 for (i=cache->numDirs; i>0; i--) {
960 cache_dir_t* dir = cache->dirs[i-1];
961 if (dir->childCount <= 0 && !dir->deleted) {
962 delete_cache_dir(path, dir);
963 }
964 }
965
966 CACHE_NOISY(ALOGI("Trimming files..."));
967 for (i=0; i<cache->numFiles; i++) {
968 skip++;
969 if (skip > 10) {
Jeff Sharkey41ea4242015-04-09 11:34:03 -0700970 if (data_disk_free(data_path) > free_size) {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700971 return;
972 }
973 skip = 0;
974 }
975 cache_file_t* file = cache->files[i];
976 strcpy(create_dir_path(path, file->dir), file->name);
977 ALOGI("DEL (mod %d) %s\n", (int)file->modTime, path);
978 if (unlink(path) < 0) {
979 ALOGE("Couldn't unlink %s: %s\n", path, strerror(errno));
980 }
981 file->dir->childCount--;
982 if (file->dir->childCount <= 0) {
983 delete_cache_dir(path, file->dir);
984 }
985 }
986}
987
988void finish_cache_collection(cache_t* cache)
989{
Chih-Hung Hsieh99d9fb12014-09-11 14:44:46 -0700990 CACHE_NOISY(size_t i;)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700991
992 CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles));
993 CACHE_NOISY(
994 for (i=0; i<cache->numDirs; i++) {
995 cache_dir_t* dir = cache->dirs[i];
996 ALOGI("dir #%d: %p %s parent=%p\n", i, dir, dir->name, dir->parent);
997 })
998 CACHE_NOISY(
999 for (i=0; i<cache->numFiles; i++) {
1000 cache_file_t* file = cache->files[i];
1001 ALOGI("file #%d: %p %s time=%d dir=%p\n", i, file, file->name,
1002 (int)file->modTime, file->dir);
1003 })
1004 void* block = cache->memBlocks;
1005 while (block != NULL) {
1006 void* nextBlock = *(void**)block;
1007 CACHE_NOISY(ALOGI("Freeing cache mem block: %p", block));
1008 free(block);
1009 block = nextBlock;
1010 }
1011 free(cache);
1012}
1013
1014/**
Calin Juravlec597b6d2014-08-19 17:43:05 +01001015 * Validate that the path is valid in the context of the provided directory.
1016 * The path is allowed to have at most one subdirectory and no indirections
1017 * to top level directories (i.e. have "..").
1018 */
Jeff Sharkeye23a1322015-04-06 16:19:39 -07001019static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) {
Calin Juravlec597b6d2014-08-19 17:43:05 +01001020 size_t dir_len = dir->len;
1021 const char* subdir = strchr(path + dir_len, '/');
1022
1023 // Only allow the path to have at most one subdirectory.
1024 if (subdir != NULL) {
1025 ++subdir;
Jeff Sharkeye23a1322015-04-06 16:19:39 -07001026 if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
Calin Juravlec597b6d2014-08-19 17:43:05 +01001027 ALOGE("invalid apk path '%s' (subdir?)\n", path);
1028 return -1;
1029 }
1030 }
1031
1032 // Directories can't have a period directly after the directory markers to prevent "..".
1033 if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) {
1034 ALOGE("invalid apk path '%s' (trickery)\n", path);
1035 return -1;
1036 }
1037
1038 return 0;
1039}
1040
1041/**
Mike Lockwood94afecf2012-10-24 10:45:23 -07001042 * Checks whether a path points to a system app (.apk file). Returns 0
1043 * if it is a system app or -1 if it is not.
1044 */
1045int validate_system_app_path(const char* path) {
1046 size_t i;
1047
1048 for (i = 0; i < android_system_dirs.count; i++) {
1049 const size_t dir_len = android_system_dirs.dirs[i].len;
1050 if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
Jeff Sharkeye23a1322015-04-06 16:19:39 -07001051 return validate_path(android_system_dirs.dirs + i, path, 1);
Mike Lockwood94afecf2012-10-24 10:45:23 -07001052 }
1053 }
1054
1055 return -1;
1056}
1057
1058/**
1059 * Get the contents of a environment variable that contains a path. Caller
1060 * owns the string that is inserted into the directory record. Returns
1061 * 0 on success and -1 on error.
1062 */
1063int get_path_from_env(dir_rec_t* rec, const char* var) {
1064 const char* path = getenv(var);
1065 int ret = get_path_from_string(rec, path);
1066 if (ret < 0) {
1067 ALOGW("Problem finding value for environment variable %s\n", var);
1068 }
1069 return ret;
1070}
1071
1072/**
1073 * Puts the string into the record as a directory. Appends '/' to the end
1074 * of all paths. Caller owns the string that is inserted into the directory
1075 * record. A null value will result in an error.
1076 *
1077 * Returns 0 on success and -1 on error.
1078 */
1079int get_path_from_string(dir_rec_t* rec, const char* path) {
1080 if (path == NULL) {
1081 return -1;
1082 } else {
1083 const size_t path_len = strlen(path);
1084 if (path_len <= 0) {
1085 return -1;
1086 }
1087
1088 // Make sure path is absolute.
1089 if (path[0] != '/') {
1090 return -1;
1091 }
1092
1093 if (path[path_len - 1] == '/') {
1094 // Path ends with a forward slash. Make our own copy.
1095
1096 rec->path = strdup(path);
1097 if (rec->path == NULL) {
1098 return -1;
1099 }
1100
1101 rec->len = path_len;
1102 } else {
1103 // Path does not end with a slash. Generate a new string.
1104 char *dst;
1105
1106 // Add space for slash and terminating null.
1107 size_t dst_size = path_len + 2;
1108
Jeff Sharkey19803802015-04-07 12:44:51 -07001109 rec->path = (char*) malloc(dst_size);
Mike Lockwood94afecf2012-10-24 10:45:23 -07001110 if (rec->path == NULL) {
1111 return -1;
1112 }
1113
1114 dst = rec->path;
1115
1116 if (append_and_increment(&dst, path, &dst_size) < 0
1117 || append_and_increment(&dst, "/", &dst_size)) {
1118 ALOGE("Error canonicalizing path");
1119 return -1;
1120 }
1121
1122 rec->len = dst - rec->path;
1123 }
1124 }
1125 return 0;
1126}
1127
1128int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
1129 dst->len = src->len + strlen(suffix);
1130 const size_t dstSize = dst->len + 1;
1131 dst->path = (char*) malloc(dstSize);
1132
1133 if (dst->path == NULL
1134 || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
1135 != (ssize_t) dst->len) {
1136 ALOGE("Could not allocate memory to hold appended path; aborting\n");
1137 return -1;
1138 }
1139
1140 return 0;
1141}
1142
1143/**
Narayan Kamathd845c962015-06-04 13:20:27 +01001144 * Check whether path points to a valid path for an APK file. The path must
1145 * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
1146 * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
1147 * is encountered.
Mike Lockwood94afecf2012-10-24 10:45:23 -07001148 */
Narayan Kamathd845c962015-06-04 13:20:27 +01001149static int validate_apk_path_internal(const char *path, int maxSubdirs) {
Calin Juravlec597b6d2014-08-19 17:43:05 +01001150 const dir_rec_t* dir = NULL;
Mike Lockwood94afecf2012-10-24 10:45:23 -07001151 if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
Calin Juravlec597b6d2014-08-19 17:43:05 +01001152 dir = &android_app_dir;
Mike Lockwood94afecf2012-10-24 10:45:23 -07001153 } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
Calin Juravlec597b6d2014-08-19 17:43:05 +01001154 dir = &android_app_private_dir;
Todd Kennedy5c1a9102015-11-23 15:18:10 -08001155 } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) {
1156 dir = &android_app_ephemeral_dir;
Mike Lockwood94afecf2012-10-24 10:45:23 -07001157 } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
Calin Juravlec597b6d2014-08-19 17:43:05 +01001158 dir = &android_asec_dir;
Jeff Sharkeye23a1322015-04-06 16:19:39 -07001159 } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
1160 dir = &android_mnt_expand_dir;
Narayan Kamathd845c962015-06-04 13:20:27 +01001161 if (maxSubdirs < 2) {
1162 maxSubdirs = 2;
1163 }
Mike Lockwood94afecf2012-10-24 10:45:23 -07001164 } else {
Mike Lockwood94afecf2012-10-24 10:45:23 -07001165 return -1;
1166 }
1167
Jeff Sharkeye23a1322015-04-06 16:19:39 -07001168 return validate_path(dir, path, maxSubdirs);
Mike Lockwood94afecf2012-10-24 10:45:23 -07001169}
1170
Narayan Kamathd845c962015-06-04 13:20:27 +01001171int validate_apk_path(const char* path) {
1172 return validate_apk_path_internal(path, 1 /* maxSubdirs */);
1173}
1174
1175int validate_apk_path_subdirs(const char* path) {
1176 return validate_apk_path_internal(path, 3 /* maxSubdirs */);
1177}
1178
Mike Lockwood94afecf2012-10-24 10:45:23 -07001179int append_and_increment(char** dst, const char* src, size_t* dst_size) {
1180 ssize_t ret = strlcpy(*dst, src, *dst_size);
1181 if (ret < 0 || (size_t) ret >= *dst_size) {
1182 return -1;
1183 }
1184 *dst += ret;
1185 *dst_size -= ret;
1186 return 0;
1187}
1188
Jeff Sharkey19803802015-04-07 12:44:51 -07001189char *build_string2(const char *s1, const char *s2) {
Mike Lockwood94afecf2012-10-24 10:45:23 -07001190 if (s1 == NULL || s2 == NULL) return NULL;
1191
1192 int len_s1 = strlen(s1);
1193 int len_s2 = strlen(s2);
1194 int len = len_s1 + len_s2 + 1;
Jeff Sharkey19803802015-04-07 12:44:51 -07001195 char *result = (char *) malloc(len);
Mike Lockwood94afecf2012-10-24 10:45:23 -07001196 if (result == NULL) return NULL;
1197
1198 strcpy(result, s1);
1199 strcpy(result + len_s1, s2);
1200
1201 return result;
1202}
1203
Jeff Sharkey19803802015-04-07 12:44:51 -07001204char *build_string3(const char *s1, const char *s2, const char *s3) {
Mike Lockwood94afecf2012-10-24 10:45:23 -07001205 if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
1206
1207 int len_s1 = strlen(s1);
1208 int len_s2 = strlen(s2);
1209 int len_s3 = strlen(s3);
1210 int len = len_s1 + len_s2 + len_s3 + 1;
Jeff Sharkey19803802015-04-07 12:44:51 -07001211 char *result = (char *) malloc(len);
Mike Lockwood94afecf2012-10-24 10:45:23 -07001212 if (result == NULL) return NULL;
1213
1214 strcpy(result, s1);
1215 strcpy(result + len_s1, s2);
1216 strcpy(result + len_s1 + len_s2, s3);
1217
1218 return result;
1219}
1220
Robin Lee095c7632014-04-25 15:05:19 +01001221int ensure_config_user_dirs(userid_t userid) {
1222 char config_user_path[PATH_MAX];
Robin Lee095c7632014-04-25 15:05:19 +01001223
1224 // writable by system, readable by any app within the same user
Robin Lee60fd3fe2014-10-07 16:55:02 +01001225 const int uid = multiuser_get_uid(userid, AID_SYSTEM);
1226 const int gid = multiuser_get_uid(userid, AID_EVERYBODY);
Robin Lee095c7632014-04-25 15:05:19 +01001227
1228 // Ensure /data/misc/user/<userid> exists
1229 create_user_config_path(config_user_path, userid);
1230 if (fs_prepare_dir(config_user_path, 0750, uid, gid) == -1) {
1231 return -1;
1232 }
1233
1234 return 0;
1235}
Andreas Gampe02d0de52015-11-11 20:43:16 -08001236
1237int wait_child(pid_t pid)
1238{
1239 int status;
1240 pid_t got_pid;
1241
1242 while (1) {
1243 got_pid = waitpid(pid, &status, 0);
1244 if (got_pid == -1 && errno == EINTR) {
1245 printf("waitpid interrupted, retrying\n");
1246 } else {
1247 break;
1248 }
1249 }
1250 if (got_pid != pid) {
1251 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
1252 (int) pid, (int) got_pid, strerror(errno));
1253 return 1;
1254 }
1255
1256 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1257 return 0;
1258 } else {
1259 return status; /* always nonzero */
1260 }
1261}
1262
1263} // namespace installd
1264} // namespace android