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