Linux-Development-Sys Digest #924, Volume #7      Thu, 1 Jun 00 01:13:13 EDT

Contents:
  Re: /proc changes in 2.4.0-test... (Sam Birch)
  Re: [Q] Hook system call (Sam Birch)
  Re: Detecting whether another process has a file open (Sam Birch)
  Re: Problem with kernel module programming... (Sam Birch)

----------------------------------------------------------------------------

From: Sam Birch <[EMAIL PROTECTED]>
Subject: Re: /proc changes in 2.4.0-test...
Reply-To: [EMAIL PROTECTED]
Date: Thu, 01 Jun 2000 04:24:13 GMT

Alexander,

Firstly, thank you very much for your assistance!  I have ported my
code to the 2.4.0-test set successfully now; however, some of your
advice created a few more questions (further below).  

Regarding your last comment about sending you my code, I can email you
a diff of 2.4.0-test1 and my work, but you may be appalled... I am
really quite a beginner, not only to kernel coding, but to C as well.
Though I have a good deal of pascal/delphi coding experience, this is
realy a teeth-cutting project for me.  

Please let me know if you are willing to look it over.  If so, I would
have another sticky question about locking...

On 29 May 2000 05:38:36 -0400, [EMAIL PROTECTED] (Alexander Viro)
wrote:
>In article <[EMAIL PROTECTED]>,
>Sam Birch  <[EMAIL PROTECTED]> wrote:
>>Hello,
>>
>>I wrote a kernel module which used a proc file for both read and write
>>(as well as ioctl...though I am not sure this is acceptable...).  It
>
>The ioctl part? In principle it's better to add a second file and let
>the read()/write() work on it - for a lot of reasons, not the last of
>them being that you can control the thing with echo(1) that way.

I have used the same proc entry for read, write, and ioctl.  This
"now" works in both 2.2 and 2.4 kernels.  Are there reasons I should
separate them?

>>works fine under 2.2.15.  I am endeavoring to port it up to the
>>2.4.0-test1 tree, but am having problems.
>
>>In 2.2.15, my methodology was:
>>1) I defined a struct file_operations to use my own functions for
>>read, write, and ioctl.
>>2) I defined a struct of inode_operations to use my file_operations
>>and permissions.
>
>Do you really need special permissions in the thing?

I don't think I do, but I saw it used in some sample code I came
across.  It worked, so I didn't question it.  For the most part, I
simply say root can write, everyone can read...that's probably the
default, isn't it?

>>3) I defined a struct of proc_dir_entry, configuring name, file
>>modes...and using my inode_operations.
>
>       Forget that. Statically allocated (or kmalloc()-created, whatever)
>proc_dir_entries are LARTable offense now. Use procfs functions to create
>them.

Please forgive my ignorance, but what is LART, as in LARTable?

>>4) I used proc_register to push my proc_dir_entry into the proc file
>>system.
>
>Ditto.

I am getting the picture that statically registering a proc_dir_entry
is bad, but I am not sure I see the real difference.  I get the
feeling that if I understood the difference, I could be accomplishing
my goals more simply...

Is there a readme/whitepaper/thread I could read up on the qualities
of the procfs methodology?

>>All worked as I desired it to...
>>
>>In 2.4.0-test1, I found the usage of proc has changed, but I am
>>struggling at figuring it out.  Below are my
>>observations/results/questions:
>>
>>OBSERVATIONS:
>>1) proc_register is now static. 
>
>Yes, it is.
>
>>2) create_proc_entry now performs a few things, then uses
>>proc_register the way I think I would have...? (okay, partially a
>>question...)
>
>Yes, and it is the right interface, if you are creating a regular file.
>For directories - proc_mkdir(), for symlinks and devices - proc_symlink()/
>proc_mknod() resp.
>
>>3) proc_dir_entry->get_info is used in net/wanrouter/wanproc.c for
>>outputting info to the user.
>
>Yes, default file_operations are using that as (one of the) callback(s).
>
>>4) the wanproc.c file defined the file_operations/inode_operations
>>differently than I have seen them for 2.2.x.  Is this way correct...if
>>so, is it functionally different than the old way? (ahhh, another
>>question in the observation section...oh well)
>
>->proc_fops and ->proc_iops resp.
>
>>3) Is the file_operations ignored for the proc fs now?
>
>Not. If you want your file_operations - set ->proc_fops. Going for a
>couple of files with ioctl() turned into read()/write() on the second
>file may be a good idea for independent reasons and then may not need
>special  file_operations, but if you want to keep the special ones -
>see above.
>
>>2) Is proc_dir_entry->config_info the only way to output to a user
>>reading my proc file?
>
>Not. Another variant in ->read_proc() and yet another - using your own
>file_operations.
>
>>3) If I use proc_dir_entry->config_info to get info back to the user,
>>what can I use to get the text a user writes to my proc file?
>
>Your own file_operations or ->write_proc()
>
>>4) How can I use my ioctl call?
>
>Now, that's up to you - IMO they tend to be quite a nasty PITA, but if you
>are of S&M type and want to use this abortion of syscall - you are welcome,
>use you own file_operations.

