[9] | 1 | /* mkproto - make an mkfs prototype Author: Andrew Cagney */
|
---|
| 2 |
|
---|
| 3 | /* Submitted by: cagney@chook.ua.oz (Andrew Cagney - aka Noid) */
|
---|
| 4 |
|
---|
| 5 | #include <sys/types.h>
|
---|
| 6 | #include <sys/stat.h>
|
---|
| 7 | #include <limits.h>
|
---|
| 8 | #include <dirent.h>
|
---|
| 9 | #include <stdlib.h>
|
---|
| 10 | #include <string.h>
|
---|
| 11 | #include <stdio.h>
|
---|
| 12 | #include <unistd.h>
|
---|
| 13 |
|
---|
| 14 | /* The default values for the prototype file */
|
---|
| 15 | #define DEF_UID 2 /* bin */
|
---|
| 16 | #define DEF_GID 1 /* daemon group */
|
---|
| 17 | #define DEF_PROT 0555 /* a=re */
|
---|
| 18 | #define DEF_BLOCKS 360
|
---|
| 19 | #define DEF_INODES 63
|
---|
| 20 | #define DEF_INDENTSTR "\t"
|
---|
| 21 |
|
---|
| 22 | #ifndef major
|
---|
| 23 | #define major(x) ( (x>>8) & 0377)
|
---|
| 24 | #define minor(x) (x & 0377)
|
---|
| 25 | #endif
|
---|
| 26 |
|
---|
| 27 | /* Globals. */
|
---|
| 28 | int count, origlen, tabs;
|
---|
| 29 | int gid, uid, prot, same_uid, same_gid, same_prot, blocks, inodes;
|
---|
| 30 | int block_given, inode_given, dprot;
|
---|
| 31 | char *indentstr;
|
---|
| 32 | char *proto_file, *top;
|
---|
| 33 | FILE *outfile;
|
---|
| 34 |
|
---|
| 35 | extern int optind;
|
---|
| 36 | extern char *optarg;
|
---|
| 37 |
|
---|
| 38 | _PROTOTYPE(int main, (int argc, char **argv));
|
---|
| 39 | _PROTOTYPE(void descend, (char *dirname));
|
---|
| 40 | _PROTOTYPE(void display_attrib, (char *name, struct stat *st));
|
---|
| 41 | _PROTOTYPE(void usage, (char *binname));
|
---|
| 42 | _PROTOTYPE(void open_outfile, (void));
|
---|
| 43 |
|
---|
| 44 | int main(argc, argv)
|
---|
| 45 | int argc;
|
---|
| 46 | char *argv[];
|
---|
| 47 | {
|
---|
| 48 | char *dir;
|
---|
| 49 | struct stat st;
|
---|
| 50 | int op;
|
---|
| 51 |
|
---|
| 52 | gid = DEF_GID;
|
---|
| 53 | uid = DEF_UID;
|
---|
| 54 | prot = DEF_PROT;
|
---|
| 55 | blocks = DEF_BLOCKS;
|
---|
| 56 | inodes = DEF_INODES;
|
---|
| 57 | indentstr = DEF_INDENTSTR;
|
---|
| 58 | inode_given = 0;
|
---|
| 59 | block_given = 0;
|
---|
| 60 | top = 0;
|
---|
| 61 | same_uid = 0;
|
---|
| 62 | same_gid = 0;
|
---|
| 63 | same_prot = 0;
|
---|
| 64 | while ((op = getopt(argc, argv, "b:g:i:p:t:u:d:s")) != EOF) {
|
---|
| 65 | switch (op) {
|
---|
| 66 | case 'b':
|
---|
| 67 | blocks = atoi(optarg);
|
---|
| 68 | block_given = 1;
|
---|
| 69 | break;
|
---|
| 70 | case 'g':
|
---|
| 71 | gid = atoi(optarg);
|
---|
| 72 | if (gid == 0) usage(argv[0]);
|
---|
| 73 | same_gid = 0;
|
---|
| 74 | break;
|
---|
| 75 | case 'i':
|
---|
| 76 | inodes = atoi(optarg);
|
---|
| 77 | inode_given = 1;
|
---|
| 78 | break;
|
---|
| 79 | case 'p':
|
---|
| 80 | sscanf(optarg, "%o", &prot);
|
---|
| 81 | if (prot == 0) usage(argv[0]);
|
---|
| 82 | same_prot = 0;
|
---|
| 83 | break;
|
---|
| 84 | case 's':
|
---|
| 85 | same_prot = 1;
|
---|
| 86 | same_uid = 1;
|
---|
| 87 | same_gid = 1;
|
---|
| 88 | break;
|
---|
| 89 | case 't': top = optarg; break;
|
---|
| 90 | case 'u':
|
---|
| 91 | uid = atoi(optarg);
|
---|
| 92 | if (uid == 0) usage(argv[0]);
|
---|
| 93 | same_uid = 0;
|
---|
| 94 | break;
|
---|
| 95 | case 'd': indentstr = optarg; break;
|
---|
| 96 | default: /* Illegal options */
|
---|
| 97 | usage(argv[0]);
|
---|
| 98 | }
|
---|
| 99 | }
|
---|
| 100 |
|
---|
| 101 | if (optind >= argc) {
|
---|
| 102 | usage(argv[0]);
|
---|
| 103 | } else {
|
---|
| 104 | dir = argv[optind];
|
---|
| 105 | optind++;
|
---|
| 106 | proto_file = argv[optind];
|
---|
| 107 | }
|
---|
| 108 | if (!top) top = dir;
|
---|
| 109 | open_outfile();
|
---|
| 110 | if (block_given && !inode_given) inodes = (blocks / 3) + 8;
|
---|
| 111 | if (!block_given && inode_given) usage(argv[0]);
|
---|
| 112 | count = 1;
|
---|
| 113 | tabs = 0;
|
---|
| 114 | origlen = strlen(dir);
|
---|
| 115 |
|
---|
| 116 | /* Check that it really is a directory */
|
---|
| 117 | stat(dir, &st);
|
---|
| 118 | if ((st.st_mode & S_IFMT) != S_IFDIR) {
|
---|
| 119 | fprintf(stderr, "mkproto: %s must be a directory\n", dir);
|
---|
| 120 | usage(argv[0]);
|
---|
| 121 | }
|
---|
| 122 | fprintf(outfile, "boot\n%d %d\n", blocks, inodes);
|
---|
| 123 | display_attrib("", &st);
|
---|
| 124 | fprintf(outfile, "\n");
|
---|
| 125 | descend(dir);
|
---|
| 126 | fprintf(outfile, "$\n");
|
---|
| 127 | return(0);
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | /* Output the prototype spec for this directory. */
|
---|
| 131 | void descend(dirname)
|
---|
| 132 | char *dirname;
|
---|
| 133 | {
|
---|
| 134 | struct dirent *dp;
|
---|
| 135 | DIR *dirp;
|
---|
| 136 | char *name, *temp, *tempend;
|
---|
| 137 | int i;
|
---|
| 138 | struct stat st;
|
---|
| 139 | mode_t mode;
|
---|
| 140 |
|
---|
| 141 | dirp = opendir(dirname);
|
---|
| 142 | if (dirp == NULL) {
|
---|
| 143 | fprintf(stderr, "unable to open directory %s\n", dirname);
|
---|
| 144 | return;
|
---|
| 145 | }
|
---|
| 146 | tabs++;
|
---|
| 147 | temp = (char *) malloc(sizeof(char) * strlen(dirname) +1 + PATH_MAX);
|
---|
| 148 | strcpy(temp, dirname);
|
---|
| 149 | strcat(temp, "/");
|
---|
| 150 | tempend = &temp[strlen(temp)];
|
---|
| 151 |
|
---|
| 152 | for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
|
---|
| 153 | name = dp->d_name;
|
---|
| 154 |
|
---|
| 155 | count++;
|
---|
| 156 | strcpy(tempend, name);
|
---|
| 157 |
|
---|
| 158 | if (stat(temp, &st) == -1) {
|
---|
| 159 | fprintf(stderr, "cant get status of '%s' \n", temp);
|
---|
| 160 | continue;
|
---|
| 161 | }
|
---|
| 162 | if (name[0] == '.' && (name[1] == 0 ||
|
---|
| 163 | (name[1] == '.' && name[2] == 0)))
|
---|
| 164 | continue;
|
---|
| 165 |
|
---|
| 166 | display_attrib(name, &st);
|
---|
| 167 |
|
---|
| 168 | mode = st.st_mode & S_IFMT;
|
---|
| 169 | if (mode == S_IFDIR) {
|
---|
| 170 | fprintf(outfile, "\n");
|
---|
| 171 | descend(temp);
|
---|
| 172 | for (i = 0; i < tabs; i++) {
|
---|
| 173 | fprintf(outfile, indentstr);
|
---|
| 174 | }
|
---|
| 175 | fprintf(outfile, "$\n");
|
---|
| 176 | continue;
|
---|
| 177 | }
|
---|
| 178 | if (mode == S_IFBLK || mode == S_IFCHR) {
|
---|
| 179 | fprintf(outfile, " %d %d\n", major(st.st_rdev), minor(st.st_rdev));
|
---|
| 180 | continue;
|
---|
| 181 | }
|
---|
| 182 | if (mode == S_IFREG) {
|
---|
| 183 | i = origlen;
|
---|
| 184 | fprintf(outfile, "%s%s", indentstr, top);
|
---|
| 185 | while (temp[i] != '\0') {
|
---|
| 186 | fputc(temp[i], outfile);
|
---|
| 187 | i++;
|
---|
| 188 | }
|
---|
| 189 | fprintf(outfile, "\n");
|
---|
| 190 | continue;
|
---|
| 191 | }
|
---|
| 192 | fprintf(outfile, " /dev/null");
|
---|
| 193 | fprintf(stderr,"File\n\t%s\n has an invalid mode, made empty.\n",temp);
|
---|
| 194 | }
|
---|
| 195 | closedir(dirp);
|
---|
| 196 | free(temp);
|
---|
| 197 | tabs--;
|
---|
| 198 | }
|
---|
| 199 |
|
---|
| 200 |
|
---|
| 201 | void display_attrib(name, st)
|
---|
| 202 | char *name;
|
---|
| 203 | struct stat *st;
|
---|
| 204 | {
|
---|
| 205 | /* Output the specification for a single file */
|
---|
| 206 |
|
---|
| 207 | int i;
|
---|
| 208 |
|
---|
| 209 | if (same_uid) uid = st->st_uid;
|
---|
| 210 | if (same_gid) gid = st->st_gid;
|
---|
| 211 | if (same_prot)
|
---|
| 212 | prot = st->st_mode & 0777; /***** This one is a bit shady *****/
|
---|
| 213 | for (i = 0; i < tabs; i++) fprintf(outfile, indentstr);
|
---|
| 214 | fprintf(outfile, "%s%s%c%c%c%3o %d %d",
|
---|
| 215 | name,
|
---|
| 216 | *name == '\0' ? "" : indentstr, /* stop the tab for a null name */
|
---|
| 217 | (st->st_mode & S_IFMT) == S_IFDIR ? 'd' :
|
---|
| 218 | (st->st_mode & S_IFMT) == S_IFCHR ? 'c' :
|
---|
| 219 | (st->st_mode & S_IFMT) == S_IFBLK ? 'b' :
|
---|
| 220 | '-', /* file type */
|
---|
| 221 | (st->st_mode & S_ISUID) ? 'u' : '-', /* set uid */
|
---|
| 222 | (st->st_mode & S_ISGID) ? 'g' : '-', /* set gid */
|
---|
| 223 | prot,
|
---|
| 224 | uid,
|
---|
| 225 | gid);
|
---|
| 226 | }
|
---|
| 227 |
|
---|
| 228 | void usage(binname)
|
---|
| 229 | char *binname;
|
---|
| 230 | {
|
---|
| 231 | fprintf(stderr, "Usage: %s [options] source_directory [prototype_file]\n", binname);
|
---|
| 232 | fprintf(stderr, "options:\n");
|
---|
| 233 | fprintf(stderr, " -b n\t\t file system size is n blocks (default %d)\n", DEF_BLOCKS);
|
---|
| 234 | fprintf(stderr, " -d STRING\t define the indentation characters (default %s)\n", "(none)");
|
---|
| 235 | fprintf(stderr, " -g n\t\t use n as the gid on all files (default %d)\n", DEF_GID);
|
---|
| 236 | fprintf(stderr, " -i n\t\t file system gets n i-nodes (default %d)\n", DEF_INODES);
|
---|
| 237 | fprintf(stderr, " -p nnn\t use nnn (octal) as mode on all files (default %o)\n", DEF_PROT);
|
---|
| 238 | fprintf(stderr, " -s \t\t use the same uid, gid and mode as originals have\n");
|
---|
| 239 | fprintf(stderr, " -t ROOT\t inital path prefix for each entry\n");
|
---|
| 240 | fprintf(stderr, " -u n\t\t use nnn as the uid on all files (default %d)\n", DEF_UID);
|
---|
| 241 | exit(1);
|
---|
| 242 | }
|
---|
| 243 |
|
---|
| 244 | void open_outfile()
|
---|
| 245 | {
|
---|
| 246 | if (proto_file == NULL)
|
---|
| 247 | outfile = stdout;
|
---|
| 248 | else if ((outfile = fopen(proto_file, "w")) == NULL)
|
---|
| 249 | fprintf(stderr, "Cannot create %s\n ", proto_file);
|
---|
| 250 | }
|
---|