commands.c 32.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
** you may not use this file except in compliance with the License. 
** You may obtain a copy of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** Unless required by applicable law or agreed to in writing, software 
** distributed under the License is distributed on an "AS IS" BASIS, 
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
** See the License for the specific language governing permissions and 
** limitations under the License.
*/

#include "installd.h"
18
#include <diskusage/dirsize.h>
19 20
#include <selinux/android.h>

21 22 23 24 25 26 27
/* Directory records that are used in execution of commands. */
dir_rec_t android_data_dir;
dir_rec_t android_asec_dir;
dir_rec_t android_app_dir;
dir_rec_t android_app_private_dir;
dir_rec_array_t android_system_dirs;

Kenny Root's avatar
Kenny Root committed
28
int install(const char *pkgname, uid_t uid, gid_t gid)
29 30 31 32 33
{
    char pkgdir[PKG_PATH_MAX];
    char libdir[PKG_PATH_MAX];

    if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
34
        ALOGE("invalid uid/gid: %d %d\n", uid, gid);
35 36
        return -1;
    }
37

38
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
39
        ALOGE("cannot create package path\n");
Kenny Root's avatar
Kenny Root committed
40
        return -1;
41 42 43
    }

    if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
44
        ALOGE("cannot create package lib path\n");
Kenny Root's avatar
Kenny Root committed
45
        return -1;
46
    }
47

48
    if (mkdir(pkgdir, 0751) < 0) {
49
        ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
50 51
        return -errno;
    }
52
    if (chmod(pkgdir, 0751) < 0) {
53
        ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
54 55 56
        unlink(pkgdir);
        return -errno;
    }
57

58
    if (mkdir(libdir, 0755) < 0) {
59
        ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
60
        unlink(pkgdir);
61 62 63
        return -errno;
    }
    if (chmod(libdir, 0755) < 0) {
64
        ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
65 66
        unlink(libdir);
        unlink(pkgdir);
67 68 69
        return -errno;
    }
    if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
70
        ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
71 72 73 74
        unlink(libdir);
        unlink(pkgdir);
        return -errno;
    }
75

Kenny Root's avatar
Kenny Root committed
76
    if (selinux_android_setfilecon(libdir, pkgname, uid) < 0) {
77
        ALOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
78 79 80 81 82
        unlink(libdir);
        unlink(pkgdir);
        return -errno;
    }

83 84 85 86
    if (chown(pkgdir, uid, gid) < 0) {
        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
        unlink(libdir);
        unlink(pkgdir);
87 88
        return -errno;
    }
89

90 91 92
    return 0;
}

93
int uninstall(const char *pkgname, uid_t persona)
94 95 96
{
    char pkgdir[PKG_PATH_MAX];

97
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root's avatar
Kenny Root committed
98
        return -1;
99

100 101
    /* delete contents AND directory, no exceptions */
    return delete_dir_contents(pkgdir, 1, NULL);
102 103
}

Kenny Root's avatar
Kenny Root committed
104
int renamepkg(const char *oldpkgname, const char *newpkgname)
105 106 107 108
{
    char oldpkgdir[PKG_PATH_MAX];
    char newpkgdir[PKG_PATH_MAX];

109
    if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root's avatar
Kenny Root committed
110
        return -1;
111
    if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root's avatar
Kenny Root committed
112
        return -1;
113 114

    if (rename(oldpkgdir, newpkgdir) < 0) {
115
        ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
116 117 118 119 120
        return -errno;
    }
    return 0;
}

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
{
    char pkgdir[PKG_PATH_MAX];
    struct stat s;
    int rc = 0;

    if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
        ALOGE("invalid uid/gid: %d %d\n", uid, gid);
        return -1;
    }

    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
        ALOGE("cannot create package path\n");
        return -1;
    }

    if (stat(pkgdir, &s) < 0) return -1;

    if (s.st_uid != 0 || s.st_gid != 0) {
        ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
        return -1;
    }

    if (chmod(pkgdir, 0751) < 0) {
        ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
        unlink(pkgdir);
        return -errno;
    }
    if (chown(pkgdir, uid, gid) < 0) {
        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
        unlink(pkgdir);
        return -errno;
    }

    return 0;
}

158
int delete_user_data(const char *pkgname, uid_t persona)
159 160 161
{
    char pkgdir[PKG_PATH_MAX];

162
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root's avatar
Kenny Root committed
163
        return -1;
164

165
    /* delete contents, excluding "lib", but not the directory itself */
166 167 168
    return delete_dir_contents(pkgdir, 0, "lib");
}

