Need some help hacking kernel.... (libc->kernel file operations)

Dave Cinege (dcinege@psychosis.com)
Fri, 02 Jan 98 14:57:08 -0500


Myself and a friend (Dima) are adding untar support to the initrd code so special
archives can be used instead of those nasty raw images for boot disk's.
(It's a little more complex then that, but to save space....)

I have manged to finish up the new loading, uncompressing, etc functions in
linux/drivers/block/rd.c. I'm now left with an uncompressed tar archive in
/dev/ram1, that I can yank out from user space after boot.

We must now convert some libc untar code to work from the kernel.
The problem is neither Dima nor I know how to properly handle some of the file
operations from within the kernel.
IE the creation of files under the filesystem on the mounted root:
mkdir();
symlink();
chmod();
mknod();
etc

Below is the jist of our untar code. It's pretty much a mess right now but you can
see what is going on. crd_infp (static struct file) is set all up in rd.c (just like before
the gunzip part) and is pointing to the beginning of /dev/ram1. /dev/ram0 is already
mounted as root and has a filesystem in it. (All of this done by the rd.c code)

If you want to run through the code and put some comments, or just point us to a
good reference on how to convert this it would be most helpful. The /* FIXME: */
parts are where we are really lost.

/*
* untar() -- see comments for return codes
* outfd may be left open on error return !!
*/

//Dunno if any of this is right.
/* not sure if it matters as we include this file into rd.c
* which already has all these #include's anyway
* move the #include "untar.c" directive few lines lower
* in rd.c, tho' -- below the definition of fill_inbuf(),
* otherwise gcc will barf (I think)
*/
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/stat.h>
#include <linux/fcntl.h>

#include <linux/kernel.h> /* for simple_strtoul() & printk() */
#include <linux/stddef.h> /* NULL, size_t */
#include <linux/fs.h>

#ifndef STATIC

#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
# include <sys/types.h>
# include <stdlib.h>
//stdlib conlides with the *malloc def
#endif

#define STATIC
#endif /* !STATIC */

STATIC int untar(void);

STATIC int untar(void)
{

#include "untar.h"

char c;
int err;
struct file *outfd;
int isreg, isdir, islnk, ischr, isblk, isfifo;
unsigned long i, fsize, fmode, fuid, fgid;
union TarInfo *tarInfo; /* 512 bytes */
int len = 512; /* sizeof(union TarInfo); */

tarInfo = kmalloc(len,GFP_KERNEL);
if(tarInfo == 0) {
printk(KERN_ERR "RAMDISK: can't allocate tar buffer\n");
return(-1);
}
memset(tarInfo,0,len);

/* cd to target dir or return 1 */
/* if((err=chdir(path)) == -1) return(1); */
//Im lost how we do this from the kernel...

/* we probably don't -- just make sure all tarballs are done in '/'
* otherwise we could probably use sys_chdir() in ../../fs/open.c
* what do you think?
*/
//I think we just don't : >


/* main loop */
while(1) {
isreg=FALSE; isdir=FALSE; islnk=FALSE; ischr=FALSE; isblk=FALSE;
isfifo=FALSE;

/* read header or return short read */
err=crd_infp->f_op->read(crd_infp->f_inode,crd_infp,tarInfo,len);
if(err < len)
if(err == 0) return(0);
else {
printk(KERN_ERR "RAMDISK: corrupt tar archive\n");
kfree(tarInfo);
return(-1);
}
/*
* thing is, tar pads the archive with a few blocks of 0's in the end, so
* when we read the next block and its 1st byte is 0 it is most probably
* padding -- really means EOF -- unless the tarball is stuffed :(
* I could check if all 512 bytes are 0's and then it's definitely an EOF.
* For now let's just return 0
*/
if(tarInfo->header.name[0] == '\0') {
kfree(tarInfo);
return(0);
}
fmode=simple_strtoul(tarInfo->header.mode,(char **)NULL,8);
fuid=simple_strtoul(tarInfo->header.uid,(char **)NULL,8);
fgid=simple_strtoul(tarInfo->header.gid,(char **)NULL,8);
fsize=simple_strtoul(tarInfo->header.size,(char **)NULL,8);

/* check the type */
switch(tarInfo->header.typeflag) {
case AREGTYPE :
case REGTYPE :
isreg=TRUE;

/* FIXME : create() */
outfd=crd_infp->f_inode->i_op->create(tarInfo->header.name);
if(outfd== -1) {
/* yell */
kfree(tarInfo);
return(-1);
}
/* dump the file */
// hmm fsize crd_infp->f_size? Im not sure if we have a size here
//If not, I can figure it out buy looking at outfile.f_pos before
//I reset it to 0.
for(i=0;i<fsize;i++) {

err=crd_infp->f_op->read(crd_infp->f_inode,crd_infp,&c,1);
if(err < 1) {
kfree(tarInfo);
return(-1);
}
/* FIXME: write */
err=crd_infp->f_op->write(outfd->f_inode,crd_infp,&c,1);
if(err < 1) {
kfree(tarInfo);
return(-1);
}
}
/* ?? */
if(outfd->f_op->release)
outfd->f_op->release(outfd->f_inode,outfd);
break;

case LNKTYPE : /* hardlinks are restored as symlinks? */
case SYMTYPE : /* do we really have to use hardlinks? */
/* at the moment ctar converts hardlinks to files 'cos otherwise
* it'd have to open a whole new can of worms -- keeping track of
* all the links to a give file etc... something else to fix later
*/
islnk=TRUE;
/* FIXME: symlink() */
err=symlink(tarInfo->header.linkname,tarInfo->header.name);
break;

case CHRTYPE : /* char device */
case BLKTYPE : /* block device */
case FIFOTYPE : /* named pipe */
/* FIXME: makedev, mknod() */
fdev=MKDEV(simple_strtoul(tarInfo->header.devmajor,(char **)NULL,8),
simple_strtoul(tarInfo->header.devminor,(char **)NULL,8));
err=mknod(tarInfo->header.name,fmode,fdev);
break;

case DIRTYPE : /* directory */
/*
* ctar always(?) stores directory before its contents so we shouldn't
* run into problem where file creation fails because some upper dir in
* the path doesn't exist. is it really so, I wonder
*/
/* FIXME: mkdir() */
err=mkdir(tarInfo->header.name,fmode);
break;

default:
printk(KERN_ERR "RAMDISK: corrupt tar archive\n");
kfree(tarInfo);
return(-1);
}
/* chmod and chown the file */
/* FIXME: chmod(), chown() */
if(!islnk) {
err=chown(tarInfo->header.name,fuid,fgid);
err=chmod(tarInfo->header.name,fmode);
}
/* skip to the next header */
if(isreg)
if(fsize%TARBLOCKSIZE != 0)

lseek(infd,(off_t)(TARBLOCKSIZE*(fsize/TARBLOCKSIZE+1)-fsize),CURRENT);
//SEEK_CUR failed was not found. From what I can see in the rest of the rd.c
//code it should be CURRENT (but dont take my word for this)

} /* end main loop */
}

-------------------------------------------------------------------------
http://www.psychosis.com/emc/ Elite MicroComputers 908-541-4214
http://www.psychosis.com/linux-router/ Linux Router Project