• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 #include "cutils/misc.h"
32 #include "cutils/properties.h"
33 #include "edify/expr.h"
34 #include "mincrypt/sha.h"
35 #include "minzip/DirUtil.h"
36 #include "mtdutils/mounts.h"
37 #include "mtdutils/mtdutils.h"
38 #include "updater.h"
39 #include "applypatch/applypatch.h"
40 
41 #ifdef USE_EXT4
42 #include "make_ext4fs.h"
43 #endif
44 
45 // mount(fs_type, partition_type, location, mount_point)
46 //
47 //    fs_type="yaffs2" partition_type="MTD"     location=partition
48 //    fs_type="ext4"   partition_type="EMMC"    location=device
MountFn(const char * name,State * state,int argc,Expr * argv[])49 Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
50     char* result = NULL;
51     if (argc != 4) {
52         return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
53     }
54     char* fs_type;
55     char* partition_type;
56     char* location;
57     char* mount_point;
58     if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
59                  &location, &mount_point) < 0) {
60         return NULL;
61     }
62 
63     if (strlen(fs_type) == 0) {
64         ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
65         goto done;
66     }
67     if (strlen(partition_type) == 0) {
68         ErrorAbort(state, "partition_type argument to %s() can't be empty",
69                    name);
70         goto done;
71     }
72     if (strlen(location) == 0) {
73         ErrorAbort(state, "location argument to %s() can't be empty", name);
74         goto done;
75     }
76     if (strlen(mount_point) == 0) {
77         ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
78         goto done;
79     }
80 
81 #ifdef HAVE_SELINUX
82     char *secontext = NULL;
83 
84     if (sehandle) {
85         selabel_lookup(sehandle, &secontext, mount_point, 0755);
86         setfscreatecon(secontext);
87     }
88 #endif
89 
90     mkdir(mount_point, 0755);
91 
92 #ifdef HAVE_SELINUX
93     if (secontext) {
94         freecon(secontext);
95         setfscreatecon(NULL);
96     }
97 #endif
98 
99     if (strcmp(partition_type, "MTD") == 0) {
100         mtd_scan_partitions();
101         const MtdPartition* mtd;
102         mtd = mtd_find_partition_by_name(location);
103         if (mtd == NULL) {
104             fprintf(stderr, "%s: no mtd partition named \"%s\"",
105                     name, location);
106             result = strdup("");
107             goto done;
108         }
109         if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
110             fprintf(stderr, "mtd mount of %s failed: %s\n",
111                     location, strerror(errno));
112             result = strdup("");
113             goto done;
114         }
115         result = mount_point;
116     } else {
117         if (mount(location, mount_point, fs_type,
118                   MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
119             fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
120                     name, location, mount_point, strerror(errno));
121             result = strdup("");
122         } else {
123             result = mount_point;
124         }
125     }
126 
127 done:
128     free(fs_type);
129     free(partition_type);
130     free(location);
131     if (result != mount_point) free(mount_point);
132     return StringValue(result);
133 }
134 
135 
136 // is_mounted(mount_point)
IsMountedFn(const char * name,State * state,int argc,Expr * argv[])137 Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
138     char* result = NULL;
139     if (argc != 1) {
140         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
141     }
142     char* mount_point;
143     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
144         return NULL;
145     }
146     if (strlen(mount_point) == 0) {
147         ErrorAbort(state, "mount_point argument to unmount() can't be empty");
148         goto done;
149     }
150 
151     scan_mounted_volumes();
152     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
153     if (vol == NULL) {
154         result = strdup("");
155     } else {
156         result = mount_point;
157     }
158 
159 done:
160     if (result != mount_point) free(mount_point);
161     return StringValue(result);
162 }
163 
164 
UnmountFn(const char * name,State * state,int argc,Expr * argv[])165 Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
166     char* result = NULL;
167     if (argc != 1) {
168         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
169     }
170     char* mount_point;
171     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
172         return NULL;
173     }
174     if (strlen(mount_point) == 0) {
175         ErrorAbort(state, "mount_point argument to unmount() can't be empty");
176         goto done;
177     }
178 
179     scan_mounted_volumes();
180     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
181     if (vol == NULL) {
182         fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
183         result = strdup("");
184     } else {
185         unmount_mounted_volume(vol);
186         result = mount_point;
187     }
188 
189 done:
190     if (result != mount_point) free(mount_point);
191     return StringValue(result);
192 }
193 
194 
195 // format(fs_type, partition_type, location, fs_size, mount_point)
196 //
197 //    fs_type="yaffs2" partition_type="MTD"     location=partition fs_size=<bytes> mount_point=<location>
198 //    fs_type="ext4"   partition_type="EMMC"    location=device    fs_size=<bytes> mount_point=<location>
199 //    if fs_size == 0, then make_ext4fs uses the entire partition.
200 //    if fs_size > 0, that is the size to use
201 //    if fs_size < 0, then reserve that many bytes at the end of the partition
FormatFn(const char * name,State * state,int argc,Expr * argv[])202 Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
203     char* result = NULL;
204     if (argc != 5) {
205         return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc);
206     }
207     char* fs_type;
208     char* partition_type;
209     char* location;
210     char* fs_size;
211     char* mount_point;
212 
213     if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) {
214         return NULL;
215     }
216 
217     if (strlen(fs_type) == 0) {
218         ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
219         goto done;
220     }
221     if (strlen(partition_type) == 0) {
222         ErrorAbort(state, "partition_type argument to %s() can't be empty",
223                    name);
224         goto done;
225     }
226     if (strlen(location) == 0) {
227         ErrorAbort(state, "location argument to %s() can't be empty", name);
228         goto done;
229     }
230 
231     if (strlen(mount_point) == 0) {
232         ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
233         goto done;
234     }
235 
236     if (strcmp(partition_type, "MTD") == 0) {
237         mtd_scan_partitions();
238         const MtdPartition* mtd = mtd_find_partition_by_name(location);
239         if (mtd == NULL) {
240             fprintf(stderr, "%s: no mtd partition named \"%s\"",
241                     name, location);
242             result = strdup("");
243             goto done;
244         }
245         MtdWriteContext* ctx = mtd_write_partition(mtd);
246         if (ctx == NULL) {
247             fprintf(stderr, "%s: can't write \"%s\"", name, location);
248             result = strdup("");
249             goto done;
250         }
251         if (mtd_erase_blocks(ctx, -1) == -1) {
252             mtd_write_close(ctx);
253             fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
254             result = strdup("");
255             goto done;
256         }
257         if (mtd_write_close(ctx) != 0) {
258             fprintf(stderr, "%s: failed to close \"%s\"", name, location);
259             result = strdup("");
260             goto done;
261         }
262         result = location;
263 #ifdef USE_EXT4
264     } else if (strcmp(fs_type, "ext4") == 0) {
265         int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
266         if (status != 0) {
267             fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
268                     name, status, location);
269             result = strdup("");
270             goto done;
271         }
272         result = location;
273 #endif
274     } else {
275         fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
276                 name, fs_type, partition_type);
277     }
278 
279 done:
280     free(fs_type);
281     free(partition_type);
282     if (result != location) free(location);
283     return StringValue(result);
284 }
285 
286 
DeleteFn(const char * name,State * state,int argc,Expr * argv[])287 Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
288     char** paths = malloc(argc * sizeof(char*));
289     int i;
290     for (i = 0; i < argc; ++i) {
291         paths[i] = Evaluate(state, argv[i]);
292         if (paths[i] == NULL) {
293             int j;
294             for (j = 0; j < i; ++i) {
295                 free(paths[j]);
296             }
297             free(paths);
298             return NULL;
299         }
300     }
301 
302     bool recursive = (strcmp(name, "delete_recursive") == 0);
303 
304     int success = 0;
305     for (i = 0; i < argc; ++i) {
306         if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
307             ++success;
308         free(paths[i]);
309     }
310     free(paths);
311 
312     char buffer[10];
313     sprintf(buffer, "%d", success);
314     return StringValue(strdup(buffer));
315 }
316 
317 
ShowProgressFn(const char * name,State * state,int argc,Expr * argv[])318 Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
319     if (argc != 2) {
320         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
321     }
322     char* frac_str;
323     char* sec_str;
324     if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) {
325         return NULL;
326     }
327 
328     double frac = strtod(frac_str, NULL);
329     int sec = strtol(sec_str, NULL, 10);
330 
331     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
332     fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
333 
334     free(sec_str);
335     return StringValue(frac_str);
336 }
337 
SetProgressFn(const char * name,State * state,int argc,Expr * argv[])338 Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
339     if (argc != 1) {
340         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
341     }
342     char* frac_str;
343     if (ReadArgs(state, argv, 1, &frac_str) < 0) {
344         return NULL;
345     }
346 
347     double frac = strtod(frac_str, NULL);
348 
349     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
350     fprintf(ui->cmd_pipe, "set_progress %f\n", frac);
351 
352     return StringValue(frac_str);
353 }
354 
355 // package_extract_dir(package_path, destination_path)
PackageExtractDirFn(const char * name,State * state,int argc,Expr * argv[])356 Value* PackageExtractDirFn(const char* name, State* state,
357                           int argc, Expr* argv[]) {
358     if (argc != 2) {
359         return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
360     }
361     char* zip_path;
362     char* dest_path;
363     if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
364 
365     ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
366 
367     // To create a consistent system image, never use the clock for timestamps.
368     struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default
369 
370     bool success = mzExtractRecursive(za, zip_path, dest_path,
371                                       MZ_EXTRACT_FILES_ONLY, &timestamp,
372                                       NULL, NULL, sehandle);
373     free(zip_path);
374     free(dest_path);
375     return StringValue(strdup(success ? "t" : ""));
376 }
377 
378 
379 // package_extract_file(package_path, destination_path)
380 //   or
381 // package_extract_file(package_path)
382 //   to return the entire contents of the file as the result of this
383 //   function (the char* returned is actually a FileContents*).
PackageExtractFileFn(const char * name,State * state,int argc,Expr * argv[])384 Value* PackageExtractFileFn(const char* name, State* state,
385                            int argc, Expr* argv[]) {
386     if (argc != 1 && argc != 2) {
387         return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
388                           name, argc);
389     }
390     bool success = false;
391     if (argc == 2) {
392         // The two-argument version extracts to a file.
393 
394         char* zip_path;
395         char* dest_path;
396         if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
397 
398         ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
399         const ZipEntry* entry = mzFindZipEntry(za, zip_path);
400         if (entry == NULL) {
401             fprintf(stderr, "%s: no %s in package\n", name, zip_path);
402             goto done2;
403         }
404 
405         FILE* f = fopen(dest_path, "wb");
406         if (f == NULL) {
407             fprintf(stderr, "%s: can't open %s for write: %s\n",
408                     name, dest_path, strerror(errno));
409             goto done2;
410         }
411         success = mzExtractZipEntryToFile(za, entry, fileno(f));
412         fclose(f);
413 
414       done2:
415         free(zip_path);
416         free(dest_path);
417         return StringValue(strdup(success ? "t" : ""));
418     } else {
419         // The one-argument version returns the contents of the file
420         // as the result.
421 
422         char* zip_path;
423         Value* v = malloc(sizeof(Value));
424         v->type = VAL_BLOB;
425         v->size = -1;
426         v->data = NULL;
427 
428         if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
429 
430         ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
431         const ZipEntry* entry = mzFindZipEntry(za, zip_path);
432         if (entry == NULL) {
433             fprintf(stderr, "%s: no %s in package\n", name, zip_path);
434             goto done1;
435         }
436 
437         v->size = mzGetZipEntryUncompLen(entry);
438         v->data = malloc(v->size);
439         if (v->data == NULL) {
440             fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
441                     name, (long)v->size, zip_path);
442             goto done1;
443         }
444 
445         success = mzExtractZipEntryToBuffer(za, entry,
446                                             (unsigned char *)v->data);
447 
448       done1:
449         free(zip_path);
450         if (!success) {
451             free(v->data);
452             v->data = NULL;
453             v->size = -1;
454         }
455         return v;
456     }
457 }
458 
459 
460 // symlink target src1 src2 ...
461 //    unlinks any previously existing src1, src2, etc before creating symlinks.
SymlinkFn(const char * name,State * state,int argc,Expr * argv[])462 Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
463     if (argc == 0) {
464         return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
465     }
466     char* target;
467     target = Evaluate(state, argv[0]);
468     if (target == NULL) return NULL;
469 
470     char** srcs = ReadVarArgs(state, argc-1, argv+1);
471     if (srcs == NULL) {
472         free(target);
473         return NULL;
474     }
475 
476     int bad = 0;
477     int i;
478     for (i = 0; i < argc-1; ++i) {
479         if (unlink(srcs[i]) < 0) {
480             if (errno != ENOENT) {
481                 fprintf(stderr, "%s: failed to remove %s: %s\n",
482                         name, srcs[i], strerror(errno));
483                 ++bad;
484             }
485         }
486         if (symlink(target, srcs[i]) < 0) {
487             fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
488                     name, srcs[i], target, strerror(errno));
489             ++bad;
490         }
491         free(srcs[i]);
492     }
493     free(srcs);
494     if (bad) {
495         return ErrorAbort(state, "%s: some symlinks failed", name);
496     }
497     return StringValue(strdup(""));
498 }
499 
500 
SetPermFn(const char * name,State * state,int argc,Expr * argv[])501 Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
502     char* result = NULL;
503     bool recursive = (strcmp(name, "set_perm_recursive") == 0);
504 
505     int min_args = 4 + (recursive ? 1 : 0);
506     if (argc < min_args) {
507         return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
508     }
509 
510     char** args = ReadVarArgs(state, argc, argv);
511     if (args == NULL) return NULL;
512 
513     char* end;
514     int i;
515     int bad = 0;
516 
517     int uid = strtoul(args[0], &end, 0);
518     if (*end != '\0' || args[0][0] == 0) {
519         ErrorAbort(state, "%s: \"%s\" not a valid uid", name, args[0]);
520         goto done;
521     }
522 
523     int gid = strtoul(args[1], &end, 0);
524     if (*end != '\0' || args[1][0] == 0) {
525         ErrorAbort(state, "%s: \"%s\" not a valid gid", name, args[1]);
526         goto done;
527     }
528 
529     if (recursive) {
530         int dir_mode = strtoul(args[2], &end, 0);
531         if (*end != '\0' || args[2][0] == 0) {
532             ErrorAbort(state, "%s: \"%s\" not a valid dirmode", name, args[2]);
533             goto done;
534         }
535 
536         int file_mode = strtoul(args[3], &end, 0);
537         if (*end != '\0' || args[3][0] == 0) {
538             ErrorAbort(state, "%s: \"%s\" not a valid filemode",
539                        name, args[3]);
540             goto done;
541         }
542 
543         for (i = 4; i < argc; ++i) {
544             dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
545         }
546     } else {
547         int mode = strtoul(args[2], &end, 0);
548         if (*end != '\0' || args[2][0] == 0) {
549             ErrorAbort(state, "%s: \"%s\" not a valid mode", name, args[2]);
550             goto done;
551         }
552 
553         for (i = 3; i < argc; ++i) {
554             if (chown(args[i], uid, gid) < 0) {
555                 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
556                         name, args[i], uid, gid, strerror(errno));
557                 ++bad;
558             }
559             if (chmod(args[i], mode) < 0) {
560                 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
561                         name, args[i], mode, strerror(errno));
562                 ++bad;
563             }
564         }
565     }
566     result = strdup("");
567 
568 done:
569     for (i = 0; i < argc; ++i) {
570         free(args[i]);
571     }
572     free(args);
573 
574     if (bad) {
575         free(result);
576         return ErrorAbort(state, "%s: some changes failed", name);
577     }
578     return StringValue(result);
579 }
580 
581 
GetPropFn(const char * name,State * state,int argc,Expr * argv[])582 Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
583     if (argc != 1) {
584         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
585     }
586     char* key;
587     key = Evaluate(state, argv[0]);
588     if (key == NULL) return NULL;
589 
590     char value[PROPERTY_VALUE_MAX];
591     property_get(key, value, "");
592     free(key);
593 
594     return StringValue(strdup(value));
595 }
596 
597 
598 // file_getprop(file, key)
599 //
600 //   interprets 'file' as a getprop-style file (key=value pairs, one
601 //   per line, # comment lines and blank lines okay), and returns the value
602 //   for 'key' (or "" if it isn't defined).
FileGetPropFn(const char * name,State * state,int argc,Expr * argv[])603 Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
604     char* result = NULL;
605     char* buffer = NULL;
606     char* filename;
607     char* key;
608     if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
609         return NULL;
610     }
611 
612     struct stat st;
613     if (stat(filename, &st) < 0) {
614         ErrorAbort(state, "%s: failed to stat \"%s\": %s",
615                    name, filename, strerror(errno));
616         goto done;
617     }
618 
619 #define MAX_FILE_GETPROP_SIZE    65536
620 
621     if (st.st_size > MAX_FILE_GETPROP_SIZE) {
622         ErrorAbort(state, "%s too large for %s (max %d)",
623                    filename, name, MAX_FILE_GETPROP_SIZE);
624         goto done;
625     }
626 
627     buffer = malloc(st.st_size+1);
628     if (buffer == NULL) {
629         ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
630         goto done;
631     }
632 
633     FILE* f = fopen(filename, "rb");
634     if (f == NULL) {
635         ErrorAbort(state, "%s: failed to open %s: %s",
636                    name, filename, strerror(errno));
637         goto done;
638     }
639 
640     if (fread(buffer, 1, st.st_size, f) != st.st_size) {
641         ErrorAbort(state, "%s: failed to read %d bytes from %s",
642                    name, st.st_size+1, filename);
643         fclose(f);
644         goto done;
645     }
646     buffer[st.st_size] = '\0';
647 
648     fclose(f);
649 
650     char* line = strtok(buffer, "\n");
651     do {
652         // skip whitespace at start of line
653         while (*line && isspace(*line)) ++line;
654 
655         // comment or blank line: skip to next line
656         if (*line == '\0' || *line == '#') continue;
657 
658         char* equal = strchr(line, '=');
659         if (equal == NULL) {
660             ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
661                        name, line, filename);
662             goto done;
663         }
664 
665         // trim whitespace between key and '='
666         char* key_end = equal-1;
667         while (key_end > line && isspace(*key_end)) --key_end;
668         key_end[1] = '\0';
669 
670         // not the key we're looking for
671         if (strcmp(key, line) != 0) continue;
672 
673         // skip whitespace after the '=' to the start of the value
674         char* val_start = equal+1;
675         while(*val_start && isspace(*val_start)) ++val_start;
676 
677         // trim trailing whitespace
678         char* val_end = val_start + strlen(val_start)-1;
679         while (val_end > val_start && isspace(*val_end)) --val_end;
680         val_end[1] = '\0';
681 
682         result = strdup(val_start);
683         break;
684 
685     } while ((line = strtok(NULL, "\n")));
686 
687     if (result == NULL) result = strdup("");
688 
689   done:
690     free(filename);
691     free(key);
692     free(buffer);
693     return StringValue(result);
694 }
695 
696 
write_raw_image_cb(const unsigned char * data,int data_len,void * ctx)697 static bool write_raw_image_cb(const unsigned char* data,
698                                int data_len, void* ctx) {
699     int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
700     if (r == data_len) return true;
701     fprintf(stderr, "%s\n", strerror(errno));
702     return false;
703 }
704 
705 // write_raw_image(filename_or_blob, partition)
WriteRawImageFn(const char * name,State * state,int argc,Expr * argv[])706 Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
707     char* result = NULL;
708 
709     Value* partition_value;
710     Value* contents;
711     if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
712         return NULL;
713     }
714 
715     char* partition = NULL;
716     if (partition_value->type != VAL_STRING) {
717         ErrorAbort(state, "partition argument to %s must be string", name);
718         goto done;
719     }
720     partition = partition_value->data;
721     if (strlen(partition) == 0) {
722         ErrorAbort(state, "partition argument to %s can't be empty", name);
723         goto done;
724     }
725     if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
726         ErrorAbort(state, "file argument to %s can't be empty", name);
727         goto done;
728     }
729 
730     mtd_scan_partitions();
731     const MtdPartition* mtd = mtd_find_partition_by_name(partition);
732     if (mtd == NULL) {
733         fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition);
734         result = strdup("");
735         goto done;
736     }
737 
738     MtdWriteContext* ctx = mtd_write_partition(mtd);
739     if (ctx == NULL) {
740         fprintf(stderr, "%s: can't write mtd partition \"%s\"\n",
741                 name, partition);
742         result = strdup("");
743         goto done;
744     }
745 
746     bool success;
747 
748     if (contents->type == VAL_STRING) {
749         // we're given a filename as the contents
750         char* filename = contents->data;
751         FILE* f = fopen(filename, "rb");
752         if (f == NULL) {
753             fprintf(stderr, "%s: can't open %s: %s\n",
754                     name, filename, strerror(errno));
755             result = strdup("");
756             goto done;
757         }
758 
759         success = true;
760         char* buffer = malloc(BUFSIZ);
761         int read;
762         while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
763             int wrote = mtd_write_data(ctx, buffer, read);
764             success = success && (wrote == read);
765         }
766         free(buffer);
767         fclose(f);
768     } else {
769         // we're given a blob as the contents
770         ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size);
771         success = (wrote == contents->size);
772     }
773     if (!success) {
774         fprintf(stderr, "mtd_write_data to %s failed: %s\n",
775                 partition, strerror(errno));
776     }
777 
778     if (mtd_erase_blocks(ctx, -1) == -1) {
779         fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition);
780     }
781     if (mtd_write_close(ctx) != 0) {
782         fprintf(stderr, "%s: error closing write of %s\n", name, partition);
783     }
784 
785     printf("%s %s partition\n",
786            success ? "wrote" : "failed to write", partition);
787 
788     result = success ? partition : strdup("");
789 
790 done:
791     if (result != partition) FreeValue(partition_value);
792     FreeValue(contents);
793     return StringValue(result);
794 }
795 
796 // apply_patch_space(bytes)
ApplyPatchSpaceFn(const char * name,State * state,int argc,Expr * argv[])797 Value* ApplyPatchSpaceFn(const char* name, State* state,
798                          int argc, Expr* argv[]) {
799     char* bytes_str;
800     if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
801         return NULL;
802     }
803 
804     char* endptr;
805     size_t bytes = strtol(bytes_str, &endptr, 10);
806     if (bytes == 0 && endptr == bytes_str) {
807         ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
808                    name, bytes_str);
809         free(bytes_str);
810         return NULL;
811     }
812 
813     return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
814 }
815 
816 
817 // apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
ApplyPatchFn(const char * name,State * state,int argc,Expr * argv[])818 Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
819     if (argc < 6 || (argc % 2) == 1) {
820         return ErrorAbort(state, "%s(): expected at least 6 args and an "
821                                  "even number, got %d",
822                           name, argc);
823     }
824 
825     char* source_filename;
826     char* target_filename;
827     char* target_sha1;
828     char* target_size_str;
829     if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
830                  &target_sha1, &target_size_str) < 0) {
831         return NULL;
832     }
833 
834     char* endptr;
835     size_t target_size = strtol(target_size_str, &endptr, 10);
836     if (target_size == 0 && endptr == target_size_str) {
837         ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
838                    name, target_size_str);
839         free(source_filename);
840         free(target_filename);
841         free(target_sha1);
842         free(target_size_str);
843         return NULL;
844     }
845 
846     int patchcount = (argc-4) / 2;
847     Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
848 
849     int i;
850     for (i = 0; i < patchcount; ++i) {
851         if (patches[i*2]->type != VAL_STRING) {
852             ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
853             break;
854         }
855         if (patches[i*2+1]->type != VAL_BLOB) {
856             ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
857             break;
858         }
859     }
860     if (i != patchcount) {
861         for (i = 0; i < patchcount*2; ++i) {
862             FreeValue(patches[i]);
863         }
864         free(patches);
865         return NULL;
866     }
867 
868     char** patch_sha_str = malloc(patchcount * sizeof(char*));
869     for (i = 0; i < patchcount; ++i) {
870         patch_sha_str[i] = patches[i*2]->data;
871         patches[i*2]->data = NULL;
872         FreeValue(patches[i*2]);
873         patches[i] = patches[i*2+1];
874     }
875 
876     int result = applypatch(source_filename, target_filename,
877                             target_sha1, target_size,
878                             patchcount, patch_sha_str, patches);
879 
880     for (i = 0; i < patchcount; ++i) {
881         FreeValue(patches[i]);
882     }
883     free(patch_sha_str);
884     free(patches);
885 
886     return StringValue(strdup(result == 0 ? "t" : ""));
887 }
888 
889 // apply_patch_check(file, [sha1_1, ...])
ApplyPatchCheckFn(const char * name,State * state,int argc,Expr * argv[])890 Value* ApplyPatchCheckFn(const char* name, State* state,
891                          int argc, Expr* argv[]) {
892     if (argc < 1) {
893         return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
894                           name, argc);
895     }
896 
897     char* filename;
898     if (ReadArgs(state, argv, 1, &filename) < 0) {
899         return NULL;
900     }
901 
902     int patchcount = argc-1;
903     char** sha1s = ReadVarArgs(state, argc-1, argv+1);
904 
905     int result = applypatch_check(filename, patchcount, sha1s);
906 
907     int i;
908     for (i = 0; i < patchcount; ++i) {
909         free(sha1s[i]);
910     }
911     free(sha1s);
912 
913     return StringValue(strdup(result == 0 ? "t" : ""));
914 }
915 
UIPrintFn(const char * name,State * state,int argc,Expr * argv[])916 Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
917     char** args = ReadVarArgs(state, argc, argv);
918     if (args == NULL) {
919         return NULL;
920     }
921 
922     int size = 0;
923     int i;
924     for (i = 0; i < argc; ++i) {
925         size += strlen(args[i]);
926     }
927     char* buffer = malloc(size+1);
928     size = 0;
929     for (i = 0; i < argc; ++i) {
930         strcpy(buffer+size, args[i]);
931         size += strlen(args[i]);
932         free(args[i]);
933     }
934     free(args);
935     buffer[size] = '\0';
936 
937     char* line = strtok(buffer, "\n");
938     while (line) {
939         fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
940                 "ui_print %s\n", line);
941         line = strtok(NULL, "\n");
942     }
943     fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
944 
945     return StringValue(buffer);
946 }
947 
WipeCacheFn(const char * name,State * state,int argc,Expr * argv[])948 Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
949     if (argc != 0) {
950         return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
951     }
952     fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
953     return StringValue(strdup("t"));
954 }
955 
RunProgramFn(const char * name,State * state,int argc,Expr * argv[])956 Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
957     if (argc < 1) {
958         return ErrorAbort(state, "%s() expects at least 1 arg", name);
959     }
960     char** args = ReadVarArgs(state, argc, argv);
961     if (args == NULL) {
962         return NULL;
963     }
964 
965     char** args2 = malloc(sizeof(char*) * (argc+1));
966     memcpy(args2, args, sizeof(char*) * argc);
967     args2[argc] = NULL;
968 
969     fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc);
970 
971     pid_t child = fork();
972     if (child == 0) {
973         execv(args2[0], args2);
974         fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno));
975         _exit(1);
976     }
977     int status;
978     waitpid(child, &status, 0);
979     if (WIFEXITED(status)) {
980         if (WEXITSTATUS(status) != 0) {
981             fprintf(stderr, "run_program: child exited with status %d\n",
982                     WEXITSTATUS(status));
983         }
984     } else if (WIFSIGNALED(status)) {
985         fprintf(stderr, "run_program: child terminated by signal %d\n",
986                 WTERMSIG(status));
987     }
988 
989     int i;
990     for (i = 0; i < argc; ++i) {
991         free(args[i]);
992     }
993     free(args);
994     free(args2);
995 
996     char buffer[20];
997     sprintf(buffer, "%d", status);
998 
999     return StringValue(strdup(buffer));
1000 }
1001 
1002 // Take a sha-1 digest and return it as a newly-allocated hex string.
PrintSha1(uint8_t * digest)1003 static char* PrintSha1(uint8_t* digest) {
1004     char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
1005     int i;
1006     const char* alphabet = "0123456789abcdef";
1007     for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
1008         buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
1009         buffer[i*2+1] = alphabet[digest[i] & 0xf];
1010     }
1011     buffer[i*2] = '\0';
1012     return buffer;
1013 }
1014 
1015 // sha1_check(data)
1016 //    to return the sha1 of the data (given in the format returned by
1017 //    read_file).
1018 //
1019 // sha1_check(data, sha1_hex, [sha1_hex, ...])
1020 //    returns the sha1 of the file if it matches any of the hex
1021 //    strings passed, or "" if it does not equal any of them.
1022 //
Sha1CheckFn(const char * name,State * state,int argc,Expr * argv[])1023 Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
1024     if (argc < 1) {
1025         return ErrorAbort(state, "%s() expects at least 1 arg", name);
1026     }
1027 
1028     Value** args = ReadValueVarArgs(state, argc, argv);
1029     if (args == NULL) {
1030         return NULL;
1031     }
1032 
1033     if (args[0]->size < 0) {
1034         fprintf(stderr, "%s(): no file contents received", name);
1035         return StringValue(strdup(""));
1036     }
1037     uint8_t digest[SHA_DIGEST_SIZE];
1038     SHA(args[0]->data, args[0]->size, digest);
1039     FreeValue(args[0]);
1040 
1041     if (argc == 1) {
1042         return StringValue(PrintSha1(digest));
1043     }
1044 
1045     int i;
1046     uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE);
1047     for (i = 1; i < argc; ++i) {
1048         if (args[i]->type != VAL_STRING) {
1049             fprintf(stderr, "%s(): arg %d is not a string; skipping",
1050                     name, i);
1051         } else if (ParseSha1(args[i]->data, arg_digest) != 0) {
1052             // Warn about bad args and skip them.
1053             fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping",
1054                     name, args[i]->data);
1055         } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) {
1056             break;
1057         }
1058         FreeValue(args[i]);
1059     }
1060     if (i >= argc) {
1061         // Didn't match any of the hex strings; return false.
1062         return StringValue(strdup(""));
1063     }
1064     // Found a match; free all the remaining arguments and return the
1065     // matched one.
1066     int j;
1067     for (j = i+1; j < argc; ++j) {
1068         FreeValue(args[j]);
1069     }
1070     return args[i];
1071 }
1072 
1073 // Read a local file and return its contents (the Value* returned
1074 // is actually a FileContents*).
ReadFileFn(const char * name,State * state,int argc,Expr * argv[])1075 Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
1076     if (argc != 1) {
1077         return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
1078     }
1079     char* filename;
1080     if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
1081 
1082     Value* v = malloc(sizeof(Value));
1083     v->type = VAL_BLOB;
1084 
1085     FileContents fc;
1086     if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
1087         ErrorAbort(state, "%s() loading \"%s\" failed: %s",
1088                    name, filename, strerror(errno));
1089         free(filename);
1090         free(v);
1091         free(fc.data);
1092         return NULL;
1093     }
1094 
1095     v->size = fc.size;
1096     v->data = (char*)fc.data;
1097 
1098     free(filename);
1099     return v;
1100 }
1101 
RegisterInstallFunctions()1102 void RegisterInstallFunctions() {
1103     RegisterFunction("mount", MountFn);
1104     RegisterFunction("is_mounted", IsMountedFn);
1105     RegisterFunction("unmount", UnmountFn);
1106     RegisterFunction("format", FormatFn);
1107     RegisterFunction("show_progress", ShowProgressFn);
1108     RegisterFunction("set_progress", SetProgressFn);
1109     RegisterFunction("delete", DeleteFn);
1110     RegisterFunction("delete_recursive", DeleteFn);
1111     RegisterFunction("package_extract_dir", PackageExtractDirFn);
1112     RegisterFunction("package_extract_file", PackageExtractFileFn);
1113     RegisterFunction("symlink", SymlinkFn);
1114     RegisterFunction("set_perm", SetPermFn);
1115     RegisterFunction("set_perm_recursive", SetPermFn);
1116 
1117     RegisterFunction("getprop", GetPropFn);
1118     RegisterFunction("file_getprop", FileGetPropFn);
1119     RegisterFunction("write_raw_image", WriteRawImageFn);
1120 
1121     RegisterFunction("apply_patch", ApplyPatchFn);
1122     RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1123     RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
1124 
1125     RegisterFunction("read_file", ReadFileFn);
1126     RegisterFunction("sha1_check", Sha1CheckFn);
1127 
1128     RegisterFunction("wipe_cache", WipeCacheFn);
1129 
1130     RegisterFunction("ui_print", UIPrintFn);
1131 
1132     RegisterFunction("run_program", RunProgramFn);
1133 }
1134