Mail Delivery Problem

SMTP MAILER postmaster at ecf.ncsl.nist.gov
Mon Aug 13 21:24:58 AEST 1990


 ----Reason for mail failure follows----
Sending mail to host ecf.ncsl.nist.gov :
  Fatal reply code to command 'RCPT TO:<ise.ncsl.nist.gov at ecf.ncsl.nist.gov>':
  550 User "ise.ncsl.nist.gov" Unknown.


 ----Transcript of message follows----
Date: 13 Aug 90 06:45:00 EST
From: unix-wizards at BRL.MIL
Subject: UNIX-WIZARDS Digest  V10#115
To: "ise.ncsl.nist.gov" <ise.ncsl.nist.gov at ecf.ncsl.nist.gov>

Return-Path: <unixwiz-request at ecf.ncsl.nist.gov>
Received: from SEM.BRL.MIL by ecf.ncsl.nist.gov with SMTP ; 
          Mon, 13 Aug 90 06:44:51 EST
Received: from SEM.BRL.MIL by SEM.BRL.MIL id aa02332; 13 Aug 90 5:59 EDT
Received: from sem.brl.mil by SEM.BRL.MIL id aa02296; 13 Aug 90 5:45 EDT
Date:       Mon, 13 Aug 90 05:45:04 EST
From:       The Moderator (Mike Muuss) <Unix-Wizards-Request at BRL.MIL>
To:         UNIX-WIZARDS at BRL.MIL
Reply-To:   UNIX-WIZARDS at BRL.MIL
Subject:    UNIX-WIZARDS Digest  V10#115
Message-ID:  <9008130545.aa02296 at SEM.BRL.MIL>

UNIX-WIZARDS Digest          Mon, 13 Aug 1990              V10#115

Today's Topics:
              Re: Help needed with System V message queues
                            Re: nested loops
                  evaluating ${10} and above in sh/ksh
      Re: Getting CPU information on unterminatted child processes
                 Re: Cron - First Saturday of the month

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

From: George Bogatko <bogatko at lzga.att.com>
Subject: Re: Help needed with System V message queues
Keywords: SYSV messagequeue
Date: 8 Aug 90 16:36:56 GMT
To:       unix-wizards at sem.brl.mil

HI:

A while ago, I got sick of wondering what the tunables for messages meant.
The result was a writeup which was begun, interrupted, and never
finished.  This is what remains of it.  It is 500+ lines long, so you
may want to skip all this if message queues leave you cold.  After it,
in a second posting is a 'pic' file of how messages are stored in memory.

This may answer some questions about message queues, and how they work.

If I see enough interest, I may finish the writeup.

************

OVERVIEW

In /etc/master.d there is a file, called msg that contains
the tunable parameters for the device driver that handles
the UNIXTM message queue system.  This file contains lines
similar to the following:

    MSGMAP  = 100
    MSGMAX  = 2048
    MSGMNB  = 4096
    MSGMNI  = 50
    MSGSSZ  = 8
    MSGTQL  = 40
    MSGSEG  = 1024

The meaning of these parameters, as stated in the manual
Operations and Administration Series: Performance Mangement
under the chapter Tunable Parameters Definitions is:

MSGMAP	 specifies the size of the memory control map
	      used to manage message segments.  If this
	      value is insufficient to handle the message
	      type facilities, a warning message is sent ot
	      the console.

MSGMAX	 specifies in bytes the maximum size of a
	      message sent.  When receiving a message, a
	      value larger than this parameter can be used
	      to ensure that the whole message is received
	      and not truncated.

MSGMNB	 specifies the maximum length, in bytes of a
	      message queue.  The owner of a facility can
	      lower this value, but only the superuser can
	      raise it.

MSGSEG	 Specifies the number of message segments in
	      the system.  MSGSEG * MSGSSZ should be less
	      than 131,072 bytes (128 kilobytes).

MSGSSZ	 specifies the size in bytes of a message
	      segment as stored in memory.  Each message is
	      stored in a contiguous message segment.  The
	      larger the segments are, the greater the
	      chance of having wasted memory at the end of
	      each message.  MSGSSZ * MSGSEG should be less
	      than 131,072 bytes (128 kilobytes).

MSGTQL	 specifies the number of message queue headers
	      on all message queues sytem-wide, and thus,
	      the number of outstanding messages.


