1 /* mkproto - make an mkfs prototype Author: Andrew Cagney */
3 /* Submitted by: cagney@chook.ua.oz (Andrew Cagney - aka Noid) */
7 #include <minix/minlib.h>
17 /* The default values for the prototype file */
18 #define DEF_UID 2 /* bin */
19 #define DEF_GID 1 /* daemon group */
20 #define DEF_PROT 0555 /* a=re */
21 #define DEF_BLOCKS 360
23 #define DEF_INDENTSTR "\t"
26 #define major(x) ( (x>>8) & 0377)
27 #define minor(x) (x & 0377)
31 int count
, origlen
, tabs
;
32 int gid
, uid
, prot
, same_uid
, same_gid
, same_prot
, blocks
, inodes
;
33 int block_given
, inode_given
, dprot
;
35 char *proto_file
, *top
;
41 int main(int argc
, char **argv
);
42 void descend(char *dirname
);
43 void display_attrib(const char *name
, struct stat
*st
);
44 void usage(char *binname
);
45 void open_outfile(void);
47 /* Returned by minix_readdir */
48 #define ME_MAXNAME 256
50 char d_name
[ME_MAXNAME
];
53 struct me_dirent
*minix_readdir(DIR *, int *n
);
54 void minix_free_readdir(struct me_dirent
*md
, int n
);
57 /* Compare dirent objects for order */
58 static int cmp_dirent(const void *d1
, const void *d2
)
60 struct me_dirent
*dp1
= (struct me_dirent
*) d1
,
61 *dp2
= (struct me_dirent
*) d2
;
62 return strcmp(dp1
->d_name
, dp2
->d_name
);
65 /* Return array of me_dirents. */
66 struct me_dirent
*minix_readdir(DIR *dirp
, int *n
)
70 struct me_dirent
*dirents
= NULL
;
71 int reserved_dirents
= 0;
74 while((rdp
= readdir(dirp
)) != NULL
) {
75 if(entries
>= reserved_dirents
) {
76 struct me_dirent
*newdirents
;
77 int newreserved
= (2*(reserved_dirents
+1));
78 if(!(newdirents
= realloc(dirents
, newreserved
*
84 reserved_dirents
= newreserved
;
87 assert(entries
< reserved_dirents
);
88 assert(strlen(rdp
->d_name
) < sizeof(dp
->d_name
));
89 dp
= &dirents
[entries
];
90 memset(dp
, 0, sizeof(*dp
));
91 strcpy(dp
->d_name
, rdp
->d_name
);
95 /* Assume directories contain at least "." and "..", and
96 * therefore the array exists.
101 /* normalize (sort) them */
102 qsort(dirents
, entries
, sizeof(*dp
), cmp_dirent
);
104 /* Return no. of entries. */
110 void minix_free_readdir(struct me_dirent
*md
, int n
)
119 char *dir
= __UNCONST("");
128 indentstr
= __UNCONST(DEF_INDENTSTR
);
135 while ((op
= getopt(argc
, argv
, "b:g:i:p:t:u:d:s")) != EOF
) {
138 blocks
= atoi(optarg
);
143 if (gid
== 0) usage(argv
[0]);
147 inodes
= atoi(optarg
);
151 sscanf(optarg
, "%o", &prot
);
152 if (prot
== 0) usage(argv
[0]);
160 case 't': top
= optarg
; break;
163 if (uid
== 0) usage(argv
[0]);
166 case 'd': indentstr
= optarg
; break;
167 default: /* Illegal options */
172 if (optind
>= argc
) {
177 proto_file
= argv
[optind
];
181 if (block_given
&& !inode_given
) inodes
= (blocks
/ 3) + 8;
182 if (!block_given
&& inode_given
) usage(argv
[0]);
185 origlen
= strlen(dir
);
187 /* Check that it really is a directory */
189 if ((st
.st_mode
& S_IFMT
) != S_IFDIR
) {
190 fprintf(stderr
, "mkproto: %s must be a directory\n", dir
);
193 fprintf(outfile
, "boot\n%d %d\n", blocks
, inodes
);
194 display_attrib("", &st
);
195 fprintf(outfile
, "\n");
197 fprintf(outfile
, "$\n");
201 /* Output the prototype spec for this directory. */
202 void descend(dirname
)
205 struct me_dirent
*dirents
;
207 char *name
, *temp
, *tempend
;
211 int entries
= 0, orig_entries
;
212 struct me_dirent
*dp
;
214 dirp
= opendir(dirname
);
216 fprintf(stderr
, "unable to open directory %s\n", dirname
);
220 temp
= (char *) malloc(sizeof(char) * strlen(dirname
) +1 + PATH_MAX
);
221 strcpy(temp
, dirname
);
223 tempend
= &temp
[strlen(temp
)];
225 /* read all directory entries */
226 if(!(dirents
= minix_readdir(dirp
, &entries
)))
227 errx(1, "minix_readdir failed");
228 orig_entries
= entries
;
231 for (dp
= dirents
; entries
> 0; dp
++, entries
--) {
235 strcpy(tempend
, name
);
237 if (lstat(temp
, &st
) == -1) {
238 fprintf(stderr
, "cant get status of '%s' \n", temp
);
241 if (name
[0] == '.' && (name
[1] == 0 ||
242 (name
[1] == '.' && name
[2] == 0)))
245 display_attrib(name
, &st
);
247 mode
= st
.st_mode
& S_IFMT
;
248 if (mode
== S_IFDIR
) {
249 fprintf(outfile
, "\n");
251 for (i
= 0; i
< tabs
; i
++) {
252 fprintf(outfile
, "%s", indentstr
);
254 fprintf(outfile
, "$\n");
257 if (mode
== S_IFBLK
|| mode
== S_IFCHR
) {
258 fprintf(outfile
, " %d %d\n", major(st
.st_rdev
), minor(st
.st_rdev
));
261 if (mode
== S_IFREG
) {
263 fprintf(outfile
, "%s%s", indentstr
, top
);
264 while (temp
[i
] != '\0') {
265 fputc(temp
[i
], outfile
);
268 fprintf(outfile
, "\n");
271 if (mode
== S_IFLNK
) {
272 char linkcontent
[PATH_MAX
];
273 memset(linkcontent
, 0, sizeof(linkcontent
));
274 if(readlink(temp
, linkcontent
, sizeof(linkcontent
)) < 0) {
278 fprintf(outfile
, "%s%s\n", indentstr
, linkcontent
);
281 fprintf(outfile
, " /dev/null");
282 fprintf(stderr
,"File\n\t%s\n has an invalid mode, made empty.\n",temp
);
285 minix_free_readdir(dirents
, orig_entries
);
290 void display_attrib(name
, st
)
294 /* Output the specification for a single file */
298 if (same_uid
) uid
= st
->st_uid
;
299 if (same_gid
) gid
= st
->st_gid
;
301 prot
= st
->st_mode
& 0777; /***** This one is a bit shady *****/
302 for (i
= 0; i
< tabs
; i
++) fprintf(outfile
, "%s", indentstr
);
303 fprintf(outfile
, "%s%s%c%c%c%03o %d %d",
305 *name
== '\0' ? "" : indentstr
, /* stop the tab for a null name */
306 (st
->st_mode
& S_IFMT
) == S_IFDIR
? 'd' :
307 (st
->st_mode
& S_IFMT
) == S_IFCHR
? 'c' :
308 (st
->st_mode
& S_IFMT
) == S_IFBLK
? 'b' :
309 (st
->st_mode
& S_IFMT
) == S_IFLNK
? 's' :
311 (st
->st_mode
& S_ISUID
) ? 'u' : '-', /* set uid */
312 (st
->st_mode
& S_ISGID
) ? 'g' : '-', /* set gid */
321 fprintf(stderr
, "Usage: %s [options] source_directory [prototype_file]\n", binname
);
322 fprintf(stderr
, "options:\n");
323 fprintf(stderr
, " -b n\t\t file system size is n blocks (default %d)\n", DEF_BLOCKS
);
324 fprintf(stderr
, " -d STRING\t define the indentation characters (default %s)\n", "(none)");
325 fprintf(stderr
, " -g n\t\t use n as the gid on all files (default %d)\n", DEF_GID
);
326 fprintf(stderr
, " -i n\t\t file system gets n i-nodes (default %d)\n", DEF_INODES
);
327 fprintf(stderr
, " -p nnn\t use nnn (octal) as mode on all files (default %o)\n", DEF_PROT
);
328 fprintf(stderr
, " -s \t\t use the same uid, gid and mode as originals have\n");
329 fprintf(stderr
, " -t ROOT\t inital path prefix for each entry\n");
330 fprintf(stderr
, " -u n\t\t use nnn as the uid on all files (default %d)\n", DEF_UID
);
336 if (proto_file
== NULL
)
338 else if ((outfile
= fopen(proto_file
, "w")) == NULL
)
339 fprintf(stderr
, "Cannot create %s\n ", proto_file
);