gen_init_cpio: support file checksum archiving

Documentation/driver-api/early-userspace/buffer-format.rst includes the
specification for checksum-enabled cpio archives.  Implement support for
this format in gen_init_cpio via a new '-c' parameter.

Link: https://lkml.kernel.org/r/20220404093429.27570-6-ddiss@suse.de
Signed-off-by: David Disseldorp <ddiss@suse.de>
Suggested-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Martin Wilck <mwilck@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
David Disseldorp 2022-05-09 18:29:20 -07:00 committed by akpm
parent 3a2699cfbe
commit ea8048719a

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
@ -25,6 +27,7 @@
static unsigned int offset;
static unsigned int ino = 721;
static time_t default_mtime;
static bool do_csum = false;
struct file_handler {
const char *type;
@ -78,7 +81,7 @@ static void cpio_trailer(void)
sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
"%08X%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
do_csum ? "070702" : "070701", /* magic */
0, /* ino */
0, /* mode */
(long) 0, /* uid */
@ -110,7 +113,7 @@ static int cpio_mkslink(const char *name, const char *target,
name++;
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
"%08X%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
do_csum ? "070702" : "070701", /* magic */
ino++, /* ino */
S_IFLNK | mode, /* mode */
(long) uid, /* uid */
@ -159,7 +162,7 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
name++;
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
"%08X%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
do_csum ? "070702" : "070701", /* magic */
ino++, /* ino */
mode, /* mode */
(long) uid, /* uid */
@ -253,7 +256,7 @@ static int cpio_mknod(const char *name, unsigned int mode,
name++;
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
"%08X%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
do_csum ? "070702" : "070701", /* magic */
ino++, /* ino */
mode, /* mode */
(long) uid, /* uid */
@ -293,6 +296,29 @@ static int cpio_mknod_line(const char *line)
return rc;
}
static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
{
while (size) {
unsigned char filebuf[65536];
ssize_t this_read;
size_t i, this_size = MIN(size, sizeof(filebuf));
this_read = read(fd, filebuf, this_size);
if (this_read <= 0 || this_read > this_size)
return -1;
for (i = 0; i < this_read; i++)
*csum += filebuf[i];
size -= this_read;
}
/* seek back to the start for data segment I/O */
if (lseek(fd, 0, SEEK_SET) < 0)
return -1;
return 0;
}
static int cpio_mkfile(const char *name, const char *location,
unsigned int mode, uid_t uid, gid_t gid,
unsigned int nlinks)
@ -305,6 +331,7 @@ static int cpio_mkfile(const char *name, const char *location,
int rc = -1;
int namesize;
unsigned int i;
uint32_t csum = 0;
mode |= S_IFREG;
@ -332,6 +359,11 @@ static int cpio_mkfile(const char *name, const char *location,
goto error;
}
if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
fprintf(stderr, "Failed to checksum file %s\n", location);
goto error;
}
size = 0;
for (i = 1; i <= nlinks; i++) {
/* data goes on last link */
@ -343,7 +375,7 @@ static int cpio_mkfile(const char *name, const char *location,
namesize = strlen(name) + 1;
sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
"%08lX%08X%08X%08X%08X%08X%08X",
"070701", /* magic */
do_csum ? "070702" : "070701", /* magic */
ino, /* ino */
mode, /* mode */
(long) uid, /* uid */
@ -356,7 +388,7 @@ static int cpio_mkfile(const char *name, const char *location,
0, /* rmajor */
0, /* rminor */
namesize, /* namesize */
0); /* chksum */
size ? csum : 0); /* chksum */
push_hdr(s);
push_string(name);
push_pad();
@ -464,7 +496,7 @@ static int cpio_mkfile_line(const char *line)
static void usage(const char *prog)
{
fprintf(stderr, "Usage:\n"
"\t%s [-t <timestamp>] <cpio_list>\n"
"\t%s [-t <timestamp>] [-c] <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"
@ -499,7 +531,8 @@ static void usage(const char *prog)
"\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",
"is to use the current time for these entries.\n"
"-c: calculate and store 32-bit checksums for file data.\n",
prog);
}
@ -541,7 +574,7 @@ int main (int argc, char *argv[])
default_mtime = time(NULL);
while (1) {
int opt = getopt(argc, argv, "t:h");
int opt = getopt(argc, argv, "t:ch");
char *invalid;
if (opt == -1)
@ -556,6 +589,9 @@ int main (int argc, char *argv[])
exit(1);
}
break;
case 'c':
do_csum = true;
break;
case 'h':
case '?':
usage(argv[0]);