xref: /minix3/minix/usr.bin/toproto/toproto.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #if HAVE_NBTOOL_CONFIG_H
2*433d6423SLionel Sambuc #include "nbtool_config.h"
3*433d6423SLionel Sambuc #else
4*433d6423SLionel Sambuc #include <sys/cdefs.h>
5*433d6423SLionel Sambuc #endif
6*433d6423SLionel Sambuc 
7*433d6423SLionel Sambuc #include <stdio.h>
8*433d6423SLionel Sambuc #include <stdlib.h>
9*433d6423SLionel Sambuc #include <string.h>
10*433d6423SLionel Sambuc #include <errno.h>
11*433d6423SLionel Sambuc #include <assert.h>
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc #include <getopt.h>
14*433d6423SLionel Sambuc #include <unistd.h>
15*433d6423SLionel Sambuc 
16*433d6423SLionel Sambuc #include <sys/types.h>
17*433d6423SLionel Sambuc #include <sys/stat.h>
18*433d6423SLionel Sambuc #include <fcntl.h>
19*433d6423SLionel Sambuc 
20*433d6423SLionel Sambuc #include "pack_dev.h"
21*433d6423SLionel Sambuc 
22*433d6423SLionel Sambuc #define MAX_ENTRIES 100000
23*433d6423SLionel Sambuc #define MAX_LINE_SIZE 0xfff
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc /*
27*433d6423SLionel Sambuc  * Tool to convert the netbsd METALOG into a proto file usable by mkfs.mfs
28*433d6423SLionel Sambuc  *
29*433d6423SLionel Sambuc  * todo:
30*433d6423SLionel Sambuc  * Possibly use netbsd usr.sbin/makefs to create mfs file systems.
31*433d6423SLionel Sambuc  */
32*433d6423SLionel Sambuc 
33*433d6423SLionel Sambuc enum entry_type
34*433d6423SLionel Sambuc { ENTRY_DIR, ENTRY_FILE, ENTRY_LINK, ENTRY_BLOCK, ENTRY_CHAR };
35*433d6423SLionel Sambuc 
36*433d6423SLionel Sambuc 
37*433d6423SLionel Sambuc struct entry
38*433d6423SLionel Sambuc {
39*433d6423SLionel Sambuc 	char *path;
40*433d6423SLionel Sambuc 	char *filename;		/* point to last component in the path */
41*433d6423SLionel Sambuc 	enum entry_type type;	/* entry type */
42*433d6423SLionel Sambuc 	int mode;		/* unix mode e.g. 0755 */
43*433d6423SLionel Sambuc 	char *uid;
44*433d6423SLionel Sambuc 	char *gid;
45*433d6423SLionel Sambuc 	char *time;		/* time 1365836670.000000000 */
46*433d6423SLionel Sambuc 	char *size;
47*433d6423SLionel Sambuc 	char *link;
48*433d6423SLionel Sambuc 	/* Can't use devmajor_t/devminor_t on linux systems :( */
49*433d6423SLionel Sambuc 	int32_t dev_major;
50*433d6423SLionel Sambuc 	int32_t dev_minor;
51*433d6423SLionel Sambuc 
52*433d6423SLionel Sambuc 	/* just internal variables used to create a tree */
53*433d6423SLionel Sambuc 	int depth;
54*433d6423SLionel Sambuc 	struct entry *parent;
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc };
57*433d6423SLionel Sambuc 
58*433d6423SLionel Sambuc static struct entry entries[MAX_ENTRIES];
59*433d6423SLionel Sambuc static int entry_total_count;
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc static int
convert_to_entry(char * line,struct entry * entry)62*433d6423SLionel Sambuc convert_to_entry(char *line, struct entry *entry)
63*433d6423SLionel Sambuc {
64*433d6423SLionel Sambuc 	/* convert a input line from sanitized input into an entry */
65*433d6423SLionel Sambuc 	char *saveptr;
66*433d6423SLionel Sambuc 	char *key, *value;
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc 	saveptr = NULL;
69*433d6423SLionel Sambuc 
70*433d6423SLionel Sambuc 	/* we need to have a terminated string */
71*433d6423SLionel Sambuc 	assert(strnlen(line, MAX_LINE_SIZE - 1) != MAX_LINE_SIZE - 1);
72*433d6423SLionel Sambuc 
73*433d6423SLionel Sambuc 	/* skip comment lines */
74*433d6423SLionel Sambuc 	if (*line == '#')
75*433d6423SLionel Sambuc 		return 1;
76*433d6423SLionel Sambuc 
77*433d6423SLionel Sambuc 	line = strtok_r(line, " ", &saveptr);
78*433d6423SLionel Sambuc 
79*433d6423SLionel Sambuc 	/* skip empty lines */
80*433d6423SLionel Sambuc 	if (!line) {
81*433d6423SLionel Sambuc 		return 1;
82*433d6423SLionel Sambuc 	}
83*433d6423SLionel Sambuc 
84*433d6423SLionel Sambuc 	memset(entry, 0, sizeof(struct entry));
85*433d6423SLionel Sambuc 
86*433d6423SLionel Sambuc 	/* the first entry is the path name */
87*433d6423SLionel Sambuc 	entry->path = strndup(line, MAX_LINE_SIZE);
88*433d6423SLionel Sambuc 
89*433d6423SLionel Sambuc 	/* the next entries are key,value pairs */
90*433d6423SLionel Sambuc 	while ((line = strtok_r(NULL, " ", &saveptr)) != NULL) {
91*433d6423SLionel Sambuc 		key = value = NULL;
92*433d6423SLionel Sambuc 		char *p;
93*433d6423SLionel Sambuc 		if (strstr(line, "=") == NULL) {
94*433d6423SLionel Sambuc 			fprintf(stderr, "expected key/value pair in %s\n",
95*433d6423SLionel Sambuc 			    line);
96*433d6423SLionel Sambuc 			free(entry->path);
97*433d6423SLionel Sambuc 			return 1;
98*433d6423SLionel Sambuc 		}
99*433d6423SLionel Sambuc 		p = NULL;
100*433d6423SLionel Sambuc 		key = strtok_r(line, "=", &p);
101*433d6423SLionel Sambuc 		value = strtok_r(NULL, "=", &p);
102*433d6423SLionel Sambuc 		if (value) {
103*433d6423SLionel Sambuc 			if (strncmp(key, "type", 5) == 0) {
104*433d6423SLionel Sambuc 				if (strncmp(value, "dir", 4) == 0) {
105*433d6423SLionel Sambuc 					entry->type = ENTRY_DIR;
106*433d6423SLionel Sambuc 				} else if (strncmp(value, "file", 5) == 0) {
107*433d6423SLionel Sambuc 					entry->type = ENTRY_FILE;
108*433d6423SLionel Sambuc 				} else if (strncmp(value, "link", 5) == 0) {
109*433d6423SLionel Sambuc 					entry->type = ENTRY_LINK;
110*433d6423SLionel Sambuc 				} else if (strncmp(value, "block", 6) == 0) {
111*433d6423SLionel Sambuc 					entry->type = ENTRY_BLOCK;
112*433d6423SLionel Sambuc 				} else if (strncmp(value, "char", 5) == 0) {
113*433d6423SLionel Sambuc 					entry->type = ENTRY_CHAR;
114*433d6423SLionel Sambuc 				} else {
115*433d6423SLionel Sambuc 					fprintf(stderr,
116*433d6423SLionel Sambuc 					    "\tunknown type %s -> '%s'\n", key,
117*433d6423SLionel Sambuc 					    value);
118*433d6423SLionel Sambuc 				}
119*433d6423SLionel Sambuc 			} else if (strncmp(key, "mode", 5) == 0) {
120*433d6423SLionel Sambuc 				sscanf(value,"%o",&entry->mode);
121*433d6423SLionel Sambuc 			} else if (strncmp(key, "uid", 4) == 0) {
122*433d6423SLionel Sambuc 				entry->uid = strndup(value, MAX_LINE_SIZE);
123*433d6423SLionel Sambuc 			} else if (strncmp(key, "gid", 4) == 0) {
124*433d6423SLionel Sambuc 				entry->gid = strndup(value, MAX_LINE_SIZE);
125*433d6423SLionel Sambuc 			} else if (strncmp(key, "time", 5) == 0) {
126*433d6423SLionel Sambuc 				entry->time = strndup(value, MAX_LINE_SIZE);
127*433d6423SLionel Sambuc 			} else if (strncmp(key, "size", 5) == 0) {
128*433d6423SLionel Sambuc 				entry->size = strndup(value, MAX_LINE_SIZE);
129*433d6423SLionel Sambuc 			} else if (strncmp(key, "link", 5) == 0) {
130*433d6423SLionel Sambuc 				entry->link = strndup(value, MAX_LINE_SIZE);
131*433d6423SLionel Sambuc 			} else if (strncmp(key, "device", 7) == 0) {
132*433d6423SLionel Sambuc 				long int dev_id;
133*433d6423SLionel Sambuc 				dev_id = strtoul(value, NULL, 16);
134*433d6423SLionel Sambuc 				entry->dev_major = major_netbsd(dev_id);
135*433d6423SLionel Sambuc 				entry->dev_minor = minor_netbsd(dev_id);
136*433d6423SLionel Sambuc 			} else {
137*433d6423SLionel Sambuc 				fprintf(stderr,
138*433d6423SLionel Sambuc 				    "\tunknown attribute %s -> %s\n", key,
139*433d6423SLionel Sambuc 				    value);
140*433d6423SLionel Sambuc 			}
141*433d6423SLionel Sambuc 		}
142*433d6423SLionel Sambuc 	}
143*433d6423SLionel Sambuc 	return 0;
144*433d6423SLionel Sambuc }
145*433d6423SLionel Sambuc 
146*433d6423SLionel Sambuc static int
iterate_over_input(int fh_in,void (* callback)(char * line))147*433d6423SLionel Sambuc iterate_over_input(int fh_in, void (*callback) (char *line))
148*433d6423SLionel Sambuc {
149*433d6423SLionel Sambuc 	char buf[MAX_LINE_SIZE];
150*433d6423SLionel Sambuc 	int r_size, err;
151*433d6423SLionel Sambuc 	int line_size;
152*433d6423SLionel Sambuc 	int buf_end;
153*433d6423SLionel Sambuc 	int line_nr;
154*433d6423SLionel Sambuc 	char *p;
155*433d6423SLionel Sambuc 	memset(buf, 0, MAX_LINE_SIZE);
156*433d6423SLionel Sambuc 
157*433d6423SLionel Sambuc 	r_size = 0;
158*433d6423SLionel Sambuc 	buf_end = 0;
159*433d6423SLionel Sambuc 	line_nr = 0;
160*433d6423SLionel Sambuc 
161*433d6423SLionel Sambuc 	while (1 == 1) {
162*433d6423SLionel Sambuc 		/* fill buffer taking into account there can already be
163*433d6423SLionel Sambuc 		 * content at the start */
164*433d6423SLionel Sambuc 		r_size = read(fh_in, &buf[buf_end], MAX_LINE_SIZE - buf_end);
165*433d6423SLionel Sambuc 		if (r_size == -1) {
166*433d6423SLionel Sambuc 			err = errno;
167*433d6423SLionel Sambuc 			fprintf(stderr, "failed reading input:%s\n",
168*433d6423SLionel Sambuc 			    strerror(err));
169*433d6423SLionel Sambuc 			return 1;
170*433d6423SLionel Sambuc 		}
171*433d6423SLionel Sambuc 		/* checking for read size of 0 is not enough as the buffer
172*433d6423SLionel Sambuc 		 * still can contain content */
173*433d6423SLionel Sambuc 		buf_end = buf_end + r_size;
174*433d6423SLionel Sambuc 
175*433d6423SLionel Sambuc 		/* is there data we need to process ? */
176*433d6423SLionel Sambuc 		if (buf_end == 0) {
177*433d6423SLionel Sambuc 			return 0;	/* normal exit is here */
178*433d6423SLionel Sambuc 		}
179*433d6423SLionel Sambuc 
180*433d6423SLionel Sambuc 		/* find end of line or eof. start a the start of the buffer */
181*433d6423SLionel Sambuc 		p = buf;
182*433d6423SLionel Sambuc 		while (p < buf + buf_end) {
183*433d6423SLionel Sambuc 			if (*p == '\n' || *p == '\0') {
184*433d6423SLionel Sambuc 				/* replace either by a null terminator */
185*433d6423SLionel Sambuc 				line_nr++;
186*433d6423SLionel Sambuc 				*p = '\0';
187*433d6423SLionel Sambuc 				break;
188*433d6423SLionel Sambuc 			}
189*433d6423SLionel Sambuc 			p++;
190*433d6423SLionel Sambuc 		}
191*433d6423SLionel Sambuc 
192*433d6423SLionel Sambuc 		/* If we are at the end of the buffer we did not find a
193*433d6423SLionel Sambuc 		 * terminator */
194*433d6423SLionel Sambuc 		if (p == buf + buf_end) {
195*433d6423SLionel Sambuc 			fprintf(stderr,
196*433d6423SLionel Sambuc 			    "Line(%d) does not fit the buffer %d\n", line_nr,
197*433d6423SLionel Sambuc 			    MAX_LINE_SIZE);
198*433d6423SLionel Sambuc 			return 1;
199*433d6423SLionel Sambuc 		}
200*433d6423SLionel Sambuc 
201*433d6423SLionel Sambuc 		line_size = p - buf;	/* size of the line we currently are
202*433d6423SLionel Sambuc 					 * reading */
203*433d6423SLionel Sambuc 
204*433d6423SLionel Sambuc 		/* here we have a valid line */
205*433d6423SLionel Sambuc 		callback(buf);
206*433d6423SLionel Sambuc 
207*433d6423SLionel Sambuc 		/* copy the remaining data over to the start */
208*433d6423SLionel Sambuc 		memmove(buf, p + 1, MAX_LINE_SIZE - line_size);
209*433d6423SLionel Sambuc 		buf_end -= (line_size + 1);
210*433d6423SLionel Sambuc 	}
211*433d6423SLionel Sambuc 	return 0;
212*433d6423SLionel Sambuc }
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc static void
parse_line_cb(char * line)215*433d6423SLionel Sambuc parse_line_cb(char *line)
216*433d6423SLionel Sambuc {
217*433d6423SLionel Sambuc 	if (convert_to_entry(line, &entries[entry_total_count]) == 0) {
218*433d6423SLionel Sambuc 		entry_total_count++;
219*433d6423SLionel Sambuc 		assert(entry_total_count < MAX_ENTRIES);
220*433d6423SLionel Sambuc 	} else {
221*433d6423SLionel Sambuc 		memset(&entries[entry_total_count], 0, sizeof(struct entry));
222*433d6423SLionel Sambuc 	}
223*433d6423SLionel Sambuc }
224*433d6423SLionel Sambuc 
225*433d6423SLionel Sambuc static int
create_entries(int handle)226*433d6423SLionel Sambuc create_entries(int handle)
227*433d6423SLionel Sambuc {
228*433d6423SLionel Sambuc 	int c;
229*433d6423SLionel Sambuc 	char *p;
230*433d6423SLionel Sambuc 	struct entry *entry;
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc 	char tmppath[MAX_LINE_SIZE];
233*433d6423SLionel Sambuc 	int i;
234*433d6423SLionel Sambuc 
235*433d6423SLionel Sambuc 	if (iterate_over_input(handle, parse_line_cb)) {
236*433d6423SLionel Sambuc 		return 1;
237*433d6423SLionel Sambuc 	}
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc 	/* calculate depth for each entry */
240*433d6423SLionel Sambuc 	for (c = 0; c < entry_total_count; c++) {
241*433d6423SLionel Sambuc 		p = entries[c].path;
242*433d6423SLionel Sambuc 		while (*p != 0) {
243*433d6423SLionel Sambuc 			if (*p == '/') {
244*433d6423SLionel Sambuc 				entries[c].depth++;
245*433d6423SLionel Sambuc 			}
246*433d6423SLionel Sambuc 			p++;
247*433d6423SLionel Sambuc 		}
248*433d6423SLionel Sambuc 	}
249*433d6423SLionel Sambuc 
250*433d6423SLionel Sambuc 	/* find parent entry and set the filename */
251*433d6423SLionel Sambuc 	for (c = 0; c < entry_total_count; c++) {
252*433d6423SLionel Sambuc 		entry = &entries[c];
253*433d6423SLionel Sambuc 		if (entry->depth > 0) {
254*433d6423SLionel Sambuc 			/* calculate path */
255*433d6423SLionel Sambuc 			/* find last "/" element and "null" it */
256*433d6423SLionel Sambuc 			strncpy(tmppath, entry->path, MAX_LINE_SIZE - 1);
257*433d6423SLionel Sambuc 			i = strlen(tmppath);
258*433d6423SLionel Sambuc 			while (i > 0) {
259*433d6423SLionel Sambuc 				if (tmppath[i] == '/') {
260*433d6423SLionel Sambuc 					entry->filename = &entry->path[i + 1];
261*433d6423SLionel Sambuc 					tmppath[i] = '\0';
262*433d6423SLionel Sambuc 					break;
263*433d6423SLionel Sambuc 				}
264*433d6423SLionel Sambuc 				i--;
265*433d6423SLionel Sambuc 			}
266*433d6423SLionel Sambuc 			if (i == 0) {
267*433d6423SLionel Sambuc 				fprintf
268*433d6423SLionel Sambuc 				    (stderr,
269*433d6423SLionel Sambuc 				    "error while searching for parent path of %s\n",
270*433d6423SLionel Sambuc 				    entry->path);
271*433d6423SLionel Sambuc 				return 1;
272*433d6423SLionel Sambuc 			}
273*433d6423SLionel Sambuc 
274*433d6423SLionel Sambuc 			/* now compare with the other entries */
275*433d6423SLionel Sambuc 			for (i = 0; i < entry_total_count; i++) {
276*433d6423SLionel Sambuc 				if (strncmp(entries[i].path, tmppath,
277*433d6423SLionel Sambuc 					MAX_LINE_SIZE) == 0) {
278*433d6423SLionel Sambuc 					/* found entry */
279*433d6423SLionel Sambuc 					entry->parent = &entries[i];
280*433d6423SLionel Sambuc 					break;
281*433d6423SLionel Sambuc 				}
282*433d6423SLionel Sambuc 			}
283*433d6423SLionel Sambuc 			if (entry->parent == NULL) {
284*433d6423SLionel Sambuc 				fprintf(stderr,
285*433d6423SLionel Sambuc 				    "Failed to find parent directory of %s\n",
286*433d6423SLionel Sambuc 				    entry->path);
287*433d6423SLionel Sambuc 				return 1;
288*433d6423SLionel Sambuc 			}
289*433d6423SLionel Sambuc 			assert(entry->parent->type == ENTRY_DIR);
290*433d6423SLionel Sambuc 		} else {
291*433d6423SLionel Sambuc 			/* same in this case */
292*433d6423SLionel Sambuc 			entry->filename = entry->path;
293*433d6423SLionel Sambuc 		}
294*433d6423SLionel Sambuc 	}
295*433d6423SLionel Sambuc 
296*433d6423SLionel Sambuc 	return 0;
297*433d6423SLionel Sambuc }
298*433d6423SLionel Sambuc 
parse_mode(int mode)299*433d6423SLionel Sambuc static char * parse_mode(int mode){
300*433d6423SLionel Sambuc 	/* Convert a 4 digit octal number int a proto  entry as described in
301*433d6423SLionel Sambuc    the mkfs.mfs man page e.g. [suid-char][guid-char]0777 mode */
302*433d6423SLionel Sambuc 
303*433d6423SLionel Sambuc 	static char m[6];
304*433d6423SLionel Sambuc 	memset(m,0,6);
305*433d6423SLionel Sambuc 	char suid,guid;
306*433d6423SLionel Sambuc 	suid = (mode & 04000)?'u':'-';
307*433d6423SLionel Sambuc 	guid = (mode & 02000)?'g':'-';
308*433d6423SLionel Sambuc 	snprintf(m,6,"%c%c%3o",suid,guid,mode & 0777);
309*433d6423SLionel Sambuc 	return m;
310*433d6423SLionel Sambuc }
311*433d6423SLionel Sambuc 
parse_filename(char * path)312*433d6423SLionel Sambuc static char *parse_filename(char *path)
313*433d6423SLionel Sambuc {
314*433d6423SLionel Sambuc 	/* Skipping the first . in the path */
315*433d6423SLionel Sambuc 	return &path[1];
316*433d6423SLionel Sambuc }
317*433d6423SLionel Sambuc 
318*433d6423SLionel Sambuc static int
dump_entry(FILE * out,int mindex,const char * base_dir)319*433d6423SLionel Sambuc dump_entry(FILE * out, int mindex, const char *base_dir)
320*433d6423SLionel Sambuc {
321*433d6423SLionel Sambuc 
322*433d6423SLionel Sambuc 	int space;
323*433d6423SLionel Sambuc 	int i;
324*433d6423SLionel Sambuc 	struct entry *entry = &entries[mindex];
325*433d6423SLionel Sambuc 
326*433d6423SLionel Sambuc 	/* Ensure uid & gid are set to something meaningful. */
327*433d6423SLionel Sambuc 	if (entry->uid == NULL) {
328*433d6423SLionel Sambuc 		entry->uid = __UNCONST("0");
329*433d6423SLionel Sambuc 	}
330*433d6423SLionel Sambuc 	if (entry->gid == NULL) {
331*433d6423SLionel Sambuc 		entry->gid = __UNCONST("0");
332*433d6423SLionel Sambuc 	}
333*433d6423SLionel Sambuc 
334*433d6423SLionel Sambuc 	/* Indent the line */
335*433d6423SLionel Sambuc 	for (space = 0; space < entries[mindex].depth; space++) {
336*433d6423SLionel Sambuc 		fprintf(out, " ");
337*433d6423SLionel Sambuc 	}
338*433d6423SLionel Sambuc 	if (entry->type == ENTRY_DIR) {
339*433d6423SLionel Sambuc 		if (entries[mindex].depth > 0) {
340*433d6423SLionel Sambuc 			fprintf(out, "%s ", entry->filename);
341*433d6423SLionel Sambuc 		}
342*433d6423SLionel Sambuc 		fprintf(out, "d%s", parse_mode(entry->mode));
343*433d6423SLionel Sambuc 		fprintf(out, " %s", entry->uid);
344*433d6423SLionel Sambuc 		fprintf(out, " %s", entry->gid);
345*433d6423SLionel Sambuc 		fprintf(out, "\n");
346*433d6423SLionel Sambuc 		for (i = 0; i < entry_total_count; i++) {
347*433d6423SLionel Sambuc 			if (entries[i].parent == entry) {
348*433d6423SLionel Sambuc 				dump_entry(out, i, base_dir);
349*433d6423SLionel Sambuc 			}
350*433d6423SLionel Sambuc 		}
351*433d6423SLionel Sambuc 		for (space = 0; space < entries[mindex].depth; space++) {
352*433d6423SLionel Sambuc 			fprintf(out, " ");
353*433d6423SLionel Sambuc 		}
354*433d6423SLionel Sambuc 		fprintf(out, "$\n");
355*433d6423SLionel Sambuc 	} else if (entry->type == ENTRY_FILE) {
356*433d6423SLionel Sambuc 		fprintf(out, "%s -%s %s %s %s%s\n", entry->filename,
357*433d6423SLionel Sambuc 			parse_mode(entry->mode), entry->uid, entry->gid,
358*433d6423SLionel Sambuc 			base_dir, parse_filename(entry->path));
359*433d6423SLionel Sambuc 	} else if (entry->type == ENTRY_LINK) {
360*433d6423SLionel Sambuc 		fprintf(out, "%s s%s %s %s %s\n", entry->filename,
361*433d6423SLionel Sambuc 			parse_mode(entry->mode), entry->uid, entry->gid,
362*433d6423SLionel Sambuc 			entry->link);
363*433d6423SLionel Sambuc 	} else if (entry->type == ENTRY_CHAR) {
364*433d6423SLionel Sambuc 		fprintf(out, "%s c%s %s %s %d %d\n", entry->filename,
365*433d6423SLionel Sambuc 			parse_mode(entry->mode), entry->uid, entry->gid,
366*433d6423SLionel Sambuc 			entry->dev_major, entry->dev_minor);
367*433d6423SLionel Sambuc 	} else if (entry->type == ENTRY_BLOCK) {
368*433d6423SLionel Sambuc 		fprintf(out, "%s b%s %s %s %d %d\n", entry->filename,
369*433d6423SLionel Sambuc 			parse_mode(entry->mode), entry->uid, entry->gid,
370*433d6423SLionel Sambuc 			entry->dev_major, entry->dev_minor);
371*433d6423SLionel Sambuc 	} else {
372*433d6423SLionel Sambuc 		/* Unknown line type.  */
373*433d6423SLionel Sambuc 		fprintf(out, "#");
374*433d6423SLionel Sambuc 		fprintf(out, "%i %s\n", entry->type, entry->path);
375*433d6423SLionel Sambuc 		exit(1);
376*433d6423SLionel Sambuc 		return 1;
377*433d6423SLionel Sambuc 	}
378*433d6423SLionel Sambuc 	return 0;
379*433d6423SLionel Sambuc }
380*433d6423SLionel Sambuc 
381*433d6423SLionel Sambuc static int
dump_proto(FILE * out,const char * base_dir)382*433d6423SLionel Sambuc dump_proto(FILE * out, const char *base_dir)
383*433d6423SLionel Sambuc {
384*433d6423SLionel Sambuc 	int i;
385*433d6423SLionel Sambuc 	fprintf(out, "boot\n0 0");
386*433d6423SLionel Sambuc 	for (i = 0; i < entry_total_count; i++) {
387*433d6423SLionel Sambuc 		if (entries[i].depth == 0) {
388*433d6423SLionel Sambuc 			fprintf(out, "\n");
389*433d6423SLionel Sambuc 			dump_entry(out, i, base_dir);
390*433d6423SLionel Sambuc 		}
391*433d6423SLionel Sambuc 	}
392*433d6423SLionel Sambuc 	return 0;
393*433d6423SLionel Sambuc }
394*433d6423SLionel Sambuc 
395*433d6423SLionel Sambuc static void
print_usage(void)396*433d6423SLionel Sambuc print_usage(void)
397*433d6423SLionel Sambuc {
398*433d6423SLionel Sambuc 	printf("Usage: toproto [OPTION]...\n");
399*433d6423SLionel Sambuc 	printf
400*433d6423SLionel Sambuc 	    ("Convert a netbsd METALOG file into a proto file for mkfs.mfs.\n");
401*433d6423SLionel Sambuc 	printf("\n");
402*433d6423SLionel Sambuc 	printf("  -i input METALOG\n");
403*433d6423SLionel Sambuc 	printf("  -b base_path\n");
404*433d6423SLionel Sambuc 	printf("  -o output proto\n");
405*433d6423SLionel Sambuc 	printf("  -h show this this help and exit\n");
406*433d6423SLionel Sambuc }
407*433d6423SLionel Sambuc 
408*433d6423SLionel Sambuc int
main(int argc,char ** argv)409*433d6423SLionel Sambuc main(int argc, char **argv)
410*433d6423SLionel Sambuc {
411*433d6423SLionel Sambuc 	int ch, fh_in;
412*433d6423SLionel Sambuc 	FILE *out;
413*433d6423SLionel Sambuc 	const char *base_path;
414*433d6423SLionel Sambuc 	char *input_file, *output_file;
415*433d6423SLionel Sambuc 
416*433d6423SLionel Sambuc 	input_file = NULL;
417*433d6423SLionel Sambuc 	output_file = NULL;
418*433d6423SLionel Sambuc 	base_path = ".";
419*433d6423SLionel Sambuc 	fh_in = STDIN_FILENO;
420*433d6423SLionel Sambuc 	out = stdout;
421*433d6423SLionel Sambuc 
422*433d6423SLionel Sambuc 	while ((ch = getopt(argc, argv, "i:b:o:h")) != -1) {
423*433d6423SLionel Sambuc 		switch (ch) {
424*433d6423SLionel Sambuc 		case 'i':
425*433d6423SLionel Sambuc 			input_file = optarg;
426*433d6423SLionel Sambuc 			break;
427*433d6423SLionel Sambuc 		case 'b':
428*433d6423SLionel Sambuc 			base_path = optarg;
429*433d6423SLionel Sambuc 			break;
430*433d6423SLionel Sambuc 		case 'o':
431*433d6423SLionel Sambuc 			output_file = optarg;
432*433d6423SLionel Sambuc 			break;
433*433d6423SLionel Sambuc 		case 'h':
434*433d6423SLionel Sambuc 			print_usage();
435*433d6423SLionel Sambuc 			exit(0);
436*433d6423SLionel Sambuc 			break;
437*433d6423SLionel Sambuc 		default:
438*433d6423SLionel Sambuc 			print_usage();
439*433d6423SLionel Sambuc 			exit(1);
440*433d6423SLionel Sambuc 		}
441*433d6423SLionel Sambuc 	}
442*433d6423SLionel Sambuc 	argc -= optind;
443*433d6423SLionel Sambuc 	argv += optind;
444*433d6423SLionel Sambuc 
445*433d6423SLionel Sambuc 	if (input_file) {
446*433d6423SLionel Sambuc 		fh_in = open(input_file, O_RDONLY);
447*433d6423SLionel Sambuc 		if (fh_in == -1) {
448*433d6423SLionel Sambuc 			fprintf(stderr, "Failed to open input file (%s):%s\n",
449*433d6423SLionel Sambuc 			    input_file, strerror(errno));
450*433d6423SLionel Sambuc 			exit(1);
451*433d6423SLionel Sambuc 		}
452*433d6423SLionel Sambuc 	}
453*433d6423SLionel Sambuc 	if (output_file) {
454*433d6423SLionel Sambuc 		out = fopen(output_file, "w+");
455*433d6423SLionel Sambuc 		if (!out) {
456*433d6423SLionel Sambuc 			fprintf(stderr, "Failed to open input file (%s):%s\n",
457*433d6423SLionel Sambuc 			    input_file, strerror(errno));
458*433d6423SLionel Sambuc 			exit(1);
459*433d6423SLionel Sambuc 		}
460*433d6423SLionel Sambuc 	}
461*433d6423SLionel Sambuc 
462*433d6423SLionel Sambuc 	if (create_entries(fh_in)) {
463*433d6423SLionel Sambuc 		fprintf(stderr, "Failed to create entries\n");
464*433d6423SLionel Sambuc 		exit(1);
465*433d6423SLionel Sambuc 	}
466*433d6423SLionel Sambuc 	if (input_file)
467*433d6423SLionel Sambuc 		close(fh_in);
468*433d6423SLionel Sambuc 
469*433d6423SLionel Sambuc 	if (dump_proto(out, base_path)) {
470*433d6423SLionel Sambuc 		fprintf(stderr, "Failed to create entries\n");
471*433d6423SLionel Sambuc 		exit(1);
472*433d6423SLionel Sambuc 	}
473*433d6423SLionel Sambuc 
474*433d6423SLionel Sambuc 	if (output_file)
475*433d6423SLionel Sambuc 		fclose(out);
476*433d6423SLionel Sambuc 	return 0;
477*433d6423SLionel Sambuc }
478