static int interpret_table_entry(char *line, struct entry *root, off_t *fslen_ub) { char type, *name = NULL; unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; unsigned long start = 0, increment = 1, count = 0; if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu", SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor, &start, &increment, &count) < 0) { return 1; } if (!strcmp(name, "/")) { error_msg_and_die("Device table entries require absolute paths"); } switch (type) { case 'd': mode |= S_IFDIR; modify_entry(name, uid, gid, mode, 0, root, fslen_ub); break; case 'f': mode |= S_IFREG; modify_entry(name, uid, gid, mode, 0, root, fslen_ub); break; case 'p': mode |= S_IFIFO; modify_entry(name, uid, gid, mode, 0, root, fslen_ub); break; case 'c': case 'b': mode |= (type == 'c') ? S_IFCHR : S_IFBLK; if (count > 0) { char *buf; unsigned long i; dev_t rdev; for (i = start; i < count; i++) { asprintf(&buf, "%s%lu", name, i); rdev = makedev(major, minor + (i * increment - start)); modify_entry(buf, uid, gid, mode, rdev, root, fslen_ub); free(buf); } } else { dev_t rdev = makedev(major, minor); modify_entry(name, uid, gid, mode, rdev, root, fslen_ub); } break; default: error_msg_and_die("Unsupported file type"); } free(name); return 0; }
void addFilespec(FILE *fd, int squash_uids, int squash_perms) { unsigned long rmode, mode, uid, gid, major, minor, i; unsigned long start, increment, count, octmode, decmode; char *c, *dir, *name, *dname = NULL, *path = NULL, *path2 = NULL, *line = NULL; char type; size_t len; int argv, i2, overWrite = 0, lineno = 0; __u16 inodeType; while ( getline(&line, &len, fd) >= 0 ) { rmode = mode = uid = gid = major = minor = start = count = overWrite = 0; increment = 1; lineno++; if (( c = strchr(line, '#'))) *c = 0; if ( path ) { free( path ); path = NULL; } if ( path2 ) { free( path2 ); path2 = NULL; } argv = sscanf(line, "%" SCANF_PREFIX "s %c %ld %lu %lu %lu %lu %lu %lu %lu", SCANF_STRING(path), &type, &rmode, &uid, &gid, &major, &minor, &start, &increment, &count); if ( argv < 3 ) { if ( argv > 0 ) log_warning("device table[%d]: bad format for entry '%s' [skip]", lineno, path); continue; } i2 = 0; octmode = rmode; decmode = 0; while ( octmode != 0 ) { decmode = decmode + (octmode % 10) * pow(8, i2++); octmode = octmode / 10; } if ( squash_uids ) uid = gid = 0; mode = decmode; path2 = strdup( path ); name = basename( path ); dir = dirname( path2 ); if (( !strcmp(name, ".")) || ( !strcmp(name, "..")) || ( !strcmp(name, "/"))) { log_warning("device table[%d]: [skip]", lineno); continue; } log_action(ACT_CHDIR, dir, NULL, 0, 0, 0, 0, 0, 0, 0); if ( !do_chdir(dir)) { log_warning("device table[%d]: target directory '%s' for entry '%s' does not exist [skip]", lineno, dir, name); log_action(ACT_CHDIR, "/", NULL, 0, 0, 0, 0, 0, 0, 0); if ( !do_chdir("/")) log_error("[Filesystem error] cannot chdir to root"); continue; } if (( type != 'd' ) && ( type != 'f' ) && ( type != 'p' ) && ( type != 'c' ) && ( type != 'b' ) && ( type != 's')) { log_warning("device table[%d]: bad type '%c' for entry '%s' [skip]", lineno, type, name); continue; } if (squash_perms) { mode &= ~( LINUX_S_IRWXG | LINUX_S_IRWXO ); rmode &= ~( LINUX_S_IRWXG | LINUX_S_IRWXO); } if ( count > 0 ) { if ( dname ) { free( dname ); dname = NULL; } unsigned len; len = strlen(name) + 10; dname = malloc(len + 1); for ( i = start; i < count; i++ ) { snprintf(dname, len, "%s%lu", name, i); if (( overWrite = name_to_inode(dname))) inodeType = inode_mode(dname); if (( type == 'd' ) && ( overWrite ) && ( !LINUX_S_ISDIR(inodeType))) log_error("[Remote fs mismatch] %s/%s exists but isn't a directory when it should be.", log_cwd(), dname); else if (( type != 'd' ) && ( overWrite )) { if ( LINUX_S_ISDIR(inodeType)) log_error("[Remote fs mismatch] %s/%s exists but is a directory when it shouldn't be.", log_cwd(), dname); if ((!LINUX_S_ISREG(inodeType)) && (!LINUX_S_ISLNK(inodeType)) && (!LINUX_S_ISBLK(inodeType)) && (!LINUX_S_ISCHR(inodeType)) && (!LINUX_S_ISFIFO(inodeType)) && (!LINUX_S_ISSOCK(inodeType))) log_error("[Remote fs mismatch] Existing file %s/%s has unknown/unsupported type [0x%x].", log_cwd(), dname, inodeType); } switch ( type ) { case 'd': mode |= LINUX_S_IFDIR; log_action(ACT_MKDIR, dname, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !overWrite ) if ( !do_mkdir(dname)) log_error("[Filesystem error] cannot mkdir %s/%s", log_cwd(), dname); break; case 'c': case 'b': if ( type == 'c' ) mode |= LINUX_S_IFCHR; else mode |= LINUX_S_IFBLK; if ( overWrite ) { log_action(ACT_RM, dname, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(dname)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), dname); } log_action(ACT_MKNOD, dname, NULL, 0, 0, 0, type, major, minor + ((i * increment) - start), overWrite); if ( !do_mknod(dname, type, major, minor + ((i * increment) - start))) log_error("[Filesystem error] cannot mknod %s/%s", log_cwd(), dname); break; case 's': case 'p': if ( type == 's' ) mode |= LINUX_S_IFSOCK; else mode |= LINUX_S_IFIFO; if ( overWrite ) { log_action(ACT_RM, dname, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(dname)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), dname); } log_action(ACT_MKNOD, dname, NULL, 0, 0, 0, type, 0, 0, overWrite); if ( !do_mknod(dname, type, 0, 0)) log_error("[Filesystem error] cannot mknod %s/%s", log_cwd(), dname); break; } log_action(ACT_CHMOD, dname, NULL, rmode, 0, 0, 0, 0, 0, 0); if ( !do_chmod(dname, rmode)) log_error("[Filesystem error] cannot chmod %s/%s", log_cwd(), dname); log_action(ACT_CHOWN, dname, NULL, 0, uid, gid, 0, 0, 0, 0); if ( !do_chown(dname, uid, gid)) log_error("[Filesystem error] cannot chown %s/%s", log_cwd(), dname); } log_action(ACT_CHDIR, "/", NULL, 0, 0, 0, 0, 0, 0, 0); if ( !do_chdir("/")) log_error("[Filesystem error] cannot chdir to root"); free(dname); dname = NULL; } else { if (( overWrite = name_to_inode(name))) inodeType = inode_mode(name); if (( type == 'd' ) && ( overWrite ) && ( !LINUX_S_ISDIR(inodeType))) log_error("[Remote fs mismatch] %s/%s exists but isn't a directory when it should be.", log_cwd(), dname); else if ( type != 'd' ) { if (( overWrite ) && ( LINUX_S_ISDIR(inodeType))) log_error("[Remote fs mismatch] %s/%s exists but is a directory when it shouldn't be.", log_cwd(), dname); if (( overWrite ) && (!LINUX_S_ISREG(inodeType)) && (!LINUX_S_ISLNK(inodeType)) && (!LINUX_S_ISBLK(inodeType)) && (!LINUX_S_ISCHR(inodeType)) && (!LINUX_S_ISFIFO(inodeType)) && (!LINUX_S_ISSOCK(inodeType))) log_error("[Remote fs mismatch] Existing file %s/%s has unknown/unsupported type [0x%x].", log_cwd(), dname, inodeType); } switch ( type ) { case 'd': mode |= LINUX_S_IFDIR; log_action(ACT_MKDIR, name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !overWrite ) if ( !do_mkdir(name)) log_error("[Filesystem error] cannot mkdir %s/%s", log_cwd(), name); break; case 'c': case 'b': if ( type == 'c' ) mode |= LINUX_S_IFCHR; else mode |= LINUX_S_IFBLK; if ( overWrite ) { log_action(ACT_RM, name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(name)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), name); } log_action(ACT_MKNOD, name, NULL, 0, 0, 0, type, major, minor, overWrite); if ( !do_mknod(name, type, major, minor)) log_error("[Filesystem error] cannot mknod %s/%s", log_cwd(), name); break; case 's': case 'p': if ( type == 's' ) mode |= LINUX_S_IFSOCK; else mode |= LINUX_S_IFIFO; if ( overWrite ) { log_action(ACT_RM, name, NULL, 0, 0, 0, 0, 0, 0, overWrite); if ( !do_rm(name)) log_error("[Filesystem error] cannot rm %s/%s", log_cwd(), name); } log_action(ACT_MKNOD, name, NULL, 0, 0, 0, type, 0, 0, overWrite); if ( !do_mknod(name, type, 0, 0)) log_error("[Filesystem error] cannot mknod %s/%s", log_cwd(), name); break; } log_action(ACT_CHMOD, name, NULL, rmode, 0, 0, 0, 0, 0, 0); if ( !do_chmod(name, rmode)) log_error("[Filesystem error] cannot chmod %s/%s", log_cwd(), name); log_action(ACT_CHOWN, name, NULL, 0, uid, gid, 0, 0, 0, 0); if ( !do_chown(name, uid, gid)) log_error("[Filesystem error] cannot chown %s/%s", log_cwd(), name); log_action(ACT_CHDIR, "/", NULL, 0, 0, 0, 0, 0, 0, 0); if ( !do_chdir("/")) log_error("[Filesystem error] cannot chdir to root"); } } if ( line ) { free( line ); line = NULL; } if ( path ) { free( path ); path = NULL; } if ( path2 ) { free( path2 ); path2 = NULL; } }
/* device table entries take the form of: <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count> /dev/mem c 640 0 0 1 1 0 0 - type can be one of: f A regular file d Directory c Character special device file b Block special device file p Fifo (named pipe) I don't bother with symlinks (permissions are irrelevant), hard links (special cases of regular files), or sockets (why bother). Regular files must exist in the target root directory. If a char, block, fifo, or directory does not exist, it will be created. */ static int interpret_table_entry(struct filesystem_entry *root, char *line) { char *hostpath; char type, *name = NULL, *tmp, *dir; unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; unsigned long start = 0, increment = 1, count = 0; struct filesystem_entry *parent, *entry; if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu", SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor, &start, &increment, &count) < 0) { return 1; } if (!strcmp(name, "/")) { error_msg_and_die("Device table entries require absolute paths"); } asprintf(&hostpath, "%s%s", rootdir, name); /* Check if this file already exists... */ switch (type) { case 'd': mode |= S_IFDIR; break; case 'f': mode |= S_IFREG; break; case 'p': mode |= S_IFIFO; break; case 'c': mode |= S_IFCHR; break; case 'b': mode |= S_IFBLK; break; default: error_msg_and_die("Unsupported file type"); } entry = find_filesystem_entry(root, name, mode); if (entry) { /* Ok, we just need to fixup the existing entry * and we will be all done... */ entry->sb.st_uid = uid; entry->sb.st_gid = gid; entry->sb.st_mode = mode; if (major && minor) { entry->sb.st_rdev = makedev(major, minor); } } else { /* If parent is NULL (happens with device table entries), * try and find our parent now) */ tmp = strdup(name); dir = dirname(tmp); parent = find_filesystem_entry(root, dir, S_IFDIR); free(tmp); if (parent == NULL) { error_msg ("skipping device_table entry '%s': no parent directory!", name); free(name); free(hostpath); return 1; } switch (type) { case 'd': add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); break; case 'f': add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); break; case 'p': add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); break; case 'c': case 'b': if (count > 0) { dev_t rdev; unsigned long i; char *dname, *hpath; for (i = start; i < count; i++) { asprintf(&dname, "%s%lu", name, i); asprintf(&hpath, "%s/%s%lu", rootdir, name, i); rdev = makedev(major, minor + (i * increment - start)); add_host_filesystem_entry(dname, hpath, uid, gid, mode, rdev, parent); free(dname); free(hpath); } } else { dev_t rdev = makedev(major, minor); add_host_filesystem_entry(name, hostpath, uid, gid, mode, rdev, parent); } break; default: error_msg_and_die("Unsupported file type"); } } free(name); free(hostpath); return 0; }