1 #if HAVE_NBTOOL_CONFIG_H
2 #include "nbtool_config.h"
16 #include <sys/types.h>
22 #define MAX_ENTRIES 100000
23 #define MAX_LINE_SIZE 0xfff
27 * Tool to convert the netbsd METALOG into a proto file usable by mkfs.mfs
30 * Possibly use netbsd usr.sbin/makefs to create mfs file systems.
34 { ENTRY_DIR
, ENTRY_FILE
, ENTRY_LINK
, ENTRY_BLOCK
, ENTRY_CHAR
};
40 char *filename
; /* point to last component in the path */
41 enum entry_type type
; /* entry type */
42 int mode
; /* unix mode e.g. 0755 */
45 char *time
; /* time 1365836670.000000000 */
48 /* Can't use devmajor_t/devminor_t on linux systems :( */
52 /* just internal variables used to create a tree */
58 static struct entry entries
[MAX_ENTRIES
];
59 static int entry_total_count
;
62 convert_to_entry(char *line
, struct entry
*entry
)
64 /* convert a input line from sanitized input into an entry */
70 /* we need to have a terminated string */
71 assert(strnlen(line
, MAX_LINE_SIZE
- 1) != MAX_LINE_SIZE
- 1);
73 /* skip comment lines */
77 line
= strtok_r(line
, " ", &saveptr
);
79 /* skip empty lines */
84 memset(entry
, 0, sizeof(struct entry
));
86 /* the first entry is the path name */
87 entry
->path
= strndup(line
, MAX_LINE_SIZE
);
89 /* the next entries are key,value pairs */
90 while ((line
= strtok_r(NULL
, " ", &saveptr
)) != NULL
) {
93 if (strstr(line
, "=") == NULL
) {
94 fprintf(stderr
, "expected key/value pair in %s\n",
100 key
= strtok_r(line
, "=", &p
);
101 value
= strtok_r(NULL
, "=", &p
);
103 if (strncmp(key
, "type", 5) == 0) {
104 if (strncmp(value
, "dir", 4) == 0) {
105 entry
->type
= ENTRY_DIR
;
106 } else if (strncmp(value
, "file", 5) == 0) {
107 entry
->type
= ENTRY_FILE
;
108 } else if (strncmp(value
, "link", 5) == 0) {
109 entry
->type
= ENTRY_LINK
;
110 } else if (strncmp(value
, "block", 6) == 0) {
111 entry
->type
= ENTRY_BLOCK
;
112 } else if (strncmp(value
, "char", 5) == 0) {
113 entry
->type
= ENTRY_CHAR
;
116 "\tunknown type %s -> '%s'\n", key
,
119 } else if (strncmp(key
, "mode", 5) == 0) {
120 sscanf(value
,"%o",&entry
->mode
);
121 } else if (strncmp(key
, "uid", 4) == 0) {
122 entry
->uid
= strndup(value
, MAX_LINE_SIZE
);
123 } else if (strncmp(key
, "gid", 4) == 0) {
124 entry
->gid
= strndup(value
, MAX_LINE_SIZE
);
125 } else if (strncmp(key
, "time", 5) == 0) {
126 entry
->time
= strndup(value
, MAX_LINE_SIZE
);
127 } else if (strncmp(key
, "size", 5) == 0) {
128 entry
->size
= strndup(value
, MAX_LINE_SIZE
);
129 } else if (strncmp(key
, "link", 5) == 0) {
130 entry
->link
= strndup(value
, MAX_LINE_SIZE
);
131 } else if (strncmp(key
, "device", 7) == 0) {
133 dev_id
= strtoul(value
, NULL
, 16);
134 entry
->dev_major
= major_netbsd(dev_id
);
135 entry
->dev_minor
= minor_netbsd(dev_id
);
138 "\tunknown attribute %s -> %s\n", key
,
147 iterate_over_input(int fh_in
, void (*callback
) (char *line
))
149 char buf
[MAX_LINE_SIZE
];
155 memset(buf
, 0, MAX_LINE_SIZE
);
162 /* fill buffer taking into account there can already be
163 * content at the start */
164 r_size
= read(fh_in
, &buf
[buf_end
], MAX_LINE_SIZE
- buf_end
);
167 fprintf(stderr
, "failed reading input:%s\n",
171 /* checking for read size of 0 is not enough as the buffer
172 * still can contain content */
173 buf_end
= buf_end
+ r_size
;
175 /* is there data we need to process ? */
177 return 0; /* normal exit is here */
180 /* find end of line or eof. start a the start of the buffer */
182 while (p
< buf
+ buf_end
) {
183 if (*p
== '\n' || *p
== '\0') {
184 /* replace either by a null terminator */
192 /* If we are at the end of the buffer we did not find a
194 if (p
== buf
+ buf_end
) {
196 "Line(%d) does not fit the buffer %d\n", line_nr
,
201 line_size
= p
- buf
; /* size of the line we currently are
204 /* here we have a valid line */
207 /* copy the remaining data over to the start */
208 memmove(buf
, p
+ 1, MAX_LINE_SIZE
- line_size
);
209 buf_end
-= (line_size
+ 1);
215 parse_line_cb(char *line
)
217 if (convert_to_entry(line
, &entries
[entry_total_count
]) == 0) {
219 assert(entry_total_count
< MAX_ENTRIES
);
221 memset(&entries
[entry_total_count
], 0, sizeof(struct entry
));
226 create_entries(int handle
)
232 char tmppath
[MAX_LINE_SIZE
];
235 if (iterate_over_input(handle
, parse_line_cb
)) {
239 /* calculate depth for each entry */
240 for (c
= 0; c
< entry_total_count
; c
++) {
250 /* find parent entry and set the filename */
251 for (c
= 0; c
< entry_total_count
; c
++) {
253 if (entry
->depth
> 0) {
255 /* find last "/" element and "null" it */
256 strncpy(tmppath
, entry
->path
, MAX_LINE_SIZE
- 1);
259 if (tmppath
[i
] == '/') {
260 entry
->filename
= &entry
->path
[i
+ 1];
269 "error while searching for parent path of %s\n",
274 /* now compare with the other entries */
275 for (i
= 0; i
< entry_total_count
; i
++) {
276 if (strncmp(entries
[i
].path
, tmppath
,
277 MAX_LINE_SIZE
) == 0) {
279 entry
->parent
= &entries
[i
];
283 if (entry
->parent
== NULL
) {
285 "Failed to find parent directory of %s\n",
289 assert(entry
->parent
->type
== ENTRY_DIR
);
291 /* same in this case */
292 entry
->filename
= entry
->path
;
299 static char * parse_mode(int mode
){
300 /* Convert a 4 digit octal number int a proto entry as described in
301 the mkfs.mfs man page e.g. [suid-char][guid-char]0777 mode */
306 suid
= (mode
& 04000)?'u':'-';
307 guid
= (mode
& 02000)?'g':'-';
308 snprintf(m
,6,"%c%c%3o",suid
,guid
,mode
& 0777);
312 static char *parse_filename(char *path
)
314 /* Skipping the first . in the path */
319 dump_entry(FILE * out
, int mindex
, const char *base_dir
)
324 struct entry
*entry
= &entries
[mindex
];
326 /* Ensure uid & gid are set to something meaningful. */
327 if (entry
->uid
== NULL
) {
328 entry
->uid
= __UNCONST("0");
330 if (entry
->gid
== NULL
) {
331 entry
->gid
= __UNCONST("0");
334 /* Indent the line */
335 for (space
= 0; space
< entries
[mindex
].depth
; space
++) {
338 if (entry
->type
== ENTRY_DIR
) {
339 if (entries
[mindex
].depth
> 0) {
340 fprintf(out
, "%s ", entry
->filename
);
342 fprintf(out
, "d%s", parse_mode(entry
->mode
));
343 fprintf(out
, " %s", entry
->uid
);
344 fprintf(out
, " %s", entry
->gid
);
346 for (i
= 0; i
< entry_total_count
; i
++) {
347 if (entries
[i
].parent
== entry
) {
348 dump_entry(out
, i
, base_dir
);
351 for (space
= 0; space
< entries
[mindex
].depth
; space
++) {
355 } else if (entry
->type
== ENTRY_FILE
) {
356 fprintf(out
, "%s -%s %s %s %s%s\n", entry
->filename
,
357 parse_mode(entry
->mode
), entry
->uid
, entry
->gid
,
358 base_dir
, parse_filename(entry
->path
));
359 } else if (entry
->type
== ENTRY_LINK
) {
360 fprintf(out
, "%s s%s %s %s %s\n", entry
->filename
,
361 parse_mode(entry
->mode
), entry
->uid
, entry
->gid
,
363 } else if (entry
->type
== ENTRY_CHAR
) {
364 fprintf(out
, "%s c%s %s %s %d %d\n", entry
->filename
,
365 parse_mode(entry
->mode
), entry
->uid
, entry
->gid
,
366 entry
->dev_major
, entry
->dev_minor
);
367 } else if (entry
->type
== ENTRY_BLOCK
) {
368 fprintf(out
, "%s b%s %s %s %d %d\n", entry
->filename
,
369 parse_mode(entry
->mode
), entry
->uid
, entry
->gid
,
370 entry
->dev_major
, entry
->dev_minor
);
372 /* Unknown line type. */
374 fprintf(out
, "%i %s\n", entry
->type
, entry
->path
);
382 dump_proto(FILE * out
, const char *base_dir
)
385 fprintf(out
, "boot\n0 0");
386 for (i
= 0; i
< entry_total_count
; i
++) {
387 if (entries
[i
].depth
== 0) {
389 dump_entry(out
, i
, base_dir
);
398 printf("Usage: toproto [OPTION]...\n");
400 ("Convert a netbsd METALOG file into a proto file for mkfs.mfs.\n");
402 printf(" -i input METALOG\n");
403 printf(" -b base_path\n");
404 printf(" -o output proto\n");
405 printf(" -h show this this help and exit\n");
409 main(int argc
, char **argv
)
413 const char *base_path
;
414 char *input_file
, *output_file
;
419 fh_in
= STDIN_FILENO
;
422 while ((ch
= getopt(argc
, argv
, "i:b:o:h")) != -1) {
431 output_file
= optarg
;
446 fh_in
= open(input_file
, O_RDONLY
);
448 fprintf(stderr
, "Failed to open input file (%s):%s\n",
449 input_file
, strerror(errno
));
454 out
= fopen(output_file
, "w+");
456 fprintf(stderr
, "Failed to open input file (%s):%s\n",
457 input_file
, strerror(errno
));
462 if (create_entries(fh_in
)) {
463 fprintf(stderr
, "Failed to create entries\n");
469 if (dump_proto(out
, base_path
)) {
470 fprintf(stderr
, "Failed to create entries\n");