I chose to use an IOCTL because I read many times that adding a
syscall way to go, especially if the code is probably not going to be
rolled in the stock source tree.  Aren't syscalls more painful to deal
with as the kernel eveolves?

>For further comments I'ld really like to look at the code in question.
>Quite probably I can help you with it.

Thank you very much!
Sam


------------------------------

From: Sam Birch <[EMAIL PROTECTED]>
Subject: Re: [Q] Hook system call
Reply-To: [EMAIL PROTECTED]
Date: Thu, 01 Jun 2000 04:51:15 GMT

On Wed, 31 May 2000 21:43:34 +0900, "usenet.seri.re.kr"
<[EMAIL PROTECTED]> wrote:
>I want to modify kernel source. Is it possible?
>I wanna trace system call.
>Whenever system call is invoked, I want to know who invoke system call, what
>system call is invoked, when system call is invoked and etc................
>
>...I'll add new system call.
>After my new system call invoked,
>Whenener system cal l invoked, I want to get a file(something other) that
>contain invoked system call's information.
>
>Is that possible.
>If you know solution, please tell me.
>
>thanks for reply.
>
>                        Jongyun, Jeong........from Korea.
>

PREFACE: I am not an expert!

This can be done.  The easiest way for the logging I can think of is
using printk's and maybe also setting up a filter for it in
syslog.conf to send it to it's own file.  You can set the threshold of
the message so it will not show up on the console.  

I can think of two ways to log a syscall:
1) Insert code into the syscall within the kernel
2) write a module that intercepts the syscall(s) you are interested
in, logs the activity, then passes the call onto the real syscall
(maybe selectively based on a rule set you could code...).  There is a
very good example of how to accomplish this in the The Linux Kernel
Module Programming Guide, by Ori Pomerantz (www.linuxdoc.org).

As a note, I don't think it would be reasonable to have enough disk
space to track every syscall for any length of time...I think it would
be more practical to target specific syscalls.

HTH 
Sam


------------------------------

From: Sam Birch <[EMAIL PROTECTED]>
Subject: Re: Detecting whether another process has a file open
Reply-To: [EMAIL PROTECTED]
Date: Thu, 01 Jun 2000 04:56:05 GMT

On Wed, 31 May 2000 20:15:56 GMT, [EMAIL PROTECTED] (Nick
Craig-Wood) wrote:

