editors: updated example 6-1 of lkmpg-2.4


Previous by date: 8 Nov 2006 12:43:12 -0000 ����� ������� ��α�5����׼���, "��ٿ�
Next by date: 8 Nov 2006 12:43:12 -0000 Re: updated example 6-1 of lkmpg-2.4, Machtelt Garrels
Previous in thread:
Next in thread: 8 Nov 2006 12:43:12 -0000 Re: updated example 6-1 of lkmpg-2.4, Machtelt Garrels

Subject: updated example 6-1 of lkmpg-2.4
From: "Ian Jiang" ####@####.####
Date: 8 Nov 2006 12:43:12 -0000
Message-Id: <7b2fa1820611080443t5e4ba6e9n30e7039b033f56e3@mail.gmail.com>

To whom it concerned:

While referring to the lkmpg-2.4, I found that Example 6-1.procfs.c at
    http://www.tldp.org/LDP/lkmpg/2.4/html/x770.html
is not for kernel 2.4.x

So I added some codes to make it work according to Exmaple 5-1.procfs.c at
    http://www.tldp.org/LDP/lkmpg/2.4/html/x724.html
and it could work well under 2.4.21

I'd like to commit it here and hope that it will help. Here it is and
also attached.

============================================================
/*	procfs.c -	create a "file" in /proc, which allows both input and output.
 *
 *  2006-11-08 - Updated by Ian Jiang ####@####.####
 */

/* Kernel Programming */

#ifndef MODULE
#define MODULE
#endif

#define LINUX

#ifndef __KERNEL__
#define __KERNEL__
#endif

#include <linux/kernel.h>	 /* We're doing kernel work */
#include <linux/module.h>	 /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif


/* Necessary because we use proc fs */
#include <linux/proc_fs.h>


/* In 2.2.3 /usr/include/linux/version.h includes a
 * macro for this, but 2.0.35 doesn't - so I add it
 * here if necessary. */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif



#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
#include <asm/uaccess.h>	/* for get_user and put_user */
#endif

/* The module's file functions ********************** */


/* Here we keep the last message received, to prove
 * that we can process our input */
#define MESSAGE_LENGTH 80
static char Message[MESSAGE_LENGTH];


/* Since we use the file operations struct, we can't
 * use the special proc output provisions - we have to
 * use a standard read function, which is this function */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
static ssize_t module_output(
		struct file *file,	 /* The file read */
		char *buf, /* The buffer to put data to (in the
								* user segment) */
		size_t len,	/* The length of the buffer */
		loff_t *offset) /* Offset in the file - ignore */
#else
static int module_output(
		struct inode *inode, /* The inode read */
		struct file *file,	 /* The file read */
		char *buf, /* The buffer to put data to (in the
								* user segment) */
		int len)	/* The length of the buffer */
#endif
{
	static int finished = 0;
	int i;
	char message[MESSAGE_LENGTH+30];

	/* We return 0 to indicate end of file, that we have
	 * no more information. Otherwise, processes will
	 * continue to read from us in an endless loop. */
	if (finished) {
		finished = 0;
		return 0;
	}

	/* We use put_user to copy the string from the kernel's
	 * memory segment to the memory segment of the process
	 * that called us. get_user, BTW, is
	 * used for the reverse. */
	sprintf(message, "Last input:%s", Message);
	for(i=0; i < len && message[i]; i++)
		put_user(message[i], buf+i);


	/* Notice, we assume here that the size of the message
	 * is below len, or it will be received cut. In a real
	 * life situation, if the size of the message is less
	 * than len then we'd return len and on the second call
	 * start filling the buffer with the len+1'th byte of
	 * the message. */
	finished = 1;

	return i;	/* Return the number of bytes "read" */
}


/* This function receives input from the user when the
 * user writes to the /proc file. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
static ssize_t module_input(
		struct file *file,	 /* The file itself */
		const char *buf,		 /* The buffer with input */
		size_t length,			 /* The buffer's length */
		loff_t *offset)			/* offset to file - ignore */
