/* mkproto - make an mkfs prototype Author: Andrew Cagney */ /* Submitted by: cagney@chook.ua.oz (Andrew Cagney - aka Noid) */ #include #include #include #include #include #include #include #include /* The default values for the prototype file */ #define DEF_UID 2 /* bin */ #define DEF_GID 1 /* daemon group */ #define DEF_PROT 0555 /* a=re */ #define DEF_BLOCKS 360 #define DEF_INODES 63 #define DEF_INDENTSTR "\t" #ifndef major #define major(x) ( (x>>8) & 0377) #define minor(x) (x & 0377) #endif /* Globals. */ int count, origlen, tabs; int gid, uid, prot, same_uid, same_gid, same_prot, blocks, inodes; int block_given, inode_given, dprot; char *indentstr; char *proto_file, *top; FILE *outfile; extern int optind; extern char *optarg; _PROTOTYPE(int main, (int argc, char **argv)); _PROTOTYPE(void descend, (char *dirname)); _PROTOTYPE(void display_attrib, (char *name, struct stat *st)); _PROTOTYPE(void usage, (char *binname)); _PROTOTYPE(void open_outfile, (void)); int main(argc, argv) int argc; char *argv[]; { char *dir; struct stat st; int op; gid = DEF_GID; uid = DEF_UID; prot = DEF_PROT; blocks = DEF_BLOCKS; inodes = DEF_INODES; indentstr = DEF_INDENTSTR; inode_given = 0; block_given = 0; top = 0; same_uid = 0; same_gid = 0; same_prot = 0; while ((op = getopt(argc, argv, "b:g:i:p:t:u:d:s")) != EOF) { switch (op) { case 'b': blocks = atoi(optarg); block_given = 1; break; case 'g': gid = atoi(optarg); if (gid == 0) usage(argv[0]); same_gid = 0; break; case 'i': inodes = atoi(optarg); inode_given = 1; break; case 'p': sscanf(optarg, "%o", &prot); if (prot == 0) usage(argv[0]); same_prot = 0; break; case 's': same_prot = 1; same_uid = 1; same_gid = 1; break; case 't': top = optarg; break; case 'u': uid = atoi(optarg); if (uid == 0) usage(argv[0]); same_uid = 0; break; case 'd': indentstr = optarg; break; default: /* Illegal options */ usage(argv[0]); } } if (optind >= argc) { usage(argv[0]); } else { dir = argv[optind]; optind++; proto_file = argv[optind]; } if (!top) top = dir; open_outfile(); if (block_given && !inode_given) inodes = (blocks / 3) + 8; if (!block_given && inode_given) usage(argv[0]); count = 1; tabs = 0; origlen = strlen(dir); /* Check that it really is a directory */ stat(dir, &st); if ((st.st_mode & S_IFMT) != S_IFDIR) { fprintf(stderr, "mkproto: %s must be a directory\n", dir); usage(argv[0]); } fprintf(outfile, "boot\n%d %d\n", blocks, inodes); display_attrib("", &st); fprintf(outfile, "\n"); descend(dir); fprintf(outfile, "$\n"); return(0); } /* Output the prototype spec for this directory. */ void descend(dirname) char *dirname; { struct dirent *dp; DIR *dirp; char *name, *temp, *tempend; int i; struct stat st; mode_t mode; dirp = opendir(dirname); if (dirp == NULL) { fprintf(stderr, "unable to open directory %s\n", dirname); return; } tabs++; temp = (char *) malloc(sizeof(char) * strlen(dirname) +1 + PATH_MAX); strcpy(temp, dirname); strcat(temp, "/"); tempend = &temp[strlen(temp)]; for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { name = dp->d_name; count++; strcpy(tempend, name); if (stat(temp, &st) == -1) { fprintf(stderr, "cant get status of '%s' \n", temp); continue; } if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) continue; display_attrib(name, &st); mode = st.st_mode & S_IFMT; if (mode == S_IFDIR) { fprintf(outfile, "\n"); descend(temp); for (i = 0; i < tabs; i++) { fprintf(outfile, indentstr); } fprintf(outfile, "$\n"); continue; } if (mode == S_IFBLK || mode == S_IFCHR) { fprintf(outfile, " %d %d\n", major(st.st_rdev), minor(st.st_rdev)); continue; } if (mode == S_IFREG) { i = origlen; fprintf(outfile, "%s%s", indentstr, top); while (temp[i] != '\0') { fputc(temp[i], outfile); i++; } fprintf(outfile, "\n"); continue; } fprintf(outfile, " /dev/null"); fprintf(stderr,"File\n\t%s\n has an invalid mode, made empty.\n",temp); } closedir(dirp); free(temp); tabs--; } void display_attrib(name, st) char *name; struct stat *st; { /* Output the specification for a single file */ int i; if (same_uid) uid = st->st_uid; if (same_gid) gid = st->st_gid; if (same_prot) prot = st->st_mode & 0777; /***** This one is a bit shady *****/ for (i = 0; i < tabs; i++) fprintf(outfile, indentstr); fprintf(outfile, "%s%s%c%c%c%3o %d %d", name, *name == '\0' ? "" : indentstr, /* stop the tab for a null name */ (st->st_mode & S_IFMT) == S_IFDIR ? 'd' : (st->st_mode & S_IFMT) == S_IFCHR ? 'c' : (st->st_mode & S_IFMT) == S_IFBLK ? 'b' : '-', /* file type */ (st->st_mode & S_ISUID) ? 'u' : '-', /* set uid */ (st->st_mode & S_ISGID) ? 'g' : '-', /* set gid */ prot, uid, gid); } void usage(binname) char *binname; { fprintf(stderr, "Usage: %s [options] source_directory [prototype_file]\n", binname); fprintf(stderr, "options:\n"); fprintf(stderr, " -b n\t\t file system size is n blocks (default %d)\n", DEF_BLOCKS); fprintf(stderr, " -d STRING\t define the indentation characters (default %s)\n", "(none)"); fprintf(stderr, " -g n\t\t use n as the gid on all files (default %d)\n", DEF_GID); fprintf(stderr, " -i n\t\t file system gets n i-nodes (default %d)\n", DEF_INODES); fprintf(stderr, " -p nnn\t use nnn (octal) as mode on all files (default %o)\n", DEF_PROT); fprintf(stderr, " -s \t\t use the same uid, gid and mode as originals have\n"); fprintf(stderr, " -t ROOT\t inital path prefix for each entry\n"); fprintf(stderr, " -u n\t\t use nnn as the uid on all files (default %d)\n", DEF_UID); exit(1); } void open_outfile() { if (proto_file == NULL) outfile = stdout; else if ((outfile = fopen(proto_file, "w")) == NULL) fprintf(stderr, "Cannot create %s\n ", proto_file); }