These values are stored in a structure called "struct msginfo"
which looks like this:

struct msginfo {
	int	msgmap,
		msgmax,
		msgmnb,
		msgmni,
		msgssz,
		msgtql;
	ushort	msgseg;
};

This structure is used when the MSG driver is initialized.

Notice that the values are stored as INTS.  This bites you
in the butt later on when the value of 'msgmnb' is put
into 'msg_qbytes'.

All the structures described here are found in '/usr/include/sys/msg.h'

There are four data structures used in the message queue
universe.

struct msgbuf
    This is actually a template used by the user to hold
    the message; it is assumed (incorrectly) that the user
    knows enough to re-write this template to suit their
    needs.  The structure given in the header file msg.h is
    never used.  The only thing that must be here is the
    member "long mtype".  which must always be the first
    member.  The template looks like this:


	 struct msgbuf {
		 long    mtype;	  /* message type */
		 char    mtext[1];       /* message text */
	 };


    Notice that the size of mtext is one (1). This is not
    enough size to hold anything useful.

    Newcomers to UNIXTM messages almost always bark their
    shins on this one.

struct msg
    This is the structure that points to the address of the
    actual message in the message pool.  It looks like
    this:

	 struct msg {
		 struct msg      *msg_next;
		 long	    msg_type;
		 short	   msg_ts;
		 short	   msg_spot;
	 };

    The message queue driver keeps these structures, called
    message headers in an array, whose size is determined
    by the tunable parameter MSGTQL.  Each outstanding
    message, i.e. a message that has been sent but not yet
    received, has one of these headers associated with it.
    Thus the number of outstanding messages handled by the
    driver is determined by the setting of MSGTQL.

    The members of the structure are used as:

    msg_next
	 Even though these headers are in an array, they
	 are handled like a linked list.  This member
	 points to the next header, which is located
	 somewhere in the array.

    msg_type
	 This corresponds to the long mtype member of the
	 msgbuf structure shown above.

    msg_ts
	 This is the precise length in bytes of the message
	 that is stored in the message pool.

    msg_spot
	 This is the location in the message pool of the
	 message.  Notice that it is not a pointer.  It is
	 really an offset.  

struct msqid_ds
    This is the structure that keeps vital statistics about
    a particular message queue that is being serviced by
    the driver.  It looks like this:

	 struct msqid_ds {
		 struct ipc_perm msg_perm
		 struct msg      *msg_first;
		 struct msg      *msg_last;
		 ushort	  msg_cbytes;
		 ushort	  msg_qnum
		 ushort	  msg_qbytes;
		 ushort	  msg_lspid;
		 ushort	  msg_lrpid;
		 time_t	  msg_stime;
		 time_t	  msg_rtime;
		 time_t	  msg_ctime;
	 };

    The driver keeps these structures in an array, whose
    size is determined by the tunable parameter MSGMNI.
    Thus the maximum number of message queues handled by
    the driver is determined by the setting of MSGMNI.

    The members of the structure are used as:

    msg_perm
	 This is a structure located in ipc.h that contains
	 various permissions and ids.  It looks like this:

	      struct ipc_perm {
		      ushort  uid;    /* owner's user id */
		      ushort  gid;    /* owner's group id */
		      ushort  cuid;   /* creator's user id */
		      ushort  cgid;   /* creator's group id */
		      ushort  mode;   /* access modes */
		      ushort  seq;    /* slot usage sequence number */
		      key_t   key;    /* key */
	      };

	 This structure is used by all the drivers in the
	 IPC system.  The meaning of these variables is
	 clear from their names, and the comments; except
	 for seq.

	 This variable holds a sequence number that is used
	 to determine the msqid that is returned from the
	 msgget() call.  By constantly incrementing this
	 number, one can be sure that the same message
	 queue header will not have the same msqid returned
	 when it is re-allocated.

    msg_first
	 This is a pointer to the first struct msg member
	 in the linked list of struct msg message headers.

    msg_last
	 This is a pointer to the last struct msg member in
	 the linked list of struct msg message headers.

    msg_cbytes
	 This is the total number of bytes currently on the
	 queue.  It represents the accumulated total of all
	 the values of the struct msg member msg_ts in the
	 linked list of outstanding message headers for
	 that particular queue.

    msg_qnum
	 This is how many messages are outstanding on the
	 queue; and thus how many struct msg message
	 headers are linked to this queue header.

    msg_qbytes
	 This is an upper limit of how many bytes can be
	 outstanding on the queue.  This is an arbitrary
	 value, which is set from the value of the tunable
	 parameter MSGMNB.  This means that raising or
	 lowering this value does not alter how many total
	 messages you can have handled by the driver.  That
	 is determined by the size of the message pool.  This
	 value can be altered by either the owner/creator of
	 the message queue, or the super-user, without having
	 to change the value of MSGMNB.

    msg_lspid
	 The process id of the last process to send a
	 message.

    msg_lrpid
	 The process id of the last process to receive a
	 message.

    msg_stime
	 The last time a message was put on this queue.

    msg_rtime
	 The last time a message was taken off this queue.

    msg_ctime
	 The last time anything at all happened regarding
	 this header.

