aboutsummaryrefslogtreecommitdiff
path: root/usr/gen_init_cpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/gen_init_cpio.c')
-rw-r--r--usr/gen_init_cpio.c223
1 files changed, 167 insertions, 56 deletions
diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c
index 33dbcbf77c5..225ad244cf8 100644
--- a/usr/gen_init_cpio.c
+++ b/usr/gen_init_cpio.c
@@ -14,6 +14,7 @@
* Original work by Jeff Garzik
*
* External file lists, symlink, pipe and fifo support by Thayne Harbaugh
+ * Hard link support by Luciano Rocha
*/
#define xstr(s) #s
@@ -21,6 +22,7 @@
static unsigned int offset;
static unsigned int ino = 721;
+static time_t default_mtime;
struct file_handler {
const char *type;
@@ -101,8 +103,9 @@ static int cpio_mkslink(const char *name, const char *target,
unsigned int mode, uid_t uid, gid_t gid)
{
char s[256];
- time_t mtime = time(NULL);
+ if (name[0] == '/')
+ name++;
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
"%08X%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
@@ -111,7 +114,7 @@ static int cpio_mkslink(const char *name, const char *target,
(long) uid, /* uid */
(long) gid, /* gid */
1, /* nlink */
- (long) mtime, /* mtime */
+ (long) default_mtime, /* mtime */
(unsigned)strlen(target)+1, /* filesize */
3, /* major */
1, /* minor */
@@ -149,8 +152,9 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
uid_t uid, gid_t gid)
{
char s[256];
- time_t mtime = time(NULL);
+ if (name[0] == '/')
+ name++;
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
"%08X%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
@@ -159,7 +163,7 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
(long) uid, /* uid */
(long) gid, /* gid */
2, /* nlink */
- (long) mtime, /* mtime */
+ (long) default_mtime, /* mtime */
0, /* filesize */
3, /* major */
1, /* minor */
@@ -237,13 +241,14 @@ static int cpio_mknod(const char *name, unsigned int mode,
unsigned int maj, unsigned int min)
{
char s[256];
- time_t mtime = time(NULL);
if (dev_type == 'b')
mode |= S_IFBLK;
else
mode |= S_IFCHR;
+ if (name[0] == '/')
+ name++;
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
"%08X%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
@@ -252,7 +257,7 @@ static int cpio_mknod(const char *name, unsigned int mode,
(long) uid, /* uid */
(long) gid, /* gid */
1, /* nlink */
- (long) mtime, /* mtime */
+ (long) default_mtime, /* mtime */
0, /* filesize */
3, /* major */
1, /* minor */
@@ -286,31 +291,34 @@ static int cpio_mknod_line(const char *line)
return rc;
}
-/* Not marked static to keep the compiler quiet, as no one uses this yet... */
static int cpio_mkfile(const char *name, const char *location,
- unsigned int mode, uid_t uid, gid_t gid)
+ unsigned int mode, uid_t uid, gid_t gid,
+ unsigned int nlinks)
{
char s[256];
char *filebuf = NULL;
struct stat buf;
+ long size;
int file = -1;
int retval;
int rc = -1;
+ int namesize;
+ unsigned int i;
mode |= S_IFREG;
- retval = stat (location, &buf);
- if (retval) {
- fprintf (stderr, "File %s could not be located\n", location);
- goto error;
- }
-
file = open (location, O_RDONLY);
if (file < 0) {
fprintf (stderr, "File %s could not be opened for reading\n", location);
goto error;
}
+ retval = fstat(file, &buf);
+ if (retval) {
+ fprintf(stderr, "File %s could not be stat()'ed\n", location);
+ goto error;
+ }
+
filebuf = malloc(buf.st_size);
if (!filebuf) {
fprintf (stderr, "out of memory\n");
@@ -323,29 +331,46 @@ static int cpio_mkfile(const char *name, const char *location,
goto error;
}
- sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
- "%08X%08X%08X%08X%08X%08X%08X",
- "070701", /* magic */
- ino++, /* ino */
- mode, /* mode */
- (long) uid, /* uid */
- (long) gid, /* gid */
- 1, /* nlink */
- (long) buf.st_mtime, /* mtime */
- (int) buf.st_size, /* filesize */
- 3, /* major */
- 1, /* minor */
- 0, /* rmajor */
- 0, /* rminor */
- (unsigned)strlen(name) + 1,/* namesize */
- 0); /* chksum */
- push_hdr(s);
- push_string(name);
- push_pad();
+ size = 0;
+ for (i = 1; i <= nlinks; i++) {
+ /* data goes on last link */
+ if (i == nlinks) size = buf.st_size;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+ sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08lX%08X%08X%08X%08X%08X%08X",
+ "070701", /* magic */
+ ino, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ nlinks, /* nlink */
+ (long) buf.st_mtime, /* mtime */
+ size, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ 0); /* chksum */
+ push_hdr(s);
+ push_string(name);
+ push_pad();
+
+ if (size) {
+ if (fwrite(filebuf, size, 1, stdout) != 1) {
+ fprintf(stderr, "writing filebuf failed\n");
+ goto error;
+ }
+ offset += size;
+ push_pad();
+ }
- fwrite(filebuf, buf.st_size, 1, stdout);
- offset += buf.st_size;
- push_pad();
+ name += namesize;
+ }
+ ino++;
rc = 0;
error:
@@ -354,49 +379,102 @@ error:
return rc;
}
+static char *cpio_replace_env(char *new_location)
+{
+ char expanded[PATH_MAX + 1];
+ char *start, *end, *var;
+
+ while ((start = strstr(new_location, "${")) &&
+ (end = strchr(start + 2, '}'))) {
+ *start = *end = 0;
+ var = getenv(start + 2);
+ snprintf(expanded, sizeof expanded, "%s%s%s",
+ new_location, var ? var : "", end + 1);
+ strcpy(new_location, expanded);
+ }
+
+ return new_location;
+}
+
static int cpio_mkfile_line(const char *line)
{
char name[PATH_MAX + 1];
+ char *dname = NULL; /* malloc'ed buffer for hard links */
char location[PATH_MAX + 1];
unsigned int mode;
int uid;
int gid;
+ int nlinks = 1;
+ int end = 0, dname_len = 0;
int rc = -1;
- if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) {
+ if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
+ "s %o %d %d %n",
+ name, location, &mode, &uid, &gid, &end)) {
fprintf(stderr, "Unrecognized file format '%s'", line);
goto fail;
}
- rc = cpio_mkfile(name, location, mode, uid, gid);
+ if (end && isgraph(line[end])) {
+ int len;
+ int nend;
+
+ dname = malloc(strlen(line));
+ if (!dname) {
+ fprintf (stderr, "out of memory (%d)\n", dname_len);
+ goto fail;
+ }
+
+ dname_len = strlen(name) + 1;
+ memcpy(dname, name, dname_len);
+
+ do {
+ nend = 0;
+ if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
+ name, &nend) < 1)
+ break;
+ len = strlen(name) + 1;
+ memcpy(dname + dname_len, name, len);
+ dname_len += len;
+ nlinks++;
+ end += nend;
+ } while (isgraph(line[end]));
+ } else {
+ dname = name;
+ }
+ rc = cpio_mkfile(dname, cpio_replace_env(location),
+ mode, uid, gid, nlinks);
fail:
+ if (dname_len) free(dname);
return rc;
}
-void usage(const char *prog)
+static void usage(const char *prog)
{
fprintf(stderr, "Usage:\n"
- "\t%s <cpio_list>\n"
+ "\t%s [-t <timestamp>] <cpio_list>\n"
"\n"
"<cpio_list> is a file containing newline separated entries that\n"
"describe the files to be included in the initramfs archive:\n"
"\n"
"# a comment\n"
- "file <name> <location> <mode> <uid> <gid>\n"
+ "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
"dir <name> <mode> <uid> <gid>\n"
"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
"slink <name> <target> <mode> <uid> <gid>\n"
"pipe <name> <mode> <uid> <gid>\n"
"sock <name> <mode> <uid> <gid>\n"
"\n"
- "<name> name of the file/dir/nod/etc in the archive\n"
- "<location> location of the file in the current filesystem\n"
- "<target> link target\n"
- "<mode> mode/permissions of the file\n"
- "<uid> user id (0=root)\n"
- "<gid> group id (0=root)\n"
- "<dev_type> device type (b=block, c=character)\n"
- "<maj> major number of nod\n"
- "<min> minor number of nod\n"
+ "<name> name of the file/dir/nod/etc in the archive\n"
+ "<location> location of the file in the current filesystem\n"
+ " expands shell variables quoted with ${}\n"
+ "<target> link target\n"
+ "<mode> mode/permissions of the file\n"
+ "<uid> user id (0=root)\n"
+ "<gid> group id (0=root)\n"
+ "<dev_type> device type (b=block, c=character)\n"
+ "<maj> major number of nod\n"
+ "<min> minor number of nod\n"
+ "<hard links> space separated list of other links to file\n"
"\n"
"example:\n"
"# A simple initramfs\n"
@@ -404,7 +482,11 @@ void usage(const char *prog)
"nod /dev/console 0600 0 0 c 5 1\n"
"dir /root 0700 0 0\n"
"dir /sbin 0755 0 0\n"
- "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n",
+ "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+ "\n"
+ "<timestamp> is time in seconds since Epoch that will be used\n"
+ "as mtime for symlinks, special files and directories. The default\n"
+ "is to use the current time for these entries.\n",
prog);
}
@@ -442,15 +524,42 @@ int main (int argc, char *argv[])
char *args, *type;
int ec = 0;
int line_nr = 0;
+ const char *filename;
+
+ default_mtime = time(NULL);
+ while (1) {
+ int opt = getopt(argc, argv, "t:h");
+ char *invalid;
+
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 't':
+ default_mtime = strtol(optarg, &invalid, 10);
+ if (!*optarg || *invalid) {
+ fprintf(stderr, "Invalid timestamp: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(opt == 'h' ? 0 : 1);
+ }
+ }
- if (2 != argc) {
+ if (argc - optind != 1) {
usage(argv[0]);
exit(1);
}
-
- if (! (cpio_list = fopen(argv[1], "r"))) {
+ filename = argv[optind];
+ if (!strcmp(filename, "-"))
+ cpio_list = stdin;
+ else if (!(cpio_list = fopen(filename, "r"))) {
fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
- argv[1], strerror(errno));
+ filename, strerror(errno));
usage(argv[0]);
exit(1);
}
@@ -471,6 +580,7 @@ int main (int argc, char *argv[])
"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
line_nr, line);
ec = -1;
+ break;
}
if ('\n' == *type) {
@@ -506,7 +616,8 @@ int main (int argc, char *argv[])
line_nr, line);
}
}
- cpio_trailer();
+ if (ec == 0)
+ cpio_trailer();
exit(ec);
}