169 170 171 172 173 174 175 176 177 178
int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
{
    char pkgdir[PKG_PATH_MAX];
    char real_libdir[PKG_PATH_MAX];

    // Create the data dir for the package
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
        return -1;
    }
    if (mkdir(pkgdir, 0751) < 0) {
179
        ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
180 181
        return -errno;
    }
Kenny Root's avatar
Kenny Root committed
182 183
    if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
        ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
184 185 186
        unlink(pkgdir);
        return -errno;
    }
Kenny Root's avatar
Kenny Root committed
187 188
    if (chown(pkgdir, uid, uid) < 0) {
        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
189 190 191 192
        unlink(pkgdir);
        return -errno;
    }

193 194 195 196 197 198 199 200 201 202 203 204 205
    return 0;
}

int delete_persona(uid_t persona)
{
    char pkgdir[PKG_PATH_MAX];

    if (create_persona_path(pkgdir, persona))
        return -1;

    return delete_dir_contents(pkgdir, 1, NULL);
}

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
{
    char src_data_dir[PKG_PATH_MAX];
    char pkg_path[PKG_PATH_MAX];
    DIR *d;
    struct dirent *de;
    struct stat s;
    uid_t uid;

    if (create_persona_path(src_data_dir, src_persona)) {
        return -1;
    }

    d = opendir(src_data_dir);
    if (d != NULL) {
        while ((de = readdir(d))) {
            const char *name = de->d_name;

            if (de->d_type == DT_DIR) {
                int subfd;
                    /* always skip "." and ".." */
                if (name[0] == '.') {
                    if (name[1] == 0) continue;
                    if ((name[1] == '.') && (name[2] == 0)) continue;
                }
                /* Create the full path to the package's data dir */
                create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
                /* Get the file stat */
                if (stat(pkg_path, &s) < 0) continue;
                /* Get the uid of the package */
                ALOGI("Adding datadir for uid = %d\n", s.st_uid);
                uid = (uid_t) s.st_uid % PER_USER_RANGE;
                /* Create the directory for the target */
                make_user_data(name, uid + target_persona * PER_USER_RANGE,
                               target_persona);
            }
        }
        closedir(d);
    }
    return 0;
}

Kenny Root's avatar
Kenny Root committed
248
int delete_cache(const char *pkgname)
249 250 251
{
    char cachedir[PKG_PATH_MAX];

252
    if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root's avatar
Kenny Root committed
253
        return -1;
254 255 256 257 258

        /* delete contents, not the directory, no exceptions */
    return delete_dir_contents(cachedir, 0, 0);
}

259
static int64_t disk_free()
260 261
{
    struct statfs sfs;
262
    if (statfs(android_data_dir.path, &sfs) == 0) {
263 264
        return sfs.f_bavail * sfs.f_bsize;
    } else {
265
        ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
266 267 268 269 270 271 272 273 274 275 276
        return -1;
    }
}

/* Try to ensure free_size bytes of storage are available.
 * Returns 0 on success.
 * This is rather simple-minded because doing a full LRU would
 * be potentially memory-intensive, and without atime it would
 * also require that apps constantly modify file metadata even
 * when just reading from the cache, which is pretty awful.
 */
277
int free_cache(int64_t free_size)
278 279 280 281 282
{
    const char *name;
    int dfd, subfd;
    DIR *d;
    struct dirent *de;
283
    int64_t avail;
Kenny Root's avatar
Kenny Root committed
284
    char datadir[PKG_PATH_MAX];
285 286 287 288

    avail = disk_free();
    if (avail < 0) return -1;

289
    ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
290 291
    if (avail >= free_size) return 0;

Kenny Root's avatar
Kenny Root committed
292
    if (create_persona_path(datadir, 0)) {
293
        ALOGE("couldn't get directory for persona 0");
Kenny Root's avatar
Kenny Root committed
294 295 296 297
        return -1;
    }

    d = opendir(datadir);
298
    if (d == NULL) {
299
        ALOGE("cannot open %s: %s\n", datadir, strerror(errno));
300 301 302 303 304 305 306 307
        return -1;
    }
    dfd = dirfd(d);

    while ((de = readdir(d))) {
        if (de->d_type != DT_DIR) continue;
        name = de->d_name;

308
        /* always skip "." and ".." */
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
        if (name[0] == '.') {
            if (name[1] == 0) continue;
            if ((name[1] == '.') && (name[2] == 0)) continue;
        }

        subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
        if (subfd < 0) continue;

        delete_dir_contents_fd(subfd, "cache");
        close(subfd);

        avail = disk_free();
        if (avail >= free_size) {
            closedir(d);
            return 0;
        }
    }
    closedir(d);
327 328

    /* Fail case - not possible to free space */
329 330 331 332 333 334 335 336
    return -1;
}

