blob: 2336f614d15084e34e57c3749326fd88db69114f [file] [log] [blame]
Doug Zongker9931f7f2009-06-10 14:11:53 -07001/*
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 <stdio.h>
18#include <errno.h>
19#include <stdarg.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/mount.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <unistd.h>
26
27#include "edify/expr.h"
28#include "minzip/DirUtil.h"
29#include "mtdutils/mounts.h"
30#include "mtdutils/mtdutils.h"
31#include "updater.h"
32
33char* ErrorAbort(void* cookie, char* format, ...) {
34 char* buffer = malloc(4096);
35 va_list v;
36 va_start(v, format);
37 vsnprintf(buffer, 4096, format, v);
38 va_end(v);
39 SetError(buffer);
40 return NULL;
41}
42
43// mount(type, location, mount_point)
44//
45// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
46// type="vfat" location="/dev/block/<whatever>" to mount a device
47char* MountFn(const char* name, void* cookie, int argc, Expr* argv[]) {
48 char* result = NULL;
49 if (argc != 3) {
50 return ErrorAbort(cookie, "%s() expects 3 args, got %d", name, argc);
51 }
52 char* type;
53 char* location;
54 char* mount_point;
55 if (ReadArgs(cookie, argv, 3, &type, &location, &mount_point) < 0) {
56 return NULL;
57 }
58
59 if (strlen(type) == 0) {
60 ErrorAbort(cookie, "type argument to %s() can't be empty", name);
61 goto done;
62 }
63 if (strlen(location) == 0) {
64 ErrorAbort(cookie, "location argument to %s() can't be empty", name);
65 goto done;
66 }
67 if (strlen(mount_point) == 0) {
68 ErrorAbort(cookie, "mount_point argument to %s() can't be empty", name);
69 goto done;
70 }
71
72 mkdir(mount_point, 0755);
73
74 if (strcmp(type, "MTD") == 0) {
75 mtd_scan_partitions();
76 const MtdPartition* mtd;
77 mtd = mtd_find_partition_by_name(location);
78 if (mtd == NULL) {
79 fprintf(stderr, "%s: no mtd partition named \"%s\"",
80 name, location);
81 result = strdup("");
82 goto done;
83 }
84 if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) {
85 fprintf(stderr, "mtd mount of %s failed: %s\n",
86 location, strerror(errno));
87 result = strdup("");
88 goto done;
89 }
90 result = mount_point;
91 } else {
92 if (mount(location, mount_point, type,
93 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
94 result = strdup("");
95 } else {
96 result = mount_point;
97 }
98 }
99
100done:
101 free(type);
102 free(location);
103 if (result != mount_point) free(mount_point);
104 return result;
105}
106
107char* UnmountFn(const char* name, void* cookie, int argc, Expr* argv[]) {
108 char* result = NULL;
109 if (argc != 1) {
110 return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc);
111 }
112 char* mount_point;
113 if (ReadArgs(cookie, argv, 1, &mount_point) < 0) {
114 return NULL;
115 }
116 if (strlen(mount_point) == 0) {
117 ErrorAbort(cookie, "mount_point argument to unmount() can't be empty");
118 goto done;
119 }
120
121 scan_mounted_volumes();
122 const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
123 if (vol == NULL) {
124 fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point);
125 result = strdup("");
126 } else {
127 unmount_mounted_volume(vol);
128 result = mount_point;
129 }
130
131done:
132 if (result != mount_point) free(mount_point);
133 return result;
134}
135// format(type, location)
136//
137// type="MTD" location=partition
138char* FormatFn(const char* name, void* cookie, int argc, Expr* argv[]) {
139 char* result = NULL;
140 if (argc != 2) {
141 return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
142 }
143 char* type;
144 char* location;
145 if (ReadArgs(cookie, argv, 2, &type, &location) < 0) {
146 return NULL;
147 }
148
149 if (strlen(type) == 0) {
150 ErrorAbort(cookie, "type argument to %s() can't be empty", name);
151 goto done;
152 }
153 if (strlen(location) == 0) {
154 ErrorAbort(cookie, "location argument to %s() can't be empty", name);
155 goto done;
156 }
157
158 if (strcmp(type, "MTD") == 0) {
159 mtd_scan_partitions();
160 const MtdPartition* mtd = mtd_find_partition_by_name(location);
161 if (mtd == NULL) {
162 fprintf(stderr, "%s: no mtd partition named \"%s\"",
163 name, location);
164 result = strdup("");
165 goto done;
166 }
167 MtdWriteContext* ctx = mtd_write_partition(mtd);
168 if (ctx == NULL) {
169 fprintf(stderr, "%s: can't write \"%s\"", name, location);
170 result = strdup("");
171 goto done;
172 }
173 if (mtd_erase_blocks(ctx, -1) == -1) {
174 mtd_write_close(ctx);
175 fprintf(stderr, "%s: failed to erase \"%s\"", name, location);
176 result = strdup("");
177 goto done;
178 }
179 if (mtd_write_close(ctx) != 0) {
180 fprintf(stderr, "%s: failed to close \"%s\"", name, location);
181 result = strdup("");
182 goto done;
183 }
184 result = location;
185 } else {
186 fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
187 }
188
189done:
190 free(type);
191 if (result != location) free(location);
192 return result;
193}
194
195char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) {
196 char** paths = malloc(argc * sizeof(char*));
197 int i;
198 for (i = 0; i < argc; ++i) {
199 paths[i] = Evaluate(cookie, argv[i]);
200 if (paths[i] == NULL) {
201 int j;
202 for (j = 0; j < i; ++i) {
203 free(paths[j]);
204 }
205 free(paths);
206 return NULL;
207 }
208 }
209
210 bool recursive = (strcmp(name, "delete_recursive") == 0);
211
212 int success = 0;
213 for (i = 0; i < argc; ++i) {
214 if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0)
215 ++success;
216 free(paths[i]);
217 }
218 free(paths);
219
220 char buffer[10];
221 sprintf(buffer, "%d", success);
222 return strdup(buffer);
223}
224
225char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) {
226 if (argc != 2) {
227 return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
228 }
229 char* frac_str;
230 char* sec_str;
231 if (ReadArgs(cookie, argv, 2, &frac_str, &sec_str) < 0) {
232 return NULL;
233 }
234
235 double frac = strtod(frac_str, NULL);
236 int sec = strtol(sec_str, NULL, 10);
237
238 UpdaterInfo* ui = (UpdaterInfo*)cookie;
239 fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec);
240
241 free(frac_str);
242 free(sec_str);
243 return strdup("");
244}
245
246// package_extract package_path destination_path
247char* PackageExtractFn(const char* name, void* cookie, int argc, Expr* argv[]) {
248 if (argc != 2) {
249 return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc);
250 }
251 char* zip_path;
252 char* dest_path;
253 if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL;
254
255 ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip;
256
257 // To create a consistent system image, never use the clock for timestamps.
258 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
259
260 bool success = mzExtractRecursive(za, zip_path, dest_path,
261 MZ_EXTRACT_FILES_ONLY, &timestamp,
262 NULL, NULL);
263 free(zip_path);
264 free(dest_path);
265 return strdup(success ? "t" : "");
266}
267
268// symlink target src1 src2 ...
269char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) {
270 if (argc == 0) {
271 return ErrorAbort(cookie, "%s() expects 1+ args, got %d", name, argc);
272 }
273 char* target;
274 target = Evaluate(cookie, argv[0]);
275 if (target == NULL) return NULL;
276
277 char** srcs = ReadVarArgs(cookie, argc-1, argv+1);
278 if (srcs == NULL) {
279 free(target);
280 return NULL;
281 }
282
283 int i;
284 for (i = 0; i < argc-1; ++i) {
285 symlink(target, srcs[i]);
286 free(srcs[i]);
287 }
288 free(srcs);
289 return strdup("");
290}
291
292char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) {
293 char* result = NULL;
294 bool recursive = (strcmp(name, "set_perm_recursive") == 0);
295
296 int min_args = 4 + (recursive ? 1 : 0);
297 if (argc < min_args) {
298 return ErrorAbort(cookie, "%s() expects %d+ args, got %d", name, argc);
299 }
300
301 char** args = ReadVarArgs(cookie, argc, argv);
302 if (args == NULL) return NULL;
303
304 char* end;
305 int i;
306
307 int uid = strtoul(args[0], &end, 0);
308 if (*end != '\0' || args[0][0] == 0) {
309 ErrorAbort(cookie, "%s: \"%s\" not a valid uid", name, args[0]);
310 goto done;
311 }
312
313 int gid = strtoul(args[1], &end, 0);
314 if (*end != '\0' || args[1][0] == 0) {
315 ErrorAbort(cookie, "%s: \"%s\" not a valid gid", name, args[1]);
316 goto done;
317 }
318
319 if (recursive) {
320 int dir_mode = strtoul(args[2], &end, 0);
321 if (*end != '\0' || args[2][0] == 0) {
322 ErrorAbort(cookie, "%s: \"%s\" not a valid dirmode", name, args[2]);
323 goto done;
324 }
325
326 int file_mode = strtoul(args[3], &end, 0);
327 if (*end != '\0' || args[3][0] == 0) {
328 ErrorAbort(cookie, "%s: \"%s\" not a valid filemode",
329 name, args[3]);
330 goto done;
331 }
332
333 for (i = 4; i < argc; ++i) {
334 dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode);
335 }
336 } else {
337 int mode = strtoul(args[2], &end, 0);
338 if (*end != '\0' || args[2][0] == 0) {
339 ErrorAbort(cookie, "%s: \"%s\" not a valid mode", name, args[2]);
340 goto done;
341 }
342
343 for (i = 4; i < argc; ++i) {
344 chown(args[i], uid, gid);
345 chmod(args[i], mode);
346 }
347 }
348 result = strdup("");
349
350done:
351 for (i = 0; i < argc; ++i) {
352 free(args[i]);
353 }
354 free(args);
355
356 return result;
357}
358
359void RegisterInstallFunctions() {
360 RegisterFunction("mount", MountFn);
361 RegisterFunction("unmount", UnmountFn);
362 RegisterFunction("format", FormatFn);
363 RegisterFunction("show_progress", ShowProgressFn);
364 RegisterFunction("delete", DeleteFn);
365 RegisterFunction("delete_recursive", DeleteFn);
366 RegisterFunction("package_extract", PackageExtractFn);
367 RegisterFunction("symlink", SymlinkFn);
368 RegisterFunction("set_perm", SetPermFn);
369 RegisterFunction("set_perm_recursive", SetPermFn);
370}