>What I need is a foolproof way of detecting whether another process
>has a file open on the local machine.  My program needs to process
>files in a directory after they have been completely written from
>another process (or possibly from a network file system).
>
>fuser works quite well, but it has to do an awful lot of work to
>decide whether a file is open (it looks through every directory in
>/proc/[0-9]*/ and then looks at the links of the directories within
>it.  On my system that is over 1000 directory entries!  It also
>doesn't find all processes unless you are root (or you setuid fuser)
>and it doesn't (always?) find kernel accesses either.
>
>Given that I don't have any control over the process which is creating
>the files (I can't make it use locking or any renaming scheme) what
>can I do?  It seems that the kernel knows the answer (when you unlink
>an inode it doesn't disappear unless the number of links and the
>number of processes with the inode open are both zero).  I should be
>able to ask it given a filing system and an inode is this in use.  I
>haven't found a way to do that though - I couldn't find any system
>calls which take an inode number.
>
>Any ideas?
>
>TIA

You might be able to write a module which intercepts all the file
opens/closes and keeps somewhat of a state table.  Then possibly use a
rw ioctl to pass a query about a given file to the module from a
user-space program and the answer back.

Just a thought...
Sam

------------------------------

From: Sam Birch <[EMAIL PROTECTED]>
Subject: Re: Problem with kernel module programming...
Reply-To: [EMAIL PROTECTED]
Date: Thu, 01 Jun 2000 05:02:19 GMT

On Thu, 01 Jun 2000 02:21:04 -0400, "Robichaud, Jean-Philippe
[BAN:6S33:EXCH]" <[EMAIL PROTECTED]> wrote:

>For some reason, I must program a kernel module that ping another
>computer...  My problem I that if I include the netinet/ip_icmp.h file,
>I get a lot of "was redifined" error and if I don't include it, I get
>undefined symbol error...  Any tips ?
>
>     thanks.

It is my understanding that including "any" non-kernel headers is not
good.  I would look to see what symbols are undefined and code them
into your module/module header...as long as they don't collide with a
standard kernel definition.

HTH Sam

>P.S., here is the entire file I'm working on... (it is not complete, but
>I should work like this...)
>there is some part of the code doing nothing right now, but that what
>I'm working on...
>
>
>/* Create a "file" in /proc for input and output... */
>
>#include <linux/kernel.h>
>#include <linux/module.h>
>
>#if CONFIG_MODVERSIONS==1
>#define MODVERSIONS
>#include <linux/modversions.h>
>#endif
>
>
>#include <linux/proc_fs.h>
>#include <asm/uaccess.h> /* for get_user & put_user */
>
>#include <linux/sched.h>
>#include <linux/tty.h>
>
>#if(0)
>
>#include <signal.h> 
>#include <errno.h>
>#include <sys/time.h>
>
>#include <sys/param.h>
>#include <sys/types.h>
>#include <sys/socket.h>
>#include <sys/file.h>
>
>#include <netinet/in_systm.h>
>#include <netinet/in.h>
>
>#include <netinet/ip.h>
>
>
>#include <netinet/ip_icmp.h>
>#endif
>
>#include <netdb.h>
>
>
>
>void print_string(char *str);
>
>       
>
>
>
>
>#define MESSAGE_LENGTH 80
>static char Message[MESSAGE_LENGTH];
>
>static ssize_t module_output(
>       struct file *file,
>       char *buf, 
>       size_t len,
>       loff_t *offset)
>{
> static int finished = 0;
> int i;
> char message[MESSAGE_LENGTH+30];
>
> if (finished) {
>       finished=0;
>       return 0;
> }
>
> sprintf(message,"Last input:%s",Message);
> for(i=0; i<len &&message[i];i++)
>        put_user(message[i],buf+i);
> finished =1;
> return i;
>}
>
>
>static ssize_t module_input (
>       struct file *file,
>       const char *buf,
>       size_t length,
>       loff_t *offset)
>{
> int i;
>
> for(i=0; i<MESSAGE_LENGTH-1 && i<length;i++)
>       get_user(Message[i],buf+i);
> Message[i] = '\0';
> return i;
>}
>
>
>static int module_permission(struct inode *inode, int op)
>{
> if(op==4|| (op== 2 && current->euid == 0))
>       return 0;
>
> return -EACCES;
>}
>
>int module_open(struct inode *inode, struct file *file)
>{
> MOD_INC_USE_COUNT;
>
> return 0;
>}
>
>int module_close(struct inode *inode, struct file *file)
>{
> MOD_DEC_USE_COUNT;
>
> return 0;
>}
>
>/* structures to reguster as the /proc file with
> * pointers to all the relevant functions       */
>
>
>/****************************************
> * structure File_Ops_4_Our_Proc_File  *
> *                                                                             *
> * This define each function that will         *
> * handle each action taken on the             *
> * "file"                                                              *
> *                                                                             *
> ****************************************/
>
>static struct file_operations File_Ops_4_Our_Proc_File =
>{
>       NULL,                   /* lseek*/
>       module_output,  /*"read" from the file*/
>       module_input,   /*"write from the file*/
>       NULL,                   /* readdir*/
>       NULL,                   /* select*/
>       NULL,                   /* ioctl*/
>       NULL,                   /* mmap*/
>       module_open,    /* opening the file*/
>       NULL,                   /* flush*/
>       module_close    /* closing the file*/
>       /* there is other things /usr/include/linux/fs.h
>     * but we don't need them and they are assumed as NULL */
>};
>
>/****************************************
> * structure Inode_Ops_4_Our_Proc_File *
> *                                                                             *
> * This define each function that will         *
> * handle each action taken on the             *
> * inode                                                               *
> *                                                                             *
> ****************************************/
>
>static struct inode_operations Inode_Ops_4_Our_Proc_File = 
>{
>       &File_Ops_4_Our_Proc_File,      /* functions linked to actions on the 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                       /* ckeck for permissions*/
>};
>
>/****************************************
> * structure Our_Proc_File                             *
> *                                                                             *
> * This is our /proc directory entry   *
> * i.e. our file in /proc directory            *
> *                                                                             *
> * Contains the details of the "file"  *
> *                                                                             *
> ****************************************/
>
>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",                                      /* name of the file */
>       S_IFREG | S_IRUGO | S_IWUSR,    /* file mode */
>       1,                                                              /* number of 
>link */
>       0, 0,                                                   /* uid and gid of the 
>owner (root) */
>       80,                                                             /* size of 
>file reported by ls */
>       &Inode_Ops_4_Our_Proc_File,             /* inode structure of the file */
>       NULL                                                    /* read function of 
>the file (actually 
>                                                                        * in 
>Inode...)*/
>};
>
>/***************************************
> * Function init_module()              *
> *                                     *
> * This function is called when insmod *
> * command is run.  It register the    *
> * /proc file and return the result    *
> *                                     *
> ***************************************/
>
>int init_module()
>{
> int a; 
>
> char str[80];
> a = proc_register(&proc_root, &Our_Proc_File);
> sprintf(str,"return value : %d",a);   
> print_string(str);
> return a;
>}
>
>/***************************************
> * Function cleanup_module()           *
> *                                     *
> * This function is called when rmmod  *
> * command is run.  It unreguster the  *
> * /proc file                          *
> *                                     *
> ***************************************/
>
>void cleanup_module()
>{
> proc_unregister(&proc_root, Our_Proc_File.low_ino);
>}
>
>/***************************************
> * Function print_string(str)          *
> *                                     *
> * take str and prints it on the       *
> * actual console using the current    *
> * pointer and the write method.       *
> *                                     *
> * This replace printk                 *
> ***************************************/
>
>void print_string(char *str)
>{
>       struct tty_struct *my_tty;
>       my_tty = current->tty;
>
>       if(my_tty != NULL) {            /* will be NULL if it's a deamon */
>               (*(my_tty->driver).write)(
>                       my_tty,
>                       0,
>                       str,
>                       strlen(str));
>               (*(my_tty->driver).write)( /* Add manually the newline and return */
>                       my_tty,
>                       0,
>                       "\015\012",
>                       2);
>       }
>} /* End of print_string() */
>
>/*
> *                     P I N G . C
> *
> * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
> * measure round-trip-delays and packet loss across network paths.
> *
> * Author -
> *     Mike Muuss
> *     U. S. Army Ballistic Research Laboratory
> *     December, 1983
> * Modified at Uc Berkeley
> *
> * Changed argument to inet_ntoa() to be struct in_addr instead of
>u_long
> * DFM BRL 1992
> *
> * Status -
> *     Public Domain.  Distribution Unlimited.
> *
> * Bugs -
> *     More statistics could always be gathered.
> *     This program has to run SUID to ROOT to access the ICMP socket.
> */
>
>#define        MAXWAIT         5       /* max time to wait for response, sec. */
>#define        MAXPACKET       4096    /* max packet size */
>#define VERBOSE                1       /* verbose flag */
>#define QUIET          2       /* quiet flag */
>#define FLOOD          4       /* floodping flag */
>#define DEFAULT_PACKET_SIZE 8
>#ifndef MAXHOSTNAMELEN
>#define MAXHOSTNAMELEN 64
>#endif
>
>u_char packet[MAXPACKET];
>int        i, 
>               pingflags, 
>               options;
>extern int errno;
>
>int                            s;                      /* Socket file descriptor */
>struct hostent                 *hp;            /* Pointer to host info */
>struct timezone        tz;                     /* leftover */
>
>struct sockaddr        whereto;        /* Who to ping */
>int                            datalen;        /* How much data */
>
>char usage[] = "Usage:  ping host_ip_address \n";
>
>char *hostname;
>char hnamebuf[MAXHOSTNAMELEN];
>
>int npackets           = 3;
>int ntransmitted       = 0;            /* sequence # for outbound packets = #sent */
>int ident;
>
>int nreceived          = 0;            /* # of packets we got back */
>int tmin                       = 999999999;
>int tmax                       = 0;
>int tsum                       = 0;            /* sum of all times, for doing average 
>*/
>int finish(), 
>       catcher();
>char *inet_ntoa();
>
>void ping(void)
>{
>       struct sockaddr_in from;
>       struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
>       int on = 1;
>       struct protoent *proto;
>
>       bzero((char *)&whereto, sizeof(struct sockaddr) );
>       to->sin_family = AF_INET;
>       to->sin_addr.s_addr = inet_addr("47.115.51.38");
>       if(to->sin_addr.s_addr != (unsigned)-1) {
>               strcpy(hnamebuf, "47.115.51.38");
>               hostname = hnamebuf;
>       } else {
>               printk(" Use numerical ip adress only\n");
>               exit(1);
>       }
>
>       datalen = DEFAULT_PACKET_SIZE ;
>
>       ident = getpid() & 0xFFFF;
>
>       if ((proto = getprotobyname("icmp")) == NULL) {
>               printk("icmp: unknown protocol\n");
>               exit(10);
>       }
>
>       if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
>               perror("ping: socket");
>               exit(5);
>       }
>
>       printk("PING %s (%s): %d data bytes\n", hostname,
>                                                                                      
> inet_ntoa(to->sin_addr), 
>                                                                                      
> datalen);
>
>       signal(SIGINT, (void *) finish );
>       signal(SIGALRM, (void *) catcher);
>
>       if(!(pingflags & FLOOD))
>               catcher();      /* start things going */
>
>       for (;;) {
>               int len = sizeof (packet);
>               int fromlen = sizeof (from);
>               int cc;
>               struct timeval timeout;
>               int fdmask = 1 << s;
>
>               timeout.tv_sec = 0;
>               timeout.tv_usec = 5000;
>
>               if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) {
>                       if( errno == EINTR ){
>                               printk("pass by here\n");
>                               continue;
>                       }
>                       perror("ping: recvfrom");
>                       continue;
>               }
>               pr_pack( packet, cc, &from ); 
>               if (npackets && nreceived >= npackets)
>                       finish();
>       }
>       /*NOTREACHED*/
>}
>
>/*
> *                     C A T C H E R
> * 
> * This routine causes another PING to be transmitted, and then
> * schedules another SIGALRM for 1 second from now.
> * 
> */
>int catcher(void)
>{
>       int waittime;
>
>       pinger();
>       if (npackets == 0 || ntransmitted < npackets)
>               alarm(1);
>       else {
>               if (nreceived) {
>                       waittime = 2 * tmax / 1000;
>                       if (waittime == 0)
>                               waittime = 1;
>               } else
>                       waittime = MAXWAIT;
>               signal(SIGALRM, (void *) finish);
>               /* if the last ping dosen't answer, finish */
>               alarm(waittime); 
>       }
>}
>
>/*
> *                     P I N G E R
> * 
> * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
> * will be added on by the kernel.  The ID field is our UNIX process ID,
> * and the sequence number is an ascending integer.  The first 8 bytes
> * of the data portion are used to hold a UNIX "timeval" struct in VAX
> * byte-order, to compute the round-trip time.
> */
>void pinger(void)
>{
>       static u_char outpack[MAXPACKET];
>       register struct icmp *icp = (struct icmp *) outpack;
>       int i, cc;
>       register struct timeval *tp = (struct timeval *) &outpack[8];
>       register u_char *datap = &outpack[8+sizeof(struct timeval)];
>
>       icp->icmp_type = ICMP_ECHO;
>       icp->icmp_code = 0;
>       icp->icmp_cksum = 0;
>       icp->icmp_seq = ntransmitted++;
>       icp->icmp_id = ident;           /* ID */
>
>       cc = datalen+8;                 /* skips ICMP portion */
>
>       for( i=8; i<datalen; i++)       /* skip 8 for time */
>               *datap++ = i;
>
>       /* Compute ICMP checksum here */
>       icp->icmp_cksum = in_cksum( icp, cc );
>
>       /* cc = sendto(s, msg, len, flags, to, tolen) */
>       i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
>
>       if( i < 0 || i != cc )  {
>               if( i<0 )  perror("sendto");
>               printk("ping: wrote %s %d chars, ret=%d\n",
>                       hostname, cc, i );
>       }
>}
>
>/*
> *                     P R _ T Y P E
> *
> * Convert an ICMP "type" field to a printable string.
> */
>char * pr_type( t )
>register int t;
>{
>       static char *ttab[] = {
>               "Echo Reply",
>               "ICMP 1",
>               "ICMP 2",
>               "Dest Unreachable",
>               "Source Quench",
>               "Redirect",
>               "ICMP 6",
>               "ICMP 7",
>               "Echo",
>               "ICMP 9",
>               "ICMP 10",
>               "Time Exceeded",
>               "Parameter Problem",
>               "Timestamp",
>               "Timestamp Reply",
>               "Info Request",
>               "Info Reply"
>       };
>
>       if( t < 0 || t > 16 )
>               return("OUT-OF-RANGE");
>
>       return(ttab[t]);
>}
>
>/*
> *                     P R _ P A C K
> *
> * Print out the packet, if it came from us.  This logic is necessary
> * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
> * which arrive ('tis only fair).  This permits multiple copies of this
> * program to be run without having intermingled output (or
>statistics!).
> */
>void pr_pack( buf, cc, from )
>char *buf;
>int cc;
>struct sockaddr_in *from;
>{
>       struct ip *ip;
>       register struct icmp *icp;
>       register long *lp = (long *) packet;
>       register int i;
>       struct timeval tv;
>       struct timeval *tp;
>       int hlen, triptime;
>
>       from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr );
>       gettimeofday( &tv, &tz );
>
>       ip = (struct ip *) buf;
>       hlen = ip->ip_hl << 2;
>
>       cc -= hlen;
>       icp = (struct icmp *)(buf + hlen);
>
>       if( icp->icmp_id != ident )
>               return;                 /* 'Twas not our ECHO */
>
>
>       if(!(pingflags & QUIET)) {
>               if(pingflags != FLOOD) {
>                       printk("%d bytes from %s: icmp_seq=%d", cc,
>                         inet_ntoa(from->sin_addr),
>                         icp->icmp_seq );      /* DFM */
>                         putchar('\n');
>               } else {
>                       putchar('\b');
>               }
>       }
>       nreceived++;
>}
>
>
>/*
> *                     I N _ C K S U M
> *
> * Checksum routine for Internet Protocol family headers (C Version)
> *
> */
>int in_cksum(addr, len)
>u_short *addr;
>int len;
>{
>       register int nleft = len;
>       register u_short *w = addr;
>       register u_short answer;
>       register int sum = 0;
>
>       /*
>        *  Our algorithm is simple, using a 32 bit accumulator (sum),
>        *  we add sequential 16 bit words to it, and at the end, fold
>        *  back all the carry bits from the top 16 bits into the lower
>        *  16 bits.
>        */
>       while( nleft > 1 )  {
>               sum += *w++;
>               nleft -= 2;
>       }
>
>       /* mop up an odd byte, if necessary */
>       if( nleft == 1 ) {
>               u_short u = 0;
>
>               *(u_char *)(&u) = *(u_char *)w ;
>               sum += u;
>       }
>
>       /*
>        * add back carry outs from top 16 bits to low 16 bits
>        */
>       sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
>       sum += (sum >> 16);                     /* add carry */
>       answer = ~sum;                          /* truncate to 16 bits */
>       return (answer);
>}
>
>/*
> *                     F I N I S H
> *
> */
>int finish(void)
>{
>       exit(0);
>}


------------------------------


** FOR YOUR REFERENCE **

The service address, to which questions about the list itself and requests
to be added to or deleted from it should be directed, is:

    Internet: [EMAIL PROTECTED]

You can send mail to the entire list (and comp.os.linux.development.system) via:

    Internet: [EMAIL PROTECTED]

Linux may be obtained via one of these FTP sites:
    ftp.funet.fi                                pub/Linux
    tsx-11.mit.edu                              pub/linux
    sunsite.unc.edu                             pub/Linux

End of Linux-Development-System Digest
******************************

Reply via email to