2004-12-18 02:38:21 +03:00
# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <string.h>
# include <unistd.h>
# include <time.h>
# include <fcntl.h>
# include <errno.h>
# include <ctype.h>
# include <limits.h>
2005-05-14 14:23:53 +04:00
/*
* Original work by Jeff Garzik
*
* External file lists , symlink , pipe and fifo support by Thayne Harbaugh
*/
2004-12-18 02:38:21 +03:00
# define xstr(s) #s
# define str(s) xstr(s)
static unsigned int offset ;
static unsigned int ino = 721 ;
2005-05-14 14:23:53 +04:00
struct file_handler {
2004-12-18 02:38:21 +03:00
const char * type ;
int ( * handler ) ( const char * line ) ;
} ;
static void push_string ( const char * name )
{
unsigned int name_len = strlen ( name ) + 1 ;
fputs ( name , stdout ) ;
putchar ( 0 ) ;
offset + = name_len ;
}
static void push_pad ( void )
{
while ( offset & 3 ) {
putchar ( 0 ) ;
offset + + ;
}
}
static void push_rest ( const char * name )
{
unsigned int name_len = strlen ( name ) + 1 ;
unsigned int tmp_ofs ;
fputs ( name , stdout ) ;
putchar ( 0 ) ;
offset + = name_len ;
tmp_ofs = name_len + 110 ;
while ( tmp_ofs & 3 ) {
putchar ( 0 ) ;
offset + + ;
tmp_ofs + + ;
}
}
static void push_hdr ( const char * s )
{
fputs ( s , stdout ) ;
offset + = 110 ;
}
static void cpio_trailer ( void )
{
char s [ 256 ] ;
const char name [ ] = " TRAILER!!! " ;
sprintf ( s , " %s%08X%08X%08lX%08lX%08X%08lX "
" %08X%08X%08X%08X%08X%08X%08X " ,
" 070701 " , /* magic */
0 , /* ino */
0 , /* mode */
( long ) 0 , /* uid */
( long ) 0 , /* gid */
1 , /* nlink */
( long ) 0 , /* mtime */
0 , /* filesize */
0 , /* major */
0 , /* minor */
0 , /* rmajor */
0 , /* rminor */
2005-05-14 14:23:53 +04:00
( unsigned ) strlen ( name ) + 1 , /* namesize */
2004-12-18 02:38:21 +03:00
0 ) ; /* chksum */
push_hdr ( s ) ;
push_rest ( name ) ;
while ( offset % 512 ) {
putchar ( 0 ) ;
offset + + ;
}
}
2005-05-14 14:23:53 +04:00
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 ) ;
sprintf ( s , " %s%08X%08X%08lX%08lX%08X%08lX "
" %08X%08X%08X%08X%08X%08X%08X " ,
" 070701 " , /* magic */
ino + + , /* ino */
S_IFLNK | mode , /* mode */
( long ) uid , /* uid */
( long ) gid , /* gid */
1 , /* nlink */
( long ) mtime , /* mtime */
( unsigned ) strlen ( target ) + 1 , /* filesize */
3 , /* major */
1 , /* minor */
0 , /* rmajor */
0 , /* rminor */
( unsigned ) strlen ( name ) + 1 , /* namesize */
0 ) ; /* chksum */
push_hdr ( s ) ;
push_string ( name ) ;
push_pad ( ) ;
push_string ( target ) ;
push_pad ( ) ;
return 0 ;
}
static int cpio_mkslink_line ( const char * line )
{
char name [ PATH_MAX + 1 ] ;
char target [ PATH_MAX + 1 ] ;
unsigned int mode ;
int uid ;
int gid ;
int rc = - 1 ;
if ( 5 ! = sscanf ( line , " % " str ( PATH_MAX ) " s % " str ( PATH_MAX ) " s %o %d %d " , name , target , & mode , & uid , & gid ) ) {
fprintf ( stderr , " Unrecognized dir format '%s' " , line ) ;
goto fail ;
}
rc = cpio_mkslink ( name , target , mode , uid , gid ) ;
fail :
return rc ;
}
static int cpio_mkgeneric ( const char * name , unsigned int mode ,
2004-12-18 02:38:21 +03:00
uid_t uid , gid_t gid )
{
char s [ 256 ] ;
time_t mtime = time ( NULL ) ;
sprintf ( s , " %s%08X%08X%08lX%08lX%08X%08lX "
" %08X%08X%08X%08X%08X%08X%08X " ,
" 070701 " , /* magic */
ino + + , /* ino */
2005-05-14 14:23:53 +04:00
mode , /* mode */
2004-12-18 02:38:21 +03:00
( long ) uid , /* uid */
( long ) gid , /* gid */
2 , /* nlink */
( long ) mtime , /* mtime */
0 , /* filesize */
3 , /* major */
1 , /* minor */
0 , /* rmajor */
0 , /* rminor */
( unsigned ) strlen ( name ) + 1 , /* namesize */
0 ) ; /* chksum */
push_hdr ( s ) ;
push_rest ( name ) ;
return 0 ;
}
2005-05-14 14:23:53 +04:00
enum generic_types {
GT_DIR ,
GT_PIPE ,
GT_SOCK
} ;
struct generic_type {
const char * type ;
mode_t mode ;
} ;
static struct generic_type generic_type_table [ ] = {
[ GT_DIR ] = {
. type = " dir " ,
. mode = S_IFDIR
} ,
[ GT_PIPE ] = {
. type = " pipe " ,
. mode = S_IFIFO
} ,
[ GT_SOCK ] = {
. type = " sock " ,
. mode = S_IFSOCK
}
} ;
static int cpio_mkgeneric_line ( const char * line , enum generic_types gt )
2004-12-18 02:38:21 +03:00
{
char name [ PATH_MAX + 1 ] ;
unsigned int mode ;
int uid ;
int gid ;
int rc = - 1 ;
if ( 4 ! = sscanf ( line , " % " str ( PATH_MAX ) " s %o %d %d " , name , & mode , & uid , & gid ) ) {
2005-05-14 14:23:53 +04:00
fprintf ( stderr , " Unrecognized %s format '%s' " ,
line , generic_type_table [ gt ] . type ) ;
2004-12-18 02:38:21 +03:00
goto fail ;
}
2005-05-14 14:23:53 +04:00
mode | = generic_type_table [ gt ] . mode ;
rc = cpio_mkgeneric ( name , mode , uid , gid ) ;
2004-12-18 02:38:21 +03:00
fail :
return rc ;
}
2005-05-14 14:23:53 +04:00
static int cpio_mkdir_line ( const char * line )
{
return cpio_mkgeneric_line ( line , GT_DIR ) ;
}
static int cpio_mkpipe_line ( const char * line )
{
return cpio_mkgeneric_line ( line , GT_PIPE ) ;
}
static int cpio_mksock_line ( const char * line )
{
return cpio_mkgeneric_line ( line , GT_SOCK ) ;
}
2004-12-18 02:38:21 +03:00
static int cpio_mknod ( const char * name , unsigned int mode ,
uid_t uid , gid_t gid , char dev_type ,
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 ;
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 ) mtime , /* mtime */
0 , /* filesize */
3 , /* major */
1 , /* minor */
maj , /* rmajor */
min , /* rminor */
( unsigned ) strlen ( name ) + 1 , /* namesize */
0 ) ; /* chksum */
push_hdr ( s ) ;
push_rest ( name ) ;
return 0 ;
}
static int cpio_mknod_line ( const char * line )
{
char name [ PATH_MAX + 1 ] ;
unsigned int mode ;
int uid ;
int gid ;
char dev_type ;
unsigned int maj ;
unsigned int min ;
int rc = - 1 ;
if ( 7 ! = sscanf ( line , " % " str ( PATH_MAX ) " s %o %d %d %c %u %u " ,
name , & mode , & uid , & gid , & dev_type , & maj , & min ) ) {
fprintf ( stderr , " Unrecognized nod format '%s' " , line ) ;
goto fail ;
}
rc = cpio_mknod ( name , mode , uid , gid , dev_type , maj , min ) ;
fail :
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 )
{
char s [ 256 ] ;
char * filebuf = NULL ;
struct stat buf ;
int file = - 1 ;
int retval ;
int rc = - 1 ;
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 ;
}
filebuf = malloc ( buf . st_size ) ;
if ( ! filebuf ) {
fprintf ( stderr , " out of memory \n " ) ;
goto error ;
}
retval = read ( file , filebuf , buf . st_size ) ;
if ( retval < 0 ) {
fprintf ( stderr , " Can not read %s file \n " , 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 ( ) ;
2005-05-14 14:23:53 +04:00
fwrite ( filebuf , buf . st_size , 1 , stdout ) ;
2004-12-18 02:38:21 +03:00
offset + = buf . st_size ;
push_pad ( ) ;
rc = 0 ;
2018-05-09 15:21:26 +03:00
2004-12-18 02:38:21 +03:00
error :
if ( filebuf ) free ( filebuf ) ;
if ( file > = 0 ) close ( file ) ;
return rc ;
}
static int cpio_mkfile_line ( const char * line )
{
char name [ PATH_MAX + 1 ] ;
char location [ PATH_MAX + 1 ] ;
unsigned int mode ;
int uid ;
int gid ;
int rc = - 1 ;
if ( 5 ! = sscanf ( line , " % " str ( PATH_MAX ) " s % " str ( PATH_MAX ) " s %o %d %d " , name , location , & mode , & uid , & gid ) ) {
fprintf ( stderr , " Unrecognized file format '%s' " , line ) ;
goto fail ;
}
rc = cpio_mkfile ( name , location , mode , uid , gid ) ;
fail :
return rc ;
}
void usage ( const char * prog )
{
fprintf ( stderr , " Usage: \n "
" \t %s <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 "
2005-05-14 14:23:53 +04:00
" file <name> <location> <mode> <uid> <gid> \n "
2004-12-18 02:38:21 +03:00
" dir <name> <mode> <uid> <gid> \n "
" nod <name> <mode> <uid> <gid> <dev_type> <maj> <min> \n "
2005-05-14 14:23:53 +04:00
" slink <name> <target> <mode> <uid> <gid> \n "
" pipe <name> <mode> <uid> <gid> \n "
" sock <name> <mode> <uid> <gid> \n "
2004-12-18 02:38:21 +03:00
" \n "
2005-05-14 14:23:53 +04:00
" <name> name of the file/dir/nod/etc in the archive \n "
2004-12-18 02:38:21 +03:00
" <location> location of the file in the current filesystem \n "
2005-05-14 14:23:53 +04:00
" <target> link target \n "
2004-12-18 02:38:21 +03:00
" <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 "
" \n "
" example: \n "
" # A simple initramfs \n "
" dir /dev 0755 0 0 \n "
" 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 " ,
prog ) ;
}
2005-05-14 14:23:53 +04:00
struct file_handler file_handler_table [ ] = {
2004-12-18 02:38:21 +03:00
{
. type = " file " ,
. handler = cpio_mkfile_line ,
} , {
. type = " nod " ,
. handler = cpio_mknod_line ,
} , {
. type = " dir " ,
. handler = cpio_mkdir_line ,
2005-05-14 14:23:53 +04:00
} , {
. type = " slink " ,
. handler = cpio_mkslink_line ,
} , {
. type = " pipe " ,
. handler = cpio_mkpipe_line ,
} , {
. type = " sock " ,
. handler = cpio_mksock_line ,
2004-12-18 02:38:21 +03:00
} , {
. type = NULL ,
. handler = NULL ,
}
} ;
# define LINE_SIZE (2 * PATH_MAX + 50)
int main ( int argc , char * argv [ ] )
{
FILE * cpio_list ;
char line [ LINE_SIZE ] ;
char * args , * type ;
int ec = 0 ;
int line_nr = 0 ;
if ( 2 ! = argc ) {
usage ( argv [ 0 ] ) ;
exit ( 1 ) ;
}
if ( ! strcmp ( argv [ 1 ] , " - " ) ) {
cpio_list = stdin ;
} else if ( ! ( cpio_list = fopen ( argv [ 1 ] , " r " ) ) ) {
fprintf ( stderr , " ERROR: unable to open '%s': %s \n \n " ,
2005-05-14 14:23:53 +04:00
argv [ 1 ] , strerror ( errno ) ) ;
2004-12-18 02:38:21 +03:00
usage ( argv [ 0 ] ) ;
exit ( 1 ) ;
}
while ( fgets ( line , LINE_SIZE , cpio_list ) ) {
int type_idx ;
size_t slen = strlen ( line ) ;
line_nr + + ;
if ( ' # ' = = * line ) {
/* comment - skip to next line */
continue ;
}
if ( ! ( type = strtok ( line , " \t " ) ) ) {
fprintf ( stderr ,
" ERROR: incorrect format, could not locate file type line %d: '%s' \n " ,
line_nr , line ) ;
ec = - 1 ;
}
if ( ' \n ' = = * type ) {
/* a blank line */
continue ;
}
if ( slen = = strlen ( type ) ) {
/* must be an empty line */
continue ;
}
if ( ! ( args = strtok ( NULL , " \n " ) ) ) {
fprintf ( stderr ,
" ERROR: incorrect format, newline required line %d: '%s' \n " ,
line_nr , line ) ;
ec = - 1 ;
}
2005-05-14 14:23:53 +04:00
for ( type_idx = 0 ; file_handler_table [ type_idx ] . type ; type_idx + + ) {
2004-12-18 02:38:21 +03:00
int rc ;
2005-05-14 14:23:53 +04:00
if ( ! strcmp ( line , file_handler_table [ type_idx ] . type ) ) {
if ( ( rc = file_handler_table [ type_idx ] . handler ( args ) ) ) {
2004-12-18 02:38:21 +03:00
ec = rc ;
fprintf ( stderr , " line %d \n " , line_nr ) ;
}
break ;
}
}
2005-05-14 14:23:53 +04:00
if ( NULL = = file_handler_table [ type_idx ] . type ) {
2004-12-18 02:38:21 +03:00
fprintf ( stderr , " unknown file type line %d: '%s' \n " ,
line_nr , line ) ;
}
}
cpio_trailer ( ) ;
exit ( ec ) ;
}