int move_dex(const char *src, const char *dst)
{
    char src_dex[PKG_PATH_MAX];
    char dst_dex[PKG_PATH_MAX];

337 338
    if (validate_apk_path(src)) return -1;
    if (validate_apk_path(dst)) return -1;
339 340 341 342

    if (create_cache_path(src_dex, src)) return -1;
    if (create_cache_path(dst_dex, dst)) return -1;

343
    ALOGV("move %s -> %s\n", src_dex, dst_dex);
344
    if (rename(src_dex, dst_dex) < 0) {
345
        ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
346 347 348 349 350 351 352 353 354 355
        return -1;
    } else {
        return 0;
    }
}

int rm_dex(const char *path)
{
    char dex_path[PKG_PATH_MAX];

356
    if (validate_apk_path(path)) return -1;
357 358
    if (create_cache_path(dex_path, path)) return -1;

359
    ALOGV("unlink %s\n", dex_path);
360
    if (unlink(dex_path) < 0) {
361
        ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
362 363 364 365 366 367 368 369 370 371 372 373 374
        return -1;
    } else {
        return 0;
    }
}

int protect(char *pkgname, gid_t gid)
{
    struct stat s;
    char pkgpath[PKG_PATH_MAX];

    if (gid < AID_SYSTEM) return -1;

375
    if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
376 377 378 379 380
        return -1;

    if (stat(pkgpath, &s) < 0) return -1;

    if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
381
        ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
382 383
        return -1;
    }
384
    if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
385
        ALOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
386 387
        return -1;
    }
Kenny Root's avatar
Kenny Root committed
388 389 390 391
    if (chown(pkgpath, s.st_uid, gid) < 0) {
        ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
        return -1;
    }
392

393 394 395 396
    return 0;
}

int get_size(const char *pkgname, const char *apkpath,
397 398 399
             const char *fwdlock_apkpath, const char *asecpath,
             int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
             int64_t* _asecsize)
400 401 402 403 404 405 406
{
    DIR *d;
    int dfd;
    struct dirent *de;
    struct stat s;
    char path[PKG_PATH_MAX];

407 408 409
    int64_t codesize = 0;
    int64_t datasize = 0;
    int64_t cachesize = 0;
410
    int64_t asecsize = 0;
411 412

        /* count the source apk as code -- but only if it's not
413
         * on the /system partition and its not on the sdcard.
414
         */
415 416
    if (validate_system_app_path(apkpath) &&
            strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
        if (stat(apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
    }
        /* count the forward locked apk as code if it is given
         */
    if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
        if (stat(fwdlock_apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
    }
        /* count the cached dexfile as code */
    if (!create_cache_path(path, apkpath)) {
        if (stat(path, &s) == 0) {
            codesize += stat_size(&s);
        }
    }

435 436 437 438 439 440 441 442
        /* compute asec size if it is given
         */
    if (asecpath != NULL && asecpath[0] != '!') {
        if (stat(asecpath, &s) == 0) {
            asecsize += stat_size(&s);
        }
    }

443
    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root's avatar
Kenny Root committed
444
        goto done;
445 446 447 448 449 450 451 452
    }

    d = opendir(path);
    if (d == NULL) {
        goto done;
    }
    dfd = dirfd(d);

453 454 455 456
    /* most stuff in the pkgdir is data, except for the "cache"
     * directory and below, which is cache, and the "lib" directory
     * and below, which is code...
     */
457 458 459 460 461 462 463 464 465 466 467 468
    while ((de = readdir(d))) {
        const char *name = de->d_name;

        if (de->d_type == DT_DIR) {
            int subfd;
                /* always skip "." and ".." */
            if (name[0] == '.') {
                if (name[1] == 0) continue;
                if ((name[1] == '.') && (name[2] == 0)) continue;
            }
            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
            if (subfd >= 0) {
469
                int64_t size = calculate_dir_size(subfd);
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
                if (!strcmp(name,"lib")) {
                    codesize += size;
                } else if(!strcmp(name,"cache")) {
                    cachesize += size;
                } else {
                    datasize += size;
                }
            }
        } else {
            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
                datasize += stat_size(&s);
            }
        }
    }
    closedir(d);
done:
    *_codesize = codesize;
    *_datasize = datasize;
    *_cachesize = cachesize;
489
    *_asecsize = asecsize;
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
    return 0;
}


/* a simpler version of dexOptGenerateCacheFileName() */
int create_cache_path(char path[PKG_PATH_MAX], const char *src)
{
    char *tmp;
    int srclen;
    int dstlen;

    srclen = strlen(src);

        /* demand that we are an absolute path */
    if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
        return -1;
    }

    if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
        return -1;
    }

    dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) + 
        strlen(DALVIK_CACHE_POSTFIX) + 1;
    
    if (dstlen > PKG_PATH_MAX) {
        return -1;
    }

    sprintf(path,"%s%s%s",
            DALVIK_CACHE_PREFIX,
            src + 1, /* skip the leading / */
            DALVIK_CACHE_POSTFIX);
    
    for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
        if (*tmp == '/') {
            *tmp = '@';
        }
    }

    return 0;
}

