kbuild/usr: initramfs list fixed and simplified
[linux-flexiantxendom0-3.2.10.git] / usr / gen_init_cpio.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <time.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <ctype.h>
11 #include <limits.h>
12
13 #define xstr(s) #s
14 #define str(s) xstr(s)
15
16 static unsigned int offset;
17 static unsigned int ino = 721;
18
19 struct file_type {
20         const char *type;
21         int (*handler)(const char *line);
22 };
23
24 static void push_string(const char *name)
25 {
26         unsigned int name_len = strlen(name) + 1;
27
28         fputs(name, stdout);
29         putchar(0);
30         offset += name_len;
31 }
32
33 static void push_pad (void)
34 {
35         while (offset & 3) {
36                 putchar(0);
37                 offset++;
38         }
39 }
40
41 static void push_rest(const char *name)
42 {
43         unsigned int name_len = strlen(name) + 1;
44         unsigned int tmp_ofs;
45
46         fputs(name, stdout);
47         putchar(0);
48         offset += name_len;
49
50         tmp_ofs = name_len + 110;
51         while (tmp_ofs & 3) {
52                 putchar(0);
53                 offset++;
54                 tmp_ofs++;
55         }
56 }
57
58 static void push_hdr(const char *s)
59 {
60         fputs(s, stdout);
61         offset += 110;
62 }
63
64 static void cpio_trailer(void)
65 {
66         char s[256];
67         const char name[] = "TRAILER!!!";
68
69         sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
70                "%08X%08X%08X%08X%08X%08X%08X",
71                 "070701",               /* magic */
72                 0,                      /* ino */
73                 0,                      /* mode */
74                 (long) 0,               /* uid */
75                 (long) 0,               /* gid */
76                 1,                      /* nlink */
77                 (long) 0,               /* mtime */
78                 0,                      /* filesize */
79                 0,                      /* major */
80                 0,                      /* minor */
81                 0,                      /* rmajor */
82                 0,                      /* rminor */
83                 (unsigned)strlen(name) + 1, /* namesize */
84                 0);                     /* chksum */
85         push_hdr(s);
86         push_rest(name);
87
88         while (offset % 512) {
89                 putchar(0);
90                 offset++;
91         }
92 }
93
94 static int cpio_mkdir(const char *name, unsigned int mode,
95                        uid_t uid, gid_t gid)
96 {
97         char s[256];
98         time_t mtime = time(NULL);
99
100         sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
101                "%08X%08X%08X%08X%08X%08X%08X",
102                 "070701",               /* magic */
103                 ino++,                  /* ino */
104                 S_IFDIR | mode,         /* mode */
105                 (long) uid,             /* uid */
106                 (long) gid,             /* gid */
107                 2,                      /* nlink */
108                 (long) mtime,           /* mtime */
109                 0,                      /* filesize */
110                 3,                      /* major */
111                 1,                      /* minor */
112                 0,                      /* rmajor */
113                 0,                      /* rminor */
114                 (unsigned)strlen(name) + 1,/* namesize */
115                 0);                     /* chksum */
116         push_hdr(s);
117         push_rest(name);
118         return 0;
119 }
120
121 static int cpio_mkdir_line(const char *line)
122 {
123         char name[PATH_MAX + 1];
124         unsigned int mode;
125         int uid;
126         int gid;
127         int rc = -1;
128
129         if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
130                 fprintf(stderr, "Unrecognized dir format '%s'", line);
131                 goto fail;
132         }
133         rc = cpio_mkdir(name, mode, uid, gid);
134  fail:
135         return rc;
136 }
137
138 static int cpio_mknod(const char *name, unsigned int mode,
139                        uid_t uid, gid_t gid, char dev_type,
140                        unsigned int maj, unsigned int min)
141 {
142         char s[256];
143         time_t mtime = time(NULL);
144
145         if (dev_type == 'b')
146                 mode |= S_IFBLK;
147         else
148                 mode |= S_IFCHR;
149
150         sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
151                "%08X%08X%08X%08X%08X%08X%08X",
152                 "070701",               /* magic */
153                 ino++,                  /* ino */
154                 mode,                   /* mode */
155                 (long) uid,             /* uid */
156                 (long) gid,             /* gid */
157                 1,                      /* nlink */
158                 (long) mtime,           /* mtime */
159                 0,                      /* filesize */
160                 3,                      /* major */
161                 1,                      /* minor */
162                 maj,                    /* rmajor */
163                 min,                    /* rminor */
164                 (unsigned)strlen(name) + 1,/* namesize */
165                 0);                     /* chksum */
166         push_hdr(s);
167         push_rest(name);
168         return 0;
169 }
170
171 static int cpio_mknod_line(const char *line)
172 {
173         char name[PATH_MAX + 1];
174         unsigned int mode;
175         int uid;
176         int gid;
177         char dev_type;
178         unsigned int maj;
179         unsigned int min;
180         int rc = -1;
181
182         if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
183                          name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
184                 fprintf(stderr, "Unrecognized nod format '%s'", line);
185                 goto fail;
186         }
187         rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
188  fail:
189         return rc;
190 }
191
192 /* Not marked static to keep the compiler quiet, as no one uses this yet... */
193 static int cpio_mkfile(const char *name, const char *location,
194                         unsigned int mode, uid_t uid, gid_t gid)
195 {
196         char s[256];
197         char *filebuf = NULL;
198         struct stat buf;
199         int file = -1;
200         int retval;
201         int i;
202         int rc = -1;
203
204         mode |= S_IFREG;
205
206         retval = stat (location, &buf);
207         if (retval) {
208                 fprintf (stderr, "File %s could not be located\n", location);
209                 goto error;
210         }
211
212         file = open (location, O_RDONLY);
213         if (file < 0) {
214                 fprintf (stderr, "File %s could not be opened for reading\n", location);
215                 goto error;
216         }
217
218         filebuf = malloc(buf.st_size);
219         if (!filebuf) {
220                 fprintf (stderr, "out of memory\n");
221                 goto error;
222         }
223
224         retval = read (file, filebuf, buf.st_size);
225         if (retval < 0) {
226                 fprintf (stderr, "Can not read %s file\n", location);
227                 goto error;
228         }
229
230         sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
231                "%08X%08X%08X%08X%08X%08X%08X",
232                 "070701",               /* magic */
233                 ino++,                  /* ino */
234                 mode,                   /* mode */
235                 (long) uid,             /* uid */
236                 (long) gid,             /* gid */
237                 1,                      /* nlink */
238                 (long) buf.st_mtime,    /* mtime */
239                 (int) buf.st_size,      /* filesize */
240                 3,                      /* major */
241                 1,                      /* minor */
242                 0,                      /* rmajor */
243                 0,                      /* rminor */
244                 (unsigned)strlen(name) + 1,/* namesize */
245                 0);                     /* chksum */
246         push_hdr(s);
247         push_string(name);
248         push_pad();
249
250         for (i = 0; i < buf.st_size; ++i)
251                 fputc(filebuf[i], stdout);
252         offset += buf.st_size;
253         push_pad();
254         rc = 0;
255         
256 error:
257         if (filebuf) free(filebuf);
258         if (file >= 0) close(file);
259         return rc;
260 }
261
262 static int cpio_mkfile_line(const char *line)
263 {
264         char name[PATH_MAX + 1];
265         char location[PATH_MAX + 1];
266         unsigned int mode;
267         int uid;
268         int gid;
269         int rc = -1;
270
271         if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) {
272                 fprintf(stderr, "Unrecognized file format '%s'", line);
273                 goto fail;
274         }
275         rc = cpio_mkfile(name, location, mode, uid, gid);
276  fail:
277         return rc;
278 }
279
280 void usage(const char *prog)
281 {
282         fprintf(stderr, "Usage:\n"
283                 "\t%s <cpio_list>\n"
284                 "\n"
285                 "<cpio_list> is a file containing newline separated entries that\n"
286                 "describe the files to be included in the initramfs archive:\n"
287                 "\n"
288                 "# a comment\n"
289                 "file <name> <location> <mode> <uid> <gid> \n"
290                 "dir <name> <mode> <uid> <gid>\n"
291                 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
292                 "\n"
293                 "<name>      name of the file/dir/nod in the archive\n"
294                 "<location>  location of the file in the current filesystem\n"
295                 "<mode>      mode/permissions of the file\n"
296                 "<uid>       user id (0=root)\n"
297                 "<gid>       group id (0=root)\n"
298                 "<dev_type>  device type (b=block, c=character)\n"
299                 "<maj>       major number of nod\n"
300                 "<min>       minor number of nod\n"
301                 "\n"
302                 "example:\n"
303                 "# A simple initramfs\n"
304                 "dir /dev 0755 0 0\n"
305                 "nod /dev/console 0600 0 0 c 5 1\n"
306                 "dir /root 0700 0 0\n"
307                 "dir /sbin 0755 0 0\n"
308                 "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n",
309                 prog);
310 }
311
312 struct file_type file_type_table[] = {
313         {
314                 .type    = "file",
315                 .handler = cpio_mkfile_line,
316         }, {
317                 .type    = "nod",
318                 .handler = cpio_mknod_line,
319         }, {
320                 .type    = "dir",
321                 .handler = cpio_mkdir_line,
322         }, {
323                 .type    = NULL,
324                 .handler = NULL,
325         }
326 };
327
328 #define LINE_SIZE (2 * PATH_MAX + 50)
329
330 int main (int argc, char *argv[])
331 {
332         FILE *cpio_list;
333         char line[LINE_SIZE];
334         char *args, *type;
335         int ec = 0;
336         int line_nr = 0;
337
338         if (2 != argc) {
339                 usage(argv[0]);
340                 exit(1);
341         }
342
343         if (! (cpio_list = fopen(argv[1], "r"))) {
344                 fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
345                         argv[1], strerror(errno));
346                 usage(argv[0]);
347                 exit(1);
348         }
349
350         while (fgets(line, LINE_SIZE, cpio_list)) {
351                 int type_idx;
352                 size_t slen = strlen(line);
353
354                 line_nr++;
355
356                 if ('#' == *line) {
357                         /* comment - skip to next line */
358                         continue;
359                 }
360
361                 if (! (type = strtok(line, " \t"))) {
362                         fprintf(stderr,
363                                 "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
364                                 line_nr, line);
365                         ec = -1;
366                 }
367
368                 if ('\n' == *type) {
369                         /* a blank line */
370                         continue;
371                 }
372
373                 if (slen == strlen(type)) {
374                         /* must be an empty line */
375                         continue;
376                 }
377
378                 if (! (args = strtok(NULL, "\n"))) {
379                         fprintf(stderr,
380                                 "ERROR: incorrect format, newline required line %d: '%s'\n",
381                                 line_nr, line);
382                         ec = -1;
383                 }
384
385                 for (type_idx = 0; file_type_table[type_idx].type; type_idx++) {
386                         int rc;
387                         if (! strcmp(line, file_type_table[type_idx].type)) {
388                                 if ((rc = file_type_table[type_idx].handler(args))) {
389                                         ec = rc;
390                                         fprintf(stderr, " line %d\n", line_nr);
391                                 }
392                                 break;
393                         }
394                 }
395
396                 if (NULL == file_type_table[type_idx].type) {
397                         fprintf(stderr, "unknown file type line %d: '%s'\n",
398                                 line_nr, line);
399                 }
400         }
401         cpio_trailer();
402
403         exit(ec);
404 }