The message pool
    There is no formal name for the pool in the msg.h
    structure.  The message pool is an amorphous blob of
    memory.  It is obtained by a call to the kernel function
    kseg() which returns the base address of a segment of kernel
    memory.  This address is cast to type paddr_t (physical
    address type) which on the 3B2 line is a long.  It is
    treated as a contiguous array of single bytes.  Think of it
    as a char array.

    This size of this blob is determined by multiplying the
    values in the two tunable parameters MSGSEG and MSGSSZ.
    The result of the multiplication is then rounded up to
    the nearest page size.  This size is passed as a
    parameter to kseg().

    The argument to kseg() is a request for pages of
    memory, in the range 1 - 64.  64 pages (128K) is the
    upper limit of memory that will be returned by kseg().
    This is why the tunable parameters guide mentioned
    above says:

    "MSGSSZ * MSGSEG should be less than 131,072 bytes (128 kilobytes)."


SENDING A MESSAGE

Before diving in to how the driver handles messages, it
might be best to present a general picture of how
outstanding messages are stored.

Recall from part 1 that there are four data structures
involved in the process:  struct msgbuf, struct msg, struct
msqid_ds, and the memory pool.  Briefly, the msqid_ds
structure points to the first instance of a message header,
which is a msg structure.  Each message header points to the
next message header in the linked list of outstanding
messages.  Each message header contains the offset in the
memory pool where the actual message is being stored.

The memory pool is logically divided into segments (of size
MSGSSZ), and total number of these segments is of size
MSGSEG.  When a message is actually stored, it will occupy
as much space as necessary, rounded up to the nearest
segment size.  From this it can be seen that unless the
message size aligns with the MSGSSZ segment size, there will
be some wasted bytes associated with each stored message.

The enclosed diagram Mapping a Message Queue ID to a 28 Byte
Message in Kernal Memory displays the association of all
these data structures in the job of holding a 28 byte
message in memory.

****  SEE FOLLOWING POSTING FOR PIC FILE ****

3.1  Conversion of a user supplied message queue ID (msqid)
    to a pointer to a struct msqid_ds queue header

This is a fundamental algorighm in the whole process, and is
called from many places in the driver;

algorithm 'msgconv'

   convert msqid to msqid_ds structure
   {
1.      pointer = address of array,
		 offset by msqid
		 modulo MSGMNI

2.      lock the reference to the structure

3.      if(the structure is not in use) ||
	  the sequence number doesn't equal
	  the msqid divided by MSGMNI)
	      return EINVAL

4.      return the pointer found in step 1.
   }

step 1. convert msqid to pointer
    Remember that the msqid_ds structures are held in an
    array of size MSGMNI.  Assuming that the call msgget()
    works correctly (it does),  the msqid that is returned
    from that call will always be the result of an
    incrementing sequence number (remember struct
    ipc_perm.ushort seq?)  times the value of MSGMNI, plus
    the offset into the msqid_ds array of the assigned
    message header.  Thus if MSGMNI is 100, the sequence
    number 3, and the offset 30, the message queue id
    returned by msgget() would be 330.

    The line that converts the msqid back to the offset is
    simply:

	    qp = &msgque[id % msginfo.msgmni];

    Which is to say that the offset of the array (here
    msgque) is msqid modulo MSGMNI.  In our example, this
    would be 30, which is indeed the offset of the array.