static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
    const char* dexopt_flags)
{
    static const char* DEX_OPT_BIN = "/system/bin/dexopt";
    static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
    char zip_num[MAX_INT_LEN];
    char odex_num[MAX_INT_LEN];

    sprintf(zip_num, "%d", zip_fd);
    sprintf(odex_num, "%d", odex_fd);

    execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
        dexopt_flags, (char*) NULL);
546
    ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
}

static int wait_dexopt(pid_t pid, const char* apk_path)
{
    int status;
    pid_t got_pid;

    /*
     * Wait for the optimization process to finish.
     */
    while (1) {
        got_pid = waitpid(pid, &status, 0);
        if (got_pid == -1 && errno == EINTR) {
            printf("waitpid interrupted, retrying\n");
        } else {
            break;
        }
    }
    if (got_pid != pid) {
566
        ALOGW("waitpid failed: wanted %d, got %d: %s\n",
567 568 569 570 571
            (int) pid, (int) got_pid, strerror(errno));
        return 1;
    }

    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
572
        ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
573 574
        return 0;
    } else {
575
        ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
            apk_path, status);
        return status;      /* always nonzero */
    }
}

int dexopt(const char *apk_path, uid_t uid, int is_public)
{
    struct utimbuf ut;
    struct stat apk_stat, dex_stat;
    char dex_path[PKG_PATH_MAX];
    char dexopt_flags[PROPERTY_VALUE_MAX];
    char *end;
    int res, zip_fd=-1, odex_fd=-1;

        /* Before anything else: is there a .odex file?  If so, we have
         * pre-optimized the apk and there is nothing to do here.
         */
    if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
        return -1;
    }

    /* platform-specific flags affecting optimization and verification */
    property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");

    strcpy(dex_path, apk_path);
    end = strrchr(dex_path, '.');
    if (end != NULL) {
        strcpy(end, ".odex");
        if (stat(dex_path, &dex_stat) == 0) {
            return 0;
        }
    }

    if (create_cache_path(dex_path, apk_path)) {
        return -1;
    }

    memset(&apk_stat, 0, sizeof(apk_stat));
    stat(apk_path, &apk_stat);

    zip_fd = open(apk_path, O_RDONLY, 0);
    if (zip_fd < 0) {
618
        ALOGE("dexopt cannot open '%s' for input\n", apk_path);
619 620 621 622 623 624
        return -1;
    }

    unlink(dex_path);
    odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
    if (odex_fd < 0) {
625
        ALOGE("dexopt cannot open '%s' for output\n", dex_path);
626 627 628
        goto fail;
    }
    if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
629
        ALOGE("dexopt cannot chown '%s'\n", dex_path);
630 631 632 633 634
        goto fail;
    }
    if (fchmod(odex_fd,
               S_IRUSR|S_IWUSR|S_IRGRP |
               (is_public ? S_IROTH : 0)) < 0) {
635
        ALOGE("dexopt cannot chmod '%s'\n", dex_path);
636 637 638
        goto fail;
    }

639
    ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
