install.c revision f3bb31c32fa879ccce358c15c93b7bd8582d1756
1/*
2 * Copyright (C) 2009 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 <ctype.h>
18#include <errno.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/mount.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <unistd.h>
28#include <fcntl.h>
29#include <time.h>
30#include <selinux/selinux.h>
31#include <ftw.h>
32#include <sys/capability.h>
33#include <sys/xattr.h>
34#include <linux/xattr.h>
35#include <inttypes.h>
36
37#include "cutils/misc.h"
38#include "cutils/properties.h"
39#include "edify/expr.h"
40#include "mincrypt/sha.h"
41#include "minzip/DirUtil.h"
42#include "mtdutils/mounts.h"
43#include "mtdutils/mtdutils.h"
44#include "updater.h"
45#include "applypatch/applypatch.h"
46
47#ifdef USE_EXT4
48#include "make_ext4fs.h"
49#endif
50
51// mount(fs_type, partition_type, location, mount_point)
52//
53//    fs_type="yaffs2" partition_type="MTD"     location=partition
54//    fs_type="ext4"   partition_type="EMMC"    location=device
55Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
56    char* result = NULL;
57    if (argc != 4) {
58        return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
59    }
60    char* fs_type;
61    char* partition_type;
62    char* location;
63    char* mount_point;
64    if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
65                 &location, &mount_point) < 0) {
66        return NULL;
67    }
68
69    if (strlen(fs_type) == 0) {
70        ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
71        goto done;
72    }
73    if (strlen(partition_type) == 0) {
74        ErrorAbort(state, "partition_type argument to %s() can't be empty",
75                   name);
76        goto done;
77    }
78    if (strlen(location) == 0) {
79        ErrorAbort(state, "location argument to %s() can't be empty", name);
80        goto done;
81    }
82    if (strlen(mount_point) == 0) {
83        ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
84        goto done;
85    }
86
87    char *secontext = NULL;
88
89    if (sehandle) {
90        selabel_lookup(sehandle, &secontext, mount_point, 0755);
91        setfscreatecon(secontext);
92    }
93
94    mkdir(mount_point, 0755);
95
96    if (secontext) {
97        freecon(secontext);
98        setfscreatecon(NULL);
99    }
100
101    if (strcmp(partition_type, "MTD") == 0) {
102        mtd_scan_partitions();
103        const MtdPartition* mtd;
104        mtd = mtd_find_partition_by_name(location);
105        if (mtd == NULL) {
106            printf("%s: no mtd partition named \"%s\"",
107                    name, location);
108            result = strdup("");
109            goto done;
110        }
111        if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
112            printf("mtd mount of %s failed: %s\n",
113                    location, strerror(errno));
114            result = strdup("");
115            goto done;
116        }
117        result = mount_point;
118    } else {
119        if (mount(location, mount_point, fs_type,
120                  MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
121            printf("%s: failed to mount %s at %s: %s\n",
122                    name, location, mount_point, strerror(errno));
123            result = strdup("");
124        } else {
125            result = mount_point;
126        }
127    }
128
129done:
130    free(fs_type);
131    free(partition_type);
132    free(location);
133    if (result != mount_point) free(mount_point);
134    return StringValue(result);
135}
136
137
138// is_mounted(mount_point)
139Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
140    char* result = NULL;
141    if (argc != 1) {
142        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
143    }
144    char* mount_point;
145    if (ReadArgs(state, argv, 1, &mount_point) < 0) {
146        return NULL;
147    }
148    if (strlen(mount_point) == 0) {
149        ErrorAbort(state, "mount_point argument to unmount() can't be empty");
150        goto done;
151    }
152
153    scan_mounted_volumes();
154    const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
155    if (vol == NULL) {
156        result = strdup("");
157    } else {
158        result = mount_point;
159    }
160
161done:
162    if (result != mount_point) free(mount_point);
163    return StringValue(result);
164}
165
166
167Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
168    char* result = NULL;
169    if (argc != 1) {
170        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
171    }
172    char* mount_point;
173    if (ReadArgs(state, argv, 1, &mount_point) < 0) {
174        return NULL;
175    }
176    if (strlen(mount_point) == 0) {
177        ErrorAbort(state, "mount_point argument to unmount() can't be empty");
178        goto done;
179    }
180
181    scan_mounted_volumes();
182    const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
183    if (vol == NULL) {
184        printf("unmount of %s failed; no such volume\n", mount_point);
185        result = strdup("");
186    } else {
187        unmount_mounted_volume(vol);
188        result = mount_point;
189    }
190
191done:
192    if (result != mount_point) free(mount_point);
193    return StringValue(result);
194}
195
196
197// format(fs_type, partition_type, location, fs_size, mount_point)
198//
199//    fs_type="yaffs2" partition_type="MTD"     location=partition fs_size=<bytes> mount_point=<location>
200//    fs_type="ext4"   partition_type="EMMC"    location=device    fs_size=<bytes> mount_point=<location>
201//    if fs_size == 0, then make_ext4fs uses the entire partition.
202//    if fs_size > 0, that is the size to use
203//    if fs_size < 0, then reserve that many bytes at the end of the partition
204Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
205    char* result = NULL;
206    if (argc != 5) {
207        return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc);
208    }
209    char* fs_type;
210    char* partition_type;
211    char* location;
212    char* fs_size;
213    char* mount_point;
214
215    if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) {
216        return NULL;
217    }
218
219    if (strlen(fs_type) == 0) {
220        ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
221        goto done;
222    }
223    if (strlen(partition_type) == 0) {
224        ErrorAbort(state, "partition_type argument to %s() can't be empty",
225                   name);
226        goto done;
227    }
228    if (strlen(location) == 0) {
229        ErrorAbort(state, "location argument to %s() can't be empty", name);
230        goto done;
231    }
232
233    if (strlen(mount_point) == 0) {
234        ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
235        goto done;
236    }
237
238    if (strcmp(partition_type, "MTD") == 0) {
239        mtd_scan_partitions();
240        const MtdPartition* mtd = mtd_find_partition_by_name(location);
241        if (mtd == NULL) {
242            printf("%s: no mtd partition named \"%s\"",
243                    name, location);
244            result = strdup("");
245            goto done;
246        }
247        MtdWriteContext* ctx = mtd_write_partition(mtd);
248        if (ctx == NULL) {
249            printf("%s: can't write \"%s\"", name, location);
250            result = strdup("");
251            goto done;
252        }
253        if (mtd_erase_blocks(ctx, -1) == -1) {
254            mtd_write_close(ctx);
255            printf("%s: failed to erase \"%s\"", name, location);
256            result = strdup("");
257            goto done;
258        }
259        if (mtd_write_close(ctx) != 0) {
260            printf("%s: failed to close \"%s\"", name, location);
261            result = strdup("");
262            goto done;
263        }
264        result = location;
265#ifdef USE_EXT4
266    } else if (strcmp(fs_type, "ext4") == 0) {
267        int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
268        if (status != 0) {
269            printf("%s: make_ext4fs failed (%d) on %s",
270                    name, status, location);
271            result = strdup("");
272            goto done;
273        }
274        result = location;
275#endif
276    } else {
277        printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"",
278                name, fs_type, partition_type);
279    }
280
281done:
282    free(fs_type);
283    free(partition_type);
284    if (result != location) free(location);
285    return StringValue(result);
286}
287
288Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) {
289    char* result = NULL;
290    if (argc != 2) {
291        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
292    }
293
294    char* src_name;
295    char* dst_name;
296
297    if (ReadArgs(state, argv, 2, &src_name, &dst_name) < 0) {
298        return NULL;
299    }
300    if (strlen(src_name) == 0) {
301        ErrorAbort(state, "src_name argument to %s() can't be empty", name);
302        goto done;
303    }
304    if (strlen(dst_name) == 0) {
305        ErrorAbort(state, "dst_name argument to %s() can't be empty",
306                   name);
307        goto done;
308    }
309
310    if (rename(src_name, dst_name) != 0) {
311        ErrorAbort(state, "Rename of %s() to %s() failed, error %s()",
312          src_name, dst_name, strerror(errno));
313    } else {
314        result = dst_name;
315    }
316
317done:
318    free(src_name);
319    if (result != dst_name) free(dst_name);
320    return StringValue(result);
321}
322
323Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
324    char** paths = malloc(argc * sizeof(char*));
325    int i;
326    for (i = 0; i < argc; ++i) {
327        paths[i] = Evaluate(state, argv[i]);
328        if (paths[i] == NULL) {
329            int j;
330            for (j = 0; j < i; ++i) {
331                free(paths[j]);
332            }
333            free(paths);
334            return NULL;
335        }
336    }
337
338    bool recursive = (strcmp(name, "delete_recursive") == 0);
339
340    int success = 0;
341    for (i = 0; i < argc; ++i) {
342        if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
343            ++success;
344        free(paths[i]);
345    }
346    free(paths);
347
348    char buffer[10];
349    sprintf(buffer, "%d", success);
350    return StringValue(strdup(buffer));
351}
352
353
354Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
355    if (argc != 2) {
356        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
357    }
358    char* frac_str;
359    char* sec_str;
360    if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
361        return NULL;
362    }
363
364    double frac = strtod(frac_str, NULL);
365    int sec = strtol(sec_str, NULL, 10);
366
367    UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
368    fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
369
370    free(sec_str);
371    return StringValue(frac_str);
372}
373
374Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
375    if (argc != 1) {
376        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
377    }
378    char* frac_str;
379    if (ReadArgs(state, argv, 1, &frac_str) < 0) {
380        return NULL;
381    }
382
383    double frac = strtod(frac_str, NULL);
384
385    UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
386    fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
387
388    return StringValue(frac_str);
389}
390
391// package_extract_dir(package_path, destination_path)
392Value* PackageExtractDirFn(const char* name, State* state,
393                          int argc, Expr* argv[]) {
394    if (argc != 2) {
395        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
396    }
397    char* zip_path;
398    char* dest_path;
399    if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
400
401    ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
402
403    // To create a consistent system image, never use the clock for timestamps.
404    struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default
405
406    bool success = mzExtractRecursive(za, zip_path, dest_path,
407                                      MZ_EXTRACT_FILES_ONLY, &timestamp,
408                                      NULL, NULL, sehandle);
409    free(zip_path);
410    free(dest_path);
411    return StringValue(strdup(success ? "t" : ""));
412}
413
414
415// package_extract_file(package_path, destination_path)
416//   or
417// package_extract_file(package_path)
418//   to return the entire contents of the file as the result of this
419//   function (the char* returned is actually a FileContents*).
420Value* PackageExtractFileFn(const char* name, State* state,
421                           int argc, Expr* argv[]) {
422    if (argc != 1 && argc != 2) {
423        return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
424                          name, argc);
425    }
426    bool success = false;
427    if (argc == 2) {
428        // The two-argument version extracts to a file.
429
430        char* zip_path;
431        char* dest_path;
432        if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
433
434        ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
435        const ZipEntry* entry = mzFindZipEntry(za, zip_path);
436        if (entry == NULL) {
437            printf("%s: no %s in package\n", name, zip_path);
438            goto done2;
439        }
440
441        FILE* f = fopen(dest_path, "wb");
442        if (f == NULL) {
443            printf("%s: can't open %s for write: %s\n",
444                    name, dest_path, strerror(errno));
445            goto done2;
446        }
447        success = mzExtractZipEntryToFile(za, entry, fileno(f));
448        fclose(f);
449
450      done2:
451        free(zip_path);
452        free(dest_path);
453        return StringValue(strdup(success ? "t" : ""));
454    } else {
455        // The one-argument version returns the contents of the file
456        // as the result.
457
458        char* zip_path;
459        Value* v = malloc(sizeof(Value));
460        v->type = VAL_BLOB;
461        v->size = -1;
462        v->data = NULL;
463
464        if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
465
466        ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
467        const ZipEntry* entry = mzFindZipEntry(za, zip_path);
468        if (entry == NULL) {
469            printf("%s: no %s in package\n", name, zip_path);
470            goto done1;
471        }
472
473        v->size = mzGetZipEntryUncompLen(entry);
474        v->data = malloc(v->size);
475        if (v->data == NULL) {
476            printf("%s: failed to allocate %ld bytes for %s\n",
477                    name, (long)v->size, zip_path);
478            goto done1;
479        }
480
481        success = mzExtractZipEntryToBuffer(za, entry,
482                                            (unsigned char *)v->data);
483
484      done1:
485        free(zip_path);
486        if (!success) {
487            free(v->data);
488            v->data = NULL;
489            v->size = -1;
490        }
491        return v;
492    }
493}
494
495// Create all parent directories of name, if necessary.
496static int make_parents(char* name) {
497    char* p;
498    for (p = name + (strlen(name)-1); p > name; --p) {
499        if (*p != '/') continue;
500        *p = '\0';
501        if (make_parents(name) < 0) return -1;
502        int result = mkdir(name, 0700);
503        if (result == 0) printf("symlink(): created [%s]\n", name);
504        *p = '/';
505        if (result == 0 || errno == EEXIST) {
506            // successfully created or already existed; we're done
507            return 0;
508        } else {
509            printf("failed to mkdir %s: %s\n", name, strerror(errno));
510            return -1;
511        }
512    }
513    return 0;
514}
515
516// symlink target src1 src2 ...
517//    unlinks any previously existing src1, src2, etc before creating symlinks.
518Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
519    if (argc == 0) {
520        return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
521    }
522    char* target;
523    target = Evaluate(state, argv[0]);
524    if (target == NULL) return NULL;
525
526    char** srcs = ReadVarArgs(state, argc-1, argv+1);
527    if (srcs == NULL) {
528        free(target);
529        return NULL;
530    }
531
532    int bad = 0;
533    int i;
534    for (i = 0; i < argc-1; ++i) {
535        if (unlink(srcs[i]) < 0) {
536            if (errno != ENOENT) {
537                printf("%s: failed to remove %s: %s\n",
538                        name, srcs[i], strerror(errno));
539                ++bad;
540            }
541        }
542        if (make_parents(srcs[i])) {
543            printf("%s: failed to symlink %s to %s: making parents failed\n",
544                    name, srcs[i], target);
545            ++bad;
546        }
547        if (symlink(target, srcs[i]) < 0) {
548            printf("%s: failed to symlink %s to %s: %s\n",
549                    name, srcs[i], target, strerror(errno));
550            ++bad;
551        }
552        free(srcs[i]);
553    }
554    free(srcs);
555    if (bad) {
556        return ErrorAbort(state, "%s: some symlinks failed", name);
557    }
558    return StringValue(strdup(""));
559}
560
561struct perm_parsed_args {
562    bool has_uid;
563    uid_t uid;
564    bool has_gid;
565    gid_t gid;
566    bool has_mode;
567    mode_t mode;
568    bool has_fmode;
569    mode_t fmode;
570    bool has_dmode;
571    mode_t dmode;
572    bool has_selabel;
573    char* selabel;
574    bool has_capabilities;
575    uint64_t capabilities;
576};
577
578static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
579    int i;
580    struct perm_parsed_args parsed;
581    int bad = 0;
582    static int max_warnings = 20;
583
584    memset(&parsed, 0, sizeof(parsed));
585
586    for (i = 1; i < argc; i += 2) {
587        if (strcmp("uid", args[i]) == 0) {
588            int64_t uid;
589            if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) {
590                parsed.uid = uid;
591                parsed.has_uid = true;
592            } else {
593                printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]);
594                bad++;
595            }
596            continue;
597        }
598        if (strcmp("gid", args[i]) == 0) {
599            int64_t gid;
600            if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) {
601                parsed.gid = gid;
602                parsed.has_gid = true;
603            } else {
604                printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]);
605                bad++;
606            }
607            continue;
608        }
609        if (strcmp("mode", args[i]) == 0) {
610            int32_t mode;
611            if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
612                parsed.mode = mode;
613                parsed.has_mode = true;
614            } else {
615                printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]);
616                bad++;
617            }
618            continue;
619        }
620        if (strcmp("dmode", args[i]) == 0) {
621            int32_t mode;
622            if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
623                parsed.dmode = mode;
624                parsed.has_dmode = true;
625            } else {
626                printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]);
627                bad++;
628            }
629            continue;
630        }
631        if (strcmp("fmode", args[i]) == 0) {
632            int32_t mode;
633            if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) {
634                parsed.fmode = mode;
635                parsed.has_fmode = true;
636            } else {
637                printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]);
638                bad++;
639            }
640            continue;
641        }
642        if (strcmp("capabilities", args[i]) == 0) {
643            int64_t capabilities;
644            if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) {
645                parsed.capabilities = capabilities;
646                parsed.has_capabilities = true;
647            } else {
648                printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]);
649                bad++;
650            }
651            continue;
652        }
653        if (strcmp("selabel", args[i]) == 0) {
654            if (args[i+1][0] != '\0') {
655                parsed.selabel = args[i+1];
656                parsed.has_selabel = true;
657            } else {
658                printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]);
659                bad++;
660            }
661            continue;
662        }
663        if (max_warnings != 0) {
664            printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]);
665            max_warnings--;
666            if (max_warnings == 0) {
667                printf("ParsedPermArgs: suppressing further warnings\n");
668            }
669        }
670    }
671    return parsed;
672}
673
674static int ApplyParsedPerms(
675        const char* filename,
676        const struct stat *statptr,
677        struct perm_parsed_args parsed)
678{
679    int bad = 0;
680
681    /* ignore symlinks */
682    if (S_ISLNK(statptr->st_mode)) {
683        return 0;
684    }
685
686    if (parsed.has_uid) {
687        if (chown(filename, parsed.uid, -1) < 0) {
688            printf("ApplyParsedPerms: chown of %s to %d failed: %s\n",
689                   filename, parsed.uid, strerror(errno));
690            bad++;
691        }
692    }
693
694    if (parsed.has_gid) {
695        if (chown(filename, -1, parsed.gid) < 0) {
696            printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n",
697                   filename, parsed.gid, strerror(errno));
698            bad++;
699        }
700    }
701
702    if (parsed.has_mode) {
703        if (chmod(filename, parsed.mode) < 0) {
704            printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
705                   filename, parsed.mode, strerror(errno));
706            bad++;
707        }
708    }
709
710    if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) {
711        if (chmod(filename, parsed.dmode) < 0) {
712            printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
713                   filename, parsed.dmode, strerror(errno));
714            bad++;
715        }
716    }
717
718    if (parsed.has_fmode && S_ISREG(statptr->st_mode)) {
719        if (chmod(filename, parsed.fmode) < 0) {
720            printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
721                   filename, parsed.fmode, strerror(errno));
722            bad++;
723        }
724    }
725
726    if (parsed.has_selabel) {
727        // TODO: Don't silently ignore ENOTSUP
728        if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) {
729            printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n",
730                   filename, parsed.selabel, strerror(errno));
731            bad++;
732        }
733    }
734
735    if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) {
736        if (parsed.capabilities == 0) {
737            if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) {
738                // Report failure unless it's ENODATA (attribute not set)
739                printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n",
740                       filename, parsed.capabilities, strerror(errno));
741                bad++;
742            }
743        } else {
744            struct vfs_cap_data cap_data;
745            memset(&cap_data, 0, sizeof(cap_data));
746            cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
747            cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff);
748            cap_data.data[0].inheritable = 0;
749            cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32);
750            cap_data.data[1].inheritable = 0;
751            if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) {
752                printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n",
753                       filename, parsed.capabilities, strerror(errno));
754                bad++;
755            }
756        }
757    }
758
759    return bad;
760}
761
762// nftw doesn't allow us to pass along context, so we need to use
763// global variables.  *sigh*
764static struct perm_parsed_args recursive_parsed_args;
765
766static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr,
767        int fileflags, struct FTW *pfwt) {
768    return ApplyParsedPerms(filename, statptr, recursive_parsed_args);
769}
770
771static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) {
772    int i;
773    int bad = 0;
774    static int nwarnings = 0;
775    struct stat sb;
776    Value* result = NULL;
777
778    bool recursive = (strcmp(name, "set_metadata_recursive") == 0);
779
780    if ((argc % 2) != 1) {
781        return ErrorAbort(state, "%s() expects an odd number of arguments, got %d",
782                          name, argc);
783    }
784
785    char** args = ReadVarArgs(state, argc, argv);
786    if (args == NULL) return NULL;
787
788    if (lstat(args[0], &sb) == -1) {
789        result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno));
790        goto done;
791    }
792
793    struct perm_parsed_args parsed = ParsePermArgs(argc, args);
794
795    if (recursive) {
796        recursive_parsed_args = parsed;
797        bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS);
798        memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args));
799    } else {
800        bad += ApplyParsedPerms(args[0], &sb, parsed);
801    }
802
803done:
804    for (i = 0; i < argc; ++i) {
805        free(args[i]);
806    }
807    free(args);
808
809    if (result != NULL) {
810        return result;
811    }
812
813    if (bad > 0) {
814        return ErrorAbort(state, "%s: some changes failed", name);
815    }
816
817    return StringValue(strdup(""));
818}
819
820Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
821    if (argc != 1) {
822        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
823    }
824    char* key;
825    key = Evaluate(state, argv[0]);
826    if (key == NULL) return NULL;
827
828    char value[PROPERTY_VALUE_MAX];
829    property_get(key, value, "");
830    free(key);
831
832    return StringValue(strdup(value));
833}
834
835
836// file_getprop(file, key)
837//
838//   interprets 'file' as a getprop-style file (key=value pairs, one
839//   per line, # comment lines and blank lines okay), and returns the value
840//   for 'key' (or "" if it isn't defined).
841Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
842    char* result = NULL;
843    char* buffer = NULL;
844    char* filename;
845    char* key;
846    if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
847        return NULL;
848    }
849
850    struct stat st;
851    if (stat(filename, &st) < 0) {
852        ErrorAbort(state, "%s: failed to stat \"%s\": %s",
853                   name, filename, strerror(errno));
854        goto done;
855    }
856
857#define MAX_FILE_GETPROP_SIZE    65536
858
859    if (st.st_size > MAX_FILE_GETPROP_SIZE) {
860        ErrorAbort(state, "%s too large for %s (max %d)",
861                   filename, name, MAX_FILE_GETPROP_SIZE);
862        goto done;
863    }
864
865    buffer = malloc(st.st_size+1);
866    if (buffer == NULL) {
867        ErrorAbort(state, "%s: failed to alloc %lld bytes", name, (long long)st.st_size+1);
868        goto done;
869    }
870
871    FILE* f = fopen(filename, "rb");
872    if (f == NULL) {
873        ErrorAbort(state, "%s: failed to open %s: %s",
874                   name, filename, strerror(errno));
875        goto done;
876    }
877
878    if (fread(buffer, 1, st.st_size, f) != st.st_size) {
879        ErrorAbort(state, "%s: failed to read %lld bytes from %s",
880                   name, (long long)st.st_size+1, filename);
881        fclose(f);
882        goto done;
883    }
884    buffer[st.st_size] = '\0';
885
886    fclose(f);
887
888    char* line = strtok(buffer, "\n");
889    do {
890        // skip whitespace at start of line
891        while (*line && isspace(*line)) ++line;
892
893        // comment or blank line: skip to next line
894        if (*line == '\0' || *line == '#') continue;
895
896        char* equal = strchr(line, '=');
897        if (equal == NULL) {
898            ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
899                       name, line, filename);
900            goto done;
901        }
902
903        // trim whitespace between key and '='
904        char* key_end = equal-1;
905        while (key_end > line && isspace(*key_end)) --key_end;
906        key_end[1] = '\0';
907
908        // not the key we're looking for
909        if (strcmp(key, line) != 0) continue;
910
911        // skip whitespace after the '=' to the start of the value
912        char* val_start = equal+1;
913        while(*val_start && isspace(*val_start)) ++val_start;
914
915        // trim trailing whitespace
916        char* val_end = val_start + strlen(val_start)-1;
917        while (val_end > val_start && isspace(*val_end)) --val_end;
918        val_end[1] = '\0';
919
920        result = strdup(val_start);
921        break;
922
923    } while ((line = strtok(NULL, "\n")));
924
925    if (result == NULL) result = strdup("");
926
927  done:
928    free(filename);
929    free(key);
930    free(buffer);
931    return StringValue(result);
932}
933
934
935static bool write_raw_image_cb(const unsigned char* data,
936                               int data_len, void* ctx) {
937    int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
938    if (r == data_len) return true;
939    printf("%s\n", strerror(errno));
940    return false;
941}
942
943// write_raw_image(filename_or_blob, partition)
944Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
945    char* result = NULL;
946
947    Value* partition_value;
948    Value* contents;
949    if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
950        return NULL;
951    }
952
953    char* partition = NULL;
954    if (partition_value->type != VAL_STRING) {
955        ErrorAbort(state, "partition argument to %s must be string", name);
956        goto done;
957    }
958    partition = partition_value->data;
959    if (strlen(partition) == 0) {
960        ErrorAbort(state, "partition argument to %s can't be empty", name);
961        goto done;
962    }
963    if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
964        ErrorAbort(state, "file argument to %s can't be empty", name);
965        goto done;
966    }
967
968    mtd_scan_partitions();
969    const MtdPartition* mtd = mtd_find_partition_by_name(partition);
970    if (mtd == NULL) {
971        printf("%s: no mtd partition named \"%s\"\n", name, partition);
972        result = strdup("");
973        goto done;
974    }
975
976    MtdWriteContext* ctx = mtd_write_partition(mtd);
977    if (ctx == NULL) {
978        printf("%s: can't write mtd partition \"%s\"\n",
979                name, partition);
980        result = strdup("");
981        goto done;
982    }
983
984    bool success;
985
986    if (contents->type == VAL_STRING) {
987        // we're given a filename as the contents
988        char* filename = contents->data;
989        FILE* f = fopen(filename, "rb");
990        if (f == NULL) {
991            printf("%s: can't open %s: %s\n",
992                    name, filename, strerror(errno));
993            result = strdup("");
994            goto done;
995        }
996
997        success = true;
998        char* buffer = malloc(BUFSIZ);
999        int read;
1000        while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
1001            int wrote = mtd_write_data(ctx, buffer, read);
1002            success = success && (wrote == read);
1003        }
1004        free(buffer);
1005        fclose(f);
1006    } else {
1007        // we're given a blob as the contents
1008        ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size);
1009        success = (wrote == contents->size);
1010    }
1011    if (!success) {
1012        printf("mtd_write_data to %s failed: %s\n",
1013                partition, strerror(errno));
1014    }
1015
1016    if (mtd_erase_blocks(ctx, -1) == -1) {
1017        printf("%s: error erasing blocks of %s\n", name, partition);
1018    }
1019    if (mtd_write_close(ctx) != 0) {
1020        printf("%s: error closing write of %s\n", name, partition);
1021    }
1022
1023    printf("%s %s partition\n",
1024           success ? "wrote" : "failed to write", partition);
1025
1026    result = success ? partition : strdup("");
1027
1028done:
1029    if (result != partition) FreeValue(partition_value);
1030    FreeValue(contents);
1031    return StringValue(result);
1032}
1033
1034// apply_patch_space(bytes)
1035Value* ApplyPatchSpaceFn(const char* name, State* state,
1036                         int argc, Expr* argv[]) {
1037    char* bytes_str;
1038    if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
1039        return NULL;
1040    }
1041
1042    char* endptr;
1043    size_t bytes = strtol(bytes_str, &endptr, 10);
1044    if (bytes == 0 && endptr == bytes_str) {
1045        ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
1046                   name, bytes_str);
1047        free(bytes_str);
1048        return NULL;
1049    }
1050
1051    return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
1052}
1053
1054
1055// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
1056Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
1057    if (argc < 6 || (argc % 2) == 1) {
1058        return ErrorAbort(state, "%s(): expected at least 6 args and an "
1059                                 "even number, got %d",
1060                          name, argc);
1061    }
1062
1063    char* source_filename;
1064    char* target_filename;
1065    char* target_sha1;
1066    char* target_size_str;
1067    if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
1068                 &target_sha1, &target_size_str) < 0) {
1069        return NULL;
1070    }
1071
1072    char* endptr;
1073    size_t target_size = strtol(target_size_str, &endptr, 10);
1074    if (target_size == 0 && endptr == target_size_str) {
1075        ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
1076                   name, target_size_str);
1077        free(source_filename);
1078        free(target_filename);
1079        free(target_sha1);
1080        free(target_size_str);
1081        return NULL;
1082    }
1083
1084    int patchcount = (argc-4) / 2;
1085    Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
1086
1087    int i;
1088    for (i = 0; i < patchcount; ++i) {
1089        if (patches[i*2]->type != VAL_STRING) {
1090            ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
1091            break;
1092        }
1093        if (patches[i*2+1]->type != VAL_BLOB) {
1094            ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
1095            break;
1096        }
1097    }
1098    if (i != patchcount) {
1099        for (i = 0; i < patchcount*2; ++i) {
1100            FreeValue(patches[i]);
1101        }
1102        free(patches);
1103        return NULL;
1104    }
1105
1106    char** patch_sha_str = malloc(patchcount * sizeof(char*));
1107    for (i = 0; i < patchcount; ++i) {
1108        patch_sha_str[i] = patches[i*2]->data;
1109        patches[i*2]->data = NULL;
1110        FreeValue(patches[i*2]);
1111        patches[i] = patches[i*2+1];
1112    }
1113
1114    int result = applypatch(source_filename, target_filename,
1115                            target_sha1, target_size,
1116                            patchcount, patch_sha_str, patches, NULL);
1117
1118    for (i = 0; i < patchcount; ++i) {
1119        FreeValue(patches[i]);
1120    }
1121    free(patch_sha_str);
1122    free(patches);
1123
1124    return StringValue(strdup(result == 0 ? "t" : ""));
1125}
1126
1127// apply_patch_check(file, [sha1_1, ...])
1128Value* ApplyPatchCheckFn(const char* name, State* state,
1129                         int argc, Expr* argv[]) {
1130    if (argc < 1) {
1131        return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
1132                          name, argc);
1133    }
1134
1135    char* filename;
1136    if (ReadArgs(state, argv, 1, &filename) < 0) {
1137        return NULL;
1138    }
1139
1140    int patchcount = argc-1;
1141    char** sha1s = ReadVarArgs(state, argc-1, argv+1);
1142
1143    int result = applypatch_check(filename, patchcount, sha1s);
1144
1145    int i;
1146    for (i = 0; i < patchcount; ++i) {
1147        free(sha1s[i]);
1148    }
1149    free(sha1s);
1150
1151    return StringValue(strdup(result == 0 ? "t" : ""));
1152}
1153
1154Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
1155    char** args = ReadVarArgs(state, argc, argv);
1156    if (args == NULL) {
1157        return NULL;
1158    }
1159
1160    int size = 0;
1161    int i;
1162    for (i = 0; i < argc; ++i) {
1163        size += strlen(args[i]);
1164    }
1165    char* buffer = malloc(size+1);
1166    size = 0;
1167    for (i = 0; i < argc; ++i) {
1168        strcpy(buffer+size, args[i]);
1169        size += strlen(args[i]);
1170        free(args[i]);
1171    }
1172    free(args);
1173    buffer[size] = '\0';
1174
1175    char* line = strtok(buffer, "\n");
1176    while (line) {
1177        fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
1178                "ui_print %s\n", line);
1179        line = strtok(NULL, "\n");
1180    }
1181    fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
1182
1183    return StringValue(buffer);
1184}
1185
1186Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
1187    if (argc != 0) {
1188        return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
1189    }
1190    fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
1191    return StringValue(strdup("t"));
1192}
1193
1194Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
1195    if (argc < 1) {
1196        return ErrorAbort(state, "%s() expects at least 1 arg", name);
1197    }
1198    char** args = ReadVarArgs(state, argc, argv);
1199    if (args == NULL) {
1200        return NULL;
1201    }
1202
1203    char** args2 = malloc(sizeof(char*) * (argc+1));
1204    memcpy(args2, args, sizeof(char*) * argc);
1205    args2[argc] = NULL;
1206
1207    printf("about to run program [%s] with %d args\n", args2[0], argc);
1208
1209    pid_t child = fork();
1210    if (child == 0) {
1211        execv(args2[0], args2);
1212        printf("run_program: execv failed: %s\n", strerror(errno));
1213        _exit(1);
1214    }
1215    int status;
1216    waitpid(child, &status, 0);
1217    if (WIFEXITED(status)) {
1218        if (WEXITSTATUS(status) != 0) {
1219            printf("run_program: child exited with status %d\n",
1220                    WEXITSTATUS(status));
1221        }
1222    } else if (WIFSIGNALED(status)) {
1223        printf("run_program: child terminated by signal %d\n",
1224                WTERMSIG(status));
1225    }
1226
1227    int i;
1228    for (i = 0; i < argc; ++i) {
1229        free(args[i]);
1230    }
1231    free(args);
1232    free(args2);
1233
1234    char buffer[20];
1235    sprintf(buffer, "%d", status);
1236
1237    return StringValue(strdup(buffer));
1238}
1239
1240// Take a sha-1 digest and return it as a newly-allocated hex string.
1241static char* PrintSha1(uint8_t* digest) {
1242    char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
1243    int i;
1244    const char* alphabet = "0123456789abcdef";
1245    for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
1246        buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
1247        buffer[i*2+1] = alphabet[digest[i] & 0xf];
1248    }
1249    buffer[i*2] = '\0';
1250    return buffer;
1251}
1252
1253// sha1_check(data)
1254//    to return the sha1 of the data (given in the format returned by
1255//    read_file).
1256//
1257// sha1_check(data, sha1_hex, [sha1_hex, ...])
1258//    returns the sha1 of the file if it matches any of the hex
1259//    strings passed, or "" if it does not equal any of them.
1260//
1261Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
1262    if (argc < 1) {
1263        return ErrorAbort(state, "%s() expects at least 1 arg", name);
1264    }
1265
1266    Value** args = ReadValueVarArgs(state, argc, argv);
1267    if (args == NULL) {
1268        return NULL;
1269    }
1270
1271    if (args[0]->size < 0) {
1272        printf("%s(): no file contents received", name);
1273        return StringValue(strdup(""));
1274    }
1275    uint8_t digest[SHA_DIGEST_SIZE];
1276    SHA_hash(args[0]->data, args[0]->size, digest);
1277    FreeValue(args[0]);
1278
1279    if (argc == 1) {
1280        return StringValue(PrintSha1(digest));
1281    }
1282
1283    int i;
1284    uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
1285    for (i = 1; i < argc; ++i) {
1286        if (args[i]->type != VAL_STRING) {
1287            printf("%s(): arg %d is not a string; skipping",
1288                    name, i);
1289        } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
1290            // Warn about bad args and skip them.
1291            printf("%s(): error parsing \"%s\" as sha-1; skipping",
1292                   name, args[i]->data);
1293        } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
1294            break;
1295        }
1296        FreeValue(args[i]);
1297    }
1298    if (i >= argc) {
1299        // Didn't match any of the hex strings; return false.
1300        return StringValue(strdup(""));
1301    }
1302    // Found a match; free all the remaining arguments and return the
1303    // matched one.
1304    int j;
1305    for (j = i+1; j < argc; ++j) {
1306        FreeValue(args[j]);
1307    }
1308    return args[i];
1309}
1310
1311// Read a local file and return its contents (the Value* returned
1312// is actually a FileContents*).
1313Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
1314    if (argc != 1) {
1315        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
1316    }
1317    char* filename;
1318    if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
1319
1320    Value* v = malloc(sizeof(Value));
1321    v->type = VAL_BLOB;
1322
1323    FileContents fc;
1324    if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
1325        ErrorAbort(state, "%s() loading \"%s\" failed: %s",
1326                   name, filename, strerror(errno));
1327        free(filename);
1328        free(v);
1329        free(fc.data);
1330        return NULL;
1331    }
1332
1333    v->size = fc.size;
1334    v->data = (char*)fc.data;
1335
1336    free(filename);
1337    return v;
1338}
1339
1340void RegisterInstallFunctions() {
1341    RegisterFunction("mount", MountFn);
1342    RegisterFunction("is_mounted", IsMountedFn);
1343    RegisterFunction("unmount", UnmountFn);
1344    RegisterFunction("format", FormatFn);
1345    RegisterFunction("show_progress", ShowProgressFn);
1346    RegisterFunction("set_progress", SetProgressFn);
1347    RegisterFunction("delete", DeleteFn);
1348    RegisterFunction("delete_recursive", DeleteFn);
1349    RegisterFunction("package_extract_dir", PackageExtractDirFn);
1350    RegisterFunction("package_extract_file", PackageExtractFileFn);
1351    RegisterFunction("symlink", SymlinkFn);
1352
1353    // Usage:
1354    //   set_metadata("filename", "key1", "value1", "key2", "value2", ...)
1355    // Example:
1356    //   set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0);
1357    RegisterFunction("set_metadata", SetMetadataFn);
1358
1359    // Usage:
1360    //   set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...)
1361    // Example:
1362    //   set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0);
1363    RegisterFunction("set_metadata_recursive", SetMetadataFn);
1364
1365    RegisterFunction("getprop", GetPropFn);
1366    RegisterFunction("file_getprop", FileGetPropFn);
1367    RegisterFunction("write_raw_image", WriteRawImageFn);
1368
1369    RegisterFunction("apply_patch", ApplyPatchFn);
1370    RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1371    RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
1372
1373    RegisterFunction("read_file", ReadFileFn);
1374    RegisterFunction("sha1_check", Sha1CheckFn);
1375    RegisterFunction("rename", RenameFn);
1376
1377    RegisterFunction("wipe_cache", WipeCacheFn);
1378
1379    RegisterFunction("ui_print", UIPrintFn);
1380
1381    RegisterFunction("run_program", RunProgramFn);
1382}
1383