step 2. Lock the reference to the structure
    A parallel char array, of size MSGMNI is kept.  Once
    the offset is found, it is used to find the associated
    lock value in this lock array. As long as this value is
    1, the process sleeps (lines 1 and two following).

	    1  while (*lockp)
	    2       sleep(lockp, PMSG);
	    3  *lockp = 1;

    When another process, which is using this message
    header, is done, it sets the value of this lock to 0,
    and issues a wakeup().  Our process then wakes up and
    now finds the value to be 0. It then stops going to
    sleep, and locks the value (line 3).

    This is what allows message queues to act "atomicly"

step 3. check the msqid value for validity
    The value of qp->msg_perm.seq is checked against the
    value of msqid divided by MSGMNI and if they don't
    match, then errno is set to EINVAL and the system call
    returns with an error (-1).  In our example, if the
    msqid is 330, then 330/100 (in integer arithmetic)
    yields 3, which is indeed the sequence number.  Thus
    the msqid is successfully converted to a valid and
    active message header.

step 4. return the queue pointer

3.2  Sending_a_message

Sending a message consists of receiving a buffer from the
user, and putting it into the message pool, with proper
labeling so that a receive request can copy that message out
of the message pool.

algorithm 'msgsnd'

   send a message
   {
1.      convert msqid to msqid_ds pointer (algorighm msgconv)

2.      if(access denied by incorrect permissions)
	   return EACCES

3.      if(byte count <= 0 || byte count > MSGMAX)
	   return EINVAL

4.      copy the message type from the user area
	   return EFAULT on error

5.      if(message type <= 0)
	   return EINVAL

   GETRES:

6.      if(queue has been removed or changed)
	   return EIDRM

7.      if( (total bytes in queue > MSGMNB) ||
	   (no free msg headers available [MSGTQL])

       {
8.	  if(IPC_NOWAIT set)
	       return EAGAIN

9.	  sleep

10.	 if(sleep was interrupted)
	       return EINTR

11.	 goto GETRES
       }

12.     call 'malloc()' to find free slot in
       message pool.

13.     if(no free space in message pool)
       {
	   if(IPC_NOWAIT set)
	       return EAGAIN

	   sleep

	   if(sleep was interrupted)
	       return EINTR

	   goto GETRES
       }

14.     assuming all is OK, copy from user to
       message pool.

15.     if(system error during copy)
       {
	   call 'mfree' to mark slot as free
	   return EFAULT
       }

16.     update 'msqid_ds' header

17.     initialize 'msg' header

18.     link 'msg' header into chain of
       related 'msg' headers.

19.     return 0
   }

*****************

At this point I was interrupted by real work, and never returned to the
writeup. The "Bach Book" has a good writeup on this stuff.

A few points however:

MSGMAX is not MSGMNB.  MSGMAX is the largest message you can send.  You
can't find out the value of MSGMAX from the msqid_ds structure.

MSGMNB can be found out from "msg_qbytes".  Recall from the above, that
you can reset this to a higher value if you are super-user
and always to a lower value if you are the owner.
What is important to note however is that this number has nothing to
do with capacity of the driver.  It is just a number that is compared against.

MSGMNB is stored in "struct msginfo" as an INT, but when the driver is
initialized, it is transfered to "struct msqid_ds" in member "msg_qbytes"
which is a "ushort".  Thus while some documentation may say that you
can have a high message queue maximum, you can only have the upper
limits of a ushort (65535).  If you set MSGMNB to a higher value
than this, it will wrap, and you will wind up with a lower value.

If you want to increase the size of the message pool, increase
MSGSEG.  NEVER INCREASE MSGSSZ.  Recall from  above:

       "The memory pool is logically divided into segments (of size
       MSGSSZ), and total number of these segments is of size
       MSGSEG.  When a message is actually stored, it will occupy
       as much space as necessary, rounded up to the nearest
       segment size.  From this it can be seen that unless the
       message size aligns with the MSGSSZ segment size, there will
       be some wasted bytes associated with each stored message."

This means that if MSGSSZ is 50 bytes, and you have a 10 byte message,
you will occupy one slot, and have 40 bytes of wasted storage hanging
around.  But if you keep the value of 8, then you will occupy 2 slots
and have 6 bytes of wasted storage hanging around.

See the following posting for a pic file of how this storage works.