640 641 642 643 644 645

    pid_t pid;
    pid = fork();
    if (pid == 0) {
        /* child -- drop privileges before continuing */
        if (setgid(uid) != 0) {
646
            ALOGE("setgid(%d) failed during dexopt\n", uid);
647 648 649
            exit(64);
        }
        if (setuid(uid) != 0) {
650
            ALOGE("setuid(%d) during dexopt\n", uid);
651 652 653
            exit(65);
        }
        if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
654
            ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
655 656 657 658 659 660 661 662
            exit(66);
        }

        run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
        exit(67);   /* only get here on exec failure */
    } else {
        res = wait_dexopt(pid, apk_path);
        if (res != 0) {
663
            ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
            goto fail;
        }
    }

    ut.actime = apk_stat.st_atime;
    ut.modtime = apk_stat.st_mtime;
    utime(dex_path, &ut);
    
    close(odex_fd);
    close(zip_fd);
    return 0;

fail:
    if (odex_fd >= 0) {
        close(odex_fd);
        unlink(dex_path);
    }
    if (zip_fd >= 0) {
        close(zip_fd);
    }
    return -1;
}
686

687 688
void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
        struct stat* statbuf)
689 690 691 692
{
    while (path[basepos] != 0) {
        if (path[basepos] == '/') {
            path[basepos] = 0;
693
            if (lstat(path, statbuf) < 0) {
694
                ALOGV("Making directory: %s\n", path);
695 696 697
                if (mkdir(path, mode) == 0) {
                    chown(path, uid, gid);
                } else {
698
                    ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
699
                }
700 701 702 703 704 705 706 707
            }
            path[basepos] = '/';
            basepos++;
        }
        basepos++;
    }
}

708 709
int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
        int dstuid, int dstgid, struct stat* statbuf)
710 711 712 713 714 715 716 717 718
{
    DIR *d;
    struct dirent *de;
    int res;

    int srcend = strlen(srcpath);
    int dstend = strlen(dstpath);
    
    if (lstat(srcpath, statbuf) < 0) {
719
        ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
720 721 722 723
        return 1;
    }
    
    if ((statbuf->st_mode&S_IFDIR) == 0) {
724 725
        mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
                dstuid, dstgid, statbuf);
726
        ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
727 728
        if (rename(srcpath, dstpath) >= 0) {
            if (chown(dstpath, dstuid, dstgid) < 0) {
729
                ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
730 731 732 733
                unlink(dstpath);
                return 1;
            }
        } else {
734
            ALOGW("Unable to rename %s to %s: %s\n",
735 736 737 738 739 740 741 742
                srcpath, dstpath, strerror(errno));
            return 1;
        }
        return 0;
    }

    d = opendir(srcpath);
    if (d == NULL) {
743
        ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
744 745 746 747 748 749 750 751 752 753 754 755 756 757
        return 1;
    }

    res = 0;
    
    while ((de = readdir(d))) {
        const char *name = de->d_name;
            /* always skip "." and ".." */
        if (name[0] == '.') {
            if (name[1] == 0) continue;
            if ((name[1] == '.') && (name[2] == 0)) continue;
        }
        
        if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
758
            ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
759 760 761 762
            continue;
        }
        
        if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
763
            ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
764 765 766 767 768 769 770
            continue;
        }
        
        srcpath[srcend] = dstpath[dstend] = '/';
        strcpy(srcpath+srcend+1, name);
        strcpy(dstpath+dstend+1, name);
        
771
        if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
772 773 774 775 776 777 778 779 780 781 782 783 784 785
            res = 1;
        }
        
        // Note: we will be leaving empty directories behind in srcpath,
        // but that is okay, the package manager will be erasing all of the
        // data associated with .apks that disappear.
        
        srcpath[srcend] = dstpath[dstend] = 0;
    }
    
    closedir(d);
    return res;
}

