blob: cde1573743c1cc3bdd85bc0ada7afae06c501083 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2008, 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*/
16
17#include "installd.h"
Kenny Root33b22642010-11-30 13:49:32 -080018#include <diskusage/dirsize.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019
Oscar Montemayora8529f62009-11-18 10:14:20 -080020int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021{
22 char pkgdir[PKG_PATH_MAX];
23 char libdir[PKG_PATH_MAX];
24
25 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
26 LOGE("invalid uid/gid: %d %d\n", uid, gid);
27 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080029
30 if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
31 if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
32 return -1;
33 if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX))
34 return -1;
35 } else {
36 if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
37 return -1;
38 if (create_pkg_path(libdir, PKG_SEC_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX))
39 return -1;
40 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080042 if (mkdir(pkgdir, 0751) < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
44 return -errno;
45 }
46 if (chown(pkgdir, uid, gid) < 0) {
47 LOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
48 unlink(pkgdir);
49 return -errno;
50 }
51 if (mkdir(libdir, 0755) < 0) {
52 LOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
53 unlink(pkgdir);
54 return -errno;
55 }
56 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
57 LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
58 unlink(libdir);
59 unlink(pkgdir);
60 return -errno;
61 }
62 return 0;
63}
64
Oscar Montemayora8529f62009-11-18 10:14:20 -080065int uninstall(const char *pkgname, int encrypted_fs_flag)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066{
67 char pkgdir[PKG_PATH_MAX];
68
Oscar Montemayora8529f62009-11-18 10:14:20 -080069 if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
70 if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
71 return -1;
72 } else {
73 if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
74 return -1;
75 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076
77 /* delete contents AND directory, no exceptions */
78 return delete_dir_contents(pkgdir, 1, 0);
79}
80
Dianne Hackbornb858dfd2010-02-02 10:49:14 -080081int renamepkg(const char *oldpkgname, const char *newpkgname, int encrypted_fs_flag)
82{
83 char oldpkgdir[PKG_PATH_MAX];
84 char newpkgdir[PKG_PATH_MAX];
85
86 if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
87 if (create_pkg_path(oldpkgdir, PKG_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX))
88 return -1;
89 if (create_pkg_path(newpkgdir, PKG_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX))
90 return -1;
91 } else {
92 if (create_pkg_path(oldpkgdir, PKG_SEC_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX))
93 return -1;
94 if (create_pkg_path(newpkgdir, PKG_SEC_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX))
95 return -1;
96 }
97
98 if (rename(oldpkgdir, newpkgdir) < 0) {
99 LOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
100 return -errno;
101 }
102 return 0;
103}
104
Oscar Montemayora8529f62009-11-18 10:14:20 -0800105int delete_user_data(const char *pkgname, int encrypted_fs_flag)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106{
107 char pkgdir[PKG_PATH_MAX];
108
Oscar Montemayora8529f62009-11-18 10:14:20 -0800109 if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
110 if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
111 return -1;
112 } else {
113 if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
114 return -1;
115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
117 /* delete contents, excluding "lib", but not the directory itself */
118 return delete_dir_contents(pkgdir, 0, "lib");
119}
120
Oscar Montemayora8529f62009-11-18 10:14:20 -0800121int delete_cache(const char *pkgname, int encrypted_fs_flag)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122{
123 char cachedir[PKG_PATH_MAX];
124
Oscar Montemayora8529f62009-11-18 10:14:20 -0800125 if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
126 if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
127 return -1;
128 } else {
129 if (create_pkg_path(cachedir, CACHE_SEC_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
130 return -1;
131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
133 /* delete contents, not the directory, no exceptions */
134 return delete_dir_contents(cachedir, 0, 0);
135}
136
Oscar Montemayora8529f62009-11-18 10:14:20 -0800137/* TODO(oam): depending on use case (ecryptfs or dmcrypt)
138 * change implementation
139 */
Kenny Root3e319a92010-09-07 13:58:28 -0700140static int64_t disk_free()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141{
142 struct statfs sfs;
143 if (statfs(PKG_DIR_PREFIX, &sfs) == 0) {
144 return sfs.f_bavail * sfs.f_bsize;
145 } else {
Kenny Root50871522010-08-04 09:14:01 -0700146 LOGE("Couldn't statfs " PKG_DIR_PREFIX ": %s\n", strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 return -1;
148 }
149}
150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151/* Try to ensure free_size bytes of storage are available.
152 * Returns 0 on success.
153 * This is rather simple-minded because doing a full LRU would
154 * be potentially memory-intensive, and without atime it would
155 * also require that apps constantly modify file metadata even
156 * when just reading from the cache, which is pretty awful.
157 */
Kenny Root3e319a92010-09-07 13:58:28 -0700158int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159{
160 const char *name;
161 int dfd, subfd;
162 DIR *d;
163 struct dirent *de;
Kenny Root3e319a92010-09-07 13:58:28 -0700164 int64_t avail;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165
166 avail = disk_free();
167 if (avail < 0) return -1;
168
Kenny Root3e319a92010-09-07 13:58:28 -0700169 LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 if (avail >= free_size) return 0;
171
Oscar Montemayora8529f62009-11-18 10:14:20 -0800172 /* First try encrypted dir */
173 d = opendir(PKG_SEC_DIR_PREFIX);
174 if (d == NULL) {
Kenny Root50871522010-08-04 09:14:01 -0700175 LOGE("cannot open %s: %s\n", PKG_SEC_DIR_PREFIX, strerror(errno));
Oscar Montemayora8529f62009-11-18 10:14:20 -0800176 } else {
177 dfd = dirfd(d);
178
179 while ((de = readdir(d))) {
180 if (de->d_type != DT_DIR) continue;
181 name = de->d_name;
182
183 /* always skip "." and ".." */
184 if (name[0] == '.') {
185 if (name[1] == 0) continue;
186 if ((name[1] == '.') && (name[2] == 0)) continue;
187 }
188
189 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
190 if (subfd < 0) continue;
191
192 delete_dir_contents_fd(subfd, "cache");
193 close(subfd);
194
195 avail = disk_free();
196 if (avail >= free_size) {
197 closedir(d);
198 return 0;
199 }
200 }
201 closedir(d);
202 }
203
204 /* Next try unencrypted dir... */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 d = opendir(PKG_DIR_PREFIX);
206 if (d == NULL) {
Kenny Root50871522010-08-04 09:14:01 -0700207 LOGE("cannot open %s: %s\n", PKG_DIR_PREFIX, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 return -1;
209 }
210 dfd = dirfd(d);
211
212 while ((de = readdir(d))) {
213 if (de->d_type != DT_DIR) continue;
214 name = de->d_name;
215
Oscar Montemayora8529f62009-11-18 10:14:20 -0800216 /* always skip "." and ".." */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 if (name[0] == '.') {
218 if (name[1] == 0) continue;
219 if ((name[1] == '.') && (name[2] == 0)) continue;
220 }
221
222 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
223 if (subfd < 0) continue;
224
225 delete_dir_contents_fd(subfd, "cache");
226 close(subfd);
227
228 avail = disk_free();
229 if (avail >= free_size) {
230 closedir(d);
231 return 0;
232 }
233 }
234 closedir(d);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800235
236 /* Fail case - not possible to free space */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 return -1;
238}
239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240/* used by move_dex, rm_dex, etc to ensure that the provided paths
241 * don't point anywhere other than at the APK_DIR_PREFIX
242 */
243static int is_valid_apk_path(const char *path)
244{
245 int len = strlen(APK_DIR_PREFIX);
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -0800246int nosubdircheck = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 if (strncmp(path, APK_DIR_PREFIX, len)) {
248 len = strlen(PROTECTED_DIR_PREFIX);
249 if (strncmp(path, PROTECTED_DIR_PREFIX, len)) {
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -0800250 len = strlen(SDCARD_DIR_PREFIX);
251 if (strncmp(path, SDCARD_DIR_PREFIX, len)) {
252 LOGE("invalid apk path '%s' (bad prefix)\n", path);
253 return 0;
254 } else {
255 nosubdircheck = 1;
256 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 }
258 }
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -0800259 if ((nosubdircheck != 1) && strchr(path + len, '/')) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 LOGE("invalid apk path '%s' (subdir?)\n", path);
261 return 0;
262 }
263 if (path[len] == '.') {
264 LOGE("invalid apk path '%s' (trickery)\n", path);
265 return 0;
266 }
267 return 1;
268}
269
270int move_dex(const char *src, const char *dst)
271{
272 char src_dex[PKG_PATH_MAX];
273 char dst_dex[PKG_PATH_MAX];
274
275 if (!is_valid_apk_path(src)) return -1;
276 if (!is_valid_apk_path(dst)) return -1;
277
278 if (create_cache_path(src_dex, src)) return -1;
279 if (create_cache_path(dst_dex, dst)) return -1;
280
281 LOGI("move %s -> %s\n", src_dex, dst_dex);
282 if (rename(src_dex, dst_dex) < 0) {
Kenny Root50871522010-08-04 09:14:01 -0700283 LOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 return -1;
285 } else {
286 return 0;
287 }
288}
289
290int rm_dex(const char *path)
291{
292 char dex_path[PKG_PATH_MAX];
293
294 if (!is_valid_apk_path(path)) return -1;
295 if (create_cache_path(dex_path, path)) return -1;
296
297 LOGI("unlink %s\n", dex_path);
298 if (unlink(dex_path) < 0) {
Kenny Root50871522010-08-04 09:14:01 -0700299 LOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 return -1;
301 } else {
302 return 0;
303 }
304}
305
306int protect(char *pkgname, gid_t gid)
307{
308 struct stat s;
309 char pkgpath[PKG_PATH_MAX];
310
311 if (gid < AID_SYSTEM) return -1;
312
313 if (create_pkg_path(pkgpath, PROTECTED_DIR_PREFIX, pkgname, ".apk"))
314 return -1;
315
316 if (stat(pkgpath, &s) < 0) return -1;
317
318 if (chown(pkgpath, s.st_uid, gid) < 0) {
319 LOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
320 return -1;
321 }
322
323 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
324 LOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
325 return -1;
326 }
327
328 return 0;
329}
330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331int get_size(const char *pkgname, const char *apkpath,
332 const char *fwdlock_apkpath,
Kenny Root3e319a92010-09-07 13:58:28 -0700333 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize, int encrypted_fs_flag)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334{
335 DIR *d;
336 int dfd;
337 struct dirent *de;
338 struct stat s;
339 char path[PKG_PATH_MAX];
340
Kenny Root3e319a92010-09-07 13:58:28 -0700341 int64_t codesize = 0;
342 int64_t datasize = 0;
343 int64_t cachesize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344
345 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800346 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 */
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800348 if (strncmp(apkpath, "/system", 7) != 0 &&
349 strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 if (stat(apkpath, &s) == 0) {
351 codesize += stat_size(&s);
352 }
353 }
354 /* count the forward locked apk as code if it is given
355 */
356 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
357 if (stat(fwdlock_apkpath, &s) == 0) {
358 codesize += stat_size(&s);
359 }
360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 /* count the cached dexfile as code */
362 if (!create_cache_path(path, apkpath)) {
363 if (stat(path, &s) == 0) {
364 codesize += stat_size(&s);
365 }
366 }
367
Oscar Montemayora8529f62009-11-18 10:14:20 -0800368 if (encrypted_fs_flag == 0) {
369 if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
370 goto done;
371 }
372 } else {
373 if (create_pkg_path(path, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
374 goto done;
375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 }
377
378 d = opendir(path);
379 if (d == NULL) {
380 goto done;
381 }
382 dfd = dirfd(d);
383
384 /* most stuff in the pkgdir is data, except for the "cache"
385 * directory and below, which is cache, and the "lib" directory
386 * and below, which is code...
387 */
388 while ((de = readdir(d))) {
389 const char *name = de->d_name;
390
391 if (de->d_type == DT_DIR) {
392 int subfd;
393 /* always skip "." and ".." */
394 if (name[0] == '.') {
395 if (name[1] == 0) continue;
396 if ((name[1] == '.') && (name[2] == 0)) continue;
397 }
398 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
399 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700400 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 if (!strcmp(name,"lib")) {
402 codesize += size;
403 } else if(!strcmp(name,"cache")) {
404 cachesize += size;
405 } else {
406 datasize += size;
407 }
408 }
409 } else {
410 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
411 datasize += stat_size(&s);
412 }
413 }
414 }
415 closedir(d);
416done:
417 *_codesize = codesize;
418 *_datasize = datasize;
419 *_cachesize = cachesize;
420 return 0;
421}
422
423
424/* a simpler version of dexOptGenerateCacheFileName() */
425int create_cache_path(char path[PKG_PATH_MAX], const char *src)
426{
427 char *tmp;
428 int srclen;
429 int dstlen;
430
431 srclen = strlen(src);
432
433 /* demand that we are an absolute path */
434 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
435 return -1;
436 }
437
438 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
439 return -1;
440 }
441
442 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
443 strlen(DALVIK_CACHE_POSTFIX) + 1;
444
445 if (dstlen > PKG_PATH_MAX) {
446 return -1;
447 }
448
449 sprintf(path,"%s%s%s",
450 DALVIK_CACHE_PREFIX,
451 src + 1, /* skip the leading / */
452 DALVIK_CACHE_POSTFIX);
453
454 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
455 if (*tmp == '/') {
456 *tmp = '@';
457 }
458 }
459
460 return 0;
461}
462
463static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
464 const char* dexopt_flags)
465{
466 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
467 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
468 char zip_num[MAX_INT_LEN];
469 char odex_num[MAX_INT_LEN];
470
471 sprintf(zip_num, "%d", zip_fd);
472 sprintf(odex_num, "%d", odex_fd);
473
474 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
475 dexopt_flags, (char*) NULL);
476 LOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
477}
478
479static int wait_dexopt(pid_t pid, const char* apk_path)
480{
481 int status;
482 pid_t got_pid;
483
484 /*
485 * Wait for the optimization process to finish.
486 */
487 while (1) {
488 got_pid = waitpid(pid, &status, 0);
489 if (got_pid == -1 && errno == EINTR) {
490 printf("waitpid interrupted, retrying\n");
491 } else {
492 break;
493 }
494 }
495 if (got_pid != pid) {
496 LOGW("waitpid failed: wanted %d, got %d: %s\n",
497 (int) pid, (int) got_pid, strerror(errno));
498 return 1;
499 }
500
501 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
502 LOGD("DexInv: --- END '%s' (success) ---\n", apk_path);
503 return 0;
504 } else {
505 LOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
506 apk_path, status);
507 return status; /* always nonzero */
508 }
509}
510
511int dexopt(const char *apk_path, uid_t uid, int is_public)
512{
513 struct utimbuf ut;
514 struct stat apk_stat, dex_stat;
515 char dex_path[PKG_PATH_MAX];
516 char dexopt_flags[PROPERTY_VALUE_MAX];
517 char *end;
518 int res, zip_fd=-1, odex_fd=-1;
519
520 /* Before anything else: is there a .odex file? If so, we have
521 * pre-optimized the apk and there is nothing to do here.
522 */
523 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
524 return -1;
525 }
526
527 /* platform-specific flags affecting optimization and verification */
528 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
529
530 strcpy(dex_path, apk_path);
531 end = strrchr(dex_path, '.');
532 if (end != NULL) {
533 strcpy(end, ".odex");
534 if (stat(dex_path, &dex_stat) == 0) {
535 return 0;
536 }
537 }
538
539 if (create_cache_path(dex_path, apk_path)) {
540 return -1;
541 }
542
543 memset(&apk_stat, 0, sizeof(apk_stat));
544 stat(apk_path, &apk_stat);
545
546 zip_fd = open(apk_path, O_RDONLY, 0);
547 if (zip_fd < 0) {
548 LOGE("dexopt cannot open '%s' for input\n", apk_path);
549 return -1;
550 }
551
552 unlink(dex_path);
553 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
554 if (odex_fd < 0) {
555 LOGE("dexopt cannot open '%s' for output\n", dex_path);
556 goto fail;
557 }
558 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
559 LOGE("dexopt cannot chown '%s'\n", dex_path);
560 goto fail;
561 }
562 if (fchmod(odex_fd,
563 S_IRUSR|S_IWUSR|S_IRGRP |
564 (is_public ? S_IROTH : 0)) < 0) {
565 LOGE("dexopt cannot chmod '%s'\n", dex_path);
566 goto fail;
567 }
568
569 LOGD("DexInv: --- BEGIN '%s' ---\n", apk_path);
570
571 pid_t pid;
572 pid = fork();
573 if (pid == 0) {
574 /* child -- drop privileges before continuing */
575 if (setgid(uid) != 0) {
576 LOGE("setgid(%d) failed during dexopt\n", uid);
577 exit(64);
578 }
579 if (setuid(uid) != 0) {
580 LOGE("setuid(%d) during dexopt\n", uid);
581 exit(65);
582 }
583 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
584 LOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
585 exit(66);
586 }
587
588 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
589 exit(67); /* only get here on exec failure */
590 } else {
591 res = wait_dexopt(pid, apk_path);
592 if (res != 0) {
593 LOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
594 goto fail;
595 }
596 }
597
598 ut.actime = apk_stat.st_atime;
599 ut.modtime = apk_stat.st_mtime;
600 utime(dex_path, &ut);
601
602 close(odex_fd);
603 close(zip_fd);
604 return 0;
605
606fail:
607 if (odex_fd >= 0) {
608 close(odex_fd);
609 unlink(dex_path);
610 }
611 if (zip_fd >= 0) {
612 close(zip_fd);
613 }
614 return -1;
615}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800616
617int create_move_path(char path[PKG_PATH_MAX],
618 const char* prefix,
619 const char* pkgname,
620 const char* leaf)
621{
622 if ((strlen(prefix) + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) {
623 return -1;
624 }
625
626 sprintf(path, "%s%s/%s", prefix, pkgname, leaf);
627 return 0;
628}
629
Dianne Hackbornc1552392010-03-03 16:19:01 -0800630void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
631 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800632{
633 while (path[basepos] != 0) {
634 if (path[basepos] == '/') {
635 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800636 if (lstat(path, statbuf) < 0) {
637 LOGI("Making directory: %s\n", path);
638 if (mkdir(path, mode) == 0) {
639 chown(path, uid, gid);
640 } else {
641 LOGW("Unable to make directory %s: %s\n", path, strerror(errno));
642 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800643 }
644 path[basepos] = '/';
645 basepos++;
646 }
647 basepos++;
648 }
649}
650
Dianne Hackbornc1552392010-03-03 16:19:01 -0800651int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
652 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800653{
654 DIR *d;
655 struct dirent *de;
656 int res;
657
658 int srcend = strlen(srcpath);
659 int dstend = strlen(dstpath);
660
661 if (lstat(srcpath, statbuf) < 0) {
662 LOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
663 return 1;
664 }
665
666 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800667 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
668 dstuid, dstgid, statbuf);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800669 LOGI("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800670 if (rename(srcpath, dstpath) >= 0) {
671 if (chown(dstpath, dstuid, dstgid) < 0) {
672 LOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
673 unlink(dstpath);
674 return 1;
675 }
676 } else {
677 LOGW("Unable to rename %s to %s: %s\n",
678 srcpath, dstpath, strerror(errno));
679 return 1;
680 }
681 return 0;
682 }
683
684 d = opendir(srcpath);
685 if (d == NULL) {
686 LOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
687 return 1;
688 }
689
690 res = 0;
691
692 while ((de = readdir(d))) {
693 const char *name = de->d_name;
694 /* always skip "." and ".." */
695 if (name[0] == '.') {
696 if (name[1] == 0) continue;
697 if ((name[1] == '.') && (name[2] == 0)) continue;
698 }
699
700 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
701 LOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
702 continue;
703 }
704
705 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
706 LOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
707 continue;
708 }
709
710 srcpath[srcend] = dstpath[dstend] = '/';
711 strcpy(srcpath+srcend+1, name);
712 strcpy(dstpath+dstend+1, name);
713
Dianne Hackbornc1552392010-03-03 16:19:01 -0800714 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800715 res = 1;
716 }
717
718 // Note: we will be leaving empty directories behind in srcpath,
719 // but that is okay, the package manager will be erasing all of the
720 // data associated with .apks that disappear.
721
722 srcpath[srcend] = dstpath[dstend] = 0;
723 }
724
725 closedir(d);
726 return res;
727}
728
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800729int movefiles()
730{
731 DIR *d;
732 int dfd, subfd;
733 struct dirent *de;
734 struct stat s;
735 char buf[PKG_PATH_MAX+1];
736 int bufp, bufe, bufi, readlen;
737
738 char srcpkg[PKG_NAME_MAX];
739 char dstpkg[PKG_NAME_MAX];
740 char srcpath[PKG_PATH_MAX];
741 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800742 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800743 int hasspace;
744
745 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
746 if (d == NULL) {
747 goto done;
748 }
749 dfd = dirfd(d);
750
751 /* Iterate through all files in the directory, executing the
752 * file movements requested there-in.
753 */
754 while ((de = readdir(d))) {
755 const char *name = de->d_name;
756
757 if (de->d_type == DT_DIR) {
758 continue;
759 } else {
760 subfd = openat(dfd, name, O_RDONLY);
761 if (subfd < 0) {
762 LOGW("Unable to open update commands at %s%s\n",
763 UPDATE_COMMANDS_DIR_PREFIX, name);
764 continue;
765 }
766
767 bufp = 0;
768 bufe = 0;
769 buf[PKG_PATH_MAX] = 0;
770 srcpkg[0] = dstpkg[0] = 0;
771 while (1) {
772 bufi = bufp;
773 while (bufi < bufe && buf[bufi] != '\n') {
774 bufi++;
775 }
776 if (bufi < bufe) {
777 buf[bufi] = 0;
778 LOGV("Processing line: %s\n", buf+bufp);
779 hasspace = 0;
780 while (bufp < bufi && isspace(buf[bufp])) {
781 hasspace = 1;
782 bufp++;
783 }
784 if (buf[bufp] == '#' || bufp == bufi) {
785 // skip comments and empty lines.
786 } else if (hasspace) {
787 if (dstpkg[0] == 0) {
788 LOGW("Path before package line in %s%s: %s\n",
789 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
790 } else if (srcpkg[0] == 0) {
791 // Skip -- source package no longer exists.
792 } else {
793 LOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
794 if (!create_move_path(srcpath, PKG_DIR_PREFIX, srcpkg, buf+bufp) &&
795 !create_move_path(dstpath, PKG_DIR_PREFIX, dstpkg, buf+bufp)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800796 movefileordir(srcpath, dstpath,
797 strlen(dstpath)-strlen(buf+bufp),
798 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800799 }
800 }
801 } else {
802 char* div = strchr(buf+bufp, ':');
803 if (div == NULL) {
804 LOGW("Bad package spec in %s%s; no ':' sep: %s\n",
805 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
806 } else {
807 *div = 0;
808 div++;
809 if (strlen(buf+bufp) < PKG_NAME_MAX) {
810 strcpy(dstpkg, buf+bufp);
811 } else {
812 srcpkg[0] = dstpkg[0] = 0;
813 LOGW("Package name too long in %s%s: %s\n",
814 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
815 }
816 if (strlen(div) < PKG_NAME_MAX) {
817 strcpy(srcpkg, div);
818 } else {
819 srcpkg[0] = dstpkg[0] = 0;
820 LOGW("Package name too long in %s%s: %s\n",
821 UPDATE_COMMANDS_DIR_PREFIX, name, div);
822 }
823 if (srcpkg[0] != 0) {
824 if (!create_pkg_path(srcpath, PKG_DIR_PREFIX, srcpkg,
825 PKG_DIR_POSTFIX)) {
826 if (lstat(srcpath, &s) < 0) {
827 // Package no longer exists -- skip.
828 srcpkg[0] = 0;
829 }
830 } else {
831 srcpkg[0] = 0;
832 LOGW("Can't create path %s in %s%s\n",
833 div, UPDATE_COMMANDS_DIR_PREFIX, name);
834 }
835 if (srcpkg[0] != 0) {
836 if (!create_pkg_path(dstpath, PKG_DIR_PREFIX, dstpkg,
837 PKG_DIR_POSTFIX)) {
838 if (lstat(dstpath, &s) == 0) {
839 dstuid = s.st_uid;
840 dstgid = s.st_gid;
841 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800842 // Destination package doesn't
843 // exist... due to original-package,
844 // this is normal, so don't be
845 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800846 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800847 }
848 } else {
849 srcpkg[0] = 0;
850 LOGW("Can't create path %s in %s%s\n",
851 div, UPDATE_COMMANDS_DIR_PREFIX, name);
852 }
853 }
854 LOGV("Transfering from %s to %s: uid=%d\n",
855 srcpkg, dstpkg, dstuid);
856 }
857 }
858 }
859 bufp = bufi+1;
860 } else {
861 if (bufp == 0) {
862 if (bufp < bufe) {
863 LOGW("Line too long in %s%s, skipping: %s\n",
864 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
865 }
866 } else if (bufp < bufe) {
867 memcpy(buf, buf+bufp, bufe-bufp);
868 bufe -= bufp;
869 bufp = 0;
870 }
871 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
872 if (readlen < 0) {
873 LOGW("Failure reading update commands in %s%s: %s\n",
874 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
875 break;
876 } else if (readlen == 0) {
877 break;
878 }
879 bufe += readlen;
880 buf[bufe] = 0;
881 LOGV("Read buf: %s\n", buf);
882 }
883 }
884 close(subfd);
885 }
886 }
887 closedir(d);
888done:
889 return 0;
890}
Kenny Root6a6b0072010-10-07 16:46:10 -0700891
892int linklib(const char* dataDir, const char* asecLibDir)
893{
894 char libdir[PKG_PATH_MAX];
895 struct stat s, libStat;
896 int rc = 0;
897
898 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
899 if (libdirLen >= PKG_PATH_MAX) {
900 LOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700901 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700902 }
903
904 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
905 LOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700906 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700907 }
908
909 if (stat(dataDir, &s) < 0) return -1;
910
911 if (chown(dataDir, 0, 0) < 0) {
912 LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
913 return -1;
914 }
915
916 if (chmod(dataDir, 0700) < 0) {
917 LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
918 rc = -1;
919 goto out;
920 }
921
922 if (lstat(libdir, &libStat) < 0) {
923 LOGE("couldn't stat lib dir: %s\n", strerror(errno));
924 rc = -1;
925 goto out;
926 }
927
928 if (S_ISDIR(libStat.st_mode)) {
929 if (delete_dir_contents(libdir, 1, 0) < 0) {
930 rc = -1;
931 goto out;
932 }
933 } else if (S_ISLNK(libStat.st_mode)) {
934 if (unlink(libdir) < 0) {
935 rc = -1;
936 goto out;
937 }
938 }
939
940 if (symlink(asecLibDir, libdir) < 0) {
941 LOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
942 rc = -errno;
943 goto out;
944 }
945
946 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
947 LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
948 unlink(libdir);
949 rc = -errno;
950 goto out;
951 }
952
953out:
954 if (chmod(dataDir, s.st_mode) < 0) {
955 LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
956 return -errno;
957 }
958
959 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
960 LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
961 return -errno;
962 }
963
964 return rc;
965}
966
967int unlinklib(const char* dataDir)
968{
969 char libdir[PKG_PATH_MAX];
970 struct stat s, libStat;
971 int rc = 0;
972
973 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
974 if (libdirLen >= PKG_PATH_MAX) {
975 return -1;
976 }
977
978 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
979 LOGE("library dir not written successfully: %s\n", strerror(errno));
980 return -1;
981 }
982
983 if (stat(dataDir, &s) < 0) {
984 LOGE("couldn't state data dir");
985 return -1;
986 }
987
988 if (chown(dataDir, 0, 0) < 0) {
989 LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
990 return -1;
991 }
992
993 if (chmod(dataDir, 0700) < 0) {
994 LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
995 rc = -1;
996 goto out;
997 }
998
999 if (lstat(libdir, &libStat) < 0) {
1000 LOGE("couldn't stat lib dir: %s\n", strerror(errno));
1001 rc = -1;
1002 goto out;
1003 }
1004
1005 if (S_ISDIR(libStat.st_mode)) {
1006 if (delete_dir_contents(libdir, 1, 0) < 0) {
1007 rc = -1;
1008 goto out;
1009 }
1010 } else if (S_ISLNK(libStat.st_mode)) {
1011 if (unlink(libdir) < 0) {
1012 rc = -1;
1013 goto out;
1014 }
1015 }
1016
1017 if (mkdir(libdir, 0755) < 0) {
1018 LOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
1019 rc = -errno;
1020 goto out;
1021 }
1022
1023 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
1024 LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
1025 unlink(libdir);
1026 rc = -errno;
1027 goto out;
1028 }
1029
1030out:
1031 if (chmod(dataDir, s.st_mode) < 0) {
1032 LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
1033 return -1;
1034 }
1035
1036 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
1037 LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
1038 return -1;
1039 }
1040
1041 return rc;
1042}