#else
static int module_input(
		struct inode *inode, /* The file's inode */
		struct file *file,	 /* The file itself */
		const char *buf,		 /* The buffer with the input */
		int length)					/* The buffer's length */
#endif
{
	int i;

	/* Put the input into Message, where module_output
	 * will later be able to use it */
	for(i=0; i<MESSAGE_LENGTH-1 && i<length; i++)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
		get_user(Message[i], buf+i);
	/* In version 2.2 the semantics of get_user changed,
	 * it not longer returns a character, but expects a
	 * variable to fill up as its first argument and a
	 * user segment pointer to fill it from as the its
	 * second.
	 *
	 * The reason for this change is that the version 2.2
	 * get_user can also read an short or an int. The way
	 * it knows the type of the variable it should read
	 * is by using sizeof, and for that it needs the
	 * variable itself.
	 */
#else
		Message[i] = get_user(buf+i);
#endif
	Message[i] = '\0';	/* we want a standard, zero
											 * terminated string */
	
	/* We need to return the number of input characters
	 * used */
	return i;
}



/* This function decides whether to allow an operation
 * (return zero) or not allow it (return a non-zero
 * which indicates why it is not allowed).
 *
 * The operation can be one of the following values:
 * 0 - Execute (run the "file" - meaningless in our case)
 * 2 - Write (input to the kernel module)
 * 4 - Read (output from the kernel module)
 *
 * This is the real function that checks file
 * permissions. The permissions returned by ls -l are
 * for referece only, and can be overridden here.
 */
static int module_permission(struct inode *inode, int op)
{
	/* We allow everybody to read from our module, but
	 * only root (uid 0) may write to it */
	if (op == 4 || (op == 2 && current->euid == 0))
		return 0;

	/* If it's anything else, access is denied */
	return -EACCES;
}




/* The file is opened - we don't really care about
 * that, but it does mean we need to increment the
 * module's reference count. */
int module_open(struct inode *inode, struct file *file)
{
	MOD_INC_USE_COUNT;

	return 0;
}


/* The file is closed - again, interesting only because
 * of the reference count. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
int module_close(struct inode *inode, struct file *file)
#else
void module_close(struct inode *inode, struct file *file)
#endif
{
	MOD_DEC_USE_COUNT;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
	return 0;	/* success */
#endif
}


/* Structures to register as the /proc file, with
 * pointers to all the relevant functions. ********** */



/* File operations for our proc file. This is where we
 * place pointers to all the functions called when
 * somebody tries to do something to our file. NULL
 * means we don't want to deal with something. */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
static struct file_operations File_Ops_4_Our_Proc_File =
{
	read: module_output,
	write: module_input,
	open: module_open,
	release: module_close,
};
#else
static struct file_operations File_Ops_4_Our_Proc_File =
	{
		NULL,	/* lseek */
		module_output,	/* "read" from the file */
		module_input,	 /* "write" to the file */
		NULL,	/* readdir */
		NULL,	/* select */
		NULL,	/* ioctl */
		NULL,	/* mmap */
		module_open,		/* Somebody opened the file */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
		NULL,	 /* flush, added here in version 2.2 */
#endif
		module_close,		/* Somebody closed the file */
		/* etc. etc. etc. (they are all given in
		 * /usr/include/linux/fs.h). Since we don't put
		 * anything here, the system will keep the default
		 * data, which in Unix is zeros (NULLs when taken as
		 * pointers). */
	};
#endif


/* Inode operations for our proc file. We need it so
 * we'll have some place to specify the file operations
 * structure we want to use, and the function we use for
 * permissions. It's also possible to specify functions
 * to be called for anything else which could be done to
 * an inode (although we don't bother, we just put
 * NULL). */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
static struct inode_operations Inode_Ops_4_Our_Proc_File =
{
	permission: module_permission,
};
#else
static struct inode_operations Inode_Ops_4_Our_Proc_File =
	{
		&File_Ops_4_Our_Proc_File,
		NULL, /* create */
		NULL, /* lookup */
		NULL, /* link */
		NULL, /* unlink */
		NULL, /* symlink */
		NULL, /* mkdir */
		NULL, /* rmdir */
		NULL, /* mknod */
		NULL, /* rename */
		NULL, /* readlink */
		NULL, /* follow_link */
		NULL, /* readpage */
		NULL, /* writepage */
		NULL, /* bmap */
		NULL, /* truncate */
		module_permission /* check for permissions */
	};