786 787 788 789 790 791 792 793 794 795 796 797 798
int movefiles()
{
    DIR *d;
    int dfd, subfd;
    struct dirent *de;
    struct stat s;
    char buf[PKG_PATH_MAX+1];
    int bufp, bufe, bufi, readlen;

    char srcpkg[PKG_NAME_MAX];
    char dstpkg[PKG_NAME_MAX];
    char srcpath[PKG_PATH_MAX];
    char dstpath[PKG_PATH_MAX];
799
    int dstuid=-1, dstgid=-1;
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
    int hasspace;

    d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
    if (d == NULL) {
        goto done;
    }
    dfd = dirfd(d);

        /* Iterate through all files in the directory, executing the
         * file movements requested there-in.
         */
    while ((de = readdir(d))) {
        const char *name = de->d_name;

        if (de->d_type == DT_DIR) {
            continue;
        } else {
            subfd = openat(dfd, name, O_RDONLY);
            if (subfd < 0) {
819
                ALOGW("Unable to open update commands at %s%s\n",
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
                        UPDATE_COMMANDS_DIR_PREFIX, name);
                continue;
            }
            
            bufp = 0;
            bufe = 0;
            buf[PKG_PATH_MAX] = 0;
            srcpkg[0] = dstpkg[0] = 0;
            while (1) {
                bufi = bufp;
                while (bufi < bufe && buf[bufi] != '\n') {
                    bufi++;
                }
                if (bufi < bufe) {
                    buf[bufi] = 0;
835
                    ALOGV("Processing line: %s\n", buf+bufp);
836 837 838 839 840 841 842 843 844
                    hasspace = 0;
                    while (bufp < bufi && isspace(buf[bufp])) {
                        hasspace = 1;
                        bufp++;
                    }
                    if (buf[bufp] == '#' || bufp == bufi) {
                        // skip comments and empty lines.
                    } else if (hasspace) {
                        if (dstpkg[0] == 0) {
845
                            ALOGW("Path before package line in %s%s: %s\n",
846 847 848 849
                                    UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
                        } else if (srcpkg[0] == 0) {
                            // Skip -- source package no longer exists.
                        } else {
850
                            ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
851 852
                            if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
                                    !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
853 854 855
                                movefileordir(srcpath, dstpath,
                                        strlen(dstpath)-strlen(buf+bufp),
                                        dstuid, dstgid, &s);
856 857 858 859 860
                            }
                        }
                    } else {
                        char* div = strchr(buf+bufp, ':');
                        if (div == NULL) {
861
                            ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
862 863 864 865 866 867 868 869
                                    UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
                        } else {
                            *div = 0;
                            div++;
                            if (strlen(buf+bufp) < PKG_NAME_MAX) {
                                strcpy(dstpkg, buf+bufp);
                            } else {
                                srcpkg[0] = dstpkg[0] = 0;
870
                                ALOGW("Package name too long in %s%s: %s\n",
871 872 873 874 875 876
                                        UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
                            }
                            if (strlen(div) < PKG_NAME_MAX) {
                                strcpy(srcpkg, div);
                            } else {
                                srcpkg[0] = dstpkg[0] = 0;
877
                                ALOGW("Package name too long in %s%s: %s\n",
878 879 880
                                        UPDATE_COMMANDS_DIR_PREFIX, name, div);
                            }
                            if (srcpkg[0] != 0) {
881
                                if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
882 883 884 885 886 887
                                    if (lstat(srcpath, &s) < 0) {
                                        // Package no longer exists -- skip.
                                        srcpkg[0] = 0;
                                    }
                                } else {
                                    srcpkg[0] = 0;
888
                                    ALOGW("Can't create path %s in %s%s\n",
889 890 891
                                            div, UPDATE_COMMANDS_DIR_PREFIX, name);
                                }
                                if (srcpkg[0] != 0) {
892
                                    if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
893 894 895 896
                                        if (lstat(dstpath, &s) == 0) {
                                            dstuid = s.st_uid;
                                            dstgid = s.st_gid;
                                        } else {
897 898 899 900
                                            // Destination package doesn't
                                            // exist...  due to original-package,
                                            // this is normal, so don't be
                                            // noisy about it.
901 902 903 904
                                            srcpkg[0] = 0;
                                        }
                                    } else {
                                        srcpkg[0] = 0;
905
                                        ALOGW("Can't create path %s in %s%s\n",
906 907 908
                                                div, UPDATE_COMMANDS_DIR_PREFIX, name);
                                    }
                                }
909
                                ALOGV("Transfering from %s to %s: uid=%d\n",
910 911 912 913 914 915 916 917
                                    srcpkg, dstpkg, dstuid);
                            }
                        }
                    }
                    bufp = bufi+1;
                } else {
                    if (bufp == 0) {
                        if (bufp < bufe) {
918
                            ALOGW("Line too long in %s%s, skipping: %s\n",
919 920 921 922 923 924 925 926 927
                                    UPDATE_COMMANDS_DIR_PREFIX, name, buf);
                        }
                    } else if (bufp < bufe) {
                        memcpy(buf, buf+bufp, bufe-bufp);
                        bufe -= bufp;
                        bufp = 0;
                    }
                    readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
                    if (readlen < 0) {
928
                        ALOGW("Failure reading update commands in %s%s: %s\n",
929 930 931 932 933 934 935
                                UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
                        break;
                    } else if (readlen == 0) {
                        break;
                    }
                    bufe += readlen;
                    buf[bufe] = 0;
936
                    ALOGV("Read buf: %s\n", buf);
937 938 939 940 941 942 943 944 945
                }
            }
            close(subfd);
        }
    }
    closedir(d);
done:
    return 0;
}
946 947 948 949 950 951 952 953 954

