Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/usr/gen_init_cpio.c
10814 views
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
/*
14
* Original work by Jeff Garzik
15
*
16
* External file lists, symlink, pipe and fifo support by Thayne Harbaugh
17
* Hard link support by Luciano Rocha
18
*/
19
20
#define xstr(s) #s
21
#define str(s) xstr(s)
22
23
static unsigned int offset;
24
static unsigned int ino = 721;
25
static time_t default_mtime;
26
27
struct file_handler {
28
const char *type;
29
int (*handler)(const char *line);
30
};
31
32
static void push_string(const char *name)
33
{
34
unsigned int name_len = strlen(name) + 1;
35
36
fputs(name, stdout);
37
putchar(0);
38
offset += name_len;
39
}
40
41
static void push_pad (void)
42
{
43
while (offset & 3) {
44
putchar(0);
45
offset++;
46
}
47
}
48
49
static void push_rest(const char *name)
50
{
51
unsigned int name_len = strlen(name) + 1;
52
unsigned int tmp_ofs;
53
54
fputs(name, stdout);
55
putchar(0);
56
offset += name_len;
57
58
tmp_ofs = name_len + 110;
59
while (tmp_ofs & 3) {
60
putchar(0);
61
offset++;
62
tmp_ofs++;
63
}
64
}
65
66
static void push_hdr(const char *s)
67
{
68
fputs(s, stdout);
69
offset += 110;
70
}
71
72
static void cpio_trailer(void)
73
{
74
char s[256];
75
const char name[] = "TRAILER!!!";
76
77
sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
78
"%08X%08X%08X%08X%08X%08X%08X",
79
"070701", /* magic */
80
0, /* ino */
81
0, /* mode */
82
(long) 0, /* uid */
83
(long) 0, /* gid */
84
1, /* nlink */
85
(long) 0, /* mtime */
86
0, /* filesize */
87
0, /* major */
88
0, /* minor */
89
0, /* rmajor */
90
0, /* rminor */
91
(unsigned)strlen(name)+1, /* namesize */
92
0); /* chksum */
93
push_hdr(s);
94
push_rest(name);
95
96
while (offset % 512) {
97
putchar(0);
98
offset++;
99
}
100
}
101
102
static int cpio_mkslink(const char *name, const char *target,
103
unsigned int mode, uid_t uid, gid_t gid)
104
{
105
char s[256];
106
107
if (name[0] == '/')
108
name++;
109
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
110
"%08X%08X%08X%08X%08X%08X%08X",
111
"070701", /* magic */
112
ino++, /* ino */
113
S_IFLNK | mode, /* mode */
114
(long) uid, /* uid */
115
(long) gid, /* gid */
116
1, /* nlink */
117
(long) default_mtime, /* mtime */
118
(unsigned)strlen(target)+1, /* filesize */
119
3, /* major */
120
1, /* minor */
121
0, /* rmajor */
122
0, /* rminor */
123
(unsigned)strlen(name) + 1,/* namesize */
124
0); /* chksum */
125
push_hdr(s);
126
push_string(name);
127
push_pad();
128
push_string(target);
129
push_pad();
130
return 0;
131
}
132
133
static int cpio_mkslink_line(const char *line)
134
{
135
char name[PATH_MAX + 1];
136
char target[PATH_MAX + 1];
137
unsigned int mode;
138
int uid;
139
int gid;
140
int rc = -1;
141
142
if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
143
fprintf(stderr, "Unrecognized dir format '%s'", line);
144
goto fail;
145
}
146
rc = cpio_mkslink(name, target, mode, uid, gid);
147
fail:
148
return rc;
149
}
150
151
static int cpio_mkgeneric(const char *name, unsigned int mode,
152
uid_t uid, gid_t gid)
153
{
154
char s[256];
155
156
if (name[0] == '/')
157
name++;
158
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
159
"%08X%08X%08X%08X%08X%08X%08X",
160
"070701", /* magic */
161
ino++, /* ino */
162
mode, /* mode */
163
(long) uid, /* uid */
164
(long) gid, /* gid */
165
2, /* nlink */
166
(long) default_mtime, /* mtime */
167
0, /* filesize */
168
3, /* major */
169
1, /* minor */
170
0, /* rmajor */
171
0, /* rminor */
172
(unsigned)strlen(name) + 1,/* namesize */
173
0); /* chksum */
174
push_hdr(s);
175
push_rest(name);
176
return 0;
177
}
178
179
enum generic_types {
180
GT_DIR,
181
GT_PIPE,
182
GT_SOCK
183
};
184
185
struct generic_type {
186
const char *type;
187
mode_t mode;
188
};
189
190
static struct generic_type generic_type_table[] = {
191
[GT_DIR] = {
192
.type = "dir",
193
.mode = S_IFDIR
194
},
195
[GT_PIPE] = {
196
.type = "pipe",
197
.mode = S_IFIFO
198
},
199
[GT_SOCK] = {
200
.type = "sock",
201
.mode = S_IFSOCK
202
}
203
};
204
205
static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
206
{
207
char name[PATH_MAX + 1];
208
unsigned int mode;
209
int uid;
210
int gid;
211
int rc = -1;
212
213
if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
214
fprintf(stderr, "Unrecognized %s format '%s'",
215
line, generic_type_table[gt].type);
216
goto fail;
217
}
218
mode |= generic_type_table[gt].mode;
219
rc = cpio_mkgeneric(name, mode, uid, gid);
220
fail:
221
return rc;
222
}
223
224
static int cpio_mkdir_line(const char *line)
225
{
226
return cpio_mkgeneric_line(line, GT_DIR);
227
}
228
229
static int cpio_mkpipe_line(const char *line)
230
{
231
return cpio_mkgeneric_line(line, GT_PIPE);
232
}
233
234
static int cpio_mksock_line(const char *line)
235
{
236
return cpio_mkgeneric_line(line, GT_SOCK);
237
}
238
239
static int cpio_mknod(const char *name, unsigned int mode,
240
uid_t uid, gid_t gid, char dev_type,
241
unsigned int maj, unsigned int min)
242
{
243
char s[256];
244
245
if (dev_type == 'b')
246
mode |= S_IFBLK;
247
else
248
mode |= S_IFCHR;
249
250
if (name[0] == '/')
251
name++;
252
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
253
"%08X%08X%08X%08X%08X%08X%08X",
254
"070701", /* magic */
255
ino++, /* ino */
256
mode, /* mode */
257
(long) uid, /* uid */
258
(long) gid, /* gid */
259
1, /* nlink */
260
(long) default_mtime, /* mtime */
261
0, /* filesize */
262
3, /* major */
263
1, /* minor */
264
maj, /* rmajor */
265
min, /* rminor */
266
(unsigned)strlen(name) + 1,/* namesize */
267
0); /* chksum */
268
push_hdr(s);
269
push_rest(name);
270
return 0;
271
}
272
273
static int cpio_mknod_line(const char *line)
274
{
275
char name[PATH_MAX + 1];
276
unsigned int mode;
277
int uid;
278
int gid;
279
char dev_type;
280
unsigned int maj;
281
unsigned int min;
282
int rc = -1;
283
284
if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
285
name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
286
fprintf(stderr, "Unrecognized nod format '%s'", line);
287
goto fail;
288
}
289
rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
290
fail:
291
return rc;
292
}
293
294
static int cpio_mkfile(const char *name, const char *location,
295
unsigned int mode, uid_t uid, gid_t gid,
296
unsigned int nlinks)
297
{
298
char s[256];
299
char *filebuf = NULL;
300
struct stat buf;
301
long size;
302
int file = -1;
303
int retval;
304
int rc = -1;
305
int namesize;
306
int i;
307
308
mode |= S_IFREG;
309
310
file = open (location, O_RDONLY);
311
if (file < 0) {
312
fprintf (stderr, "File %s could not be opened for reading\n", location);
313
goto error;
314
}
315
316
retval = fstat(file, &buf);
317
if (retval) {
318
fprintf(stderr, "File %s could not be stat()'ed\n", location);
319
goto error;
320
}
321
322
filebuf = malloc(buf.st_size);
323
if (!filebuf) {
324
fprintf (stderr, "out of memory\n");
325
goto error;
326
}
327
328
retval = read (file, filebuf, buf.st_size);
329
if (retval < 0) {
330
fprintf (stderr, "Can not read %s file\n", location);
331
goto error;
332
}
333
334
size = 0;
335
for (i = 1; i <= nlinks; i++) {
336
/* data goes on last link */
337
if (i == nlinks) size = buf.st_size;
338
339
if (name[0] == '/')
340
name++;
341
namesize = strlen(name) + 1;
342
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
343
"%08lX%08X%08X%08X%08X%08X%08X",
344
"070701", /* magic */
345
ino, /* ino */
346
mode, /* mode */
347
(long) uid, /* uid */
348
(long) gid, /* gid */
349
nlinks, /* nlink */
350
(long) buf.st_mtime, /* mtime */
351
size, /* filesize */
352
3, /* major */
353
1, /* minor */
354
0, /* rmajor */
355
0, /* rminor */
356
namesize, /* namesize */
357
0); /* chksum */
358
push_hdr(s);
359
push_string(name);
360
push_pad();
361
362
if (size) {
363
if (fwrite(filebuf, size, 1, stdout) != 1) {
364
fprintf(stderr, "writing filebuf failed\n");
365
goto error;
366
}
367
offset += size;
368
push_pad();
369
}
370
371
name += namesize;
372
}
373
ino++;
374
rc = 0;
375
376
error:
377
if (filebuf) free(filebuf);
378
if (file >= 0) close(file);
379
return rc;
380
}
381
382
static char *cpio_replace_env(char *new_location)
383
{
384
char expanded[PATH_MAX + 1];
385
char env_var[PATH_MAX + 1];
386
char *start;
387
char *end;
388
389
for (start = NULL; (start = strstr(new_location, "${")); ) {
390
end = strchr(start, '}');
391
if (start < end) {
392
*env_var = *expanded = '\0';
393
strncat(env_var, start + 2, end - start - 2);
394
strncat(expanded, new_location, start - new_location);
395
strncat(expanded, getenv(env_var), PATH_MAX);
396
strncat(expanded, end + 1, PATH_MAX);
397
strncpy(new_location, expanded, PATH_MAX);
398
} else
399
break;
400
}
401
402
return new_location;
403
}
404
405
406
static int cpio_mkfile_line(const char *line)
407
{
408
char name[PATH_MAX + 1];
409
char *dname = NULL; /* malloc'ed buffer for hard links */
410
char location[PATH_MAX + 1];
411
unsigned int mode;
412
int uid;
413
int gid;
414
int nlinks = 1;
415
int end = 0, dname_len = 0;
416
int rc = -1;
417
418
if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
419
"s %o %d %d %n",
420
name, location, &mode, &uid, &gid, &end)) {
421
fprintf(stderr, "Unrecognized file format '%s'", line);
422
goto fail;
423
}
424
if (end && isgraph(line[end])) {
425
int len;
426
int nend;
427
428
dname = malloc(strlen(line));
429
if (!dname) {
430
fprintf (stderr, "out of memory (%d)\n", dname_len);
431
goto fail;
432
}
433
434
dname_len = strlen(name) + 1;
435
memcpy(dname, name, dname_len);
436
437
do {
438
nend = 0;
439
if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
440
name, &nend) < 1)
441
break;
442
len = strlen(name) + 1;
443
memcpy(dname + dname_len, name, len);
444
dname_len += len;
445
nlinks++;
446
end += nend;
447
} while (isgraph(line[end]));
448
} else {
449
dname = name;
450
}
451
rc = cpio_mkfile(dname, cpio_replace_env(location),
452
mode, uid, gid, nlinks);
453
fail:
454
if (dname_len) free(dname);
455
return rc;
456
}
457
458
static void usage(const char *prog)
459
{
460
fprintf(stderr, "Usage:\n"
461
"\t%s [-t <timestamp>] <cpio_list>\n"
462
"\n"
463
"<cpio_list> is a file containing newline separated entries that\n"
464
"describe the files to be included in the initramfs archive:\n"
465
"\n"
466
"# a comment\n"
467
"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
468
"dir <name> <mode> <uid> <gid>\n"
469
"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
470
"slink <name> <target> <mode> <uid> <gid>\n"
471
"pipe <name> <mode> <uid> <gid>\n"
472
"sock <name> <mode> <uid> <gid>\n"
473
"\n"
474
"<name> name of the file/dir/nod/etc in the archive\n"
475
"<location> location of the file in the current filesystem\n"
476
" expands shell variables quoted with ${}\n"
477
"<target> link target\n"
478
"<mode> mode/permissions of the file\n"
479
"<uid> user id (0=root)\n"
480
"<gid> group id (0=root)\n"
481
"<dev_type> device type (b=block, c=character)\n"
482
"<maj> major number of nod\n"
483
"<min> minor number of nod\n"
484
"<hard links> space separated list of other links to file\n"
485
"\n"
486
"example:\n"
487
"# A simple initramfs\n"
488
"dir /dev 0755 0 0\n"
489
"nod /dev/console 0600 0 0 c 5 1\n"
490
"dir /root 0700 0 0\n"
491
"dir /sbin 0755 0 0\n"
492
"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
493
"\n"
494
"<timestamp> is time in seconds since Epoch that will be used\n"
495
"as mtime for symlinks, special files and directories. The default\n"
496
"is to use the current time for these entries.\n",
497
prog);
498
}
499
500
struct file_handler file_handler_table[] = {
501
{
502
.type = "file",
503
.handler = cpio_mkfile_line,
504
}, {
505
.type = "nod",
506
.handler = cpio_mknod_line,
507
}, {
508
.type = "dir",
509
.handler = cpio_mkdir_line,
510
}, {
511
.type = "slink",
512
.handler = cpio_mkslink_line,
513
}, {
514
.type = "pipe",
515
.handler = cpio_mkpipe_line,
516
}, {
517
.type = "sock",
518
.handler = cpio_mksock_line,
519
}, {
520
.type = NULL,
521
.handler = NULL,
522
}
523
};
524
525
#define LINE_SIZE (2 * PATH_MAX + 50)
526
527
int main (int argc, char *argv[])
528
{
529
FILE *cpio_list;
530
char line[LINE_SIZE];
531
char *args, *type;
532
int ec = 0;
533
int line_nr = 0;
534
const char *filename;
535
536
default_mtime = time(NULL);
537
while (1) {
538
int opt = getopt(argc, argv, "t:h");
539
char *invalid;
540
541
if (opt == -1)
542
break;
543
switch (opt) {
544
case 't':
545
default_mtime = strtol(optarg, &invalid, 10);
546
if (!*optarg || *invalid) {
547
fprintf(stderr, "Invalid timestamp: %s\n",
548
optarg);
549
usage(argv[0]);
550
exit(1);
551
}
552
break;
553
case 'h':
554
case '?':
555
usage(argv[0]);
556
exit(opt == 'h' ? 0 : 1);
557
}
558
}
559
560
if (argc - optind != 1) {
561
usage(argv[0]);
562
exit(1);
563
}
564
filename = argv[optind];
565
if (!strcmp(filename, "-"))
566
cpio_list = stdin;
567
else if (!(cpio_list = fopen(filename, "r"))) {
568
fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
569
filename, strerror(errno));
570
usage(argv[0]);
571
exit(1);
572
}
573
574
while (fgets(line, LINE_SIZE, cpio_list)) {
575
int type_idx;
576
size_t slen = strlen(line);
577
578
line_nr++;
579
580
if ('#' == *line) {
581
/* comment - skip to next line */
582
continue;
583
}
584
585
if (! (type = strtok(line, " \t"))) {
586
fprintf(stderr,
587
"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
588
line_nr, line);
589
ec = -1;
590
break;
591
}
592
593
if ('\n' == *type) {
594
/* a blank line */
595
continue;
596
}
597
598
if (slen == strlen(type)) {
599
/* must be an empty line */
600
continue;
601
}
602
603
if (! (args = strtok(NULL, "\n"))) {
604
fprintf(stderr,
605
"ERROR: incorrect format, newline required line %d: '%s'\n",
606
line_nr, line);
607
ec = -1;
608
}
609
610
for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
611
int rc;
612
if (! strcmp(line, file_handler_table[type_idx].type)) {
613
if ((rc = file_handler_table[type_idx].handler(args))) {
614
ec = rc;
615
fprintf(stderr, " line %d\n", line_nr);
616
}
617
break;
618
}
619
}
620
621
if (NULL == file_handler_table[type_idx].type) {
622
fprintf(stderr, "unknown file type line %d: '%s'\n",
623
line_nr, line);
624
}
625
}
626
if (ec == 0)
627
cpio_trailer();
628
629
exit(ec);
630
}
631
632