Files
s390-tools/zfcpdump/cpioinit.c
Michael Holzheu b627b8d8e1 Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version.

Changes on top of s390-tools-1.39.0:

 - Add MIT license to all source files
 - Add LICENSE file
 - Transform REAMDE to README.md (markdown)
 - Add AUTHORS.md file
 - Add CONTRIBUTING.md file
 - Move changelog from README to CHANGELOG.md file

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
2017-08-21 10:55:40 +02:00

293 lines
6.7 KiB
C

/*
* cpioinit - Tool to create cpio archives
*
* This tool can be used to create a cpio initrd for the linux kernel.
*
* The executable init program needs to be specified as parameter.
* The cpio archive is printed to stdout.
*
* Copyright IBM Corp. 2013, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
/*
* Cpio archive new header structure
*/
struct cpio_newc_header {
char c_magic[6];
char c_ino[8];
char c_mode[8];
char c_uid[8];
char c_gid[8];
char c_nlink[8];
char c_mtime[8];
char c_filesize[8];
char c_devmajor[8];
char c_devminor[8];
char c_rdevmajor[8];
char c_rdevminor[8];
char c_namesize[8];
char c_check[8];
};
/*
* Structure to specify a cpio archive entry
*/
struct cpio_line {
struct cpio_newc_header head;
const char *filename;
char *data;
unsigned int datasize;
};
/*
* Fill line with zeros to be aligned to 4 bytes
*/
static int cpio_fill_aligned(int size)
{
while (size % 4) {
printf("%c", 0);
size++;
}
return size;
}
/*
* Print a cpio_line structure to stdout
*/
static void cpio_print_ln(struct cpio_line *line)
{
unsigned int i, lnsize = 0;
for (i = 0; i < sizeof(struct cpio_newc_header); i++)
printf("%c", ((char *)&line->head)[i]);
lnsize += sizeof(struct cpio_newc_header);
if (line->filename != NULL) {
printf("%s", line->filename);
printf("%c", 0); /* print ending zero */
lnsize += strlen(line->filename) + 1;
lnsize = cpio_fill_aligned(lnsize);
}
if (line->data != NULL) {
for (i = 0; i < line->datasize; i++)
printf("%c", line->data[i]);
lnsize += line->datasize;
lnsize = cpio_fill_aligned(lnsize);
}
}
/*
* Write number in cpio new ascii format into header field with
* size of 6 chars
*/
static void cpio_insert_num6(char *head, int num)
{
char buf[7];
/* Need memcpy because snprintf addes zero at the end */
snprintf(buf, sizeof(buf), "%06x", num);
memcpy(head, buf, 6);
}
/*
* Write number in cpio new ascii format into header field with
* size of 8 chars
*/
static void cpio_insert_num8(char *head, int num)
{
char buf[9];
/* Need memcpy because snprintf addes zero at the end */
snprintf(buf, sizeof(buf), "%08x", num);
memcpy(head, buf, 8);
}
/*
* Write basics to cpio_newc_header managing the entry number,
* thus each structure write has to call this function once
*/
static void cpio_header_init(struct cpio_newc_header *head)
{
static int number;
cpio_insert_num6(head->c_magic, 0x070701);
cpio_insert_num8(head->c_ino, 0x2d1 + number);
cpio_insert_num8(head->c_uid, 0);
cpio_insert_num8(head->c_gid, 0);
cpio_insert_num8(head->c_nlink, number);
cpio_insert_num8(head->c_mtime, 0);
cpio_insert_num8(head->c_check, 0);
cpio_insert_num8(head->c_devmajor, 3);
cpio_insert_num8(head->c_devminor, 1);
number++;
}
/*
* Writes directory in cpio archive structure to stdout
*/
static void cpio_write_dir(const char *dir)
{
struct cpio_line line;
cpio_header_init(&line.head);
cpio_insert_num8(line.head.c_mode, 0x41ed);
cpio_insert_num8(line.head.c_filesize, 0);
cpio_insert_num8(line.head.c_rdevmajor, 0);
cpio_insert_num8(line.head.c_rdevminor, 0);
cpio_insert_num8(line.head.c_namesize, strlen(dir) + 1);
line.filename = dir;
line.data = NULL;
cpio_print_ln(&line);
}
/*
* Writes end of cpio archive to stdout
*/
static void cpio_write_tail()
{
struct cpio_line line;
int i;
cpio_header_init(&line.head);
cpio_insert_num8(line.head.c_ino, 0);
cpio_insert_num8(line.head.c_mode, 0);
cpio_insert_num8(line.head.c_filesize, 0);
cpio_insert_num8(line.head.c_devmajor, 0);
cpio_insert_num8(line.head.c_devminor, 0);
cpio_insert_num8(line.head.c_rdevmajor, 0);
cpio_insert_num8(line.head.c_rdevminor, 0);
cpio_insert_num8(line.head.c_namesize, 11);
line.filename = "TRAILER!!!";
line.data = NULL;
cpio_print_ln(&line);
for (i = 0; i < 30; i++)
printf("%c", 0);
}
/*
* Writes device node in cpio archive structure to stdout
*/
static void cpio_write_nod(char *name, int major, int minor, int chardev)
{
struct cpio_line line;
cpio_header_init(&line.head);
if (chardev == 1)
cpio_insert_num8(line.head.c_mode, 0x21a4);
else
cpio_insert_num8(line.head.c_mode, 0x61a4);
cpio_insert_num8(line.head.c_filesize, 0);
cpio_insert_num8(line.head.c_rdevmajor, major);
cpio_insert_num8(line.head.c_rdevminor, minor);
cpio_insert_num8(line.head.c_namesize, strlen(name) + 1);
line.filename = name;
line.data = NULL;
cpio_print_ln(&line);
}
/*
* Writes file in cpio archiv structure to stdout
*/
static void cpio_write_file(char *name, char *filedata, int filesize)
{
struct cpio_line line;
cpio_header_init(&line.head);
cpio_insert_num8(line.head.c_mode, 0x81ed);
cpio_insert_num8(line.head.c_filesize, filesize);
cpio_insert_num8(line.head.c_rdevmajor, 0);
cpio_insert_num8(line.head.c_rdevminor, 0);
cpio_insert_num8(line.head.c_namesize, strlen(name) + 1);
line.filename = name;
line.data = filedata;
line.datasize = filesize;
cpio_print_ln(&line);
}
/*
* Read size bytes from file into buffer
*/
static int read_file(const char *file, char *buf, int size)
{
int fh;
fh = open(file, O_RDONLY);
if (fh == -1) {
fprintf(stderr, "Open %s failed (%s)\n", file, strerror(errno));
return -1;
}
if (read(fh, buf, size) < 0) {
fprintf(stderr, "Read %s failed (%s)\n", file, strerror(errno));
close(fh);
return -1;
}
close(fh);
return 0;
}
/*
* Program writes a cpio archive to stdout.
* - containing device nodes needed to run scsi dumper
* - expecting init program as parameter
*/
int main(int argc, char *argv[])
{
char path[10], *filebuffer, *filename;
struct stat st;
int i;
/* First read in init file */
if (argc != 2) {
fprintf(stderr, "Usage: cpioinit <init program>\n");
return -1;
}
filename = argv[1];
if (stat(filename, &st)) {
fprintf(stderr, "Cannot open file: %s (%s)\n", filename,
strerror(errno));
return -1;
}
filebuffer = malloc(st.st_size);
if (filebuffer == NULL) {
fprintf(stderr, "Malloc %lu bytes failed\n", st.st_size);
return -1;
}
if (read_file(filename, filebuffer, st.st_size))
return -1;
/* Write init */
cpio_write_file("init", filebuffer, st.st_size);
free(filebuffer);
/* Define device nodes */
cpio_write_dir("dev");
cpio_write_dir("proc");
cpio_write_dir("sys");
cpio_write_dir("mnt");
cpio_write_nod("dev/console", 5, 1, 1);
cpio_write_nod("dev/null", 1, 3, 1);
/* Write sda for access via part offset */
cpio_write_nod("dev/sda", 8, 0, 0);
/* Write sda 1 - 15 nodes */
for (i = 1; i < 15; i++) {
snprintf(path, sizeof(path), "dev/sda%d", i);
cpio_write_nod(path, 8, i, 0);
}
cpio_write_tail();
return 0;
}