| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 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 <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 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 27 | #include "cutils/misc.h" | 
 | 28 | #include "cutils/properties.h" | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 29 | #include "edify/expr.h" | 
 | 30 | #include "minzip/DirUtil.h" | 
 | 31 | #include "mtdutils/mounts.h" | 
 | 32 | #include "mtdutils/mtdutils.h" | 
 | 33 | #include "updater.h" | 
 | 34 |  | 
 | 35 | char* ErrorAbort(void* cookie, char* format, ...) { | 
 | 36 |     char* buffer = malloc(4096); | 
 | 37 |     va_list v; | 
 | 38 |     va_start(v, format); | 
 | 39 |     vsnprintf(buffer, 4096, format, v); | 
 | 40 |     va_end(v); | 
 | 41 |     SetError(buffer); | 
 | 42 |     return NULL; | 
 | 43 | } | 
 | 44 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 45 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 46 | // mount(type, location, mount_point) | 
 | 47 | // | 
 | 48 | //   what:  type="MTD"   location="<partition>"            to mount a yaffs2 filesystem | 
 | 49 | //          type="vfat"  location="/dev/block/<whatever>"  to mount a device | 
 | 50 | char* MountFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 51 |     char* result = NULL; | 
 | 52 |     if (argc != 3) { | 
 | 53 |         return ErrorAbort(cookie, "%s() expects 3 args, got %d", name, argc); | 
 | 54 |     } | 
 | 55 |     char* type; | 
 | 56 |     char* location; | 
 | 57 |     char* mount_point; | 
 | 58 |     if (ReadArgs(cookie, argv, 3, &type, &location, &mount_point) < 0) { | 
 | 59 |         return NULL; | 
 | 60 |     } | 
 | 61 |  | 
 | 62 |     if (strlen(type) == 0) { | 
 | 63 |         ErrorAbort(cookie, "type argument to %s() can't be empty", name); | 
 | 64 |         goto done; | 
 | 65 |     } | 
 | 66 |     if (strlen(location) == 0) { | 
 | 67 |         ErrorAbort(cookie, "location argument to %s() can't be empty", name); | 
 | 68 |         goto done; | 
 | 69 |     } | 
 | 70 |     if (strlen(mount_point) == 0) { | 
 | 71 |         ErrorAbort(cookie, "mount_point argument to %s() can't be empty", name); | 
 | 72 |         goto done; | 
 | 73 |     } | 
 | 74 |  | 
 | 75 |     mkdir(mount_point, 0755); | 
 | 76 |  | 
 | 77 |     if (strcmp(type, "MTD") == 0) { | 
 | 78 |         mtd_scan_partitions(); | 
 | 79 |         const MtdPartition* mtd; | 
 | 80 |         mtd = mtd_find_partition_by_name(location); | 
 | 81 |         if (mtd == NULL) { | 
 | 82 |             fprintf(stderr, "%s: no mtd partition named \"%s\"", | 
 | 83 |                     name, location); | 
 | 84 |             result = strdup(""); | 
 | 85 |             goto done; | 
 | 86 |         } | 
 | 87 |         if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) { | 
 | 88 |             fprintf(stderr, "mtd mount of %s failed: %s\n", | 
 | 89 |                     location, strerror(errno)); | 
 | 90 |             result = strdup(""); | 
 | 91 |             goto done; | 
 | 92 |         } | 
 | 93 |         result = mount_point; | 
 | 94 |     } else { | 
 | 95 |         if (mount(location, mount_point, type, | 
 | 96 |                   MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { | 
 | 97 |             result = strdup(""); | 
 | 98 |         } else { | 
 | 99 |             result = mount_point; | 
 | 100 |         } | 
 | 101 |     } | 
 | 102 |  | 
 | 103 | done: | 
 | 104 |     free(type); | 
 | 105 |     free(location); | 
 | 106 |     if (result != mount_point) free(mount_point); | 
 | 107 |     return result; | 
 | 108 | } | 
 | 109 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 110 |  | 
 | 111 | // is_mounted(mount_point) | 
 | 112 | char* IsMountedFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 113 |     char* result = NULL; | 
 | 114 |     if (argc != 1) { | 
 | 115 |         return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc); | 
 | 116 |     } | 
 | 117 |     char* mount_point; | 
 | 118 |     if (ReadArgs(cookie, argv, 1, &mount_point) < 0) { | 
 | 119 |         return NULL; | 
 | 120 |     } | 
 | 121 |     if (strlen(mount_point) == 0) { | 
 | 122 |         ErrorAbort(cookie, "mount_point argument to unmount() can't be empty"); | 
 | 123 |         goto done; | 
 | 124 |     } | 
 | 125 |  | 
 | 126 |     scan_mounted_volumes(); | 
 | 127 |     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); | 
 | 128 |     if (vol == NULL) { | 
 | 129 |         result = strdup(""); | 
 | 130 |     } else { | 
 | 131 |         result = mount_point; | 
 | 132 |     } | 
 | 133 |  | 
 | 134 | done: | 
 | 135 |     if (result != mount_point) free(mount_point); | 
 | 136 |     return result; | 
 | 137 | } | 
 | 138 |  | 
 | 139 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 140 | char* UnmountFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 141 |     char* result = NULL; | 
 | 142 |     if (argc != 1) { | 
 | 143 |         return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc); | 
 | 144 |     } | 
 | 145 |     char* mount_point; | 
 | 146 |     if (ReadArgs(cookie, argv, 1, &mount_point) < 0) { | 
 | 147 |         return NULL; | 
 | 148 |     } | 
 | 149 |     if (strlen(mount_point) == 0) { | 
 | 150 |         ErrorAbort(cookie, "mount_point argument to unmount() can't be empty"); | 
 | 151 |         goto done; | 
 | 152 |     } | 
 | 153 |  | 
 | 154 |     scan_mounted_volumes(); | 
 | 155 |     const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); | 
 | 156 |     if (vol == NULL) { | 
 | 157 |         fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point); | 
 | 158 |         result = strdup(""); | 
 | 159 |     } else { | 
 | 160 |         unmount_mounted_volume(vol); | 
 | 161 |         result = mount_point; | 
 | 162 |     } | 
 | 163 |  | 
 | 164 | done: | 
 | 165 |     if (result != mount_point) free(mount_point); | 
 | 166 |     return result; | 
 | 167 | } | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 168 |  | 
 | 169 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 170 | // format(type, location) | 
 | 171 | // | 
 | 172 | //    type="MTD"  location=partition | 
 | 173 | char* FormatFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 174 |     char* result = NULL; | 
 | 175 |     if (argc != 2) { | 
 | 176 |         return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); | 
 | 177 |     } | 
 | 178 |     char* type; | 
 | 179 |     char* location; | 
 | 180 |     if (ReadArgs(cookie, argv, 2, &type, &location) < 0) { | 
 | 181 |         return NULL; | 
 | 182 |     } | 
 | 183 |  | 
 | 184 |     if (strlen(type) == 0) { | 
 | 185 |         ErrorAbort(cookie, "type argument to %s() can't be empty", name); | 
 | 186 |         goto done; | 
 | 187 |     } | 
 | 188 |     if (strlen(location) == 0) { | 
 | 189 |         ErrorAbort(cookie, "location argument to %s() can't be empty", name); | 
 | 190 |         goto done; | 
 | 191 |     } | 
 | 192 |  | 
 | 193 |     if (strcmp(type, "MTD") == 0) { | 
 | 194 |         mtd_scan_partitions(); | 
 | 195 |         const MtdPartition* mtd = mtd_find_partition_by_name(location); | 
 | 196 |         if (mtd == NULL) { | 
 | 197 |             fprintf(stderr, "%s: no mtd partition named \"%s\"", | 
 | 198 |                     name, location); | 
 | 199 |             result = strdup(""); | 
 | 200 |             goto done; | 
 | 201 |         } | 
 | 202 |         MtdWriteContext* ctx = mtd_write_partition(mtd); | 
 | 203 |         if (ctx == NULL) { | 
 | 204 |             fprintf(stderr, "%s: can't write \"%s\"", name, location); | 
 | 205 |             result = strdup(""); | 
 | 206 |             goto done; | 
 | 207 |         } | 
 | 208 |         if (mtd_erase_blocks(ctx, -1) == -1) { | 
 | 209 |             mtd_write_close(ctx); | 
 | 210 |             fprintf(stderr, "%s: failed to erase \"%s\"", name, location); | 
 | 211 |             result = strdup(""); | 
 | 212 |             goto done; | 
 | 213 |         } | 
 | 214 |         if (mtd_write_close(ctx) != 0) { | 
 | 215 |             fprintf(stderr, "%s: failed to close \"%s\"", name, location); | 
 | 216 |             result = strdup(""); | 
 | 217 |             goto done; | 
 | 218 |         } | 
 | 219 |         result = location; | 
 | 220 |     } else { | 
 | 221 |         fprintf(stderr, "%s: unsupported type \"%s\"", name, type); | 
 | 222 |     } | 
 | 223 |  | 
 | 224 | done: | 
 | 225 |     free(type); | 
 | 226 |     if (result != location) free(location); | 
 | 227 |     return result; | 
 | 228 | } | 
 | 229 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 230 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 231 | char* DeleteFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 232 |     char** paths = malloc(argc * sizeof(char*)); | 
 | 233 |     int i; | 
 | 234 |     for (i = 0; i < argc; ++i) { | 
 | 235 |         paths[i] = Evaluate(cookie, argv[i]); | 
 | 236 |         if (paths[i] == NULL) { | 
 | 237 |             int j; | 
 | 238 |             for (j = 0; j < i; ++i) { | 
 | 239 |                 free(paths[j]); | 
 | 240 |             } | 
 | 241 |             free(paths); | 
 | 242 |             return NULL; | 
 | 243 |         } | 
 | 244 |     } | 
 | 245 |  | 
 | 246 |     bool recursive = (strcmp(name, "delete_recursive") == 0); | 
 | 247 |  | 
 | 248 |     int success = 0; | 
 | 249 |     for (i = 0; i < argc; ++i) { | 
 | 250 |         if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0) | 
 | 251 |             ++success; | 
 | 252 |         free(paths[i]); | 
 | 253 |     } | 
 | 254 |     free(paths); | 
 | 255 |  | 
 | 256 |     char buffer[10]; | 
 | 257 |     sprintf(buffer, "%d", success); | 
 | 258 |     return strdup(buffer); | 
 | 259 | } | 
 | 260 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 261 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 262 | char* ShowProgressFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 263 |     if (argc != 2) { | 
 | 264 |         return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); | 
 | 265 |     } | 
 | 266 |     char* frac_str; | 
 | 267 |     char* sec_str; | 
 | 268 |     if (ReadArgs(cookie, argv, 2, &frac_str, &sec_str) < 0) { | 
 | 269 |         return NULL; | 
 | 270 |     } | 
 | 271 |  | 
 | 272 |     double frac = strtod(frac_str, NULL); | 
 | 273 |     int sec = strtol(sec_str, NULL, 10); | 
 | 274 |  | 
 | 275 |     UpdaterInfo* ui = (UpdaterInfo*)cookie; | 
 | 276 |     fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); | 
 | 277 |  | 
 | 278 |     free(frac_str); | 
 | 279 |     free(sec_str); | 
 | 280 |     return strdup(""); | 
 | 281 | } | 
 | 282 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 283 | // package_extract_dir(package_path, destination_path) | 
 | 284 | char* PackageExtractDirFn(const char* name, void* cookie, | 
 | 285 |                           int argc, Expr* argv[]) { | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 286 |     if (argc != 2) { | 
 | 287 |         return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); | 
 | 288 |     } | 
 | 289 |     char* zip_path; | 
 | 290 |     char* dest_path; | 
 | 291 |     if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL; | 
 | 292 |  | 
 | 293 |     ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip; | 
 | 294 |  | 
 | 295 |     // To create a consistent system image, never use the clock for timestamps. | 
 | 296 |     struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default | 
 | 297 |  | 
 | 298 |     bool success = mzExtractRecursive(za, zip_path, dest_path, | 
 | 299 |                                       MZ_EXTRACT_FILES_ONLY, ×tamp, | 
 | 300 |                                       NULL, NULL); | 
 | 301 |     free(zip_path); | 
 | 302 |     free(dest_path); | 
 | 303 |     return strdup(success ? "t" : ""); | 
 | 304 | } | 
 | 305 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 306 |  | 
 | 307 | // package_extract_file(package_path, destination_path) | 
 | 308 | char* PackageExtractFileFn(const char* name, void* cookie, | 
 | 309 |                            int argc, Expr* argv[]) { | 
 | 310 |     if (argc != 2) { | 
 | 311 |         return ErrorAbort(cookie, "%s() expects 2 args, got %d", name, argc); | 
 | 312 |     } | 
 | 313 |     char* zip_path; | 
 | 314 |     char* dest_path; | 
 | 315 |     if (ReadArgs(cookie, argv, 2, &zip_path, &dest_path) < 0) return NULL; | 
 | 316 |  | 
 | 317 |     bool success = false; | 
 | 318 |  | 
 | 319 |     ZipArchive* za = ((UpdaterInfo*)cookie)->package_zip; | 
 | 320 |     const ZipEntry* entry = mzFindZipEntry(za, zip_path); | 
 | 321 |     if (entry == NULL) { | 
 | 322 |         fprintf(stderr, "%s: no %s in package\n", name, zip_path); | 
 | 323 |         goto done; | 
 | 324 |     } | 
 | 325 |  | 
 | 326 |     FILE* f = fopen(dest_path, "wb"); | 
 | 327 |     if (f == NULL) { | 
 | 328 |         fprintf(stderr, "%s: can't open %s for write: %s\n", | 
 | 329 |                 name, dest_path, strerror(errno)); | 
 | 330 |         goto done; | 
 | 331 |     } | 
 | 332 |     success = mzExtractZipEntryToFile(za, entry, fileno(f)); | 
 | 333 |     fclose(f); | 
 | 334 |  | 
 | 335 |   done: | 
 | 336 |     free(zip_path); | 
 | 337 |     free(dest_path); | 
 | 338 |     return strdup(success ? "t" : ""); | 
 | 339 | } | 
 | 340 |  | 
 | 341 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 342 | // symlink target src1 src2 ... | 
 | 343 | char* SymlinkFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 344 |     if (argc == 0) { | 
 | 345 |         return ErrorAbort(cookie, "%s() expects 1+ args, got %d", name, argc); | 
 | 346 |     } | 
 | 347 |     char* target; | 
 | 348 |     target = Evaluate(cookie, argv[0]); | 
 | 349 |     if (target == NULL) return NULL; | 
 | 350 |  | 
 | 351 |     char** srcs = ReadVarArgs(cookie, argc-1, argv+1); | 
 | 352 |     if (srcs == NULL) { | 
 | 353 |         free(target); | 
 | 354 |         return NULL; | 
 | 355 |     } | 
 | 356 |  | 
 | 357 |     int i; | 
 | 358 |     for (i = 0; i < argc-1; ++i) { | 
 | 359 |         symlink(target, srcs[i]); | 
 | 360 |         free(srcs[i]); | 
 | 361 |     } | 
 | 362 |     free(srcs); | 
 | 363 |     return strdup(""); | 
 | 364 | } | 
 | 365 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 366 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 367 | char* SetPermFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 368 |     char* result = NULL; | 
 | 369 |     bool recursive = (strcmp(name, "set_perm_recursive") == 0); | 
 | 370 |  | 
 | 371 |     int min_args = 4 + (recursive ? 1 : 0); | 
 | 372 |     if (argc < min_args) { | 
 | 373 |         return ErrorAbort(cookie, "%s() expects %d+ args, got %d", name, argc); | 
 | 374 |     } | 
 | 375 |  | 
 | 376 |     char** args = ReadVarArgs(cookie, argc, argv); | 
 | 377 |     if (args == NULL) return NULL; | 
 | 378 |  | 
 | 379 |     char* end; | 
 | 380 |     int i; | 
 | 381 |  | 
 | 382 |     int uid = strtoul(args[0], &end, 0); | 
 | 383 |     if (*end != '\0' || args[0][0] == 0) { | 
 | 384 |         ErrorAbort(cookie, "%s: \"%s\" not a valid uid", name, args[0]); | 
 | 385 |         goto done; | 
 | 386 |     } | 
 | 387 |  | 
 | 388 |     int gid = strtoul(args[1], &end, 0); | 
 | 389 |     if (*end != '\0' || args[1][0] == 0) { | 
 | 390 |         ErrorAbort(cookie, "%s: \"%s\" not a valid gid", name, args[1]); | 
 | 391 |         goto done; | 
 | 392 |     } | 
 | 393 |  | 
 | 394 |     if (recursive) { | 
 | 395 |         int dir_mode = strtoul(args[2], &end, 0); | 
 | 396 |         if (*end != '\0' || args[2][0] == 0) { | 
 | 397 |             ErrorAbort(cookie, "%s: \"%s\" not a valid dirmode", name, args[2]); | 
 | 398 |             goto done; | 
 | 399 |         } | 
 | 400 |  | 
 | 401 |         int file_mode = strtoul(args[3], &end, 0); | 
 | 402 |         if (*end != '\0' || args[3][0] == 0) { | 
 | 403 |             ErrorAbort(cookie, "%s: \"%s\" not a valid filemode", | 
 | 404 |                        name, args[3]); | 
 | 405 |             goto done; | 
 | 406 |         } | 
 | 407 |  | 
 | 408 |         for (i = 4; i < argc; ++i) { | 
 | 409 |             dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); | 
 | 410 |         } | 
 | 411 |     } else { | 
 | 412 |         int mode = strtoul(args[2], &end, 0); | 
 | 413 |         if (*end != '\0' || args[2][0] == 0) { | 
 | 414 |             ErrorAbort(cookie, "%s: \"%s\" not a valid mode", name, args[2]); | 
 | 415 |             goto done; | 
 | 416 |         } | 
 | 417 |  | 
 | 418 |         for (i = 4; i < argc; ++i) { | 
 | 419 |             chown(args[i], uid, gid); | 
 | 420 |             chmod(args[i], mode); | 
 | 421 |         } | 
 | 422 |     } | 
 | 423 |     result = strdup(""); | 
 | 424 |  | 
 | 425 | done: | 
 | 426 |     for (i = 0; i < argc; ++i) { | 
 | 427 |         free(args[i]); | 
 | 428 |     } | 
 | 429 |     free(args); | 
 | 430 |  | 
 | 431 |     return result; | 
 | 432 | } | 
 | 433 |  | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 434 |  | 
 | 435 | char* GetPropFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 436 |     if (argc != 1) { | 
 | 437 |         return ErrorAbort(cookie, "%s() expects 1 arg, got %d", name, argc); | 
 | 438 |     } | 
 | 439 |     char* key; | 
 | 440 |     key = Evaluate(cookie, argv[0]); | 
 | 441 |     if (key == NULL) return NULL; | 
 | 442 |  | 
 | 443 |     char value[PROPERTY_VALUE_MAX]; | 
 | 444 |     property_get(key, value, ""); | 
 | 445 |     free(key); | 
 | 446 |  | 
 | 447 |     return strdup(value); | 
 | 448 | } | 
 | 449 |  | 
 | 450 |  | 
 | 451 | static bool write_raw_image_cb(const unsigned char* data, | 
 | 452 |                                int data_len, void* ctx) { | 
 | 453 |     int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len); | 
 | 454 |     if (r == data_len) return true; | 
 | 455 |     fprintf(stderr, "%s\n", strerror(errno)); | 
 | 456 |     return false; | 
 | 457 | } | 
 | 458 |  | 
 | 459 | // write_raw_image(file, partition) | 
 | 460 | char* WriteRawImageFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 461 |     char* result = NULL; | 
 | 462 |  | 
 | 463 |     char* partition; | 
 | 464 |     char* filename; | 
 | 465 |     if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) { | 
 | 466 |         return NULL; | 
 | 467 |     } | 
 | 468 |  | 
 | 469 |     if (strlen(partition) == 0) { | 
 | 470 |         ErrorAbort(cookie, "partition argument to %s can't be empty", name); | 
 | 471 |         goto done; | 
 | 472 |     } | 
 | 473 |     if (strlen(filename) == 0) { | 
 | 474 |         ErrorAbort(cookie, "file argument to %s can't be empty", name); | 
 | 475 |         goto done; | 
 | 476 |     } | 
 | 477 |  | 
 | 478 |     mtd_scan_partitions(); | 
 | 479 |     const MtdPartition* mtd = mtd_find_partition_by_name(partition); | 
 | 480 |     if (mtd == NULL) { | 
 | 481 |         fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition); | 
 | 482 |         result = strdup(""); | 
 | 483 |         goto done; | 
 | 484 |     } | 
 | 485 |  | 
 | 486 |     MtdWriteContext* ctx = mtd_write_partition(mtd); | 
 | 487 |     if (ctx == NULL) { | 
 | 488 |         fprintf(stderr, "%s: can't write mtd partition \"%s\"\n", | 
 | 489 |                 name, partition); | 
 | 490 |         result = strdup(""); | 
 | 491 |         goto done; | 
 | 492 |     } | 
 | 493 |  | 
 | 494 |     bool success; | 
 | 495 |  | 
 | 496 |     FILE* f = fopen(filename, "rb"); | 
 | 497 |     if (f == NULL) { | 
 | 498 |         fprintf(stderr, "%s: can't open %s: %s\n", | 
 | 499 |                 name, filename, strerror(errno)); | 
 | 500 |         result = strdup(""); | 
 | 501 |         goto done; | 
 | 502 |     } | 
 | 503 |  | 
 | 504 |     success = true; | 
 | 505 |     char* buffer = malloc(BUFSIZ); | 
 | 506 |     int read; | 
 | 507 |     while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { | 
 | 508 |         int wrote = mtd_write_data(ctx, buffer, read); | 
 | 509 |         success = success && (wrote == read); | 
 | 510 |         if (!success) { | 
 | 511 |             fprintf(stderr, "mtd_write_data to %s failed: %s\n", | 
 | 512 |                     partition, strerror(errno)); | 
 | 513 |         } | 
 | 514 |     } | 
 | 515 |     free(buffer); | 
 | 516 |     fclose(f); | 
 | 517 |  | 
 | 518 |     printf("%s %s partition from %s\n", | 
 | 519 |            success ? "wrote" : "failed to write", partition, filename); | 
 | 520 |  | 
 | 521 |     result = success ? partition : strdup(""); | 
 | 522 |  | 
 | 523 | done: | 
 | 524 |     if (result != partition) free(partition); | 
 | 525 |     free(filename); | 
 | 526 |     return result; | 
 | 527 | } | 
 | 528 |  | 
 | 529 | // write_firmware_image(file, partition) | 
 | 530 | // | 
 | 531 | //    partition is "radio" or "hboot" | 
 | 532 | //    file is not used until after updater exits | 
 | 533 | // | 
 | 534 | // TODO: this should live in some HTC-specific library | 
 | 535 | char* WriteFirmwareImageFn(const char* name, void* cookie, | 
 | 536 |                            int argc, Expr* argv[]) { | 
 | 537 |     char* result = NULL; | 
 | 538 |  | 
 | 539 |     char* partition; | 
 | 540 |     char* filename; | 
 | 541 |     if (ReadArgs(cookie, argv, 2, &filename, &partition) < 0) { | 
 | 542 |         return NULL; | 
 | 543 |     } | 
 | 544 |  | 
 | 545 |     if (strlen(partition) == 0) { | 
 | 546 |         ErrorAbort(cookie, "partition argument to %s can't be empty", name); | 
 | 547 |         goto done; | 
 | 548 |     } | 
 | 549 |     if (strlen(filename) == 0) { | 
 | 550 |         ErrorAbort(cookie, "file argument to %s can't be empty", name); | 
 | 551 |         goto done; | 
 | 552 |     } | 
 | 553 |  | 
 | 554 |     FILE* cmd = ((UpdaterInfo*)cookie)->cmd_pipe; | 
 | 555 |     fprintf(cmd, "firmware %s %s\n", partition, filename); | 
 | 556 |  | 
 | 557 |     printf("will write %s firmware from %s\n", partition, filename); | 
 | 558 |     result = partition; | 
 | 559 |  | 
 | 560 | done: | 
 | 561 |     if (result != partition) free(partition); | 
 | 562 |     free(filename); | 
 | 563 |     return result; | 
 | 564 | } | 
 | 565 |  | 
 | 566 |  | 
 | 567 | extern int applypatch(int argc, char** argv); | 
 | 568 |  | 
 | 569 | // apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...) | 
 | 570 | // apply_patch_check(file, sha1, ...) | 
 | 571 | // apply_patch_space(bytes) | 
 | 572 | char* ApplyPatchFn(const char* name, void* cookie, int argc, Expr* argv[]) { | 
 | 573 |     printf("in applypatchfn (%s)\n", name); | 
 | 574 |  | 
 | 575 |     char* prepend = NULL; | 
 | 576 |     if (strstr(name, "check") != NULL) { | 
 | 577 |         prepend = "-c"; | 
 | 578 |     } else if (strstr(name, "space") != NULL) { | 
 | 579 |         prepend = "-s"; | 
 | 580 |     } | 
 | 581 |  | 
 | 582 |     char** args = ReadVarArgs(cookie, argc, argv); | 
 | 583 |     if (args == NULL) return NULL; | 
 | 584 |  | 
 | 585 |     // insert the "program name" argv[0] and a copy of the "prepend" | 
 | 586 |     // string (if any) at the start of the args. | 
 | 587 |  | 
 | 588 |     int extra = 1 + (prepend != NULL ? 1 : 0); | 
 | 589 |     char** temp = malloc((argc+extra) * sizeof(char*)); | 
 | 590 |     memcpy(temp+extra, args, argc * sizeof(char*)); | 
 | 591 |     temp[0] = strdup("updater"); | 
 | 592 |     if (prepend) { | 
 | 593 |         temp[1] = strdup(prepend); | 
 | 594 |     } | 
 | 595 |     free(args); | 
 | 596 |     args = temp; | 
 | 597 |     argc += extra; | 
 | 598 |  | 
 | 599 |     printf("calling applypatch\n"); | 
 | 600 |     fflush(stdout); | 
 | 601 |     int result = applypatch(argc, args); | 
 | 602 |     printf("applypatch returned %d\n", result); | 
 | 603 |  | 
 | 604 |     int i; | 
 | 605 |     for (i = 0; i < argc; ++i) { | 
 | 606 |         free(args[i]); | 
 | 607 |     } | 
 | 608 |     free(args); | 
 | 609 |  | 
 | 610 |     switch (result) { | 
 | 611 |         case 0:   return strdup("t"); | 
 | 612 |         case 1:   return strdup(""); | 
 | 613 |         default:  return ErrorAbort(cookie, "applypatch couldn't parse args"); | 
 | 614 |     } | 
 | 615 | } | 
 | 616 |  | 
 | 617 |  | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 618 | void RegisterInstallFunctions() { | 
 | 619 |     RegisterFunction("mount", MountFn); | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 620 |     RegisterFunction("is_mounted", IsMountedFn); | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 621 |     RegisterFunction("unmount", UnmountFn); | 
 | 622 |     RegisterFunction("format", FormatFn); | 
 | 623 |     RegisterFunction("show_progress", ShowProgressFn); | 
 | 624 |     RegisterFunction("delete", DeleteFn); | 
 | 625 |     RegisterFunction("delete_recursive", DeleteFn); | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 626 |     RegisterFunction("package_extract_dir", PackageExtractDirFn); | 
 | 627 |     RegisterFunction("package_extract_file", PackageExtractFileFn); | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 628 |     RegisterFunction("symlink", SymlinkFn); | 
 | 629 |     RegisterFunction("set_perm", SetPermFn); | 
 | 630 |     RegisterFunction("set_perm_recursive", SetPermFn); | 
| Doug Zongker | 8edb00c | 2009-06-11 17:21:44 -0700 | [diff] [blame^] | 631 |  | 
 | 632 |     RegisterFunction("getprop", GetPropFn); | 
 | 633 |     RegisterFunction("write_raw_image", WriteRawImageFn); | 
 | 634 |     RegisterFunction("write_firmware_image", WriteFirmwareImageFn); | 
 | 635 |  | 
 | 636 |     RegisterFunction("apply_patch", ApplyPatchFn); | 
 | 637 |     RegisterFunction("apply_patch_check", ApplyPatchFn); | 
 | 638 |     RegisterFunction("apply_patch_space", ApplyPatchFn); | 
| Doug Zongker | 9931f7f | 2009-06-10 14:11:53 -0700 | [diff] [blame] | 639 | } |