In the msgsnd description above is:

       12.     call 'malloc()' to find free slot in
	       message pool.

       13.     if(no free space in message pool)
	       {
		   if(IPC_NOWAIT set)
		       return EAGAIN

		   sleep

		   if(sleep was interrupted)
		       return EINTR

		   goto GETRES
	       }
Notice that there no escape from this if the size of the message you are
trying to send is greater then the total amount of memory in the message
pool.  Thus you can hang forever waiting for enough room to become
available.  This will be allowed if MSGMNB is set to be greater than
( MSGSSZ * MSGSEG * (sizeof page on your machine (2048 on 3B's) ) ).
Be careful when setting the tunables!!!

When sending messages, the third parameter must be the size of
the actual message, not the size of the 'struct msgbuf', which
will be sizeof(long) bytes bigger.  If you don't pay attention
to this, you will get message trashing.   I can't recall now how,
when, or why this happens, but I guarantee that it will be mysterious,
and usually fatal.

		 struct msgbuf {
			 long    mtype;	  /* message type */
			 char    mtext[1];       /* message text */
		 };

So the safe way to use 'msgsnd' is:

typedef struct {
	long mtype;
	struct {
		char buf[10];
		int xxx;
		double yyy;
		etc...
	} mtext;
} MSG;

MSG message;

	1. msgsnd( msqid, &message, sizeof(message.mtext), 0);
OR
	2. msgsnd( msqid, &message, sizeof(message)-sizeof(long), 0);

I prefer #1.

I also prefer to send message with the fourth parameter as 0.  This will
make the message block if there is no room at the time.  It is more normal
for the message to block in a heavily loaded system then not, so you
will probably NOT want to die if you can't send the message because
there's no room.  If you are worried about deadlock, put in an
alarm call so you can time out.

When receiving messages, check for EINTR if you get a -1.
You will usually want to just wrap around and try again if you get
an interrupt (usually from an alarm call, or some other friendly signal).


Hope this (long-winded) yakking helps somebody.


GB

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

From: George Bogatko <bogatko at lzga.att.com>
Subject: Re: Help needed with System V message queues
Keywords: SYSV messagequeue
Date: 8 Aug 90 16:38:08 GMT
To:       unix-wizards at sem.brl.mil


HI:
	here is the pic file for the previous article.

*******
 .nf
 .PS
scale=100
define t851 |
[ box invis ht 74 wid 320 with .sw at 0,0
"\fR\s16\&Mapping a Message Queue ID \f1\s0" at 160,62
"\fR\s16\&to A 28 Byte Message\f1\s0" at 160,37
"\fR\s16\&in Kernal Memory\f1\s0" at 160,12
] |

define t850 |
[ box invis ht 56 wid 82 with .sw at 0,0
"\fR\s12\&MESSAGE\f1\s0" at 41,47
"\fR\s12\&QUEUE\f1\s0" at 41,28
"\fR\s12\&ID\f1\s0" at 41,9
] |

define t849 |
[ box invis ht 96 wid 16 with .sw at 0,0
"\fR\s10\&M\f1\s0" at 8,88
"\fR\s10\&S\f1\s0" at 8,72
"\fR\s10\&G\f1\s0" at 8,56
"\fR\s10\&T\f1\s0" at 8,40
"\fR\s10\&Q\f1\s0" at 8,24
"\fR\s10\&L\f1\s0" at 8,8
] |

define t848 |
[ box invis ht 64 wid 8 with .sw at 0,0
"\fR\s10\&.\f1\s0" at 4,56
"\fR\s10\&.\f1\s0" at 4,40
"\fR\s10\&.\f1\s0" at 4,24
"\fR\s10\&\f1\s0" at 4,8
] |

define t833 |
[ box invis ht 96 wid 16 with .sw at 0,0
"\fR\s10\&M\f1\s0" at 8,88
"\fR\s10\&S\f1\s0" at 8,72
"\fR\s10\&G\f1\s0" at 8,56
"\fR\s10\&M\f1\s0" at 8,40
"\fR\s10\&N\f1\s0" at 8,24
"\fR\s10\&I\f1\s0" at 8,8
] |

define t829 |
[ box invis ht 64 wid 8 with .sw at 0,0
"\fR\s10\&.\f1\s0" at 4,56
"\fR\s10\&.\f1\s0" at 4,40
"\fR\s10\&.\f1\s0" at 4,24
"\fR\s10\&\f1\s0" at 4,8
] |

define t823 |
[ box invis ht 96 wid 40 with .sw at 0,0
"\fR\s10\&M\f1\s0" at 20,88
"\fR\s10\&S\f1\s0" at 20,72
"\fR\s10\&G\f1\s0" at 20,56
"\fR\s10\&  S  \f1\s0" at 20,40
"\fR\s10\&E\f1\s0" at 20,24
"\fR\s10\&G\f1\s0" at 20,8
] |

define t809 |
[ box invis ht 64 wid 8 with .sw at 0,0
"\fR\s10\&.\f1\s0" at 4,56
"\fR\s10\&.\f1\s0" at 4,40
"\fR\s10\&.\f1\s0" at 4,24
"\fR\s10\&\f1\s0" at 4,8
] |

define t800 |
[ box invis ht 192 wid 16 with .sw at 0,0
"\fR\s10\&M\f1\s0" at 8,184
"\fR\s10\&A\f1\s0" at 8,168
"\fR\s10\&P\f1\s0" at 8,152
"\fR\s10\&P\f1\s0" at 8,136
"\fR\s10\&E\f1\s0" at 8,120
"\fR\s10\&D\f1\s0" at 8,104
"\fR\s10\&\f1\s0" at 8,88
"\fR\s10\&S\f1\s0" at 8,72
"\fR\s10\&L\f1\s0" at 8,56
"\fR\s10\&O\f1\s0" at 8,40
"\fR\s10\&T\f1\s0" at 8,24
"\fR\s10\&S\f1\s0" at 8,8
] |

define m0 |
[ box invis ht 96 wid 32 with .sw at 0,0
line  from 16,0 to 16,96 
line  from 0,0 to 32,0 
] |

box invis ht 784 wid 512 with .sw at 0,0
t851 with .nw at 114,780
line  from 464,688 to 464,648 
line -> from 104,624 to 176,624 
t850 with .nw at 11,645
box ht 72 wid 104 with .nw at 0,656 
t849 with .nw at 456,634
t848 with .nw at 396,474
"\fR\s10\&struct msg\f1\s0" at 400,406
"\fR\s10\&struct msg\f1\s0" at 400,486
"\fR\s10\&struct msg\f1\s0" at 400,518
"\fR\s10\&struct msg\f1\s0" at 400,502
"\fR\s10\&struct msg\f1\s0" at 400,534
"\fR\s10\&struct msg\f1\s0" at 400,550
"\fR\s10\&struct msg\f1\s0" at 400,566
"\fR\s10\&struct msg\f1\s0" at 400,582
"\fR\s10\&struct msg\f1\s0" at 400,598
"\fR\s10\&struct msg\f1\s0" at 400,614
"\fR\s10\&struct msg\f1\s0" at 400,630
"\fR\s10\&struct msg\f1\s0" at 400,662
"\fR\s10\&struct msg\f1\s0" at 400,646
"\fR\s10\&struct msg\f1\s0" at 400,678
line  from 360,416 to 440,416 
line  from 360,480 to 440,480 
line  from 360,496 to 440,496 
line  from 360,512 to 440,512 
line  from 360,528 to 440,528 
line  from 360,544 to 440,544 
line  from 360,560 to 440,560 
line  from 360,576 to 440,576 
line  from 360,592 to 440,592 
line  from 360,608 to 440,608 
line  from 360,624 to 440,624 
line  from 360,640 to 440,640 
line  from 360,656 to 440,656 
line  from 360,672 to 440,672 
box ht 288 wid 80 with .nw at 360,688 
line  from 448,400 to 480,400 
line  from 448,688 to 480,688 
t833 with .nw at 144,590
"\fR\s10\&struct msqid_ds\f1\s0" at 236,570
"\fR\s10\&struct msqid_ds\f1\s0" at 236,594
"\fR\s10\&struct msqid_ds\f1\s0" at 236,618
t829 with .nw at 232,506
box ht 264 wid 112 with .nw at 176,680 
line  from 176,440 to 288,440 
line  from 176,512 to 288,512 
line  from 176,536 to 288,536 
line  from 176,560 to 288,560 
line  from 176,584 to 288,584 
line  from 176,608 to 288,608 
line  from 176,632 to 288,632 
line  from 176,656 to 288,656 
"\fR\s10\&struct msqid_ds\f1\s0" at 236,666
"\fR\s10\&struct msqid_ds\f1\s0" at 236,642
"\fR\s10\&struct msqid_ds\f1\s0" at 232,426
"\fR\s10\&struct msqid_ds\f1\s0" at 236,522
"\fR\s10\&struct msqid_ds\f1\s0" at 236,546
line  from 136,416 to 168,416 
line  from 136,680 to 168,680 
line  from 152,416 to 152,488 
line  from 152,680 to 152,600 
line  from 296,320 to 296,280 
line  from 280,320 to 312,320 
line  from 296,0 to 296,64 
line  from 280,0 to 312,0 
m0 with .nw at 136,96
line  from 152,320 to 152,216 
line  from 136,320 to 168,320 
t823 with .nw at 132,202
line  from 176,344 to 192,344 
line  from 176,328 to 176,360 
"\fR\s10\&MSGSSZ\f1\s0" at 224,342
line  from 272,328 to 272,360 
line  from 272,344 to 256,344 
line  from 272,248 to 336,304 dotted
line  from 336,248 to 496,248 dotted
box ht 240 wid 160 with .nw at 336,304 
"\fR\s16\&1-8\f1\s0" at 372,273
"\fR\s12\&USED\f1\s0" at 444,273
"\fR\s16\&17-24\f1\s0" at 376,177
"\fR\s12\&USED\f1\s0" at 448,177
"\fR\s12\&USED\f1\s0" at 444,225
"\fR\s16\&9-16\f1\s0" at 376,225
"\fR\s16\&29-32\f1\s0" at 444,125
"\fR\s16\&25-28\f1\s0" at 376,125
"\fR\s12\&WASTED\f1\s0" at 452,89
"\fR\s12\&USED\f1\s0" at 376,89
line  from 408,152 to 336,152 dotted
line  from 408,152 to 408,64 
line  from 408,152 to 496,152 
line  from 336,200 to 496,200 dotted
"\fR\s12\&8\f1\s0" at 224,233
"\fR\s12\&8\f1\s0" at 224,305
t809 with .nw at 220,94
box ht 320 wid 96 with .nw at 176,320 
line  from 176,32 to 272,32 
line  from 176,104 to 272,104 
line  from 176,128 to 272,128 
line  from 176,152 to 272,152 
line  from 176,176 to 272,176 
line  from 176,200 to 272,200 
line  from 176,224 to 272,224 
line  from 176,248 to 272,248 
line  from 176,272 to 272,272 
line  from 176,296 to 272,296 
"\fR\s12\&8\f1\s0" at 224,281
"\fR\s12\&8\f1\s0" at 224,257
"\fR\s12\&8\f1\s0" at 224,113
"\fR\s12\&8\f1\s0" at 224,13
"\fR\s12\&8\f1\s0" at 224,137
"\fR\s12\&8\f1\s0" at 224,161
"\fR\s12\&8\f1\s0" at 224,185
"\fR\s12\&8\f1\s0" at 224,209
line  from 272,152 to 336,64 dotted
spline -> from 440,536\
to 512,536\
to 512,376\
to 120,376\
to 120,248\
to 176,248
spline -> from 360,536\
to 312,512\
to 360,488
spline -> from 360,584\
to 320,552\
to 360,536
spline -> from 360,632\
to 328,600\
to 360,584
line -> from 288,624 to 360,632 
t800 with .nw at 288,262
"\fR\s10\&SLOT 7\f1\s0" at 532,110
"\fR\s10\&SLOT 6\f1\s0" at 532,178
"\fR\s10\&SLOT 5\f1\s0" at 532,222
"\fR\s10\&SLOT 4\f1\s0" at 532,274
line  from 464,400 to 464,528 
 .PE
 .fi

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

From: Gilles Courcoux <gilles at pase60.convergent.com>
Subject: Re: nested loops
Date: 10 Aug 90 16:15:51 GMT
Sender: root at risky.convergent.com
To:       unix-wizards at sem.brl.mil

In article <4103 at herbie.misemi> you wrote:
>The problem lies in the  $`echo $i` statment

Right, double variable expansion like that is resolved through the use
of the eval(1) command as in :
	eval echo '$'$i

When the shell read the command, it expands it into 
	eval echo $them			# the first time !

and then eval(1) do his job : evaluating its arguments, including
variables expansion and then execute the command which is by now :
	echo one two three

The echo(1) command is needed because eval(1) then exec(2)utes its
first argument.

Your script become :

this="one two three"
that="four five six seven"
them="eight nine ten"
all="this that them"
#
for i in $all
do
	for j in `eval echo '$'$i`
	do
	echo $i $j
	done
done

Have a nice day,

Gilles Courcoux                        E-mail: sun!pyramid!ctnews!pase60!gilles
Unisys Network Computing Group         Phone:  (408) 435-7692

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

From: Chris Bertin <chrisb at risky.convergent.com>
Subject: evaluating ${10} and above in sh/ksh
Keywords: sh, ksh, eval
Date: 10 Aug 90 17:58:37 GMT
To:       unix-wizards at sem.brl.mil

There doesn't seem to be a way, in sh or ksh, to evaluate $10 and higher.
$10 and higher are evaluated as ${1}0, ${1}1, etc...
		     instead of ${10}, ${11}, etc...
I have tried many different ways and they all fail. Do you know one
that will work?

#! /bin/sh

set a b c d e f g h i j k l

arg=0

while [ $arg -le $# ]; do
	echo "evaluating \$$arg"
	eval echo $"$arg"
	eval echo $"${arg}"
	eval echo "$`eval echo $arg`"
	# Now, some of the crazy things I tried.
	# ( The parens are there when eval causes an error )
	echo "\${$arg} results in \c"
	( eval echo "\${$arg}" )
	echo "$`echo '{'``eval echo $arg``echo '}'` results in \c"
	( eval echo "$`echo '{'``eval echo $arg``echo '}'`" )
	arg=`expr $arg + 1`
done
-- 
Chris Bertin		|   chrisb at risky.Convergent.COM
Unisys			|		or
(408) 435-3762		| ...!uunet!pyramid!ctnews!risky!chrisb

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

From: "Jay A. Konigsberg" <jak at sactoh0.uucp>
Subject: Re: Getting CPU information on unterminatted child processes
Date: 11 Aug 90 09:43:04 GMT
To:       unix-wizards at sem.brl.mil

In article <1990Aug7.215320.13715 at mozart.amd.com> leight at mozart.amd.com (Timothy Leight) writes:
>I am interested in getting accurate cpu usage information
>on unterminated child processes. The getrusage() and/or times()
>system calls only return information on terminated children.
>
>What is the best method for getting this information?
>
Well, I don't know the best method, but I think I can point you in the
right direction (since no one else did).

ps -lf will provide much of the information needed, though it may not
produce enough and any way you invoke it (peopen or shell script), it
will be slow.

Another aproach is to get the information directly out of /dev/kmem.
However, all I know how to do there is get overall system usage
parameters. Specific information of /dev/kmem is probably system
specific and un-portable. However, the Sys V and Xenix 2.3.? header
file is: /usr/include/sys/sysinfo.h

Getting information about kernel level data structures on the net is
a little like asking for the moon, no one seems to have it. Anyway,
perhaps this post will generate a little discussion. I would like to
know more specifics about the Sys V kernel myself.

-- 
 -------------------------------------------------------------
Jay @ SAC-UNIX, Sacramento, Ca.   UUCP=...pacbell!sactoh0!jak
If something is worth doing, its worth doing correctly.

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

From: Randal Schwartz <merlyn at iwarp.intel.com>
Subject: Re: Cron - First Saturday of the month
Date: 12 Aug 90 05:27:30 GMT

00.90Aug1014
Sender: news at iwarp.intel.com
To:       unix-wizards at sem.brl.mil

In article <KPC00.90Aug10144909 at JUTS.ccc.amdahl.com>, kpc00 at JUTS (kpc) writes:
| Also, now that the OR is in there, which of merlyn's possibilities was
| correct?  It makes one wonder what things, if any, are not possible in
| cron without putting something in the command to be executed.

Well, we already have one.  The original request!  (See Subject: :-)

Sigh.
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn at iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

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


End of UNIX-WIZARDS Digest
**************************



More information about the Comp.unix.wizards mailing list