int linklib(const char* dataDir, const char* asecLibDir)
{
    char libdir[PKG_PATH_MAX];
    struct stat s, libStat;
    int rc = 0;

    const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
    if (libdirLen >= PKG_PATH_MAX) {
955
        ALOGE("library dir len too large");
956
        return -1;
957 958 959
    }

    if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
960
        ALOGE("library dir not written successfully: %s\n", strerror(errno));
961
        return -1;
962 963 964 965 966
    }

    if (stat(dataDir, &s) < 0) return -1;

    if (chown(dataDir, 0, 0) < 0) {
967
        ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
968 969 970 971
        return -1;
    }

    if (chmod(dataDir, 0700) < 0) {
972
        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
973 974 975 976 977
        rc = -1;
        goto out;
    }

    if (lstat(libdir, &libStat) < 0) {
978
        ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
        rc = -1;
        goto out;
    }

    if (S_ISDIR(libStat.st_mode)) {
        if (delete_dir_contents(libdir, 1, 0) < 0) {
            rc = -1;
            goto out;
        }
    } else if (S_ISLNK(libStat.st_mode)) {
        if (unlink(libdir) < 0) {
            rc = -1;
            goto out;
        }
    }

    if (symlink(asecLibDir, libdir) < 0) {
996
        ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
997 998 999 1000 1001
        rc = -errno;
        goto out;
    }

    if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
1002
        ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
1003 1004 1005 1006 1007 1008 1009
        unlink(libdir);
        rc = -errno;
        goto out;
    }

out:
    if (chmod(dataDir, s.st_mode) < 0) {
1010
        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
1011
        rc = -errno;
1012 1013 1014
    }

    if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
1015
        ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
        return -errno;
    }

    return rc;
}

int unlinklib(const char* dataDir)
{
    char libdir[PKG_PATH_MAX];
    struct stat s, libStat;
    int rc = 0;

    const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
    if (libdirLen >= PKG_PATH_MAX) {
        return -1;
    }

    if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
1034
        ALOGE("library dir not written successfully: %s\n", strerror(errno));
1035 1036 1037 1038
        return -1;
    }

    if (stat(dataDir, &s) < 0) {
1039
        ALOGE("couldn't state data dir");
1040 1041 1042 1043
        return -1;
    }

    if (chown(dataDir, 0, 0) < 0) {
1044
        ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
1045 1046 1047 1048
        return -1;
    }

    if (chmod(dataDir, 0700) < 0) {
1049
        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
1050 1051 1052 1053 1054
        rc = -1;
        goto out;
    }

    if (lstat(libdir, &libStat) < 0) {
1055
        ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
        rc = -1;
        goto out;
    }

    if (S_ISDIR(libStat.st_mode)) {
        if (delete_dir_contents(libdir, 1, 0) < 0) {
            rc = -1;
            goto out;
        }
    } else if (S_ISLNK(libStat.st_mode)) {
        if (unlink(libdir) < 0) {
            rc = -1;
            goto out;
        }
    }

    if (mkdir(libdir, 0755) < 0) {
1073
        ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
1074 1075 1076
        rc = -errno;
        goto out;
    }
1077 1078 1079 1080 1081 1082
    if (chmod(libdir, 0755) < 0) {
        ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
        unlink(libdir);
        rc = -errno;
        goto out;
    }
1083
    if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
1084
        ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
1085 1086 1087 1088 1089 1090 1091
        unlink(libdir);
        rc = -errno;
        goto out;
    }

out:
    if (chmod(dataDir, s.st_mode) < 0) {
1092
        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
1093
        rc = -1;
1094 1095 1096
    }

    if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
1097
        ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
1098 1099 1100 1101 1102
        return -1;
    }

    return rc;
}