int do_device(int nargs, char **args) { int len; char tmp[64]; char *source = args[1]; int prefix = 0; if (nargs != 5) return -1; /* Check for wildcard '*' at the end which indicates a prefix. */ len = strlen(args[1]) - 1; if (args[1][len] == '*') { args[1][len] = '\0'; prefix = 1; } /* If path starts with mtd@ lookup the mount number. */ if (!strncmp(source, "mtd@", 4)) { int n = mtd_name_to_number(source + 4); if (n >= 0) { snprintf(tmp, sizeof(tmp), "/dev/mtd/mtd%d", n); source = tmp; } } add_devperms_partners(source, get_mode(args[2]), decode_uid(args[3]), decode_uid(args[4]), prefix); return 0; }
int do_chown(int nargs, char **args) { char tmp[64]; char *target; int n; switch (nargs){ case 3: target = args[2]; break; case 4: target = args[3]; break; default: ERROR("invalid args num: %d, It should be 3 or 4\n", nargs); return -1; } if (!strncmp(target, "mtd@", 4)) { n = mtd_name_to_number(target + 4); if (n < 0) { return -1; } sprintf(tmp, "/dev/mtd/mtd%d", n); target = tmp; } //ERROR("do_chown debug: target:%s\n",target); /* GID is optional. */ if (nargs == 3) { if (chown(target, decode_uid(args[1]), -1) < 0) return -errno; } else if (nargs == 4) { if (chown(target, decode_uid(args[1]), decode_uid(args[2]))) return -errno; } else { return -1; } return 0; }
int do_ubiattach(int nargs, char **args) { char *source = args[1]; int mtd_num, ubi_num = -1; if (nargs >= 3) { ubi_num = strtol(args[2], 0, 0); } if (!strncmp(source, "mtd@", 4)) { mtd_num = mtd_name_to_number(source + 4); if (mtd_num < 0) { return -1; } } else { mtd_num = strtoul(source, 0, 0); } if (ubi_attach("/dev/ubi_ctrl", mtd_num, ubi_num)) { return -1; } return 0; }
int do_chmod(int nargs, char **args) { char tmp[64]; char *target; int n; target = args[2]; if (!strncmp(target, "mtd@", 4)) { n = mtd_name_to_number(target + 4); if (n < 0) { return -1; } sprintf(tmp, "/dev/mtd/mtd%d", n); target = tmp; } //ERROR("do_chmod debug: target:%s\n",target); mode_t mode = get_mode(args[1]); if (chmod(target, mode) < 0) { return -errno; } return 0; }
/* mount <type> <device> <path> <flags ...> <options> */ int do_mount(int nargs, char **args) { char tmp[64]; char *source, *target, *system; char *options = NULL; unsigned flags = 0; int n, i; int wait = 0; for (n = 4; n < nargs; n++) { for (i = 0; mount_flags[i].name; i++) { if (!strcmp(args[n], mount_flags[i].name)) { flags |= mount_flags[i].flag; break; } } if (!mount_flags[i].name) { if (!strcmp(args[n], "wait")) wait = 1; /* if our last argument isn't a flag, wolf it up as an option string */ else if (n + 1 == nargs) options = args[n]; } } system = args[1]; source = args[2]; target = args[3]; if (!strncmp(source, "mtd@", 4)) { n = mtd_name_to_number(source + 4); if (n < 0) { return -1; } sprintf(tmp, "/dev/block/mtdblock%d", n); if (wait) wait_for_file(tmp, COMMAND_RETRY_TIMEOUT); if (mount(tmp, target, system, flags, options) < 0) { return -1; } goto exit_success; } else if (!strncmp(source, "loop@", 5)) { int mode, loop, fd; struct loop_info info; mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; fd = open(source + 5, mode); if (fd < 0) { return -1; } for (n = 0; ; n++) { sprintf(tmp, "/dev/block/loop%d", n); loop = open(tmp, mode); if (loop < 0) { return -1; } /* if it is a blank loop device */ if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) { /* if it becomes our loop device */ if (ioctl(loop, LOOP_SET_FD, fd) >= 0) { close(fd); if (mount(tmp, target, system, flags, options) < 0) { ioctl(loop, LOOP_CLR_FD, 0); close(loop); return -1; } close(loop); goto exit_success; } } close(loop); } close(fd); ERROR("out of loopback devices"); return -1; } else { if (wait) wait_for_file(source, COMMAND_RETRY_TIMEOUT); if (mount(source, target, system, flags, options) < 0) { /* If this fails, it may be an encrypted filesystem * or it could just be wiped. If wiped, that will be * handled later in the boot process. * We only support encrypting /data. Check * if we're trying to mount it, and if so, * assume it's encrypted, mount a tmpfs instead. * Then save the orig mount parms in properties * for vold to query when it mounts the real * encrypted /data. */ if (!strcmp(target, DATA_MNT_POINT) && !partition_wiped(source)) { const char *tmpfs_options; tmpfs_options = property_get("ro.crypto.tmpfs_options"); if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV, tmpfs_options) < 0) { return -1; } /* Set the property that triggers the framework to do a minimal * startup and ask the user for a password */ property_set("ro.crypto.state", "encrypted"); property_set("vold.decrypt", "1"); } else { return -1; } } if (!strcmp(target, DATA_MNT_POINT)) { char fs_flags[32]; /* Save the original mount options */ property_set("ro.crypto.fs_type", system); property_set("ro.crypto.fs_real_blkdev", source); property_set("ro.crypto.fs_mnt_point", target); if (options) { property_set("ro.crypto.fs_options", options); } snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags); property_set("ro.crypto.fs_flags", fs_flags); } } exit_success: /* If not running encrypted, then set the property saying we are * unencrypted, and also trigger the action for a nonencrypted system. */ if (!strcmp(target, DATA_MNT_POINT)) { const char *prop; prop = property_get("ro.crypto.state"); if (! prop) { prop = "notset"; } if (strcmp(prop, "encrypted")) { property_set("ro.crypto.state", "unencrypted"); action_for_each_trigger("nonencrypted", action_add_queue_tail); } } return 0; }
/* mount <type> <device> <path> <flags ...> <options> */ int do_mount(int nargs, char **args) { char tmp[64]; char *source, *target, *system; char *options = NULL; unsigned flags = 0; int n, i; int wait = 0; for (n = 4; n < nargs; n++) { for (i = 0; mount_flags[i].name; i++) { if (!strcmp(args[n], mount_flags[i].name)) { flags |= mount_flags[i].flag; break; } } if (!mount_flags[i].name) { if (!strcmp(args[n], "wait")) wait = 1; /* if our last argument isn't a flag, wolf it up as an option string */ else if (n + 1 == nargs) options = args[n]; } } system = args[1]; source = args[2]; target = args[3]; if (!strncmp(source, "mtd@", 4)) { n = mtd_name_to_number(source + 4); if (n < 0) { return -1; } sprintf(tmp, "/dev/block/mtdblock%d", n); if (wait) wait_for_file(tmp, COMMAND_RETRY_TIMEOUT); if (mount(tmp, target, system, flags, options) < 0) { return -1; } goto exit_success; } else if (!strncmp(source, "loop@", 5)) { int mode, loop, fd; struct loop_info info; mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; fd = open(source + 5, mode); if (fd < 0) { return -1; } for (n = 0; ; n++) { sprintf(tmp, "/dev/block/loop%d", n); loop = open(tmp, mode); if (loop < 0) { return -1; } /* if it is a blank loop device */ if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) { /* if it becomes our loop device */ if (ioctl(loop, LOOP_SET_FD, fd) >= 0) { close(fd); if (mount(tmp, target, system, flags, options) < 0) { ioctl(loop, LOOP_CLR_FD, 0); close(loop); return -1; } close(loop); goto exit_success; } } close(loop); } close(fd); ERROR("out of loopback devices"); return -1; } else { if (wait) wait_for_file(source, COMMAND_RETRY_TIMEOUT); if (mount(source, target, system, flags, options) < 0) { return -1; } } exit_success: return 0; }
void set_device_permission(int nargs, char **args) { char *name; char *attr = 0; mode_t perm; uid_t uid; gid_t gid; int prefix = 0; char *endptr; int ret; char *tmp = 0; if (nargs == 0) return; if (args[0][0] == '#') return; name = args[0]; if (!strncmp(name,"/sys/", 5) && (nargs == 5)) { INFO("/sys/ rule %s %s\n",args[0],args[1]); attr = args[1]; args++; nargs--; } if (nargs != 4) { ERROR("invalid line ueventd.rc line for '%s'\n", args[0]); return; } /* If path starts with mtd@ lookup the mount number. */ if (!strncmp(name, "mtd@", 4)) { int n = mtd_name_to_number(name + 4); if (n >= 0) asprintf(&tmp, "/dev/mtd/mtd%d", n); name = tmp; } else if (!strncmp(name, "inand@", 6)) { int n = mtd_name_to_number(name + 6); if (n >= 0) asprintf(&tmp, "/dev/block/cardblkinand%d", n); name = tmp; } else{ int len = strlen(name); if (name[len - 1] == '*') { prefix = 1; name[len - 1] = '\0'; } } perm = strtol(args[1], &endptr, 8); if (!endptr || *endptr != '\0') { ERROR("invalid mode '%s'\n", args[1]); free(tmp); return; } ret = get_android_id(args[2]); if (ret < 0) { ERROR("invalid uid '%s'\n", args[2]); free(tmp); return; } uid = ret; ret = get_android_id(args[3]); if (ret < 0) { ERROR("invalid gid '%s'\n", args[3]); free(tmp); return; } gid = ret; add_dev_perms(name, attr, perm, uid, gid, prefix); free(tmp); }
static int ubi_attach_mtd(const char *name) { int ret; int mtd_num, ubi_num, vid_off; int ubi_ctrl, ubi_dev; int vols, avail_lebs, leb_size; char path[128]; struct ubi_attach_req attach_req; struct ubi_mkvol_req mkvol_req; mtd_num = mtd_name_to_number(name); if (mtd_num == -1) { return -1; } for (ubi_num = 0; ubi_num < 4; ubi_num++) { sprintf(path, "/sys/class/ubi/ubi%d/mtd_num", ubi_num); ubi_dev = open(path, O_RDONLY); if (ubi_dev != -1) { ret = read(ubi_dev, path, sizeof(path)); close(ubi_dev); if (ret > 0 && mtd_num == atoi(path)) return ubi_num; } } ubi_ctrl = open(UBI_CTRL_DEV, O_RDONLY); if (ubi_ctrl == -1) { return -1; } memset(&attach_req, 0, sizeof(struct ubi_attach_req)); attach_req.ubi_num = UBI_DEV_NUM_AUTO; attach_req.mtd_num = mtd_num; attach_req.vid_hdr_offset = UBI_VID_OFFSET_AUTO; ret = ioctl(ubi_ctrl, UBI_IOCATT, &attach_req); if (ret == -1) { close(ubi_ctrl); return -1; } ubi_num = attach_req.ubi_num; vid_off = attach_req.vid_hdr_offset; vols = ubi_dev_read_int(ubi_num, "volumes_count", -1); if (vols == 0) { sprintf(path, "/dev/ubi%d", ubi_num); ret = wait_for_file(path, 50); ubi_dev = open(path, O_RDONLY); if (ubi_dev == -1) { close(ubi_ctrl); return ubi_num; } avail_lebs = ubi_dev_read_int(ubi_num, "avail_eraseblocks", 0); leb_size = ubi_dev_read_int(ubi_num, "eraseblock_size", 0); memset(&mkvol_req, 0, sizeof(struct ubi_mkvol_req)); mkvol_req.vol_id = UBI_VOL_NUM_AUTO; mkvol_req.alignment = 1; mkvol_req.bytes = (long long)avail_lebs * leb_size; mkvol_req.vol_type = UBI_DYNAMIC_VOLUME; ret = snprintf(mkvol_req.name, UBI_MAX_VOLUME_NAME + 1, "%s", name); mkvol_req.name_len = ret; ioctl(ubi_dev, UBI_IOCMKVOL, &mkvol_req); close(ubi_dev); } close(ubi_ctrl); return ubi_num; }
/* do_mount_ubifs <vol_name> <device> <path> <flags ...> <options> */ int do_attach_ubifs(int nargs, char **args) { char tmp[64]; char *target,*vol_name,*source; char *options = NULL; unsigned flags = 0; int n, i; static int ubi_dev_num = 1; int ret; int ubi_number = 0; for (n = 4; n < nargs; n++) { for (i = 0; mount_flags[i].name; i++) { if (!strcmp(args[n], mount_flags[i].name)) { flags |= mount_flags[i].flag; break; } } /* if our last argument isn't a flag, wolf it up as an option string */ if (n + 1 == nargs && !mount_flags[i].name) options = args[n]; } vol_name = args[1]; source = args[2]; target = args[3]; if (!strncmp(source, "mtd@", 4)) { n = mtd_name_to_number(source + 4); if (n < 0) { return -1; } if (MS_REMOUNT == (flags & MS_REMOUNT)) { for (i=0;i < MAX_MTD_PARTITIONS;i++) { if (n == mtd_part_map[i].number) { ubi_number = mtd_part_map[i].ubi_number; break; } } sprintf (tmp,"ubi%d:%s",ubi_number,vol_name); } else { ret = ubi_attach_mtd ("/dev/ubi_ctrl",ubi_dev_num,n); if (0 != ret){ return -1; } for (i=0;i < MAX_MTD_PARTITIONS;i++) { if (n == mtd_part_map[i].number) { mtd_part_map[i].ubi_number = ubi_dev_num; break; } } sprintf (tmp,"ubi%d:%s",ubi_dev_num++,vol_name); } // if (mount(tmp, target, "ubifs", flags, options) < 0) { // return -1; // } } else { // if (mount(source, target, "ubifs", flags, options) < 0) { // return -1; // } } return 0; }
/* mount <type> <device> <path> <flags ...> <options> */ int do_mount(int nargs, char **args) { char tmp[64]; char *source, *target, *type; char *options = NULL; unsigned flags = 0; int n, i; int wait = 0; //add for power loss test struct stat stbuf; for (n = 4; n < nargs; n++) { for (i = 0; mount_flags[i].name; i++) { if (!strcmp(args[n], mount_flags[i].name)) { flags |= mount_flags[i].flag; break; } } if (!mount_flags[i].name) { if (!strcmp(args[n], "wait")) wait = 1; /* if our last argument isn't a flag, wolf it up as an option string */ else if (n + 1 == nargs) options = args[n]; } } type = args[1]; source = args[2]; target = args[3]; if (!strncmp(source, "mtd@", 4)) { n = mtd_name_to_number(source + 4); if (n < 0) { return -1; } sprintf(tmp, "/dev/block/mtdblock%d", n); if (wait) wait_for_file(tmp, COMMAND_RETRY_TIMEOUT); if (mount(tmp, target, type, flags, options) < 0) { return -1; } goto exit_success; } else if (!strncmp(source, "loop@", 5)) { int mode, loop, fd; struct loop_info info; mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR; fd = open(source + 5, mode); if (fd < 0) { return -1; } for (n = 0; ; n++) { sprintf(tmp, "/dev/block/loop%d", n); loop = open(tmp, mode); if (loop < 0) { return -1; } /* if it is a blank loop device */ if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) { /* if it becomes our loop device */ if (ioctl(loop, LOOP_SET_FD, fd) >= 0) { close(fd); if (mount(tmp, target, type, flags, options) < 0) { ioctl(loop, LOOP_CLR_FD, 0); close(loop); return -1; } close(loop); goto exit_success; } } close(loop); } close(fd); ERROR("out of loopback devices"); return -1; } else { #ifdef MTK_EMMC_SUPPORT struct phone_encrypt_state ps; if (!strcmp(target, DATA_MNT_POINT)) { if (misc_get_phone_encrypt_state(&ps) < 0) { printf("Failed to get encrypted status in MISC\n"); } else { printf("Success: get encrypted status: 0x%x in MISC\n", ps.state); } } #endif if (wait) wait_for_file(source, COMMAND_RETRY_TIMEOUT); if (mount(source, target, type, flags, options) < 0) { /* If this fails, it may be an encrypted filesystem * or it could just be wiped. If wiped, that will be * handled later in the boot process. * We only support encrypting /data. Check * if we're trying to mount it, and if so, * assume it's encrypted, mount a tmpfs instead. * Then save the orig mount parms in properties * for vold to query when it mounts the real * encrypted /data. */ if (!strcmp(target, DATA_MNT_POINT)) { int fd; if ((fd = open(source, O_RDONLY)) < 0) { printf("Mount /data fail because source(%s) doesn't exist.", source); return -1; } } if (!strcmp(target, DATA_MNT_POINT) && !partition_wiped(source)) { const char *tmpfs_options; tmpfs_options = property_get("ro.crypto.tmpfs_options"); if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV, tmpfs_options) < 0) { return -1; } /* Set the property that triggers the framework to do a minimal * startup and ask the user for a password */ property_set("ro.crypto.state", "encrypted"); property_set("vold.decrypt", "1"); } else { return -1; } } #ifdef MTK_EMMC_SUPPORT else { if (!strcmp(target, DATA_MNT_POINT)) { if (ps.state == PHONE_ENCRYPTED) { ps.state = PHONE_UNCRYPTED; if (misc_set_phone_encrypt_state(&ps) < 0) { printf("Failed to set encrypted status to 0x%x in MISC\n", ps.state); } else { printf("Success: Set encrypted status to 0x%x in MISC\n", ps.state); } } } } #endif if (!strcmp(target, DATA_MNT_POINT)) { char fs_flags[32]; /* Save the original mount options */ property_set("ro.crypto.fs_type", type); property_set("ro.crypto.fs_real_blkdev", source); property_set("ro.crypto.fs_mnt_point", target); if (options) { property_set("ro.crypto.fs_options", options); } snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags); property_set("ro.crypto.fs_flags", fs_flags); } if (!strncmp(type, "ext4", 4)){ if (!strncmp(target, "/data", 5)){ printf("delete lost-found in data dir\n"); system("/system/bin/rm -r /data/lost+found/*"); if (stat("/data/data", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/data file\n"); system("/system/bin/rm -r /data/data"); } if (stat("/data/system", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/system file\n"); system("/system/bin/rm -r /data/system"); } if (stat("/data/misc", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/misc file\n"); system("/system/bin/rm -r /data/misc"); } if (stat("/data/local", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/local file\n"); system("/system/bin/rm -r /data/local"); } if (stat("/data/app-private", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/app-private file\n"); system("/system/bin/rm -r /data/app-private"); } if (stat("/data/dalvik-cache", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/dalvik-cache file\n"); system("/system/bin/rm -r /data/dalvik-cache"); } if (stat("/data/property", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/property file\n"); system("/system/bin/rm -r /data/property"); } if (stat("/data/mvg_root", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/mvg_root file\n"); system("/system/bin/rm -r /data/mvg_root"); } if (stat("/data/anr", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/anr file\n"); system("/system/bin/rm -r /data/anr"); } if (stat("/data/app", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/app file\n"); system("/system/bin/rm -r /data/app"); } if (stat("/data/nvram", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/nvram file\n"); system("/system/bin/rm -r /data/nvram"); } if (stat("/data/secure", &stbuf) < 0){ printf("stat syscall fail\n"); } if (S_ISREG(stbuf.st_mode)){ printf("delete /data/secure file\n"); system("/system/bin/rm -r /data/secure"); } } if (!strncmp(target, "/cache", 6)){ printf("delete lost-found in cache dir\n"); system("/system/bin/rm -r /cache/lost+found/*"); } } } exit_success: /* If not running encrypted, then set the property saying we are * unencrypted, and also trigger the action for a nonencrypted system. */ if (!strcmp(target, DATA_MNT_POINT)) { const char *prop; prop = property_get("ro.crypto.state"); if (! prop) { prop = "notset"; } if (strcmp(prop, "encrypted")) { property_set("ro.crypto.state", "unencrypted"); action_for_each_trigger("nonencrypted", action_add_queue_tail); } } return 0; }
void set_device_permission(int nargs, char **args) { char *name; char *attr = 0; mode_t perm; uid_t uid; gid_t gid; int prefix = 0; int wildcard = 0; char *endptr; char *tmp = 0; if (nargs == 0) return; if (args[0][0] == '#') return; name = args[0]; if (!strncmp(name,"/sys/", 5) && (nargs == 5)) { INFO("/sys/ rule %s %s\n",args[0],args[1]); attr = args[1]; args++; nargs--; } if (nargs != 4) { ERROR("invalid line ueventd.rc line for '%s'\n", args[0]); return; } /* If path starts with mtd@ lookup the mount number. */ if (!strncmp(name, "mtd@", 4)) { int n = mtd_name_to_number(name + 4); if (n >= 0) asprintf(&tmp, "/dev/mtd/mtd%d", n); name = tmp; } else { int len = strlen(name); char *wildcard_chr = strchr(name, '*'); if ((name[len - 1] == '*') && (wildcard_chr == (name + len - 1))) { prefix = 1; name[len - 1] = '\0'; } else if (wildcard_chr) { wildcard = 1; } } perm = strtol(args[1], &endptr, 8); if (!endptr || *endptr != '\0') { ERROR("invalid mode '%s'\n", args[1]); free(tmp); return; } struct passwd* pwd = getpwnam(args[2]); if (!pwd) { ERROR("invalid uid '%s'\n", args[2]); free(tmp); return; } uid = pwd->pw_uid; struct group* grp = getgrnam(args[3]); if (!grp) { ERROR("invalid gid '%s'\n", args[3]); free(tmp); return; } gid = grp->gr_gid; add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard); free(tmp); }