#endif

/* Directory entry */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
static struct proc_dir_entry *Our_Proc_File;
#else
static struct proc_dir_entry Our_Proc_File =
	{
		0, /* Inode number - ignore, it will be filled by
				* proc_register[_dynamic] */
		7, /* Length of the file name */
		"rw_test", /* The file name */
		S_IFREG | S_IRUGO | S_IWUSR,
		/* File mode - this is a regular file which
		 * can be read by its owner, its group, and everybody
		 * else. Also, its owner can write to it.
		 *
		 * Actually, this field is just for reference, it's
		 * module_permission that does the actual check. It
		 * could use this field, but in our implementation it
		 * doesn't, for simplicity. */
		1,	/* Number of links (directories where the
				 * file is referenced) */
		0, 0,	/* The uid and gid for the file -
						* we give it to root */
		80, /* The size of the file reported by ls. */
		&Inode_Ops_4_Our_Proc_File,
		/* A pointer to the inode structure for
		 * the file, if we need it. In our case we
		 * do, because we need a write function. */
		NULL	
		/* The read function for the file. Irrelevant,
		 * because we put it in the inode structure above */
	};
#endif



/* Module initialization and cleanup ******************* */

/* Initialize the module - register the proc file */
int init_module()
{
	/* Success if proc_register[_dynamic] is a success,
	 * failure otherwise */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
	/* In version 2.2, proc_register assign a dynamic
	 * inode number automatically if it is zero in the
	 * structure , so there's no more need for
	 * proc_register_dynamic
	 */
	#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
	Our_Proc_File = create_proc_entry("rw_test", S_IFREG | S_IRUGO |
S_IWUSR, &proc_root);
	if (Our_Proc_File == NULL)
		return -ENOMEM;
	else {
		Our_Proc_File->proc_fops = &File_Ops_4_Our_Proc_File;
		Our_Proc_File->proc_iops = &Inode_Ops_4_Our_Proc_File;
		return 0;
	}
	#else
	return proc_register(&proc_root, &Our_Proc_File);
	#endif
#else
	return proc_register_dynamic(&proc_root, &Our_Proc_File);
#endif
}


/* Cleanup - unregister our file from /proc */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
int cleanup_module(void)
{
	remove_proc_entry("rw_test", &proc_root);
	return 0;
}
#else
void cleanup_module()
{
	proc_unregister(&proc_root, Our_Proc_File.low_ino);
}
#endif

MODULE_LICENSE("GPL");

============================================================

-- 
Ian Jiang

--> -->
 
 
<type 'exceptions.IOError'>
Python 2.5.2: /usr/bin/python
Wed May 1 02:37:20 2024

A problem occurred in a Python script. Here is the sequence of function calls leading up to the error, in the order they occurred.

 /opt/ezmlm-browse-0.20/<string> in ()
 /opt/ezmlm-browse-0.20/main.py in main()
  424 
  425         if path is not None:
  426                 main_path(path)
  427         else:
  428                 main_form()
global main_form = <function main_form at 0x97f4c6c>
 /opt/ezmlm-browse-0.20/main.py in main_form()
  378         except ImportError:
  379                 die(ctxt, "Invalid command")
  380         module.do(ctxt)
  381 
  382 def main():
module = <module 'commands.showmsg' from '/opt/ezmlm-browse-0.20/commands/showmsg.pyc'>, module.do = <function do at 0x97fd09c>, global ctxt = {'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}
 /opt/ezmlm-browse-0.20/commands/showmsg.py in do(ctxt={'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'})
   18         write(html('msg-pager') % ctxt)
   19         write('<hr>')
   20         sub_showmsg(ctxt, ctxt[MSGNUM])
   21         write('<hr>')
   22         write(html('msg-pager') % ctxt)
global sub_showmsg = <function sub_showmsg at 0x97f41ec>, ctxt = {'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, global MSGNUM = 'msgnum'
 /opt/ezmlm-browse-0.20/globalfns.py in sub_showmsg(ctxt={'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, msgnum=349)
  229         format_timestamp(ctxt, ctxt)
  230         write(html('msg-header') % ctxt)
  231         rec_showpart(ctxt, msg, 0)
  232         write(html('msg-footer') % ctxt)
  233         ctxt.pop()
global rec_showpart = <function rec_showpart at 0x97f41b4>, ctxt = {'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, msg = <email.message.Message instance at 0x985554c>
 /opt/ezmlm-browse-0.20/globalfns.py in rec_showpart(ctxt={'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, part=<email.message.Message instance at 0x985554c>, partnum=1)
  205                 else:
  206                         for p in part.get_payload():
  207                                 partnum = rec_showpart(ctxt, p, partnum+1)
  208         else:
  209                 write(html('msg-sep') % ctxt)
partnum = 1, global rec_showpart = <function rec_showpart at 0x97f41b4>, ctxt = {'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, p = <email.message.Message instance at 0x985b4cc>
 /opt/ezmlm-browse-0.20/globalfns.py in rec_showpart(ctxt={'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, part=<email.message.Message instance at 0x985b4cc>, partnum=2)
  208         else:
  209                 write(html('msg-sep') % ctxt)
  210                 sub_showpart(ctxt, part)
  211         return partnum
  212 
global sub_showpart = <function sub_showpart at 0x97f4144>, ctxt = {'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, part = <email.message.Message instance at 0x985b4cc>
 /opt/ezmlm-browse-0.20/globalfns.py in sub_showpart(ctxt={'cmd': 'showmsg', 'threadidx': 0, 'HTTP_X_FORWA...harset': 'utf-8', 'HTTP_ACCEPT_ENCODING': 'gzip'}, part=<email.message.Message instance at 0x985b4cc>)
  164         type = ctxt[TYPE] = part.get_content_type()
  165         ctxt[FILENAME] = part.get_filename()
  166         template = html('msg-' + type.replace('/', '-'))
  167         if not template:
  168                 template = html('msg-' + type[:type.find('/')])
global template = <function template at 0x97ece9c>, global html = <function html at 0x97eced4>, type = 'application/octet-stream', type.replace = <built-in method replace of str object at 0x9854aa0>
 /opt/ezmlm-browse-0.20/globalfns.py in html(name='msg-application-octet-stream')
   40 
   41 def html(name):
   42         return template(name + '.html')
   43 
   44 def xml(name):
global template = <function template at 0x97ece9c>, name = 'msg-application-octet-stream'
 /opt/ezmlm-browse-0.20/globalfns.py in template(filename='msg-application-octet-stream.html')
   31         except IOError:
   32                 if not _template_zipfile:
   33                         _template_zipfile = zipfile.ZipFile(sys.argv[0])
   34                 try:
   35                         f = _template_zipfile.open(n).read()
global _template_zipfile = None, global zipfile = <module 'zipfile' from '/usr/lib/python2.5/zipfile.pyc'>, zipfile.ZipFile = <class zipfile.ZipFile at 0x9785a4c>, global sys = <module 'sys' (built-in)>, sys.argv = ['-c', '/opt/ezmlm-browse-0.20']
 /usr/lib/python2.5/zipfile.py in __init__(self=<zipfile.ZipFile instance at 0x97f88ac>, file='-c', mode='r', compression=0, allowZip64=False)
  337             self.filename = file
  338             modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
  339             self.fp = open(file, modeDict[mode])
  340         else:
  341             self._filePassed = 1
self = <zipfile.ZipFile instance at 0x97f88ac>, self.fp = None, builtin open = <built-in function open>, file = '-c', modeDict = {'a': 'r+b', 'r': 'rb', 'w': 'wb'}, mode = 'r'

<type 'exceptions.IOError'>: [Errno 2] No such file or directory: '-c'
      args = (2, 'No such file or directory')
      errno = 2
      filename = '-c'
      message = ''
      strerror = 'No such file or directory'