You are on page 1of 65

c 1.

Process Control

c 1.1 Creating new processes: fork()


p 1.1.1 What does fork() do?
p 1.1.2 What's the difference between fork() and vfork()?
p 1.1.3 Why use _exit rather than exit in the child branch of a fork?
c 1.2 Environment variables
p 1.2.1 How can I get/set an environment variable from a program?
p 1.2.2 How can I read the whole environment?
c 1.3 How can I sleep for less than a second?
c 1.4 How can I get a finer-grained version of alarm()?
c 1.5 How can a parent and child process communicate?
c 1.6 How do I get rid of zombie processes?
p 1.6.1 What is a zombie?
p 1.6.2 How do I prevent them from occuring?
c 1.7 How do I get my program to act like a daemon?
c 1.8 How can I look at process in the system like ps does?
c 1.9 Given a pid, how can I tell if it's a running program?
c 1.10 What's the return value of system/pclose/waitpid?
c 1.11 How do I find out about a process' memory usage?
c 1.12 Why do processes never decrease in size?
c 1.13 How do I change the name of my program (as seen by `ps')?
c 1.14 How can I find a process' executable file?
p 1.14.1 So where do I put my configuration files then?
c 1.15 Why doesn't my process get SIGHUP when its parent dies?
c 1.16 How can I kill all descendents of a process?

c 2. General File handling (including pipes and sockets)

c 2.1 How to manage multiple connections?


p 2.1.1 How do I use select()?
p 2.1.2 How do I use poll()?
p 2.1.3 Can I use SysV IPC at the same time as select or poll?
c 2.2 How can I tell when the other end of a connection shuts down?
c 2.3 Best way to read directories?
c 2.4 How can I find out if someone else has a file open?
c 2.5 How do I `lock' a file?
c 2.6 How do I find out if a file has been updated by another process?
c 2.7 How does the `du' utility work?
c 2.8 How do I find the size of a file?
c 2.9 How do I expand `~' in a filename like the shell does?
c 2.10 What can I do with named pipes (FIFOs)?
p 2.10.1 What is a named pipe?
p 2.10.2 How do I create a named pipe?
p 2.10.3 How do I use a named pipe?
p 2.10.4 Can I use a named pipe across NFS?
p 2.10.5 Can multiple processes write to the pipe simultaneously?
p 2.10.6 Using named pipes in applications

c 3. Terminal I/O

c 3.1 How can I make my program not echo input?


c 3.2 How can I read single characters from the terminal?
c 3.3 How can I check and see if a key was pressed?
c 3.4 How can I move the cursor around the screen?
c 3.5 What are pttys?
c 3.6 How to handle a serial port or modem?
p 3.6.1 Serial device names and types
p 3.6.2 Setting up termios flags
å 3.6.2.1 c_iflag
å 3.6.2.2 c_oflag
å 3.6.2.3 c_cflag
å 3.6.2.4 c_lflag
å 3.6.2.5 c_cc

c 4. System Information

c 4.1 How can I tell how much memory my system has?


c 4.2 How do I check a user's password?
p 4.2.1 How do I get a user's password?
p 4.2.2 How do I get shadow passwords by uid?
p 4.2.3 How do I verify a user's password?

c 5. Miscellaneous programming

c 5.1 How do I compare strings using wildcards?


p 5.1.1 How do I compare strings using filename patterns?
p 5.1.2 How do I compare strings using regular expressions?
c 5.2 What's the best way to send mail from a program?
p 5.2.1 The simple method: /bin/mail
p 5.2.2 Invoking the MTA directly: /usr/lib/sendmail
å 5.2.2.1 Supplying the envelope explicitly
å 5.2.2.2 Allowing sendmail to deduce the recipients

c 6. Use of tools

c 6.1 How can I debug the children after a fork?


c 6.2 How to build library from other libraries?
c 6.3 How to create shared libraries / dlls?
c 6.4 Can I replace objects in a shared library?
c 6.5 How can I generate a stack dump from within a running program?
c Examples

c Catching SIGCHLD
c oeading the process table -- SUNOS 4 version
c oeading the process table -- SYSV version
c oeading the process table -- AIX 4.2 version
c oeading the process table using popen and ps
c Daemon utility functions
c Modem handling example
c ´ob Control example

1. Process Control
1.1 Creating new processes: fork()
1.1.1 What does fork() do?
â 

 
â  

 pp 

The p function is used to create a new process from an existing process. The new process
is called the child process, and the existing process is called the parent. You can tell which is
which by checking the return value from p. The parent gets the child's pid returned to him,
but the child gets 0 returned to him. Thus this simple code illustrate's the basics of it.

  

  p

 
 !  " p  
 #p$ p % p   
p& 
 p p p  p p  $$p
 
 p'(p )'
%

 *
  p+p    
 !&    pp, 
  
 %  p - " pp p$  -  
. *

 
  -  +p   - -  &   
   '/ &   01'" 
2

Of course, one can use   instead of  , but the above form is a useful
idiom.

Of help when doing this is knowing just what is and is not inherited by the child. This list can
vary depending on Unix implementation, so take it with a grain of salt. Note that the child gets
?  of these things, not the real thing.

Inherited by the child from the parent:

c process credentials (real/effective/saved UIDs and GIDs)


c environment
c stack
c memory
c open file descriptors (note that the underlying file positions are shared between the parent
and child, which can be confusing)
c close-on-exec flags
c signal handling settings
c nice value
c scheduler class
c process group ID
c session ID
c current working directory
c root directory
c file mode creation mask (umask)
c resource limits
c controlling terminal

Unique to the child:

c process ID
c different parent process ID
c Own copy of file descriptors and directory streams.
c process, text, data and other memory locks are NOT inherited.
c process times, in the tms struct
c resource utilizations are set to 0
c pending signals initialized to the empty set
c timers created by timer_create not inherited
c asynchronous input or output operations not inherited

1.1.2 What's the difference between fork() and vfork()?


Some systems have a system call p, which was originally designed as a lower-overhead
version of p. Since p involved copying the entire address space of the process, and
was therefore quite expensive, the p function was introduced (in 3.0BSD).

¦owever, since p was introduced, the implementation of p has improved
drastically, most notably with the introduction of `copy-on-write', where the copying of the
process address space is transparently faked by allowing both processes to refer to the same
physical memory until either of them modify it. This largely removes the justification for
p; indeed, a large proportion of systems now lack the original functionality of p
completely. For compatibility, though, there may still be a p call present, that simply calls
p without attempting to emulate all of the p semantics.

As a result, it is  unwise to actually make use of any of the differences between p and
p. Indeed, it is probably unwise to use p at all, unless you know exactly ¬  you
want to.

The basic difference between the two is that when a new process is created with p, the
parent process is temporarily suspended, and the child process might borrow the parent's address
space. This strange state of affairs continues until the child process either exits, or calls
., at which point the parent process continues.

This means that the child process of a p must be careful to avoid unexpectedly modifying
variables of the parent process. In particular, the child process must not return from the function
containing the p call, and it must not call .  (if it needs to exit, it should use
. ; actually, this is also true for the child of a normal p).

1.1.3 Why use _exit rather than exit in the child branch of a fork?

There are a few differences between .  and .  that become significant when p,
and especially p, is used.

The basic difference between .  and .  is that the former performs clean-up related
to user-mode constructs in the library, and calls user-supplied cleanup functions, whereas the
latter performs only the kernel cleanup for the process.

In the child branch of a p, it is normally incorrect to use . , because that can lead to
stdio buffers being flushed twice, and temporary files being unexpectedly removed. In C++ code
the situation is worse, because destructors for static objects may be run incorrectly. (There are
some unusual cases, like daemons, where the  should call .  rather than the child;
the basic rule, applicable in the overwhelming majority of cases, is that .  should be called
only once for each entry into $ .)

In the child branch of a p, the use of .  is even more dangerous, since it will affect
the state of the  process.
1.2 Environment variables
1.2.1 ¦ow can I get/set an environment variable from a program?

Getting the value of an environment variable is done by using - .

â   %

 - p  $

Setting the value of an environment variable is done by using  .

â   %

     -

The string passed to putenv must  be freed or made invalid, since a pointer to it is kept by
 . This means that it must either be a static buffer or allocated off the heap. The string
can be freed if the environment variable is redefined or deleted via another call to  .

oemember that environment variables are inherited; each process has a separate copy of the
environment. As a result, you can't change the value of an environment variable in another
process, such as the shell.

Suppose you wanted to get the value for the (345 environment variable. You would use this
code:

 

- '(345'

  '(p  p$  %(345 '


   '0 1'"
2
 

   'p   1'
2

Now suppose you wanted to create a new environment variable called 56784, with a value of
56789. This is how you'd do it.

 %:;<=>

  %"'567840 '"'56789'

  %

   '#p
"  p&   $$p
p0 1'"%
 5 - . p p$  - 
p&   p   
2

1.2.2 ¦ow can I read the whole environment?

If you don't know the names of the environment variables, then the -  function isn't much
use. In this case, you have to dig deeper into how the environment is stored.

A global variable,  p, holds a pointer to an array of pointers to environment strings, each
string in the form '?853'. A ?@99 pointer is used to mark the end of the array. Here's a
trivial program to print the current environment (like   ):

â   p

.   p

 $ 

   p
 
    AA
   '0 1'" 
 *
2

In general, the  p variable is also passed as the third, optional, parameter to $ ; that
is, the above could have been written:

â   p

 $   -" -"  

 
    AA
   '0 1'" 
 *
2

However, while pretty universally supported, this method isn't actually defined by the POSIX
standards. (It's also less useful, in general.)

1.3 ¦ow can I sleep for less than a second?


The   function, which is available on all Unixes, only allows for a duration specified in
seconds. If you want finer granularity, then you need to look for alternatives:

c Many systems have a function   


c You can use   or p, specifying no file descriptors to test; a common
technique is to write a    function based on either of these (see the
comp.unix.questions FAQ for some examples)
c If your system has itimers (most do), you can roll your own    using them (see
the BSD sources for    for how to do this)
c If you have POSIX realtime, there is a p   function

Of the above,   is probably the most portable (and strangely, it is often much more
efficient than    or an itimer-based method). However, the behaviour may be different if
signals are caught while asleep; this may or may not be an issue depending on the application.

Whichever route you choose, it is important to realise that you may be constrained by the timer
resolution of the system (some systems allow very short time intervals to be specified, others
have a resolution of, say, 10ms and will round all timings to that). Also, as for  , the
delay you specify is only a   value; after the specified period elapses, there will be an
indeterminate delay before your process next gets scheduled.

1.4 ¦ow can I get a finer-grained version of alarm()?


Modern Unixes tend to implement alarms using the  $ function, which has a higher
resolution and more options than the simple $ function. One should generally assume that
$ and  $B(B5344389 may be the same underlying timer, and accessing it
both ways may cause confusion.

Itimers can be used to implement either one-shot or repeating signals; also, there are generally 3
separate timers available:

B(B5344389
counts real (wall clock) time, and sends the #BC8945 signal
B(B5347B4(@89
counts process virtual (user CPU) time, and sends the #BC7(8945 signal
B(B534D4EF
counts user and system CPU time, and sends the #BCD4EF signal; it is intended for
interpreters to use for profiling.

Itimers, however, are not part of many of the standards, despite having been present since
4.2BSD. The POSIX realtime extensions define some similar, but different, functions.

1.5 ¦ow can a parent and child process communicate?


A parent and child can communicate through any of the normal inter-process communication
schemes (pipes, sockets, message queues, shared memory), but also have some special ways to
communicate that take advantage of their relationship as a parent and child.

One of the most obvious is that the parent can get the exit status of the child.
Since the child inherits file descriptors from its parent, the parent can open both ends of a pipe,
fork, then the parent close one end and the child close the other end of the pipe. This is what
happens when you call the p  routine to run another program from within yours, i.e. you
can write to the file descriptor returned from p  and the child process sees it as its stdin, or
you can read from the file descriptor and see what the program wrote to its stdout. (The mode
parameter to p  defines which; if you want to do both, then you can do the plumbing
yourself without too much difficulty.)

Also, the child process inherits memory segments mmapped anonymously (or by mmapping the
special file G  +p&) by the parent; these shared memory segments are not accessible from
unrelated processes.

1.6 ¦ow do I get rid of zombie processes?


1.6.1 What is a zombie?

When a program forks and the child finishes before the parent, the kernel still keeps some of its
information about the child in case the parent might need it -- for example, the parent may need
to check the child's exit status. To be able to get this information, the parent calls  ; when
this happens, the kernel can discard the information.

In the interval between the child terminating and the parent calling  , the child is said to be
a `zombie'. (If you do `ps', the child will have a `Z' in its status field to indicate this.) Even
though it's not running, it's still taking up an entry in the process table. (It consumes no other
resources, but some utilities may show bogus figures for e.g. CPU usage; this is because some
parts of the process table entry have been overlaid by accounting info to save space.)

This is not good, as the process table has a fixed number of entries and it is possible for the
system to run out of them. Even if the system doesn't run out, there is a limit on the number of
processes each user can run, which is usually smaller than the system's limit. This is one of the
reasons why you should always check if p failed, by the way!

If the parent terminates without calling wait(), the child is `adopted' by  , which handles the
work necessary to cleanup after the child. (This is a special system program with process ID 1 --
it's actually the first program to run after the system boots up).

1.6.2 ¦ow do I prevent them from occuring?

You need to ensure that your parent process calls   (or  ,  H, etc.) for
every child process that terminates; or, on some systems, you can instruct the system that you are
uninterested in child exit states.

Another approach is to p ¬?, and have the immediate child process exit straight away.
This causes the grandchild process to be orphaned, so the init process is responsible for cleaning
it up. For code to do this, see the function p; in the examples section.
To ignore child exit states, you need to do the following (check your system's manpages to see if
this works):

   - p 


  #BCBC?
â #8?E/9IJ8B(
  - #8?E/9IJ8B(
â 
  - *
â 
 -$
 K  $ 
 - p#BC/!9I"K "?@99

If this is successful, then the   functions are prevented from working; if any of them are
called, they will wait until 

child processes have terminated, then return failure with p


3/!B9I.

The other technique is to catch the SIGCHLD signal, and have the signal handler call  
or  H. See the examples section for a complete program.

1.7 ¦ow do I get my program to act like a daemon?


A daemon process is usually defined as a background process that does not belong to a terminal
session. Many system services are performed by daemons; network services, printing etc.

Simply invoking a program in the background isn't really adequate for these long-running
programs; that does not correctly detach the process from the terminal session that started it.
Also, the conventional way of starting daemons is simply to issue the command manually or
from an rc script; the daemon is expected to put  
into the background.

Here are the steps to become a daemon:

1. p so the parent can exit, this returns control to the command line or shell invoking
your program. This step is required so that the new process is guaranteed not to be a
process group leader. The next step,  , fails if you're a process group leader.
2.   to become a process group and session group leader. Since a controlling
terminal is associated with a session, and this new session has not yet acquired a
controlling terminal our process now has no controlling terminal, which is a Good Thing
for daemons.
3. p again so the parent, (the session group leader), can exit. This means that we, as a
non-session group leader, can never regain a controlling terminal.
4.  ' ' to ensure that our process doesn't keep any directory in use. Failure to do
this could make it so that an administrator couldn't unmount a filesystem, because it was
our current directory. [Equivalently, we could change to any directory containing files
important to the daemon's operation.]
5. $ * so that we have complete control over the permissions of anything we write.
We don't know what umask we may have inherited. [This step is optional]
6. p  fds 0, 1, and 2. This releases the standard in, out, and error we inherited from
our parent process. We have no way of knowing where these fds might have been
redirected to. Note that many daemons use
p to determine the limit
#/ED3?58L. #/ED3?58L tells you the maximun open files/process. Then in a loop,
the daemon can close all possible file descriptors. You have to decide if you need to do
this or not. If you think that there might be file-descriptors open you should close them,
since there's a limit on number of concurrent file descriptors.
7. Establish new open descriptors for stdin, stdout and stderr. Even if you don't plan to use
them, it is still a good idea to have them open. The precise handling of these is a matter of
taste; if you have a logfile, for example, you might wish to open it as stdout or stderr, and
open G  & as stdin; alternatively, you could open G  p p& as stderr
and/or stdout, and G  & as stdin, or any other combination that makes sense for
your particular daemon.

Almost none of this is necessary (or advisable) if your daemon is being started by  . In that
case, stdin, stdout and stderr are all set up for you to refer to the network connection, and the
ps and session manipulation should  be done (to avoid confusing  ). Only the
  and $  steps remain as useful.

1.8 ¦ow can I look at process in the system like ps does?


You really ’  want to do this.

The most portable way, by far, is to do p  $"'' and parse the output. (pscmd should
be something like G' '& on SysV systems; on BSD systems there are many possible
display options: choose one.)

In the examples section, there are two complete versions of this; one for SunOS 4, which
requires root permission to run and uses the G$ & routines to read the information from
kernel data structures; and another for SVo4 systems (including SunOS 5), which uses the
G p& filesystem.

It's even easier on systems with an SVo4.2-style G p&; just read a psinfo_t structure from the
file G p DBI p& for each PID of interest. However, this method, while probably the
cleanest, is also perhaps the least well-supported. (On FreeBSD's G p&, you read a semi-
undocumented printable string from G p DBI   &; Linux has something similar.)

1.9 Given a pid, how can I tell if it's a running program?


Use   with 0 for the signal number.

There are four possible results from this call:

c   returns 0
p this implies that a process exists with the given PID, and the system would allow
you to send signals to it. It is system-dependent whether the process could be a
zombie.
c   returns @math{-1}, p3#4/!
p either no process exists with the given PID, or security enhancements are causing
the system to deny its existence. (On some systems, the process could be a
zombie.)
c   returns @math{-1}, p3D345
p the system would not allow you to kill the specified process. This means that
either the process exists (again, it could be a zombie) or draconian security
enhancements are present (e.g. your process is not allowed to send signals to
 ’).
c   returns @math{-1}, with some other value of p
p you are in trouble!

The most-used technique is to assume that success or failure with 3D345 implies that the process
exists, and any other error implies that it doesn't.

An alternative exists, if you are writing specifically for a system (or all those systems) that
provide a G p& filesystem: checking for the existence of G p DBI& may work.

1.10 What's the return value of system/pclose/waitpid?


The return value of
$, p , or   doesn't seem to be the exit value of my
process... or the exit value is shifted left 8 bits... what's the deal?

The man page is right, and so are you! If you read the man page for   you'll find that
the return code for the process is encoded. The value returned by the process is normally in the
top 16 bits, and the rest is used for other things. You can't rely on this though, not if you want to
be portable, so the suggestion is that you use the macros provided. These are usually documented
under   or   .

Macros defined for the purpose (in G


 &) include (stat is the value returned by
 ):

JBF3LB(3I  
Non zero if child exited normally.
J3LB(#(8(@#  
exit code returned by child
JBF#BC?893I  
Non-zero if child was terminated by a signal
J(345#BC  
signal number that terminated child
JBF#(EDD3I  
non-zero if child is stopped
J#(ED#BC  
number of signal that stopped child
JBF/E?(B?@3I  
non-zero if status was for continued child
J/E43I@5D  
If JBF#BC?893I   is non-zero, this is non-zero if the process left behind a core
dump.

1.11 ¦ow do I find out about a process' memory usage?


Look at -  -, if available.

1.12 Why do processes never decrease in size?


When you free memory back to the heap with , on almost all systems that ’  reduce
the memory usage of your program. The memory d is still part of the process' address
space, and will be used to satisfy future $p requests.

If you really need to free memory back to the system, look at using $$  to allocate private
anonymous mappings. When these are unmapped, the memory really is released back to the
system. Certain implementations of $p (e.g. in the GNU C Library) automatically use
$$  where available to perform large allocations; these blocks are then returned to the system
on .

Of course, if your program increases in size when you think it shouldn't, you may have a
`memory leak' -- a bug in your program that results in unused memory not being freed.

1.13 ¦ow do I change the name of my program (as seen by


`ps')?
On BSDish systems, the program actually looks into the address space of the running process
to find the current -:>, and displays that. That enables a program to change its `name' simply
by modifying -:>.

On SysVish systems, the command name and usually the first 80 bytes of the parameters are
stored in the process' u-area, and so can't be directly modified. There may be a system call to
change this (unlikely), but otherwise the only way is to perform an ., or write into kernel
memory (dangerous, and only possible if running as root).

Some systems (notably Solaris) may have two separate versions of , one in G   %  &
with SysV behaviour, and one in G   % & with BSD behaviour. On these systems, if you
change -:>, then the BSD version of will reflect the change, and the SysV version won't.

Check to see if your system has a function  p .

1.14 ¦ow can I find a process' executable file?


This would be a good candidate for a list of `Frequently Unanswered Questions', because the fact
of asking the question usually means that the design of the program is flawed. 

You can make a `best guess' by looking at the value of -:*>. If this contains a G &, then it is
probably the absolute or relative (to the current directory at program start) path of the executable.
If it does not, then you can mimic the shell's search of the D8(! variable, looking for the
program. However, success is not guaranteed, since it is possible to invoke programs with
arbitrary values of -:*>, and in any case the executable may have been renamed or deleted
since it was started.

If all you want is to be able to print an appropriate invocation name with error messages, then the
best approach is to have $  save the value of -:*> in a global variable for use by the
entire program. While there is no guarantee whatsoever that the value in -:*> will be
meaningful, it is the best option available in most circumstances.

The most common reason people ask this question is in order to locate configuration files with
their program. This is considered to be bad form; directories containing executables should
contain   except executables, and administrative requirements often make it desirable for
configuration files to be located on different filesystems to executables.

A less common, but more legitimate, reason to do this is to allow the program to call . 
 
; this is a method used (e.g. by some versions of $ ) to completely reinitialise the
process (e.g. if a daemon receives a #BC!@D).

1.14.1 So where do I put my configuration files then?

The correct directory for this usually depends on the particular flavour of Unix you're using;
G  p D8/M8C3&, G   p  %&, G   p  &, or any of several other
possibilities. User-specific configuration files are usually hidden `dotfiles' under N!E53 (e.g.
GN!E53 .&).

From the point of view of a package that is expected to be usable across a range of systems, this
usually implies that the location of any sitewide configuration files will be a compiled-in default,
possibly using a G  .& option on a configure script (Autoconf scripts do this). You
might wish to allow this to be overridden at runtime by an environment variable. (If you're not
using a configure script, then put the default in the Makefile as a GI& option on compiles, or
put it in a Gp -& header file, or something similar.)

User-specific configuration should be either a single dotfile under N!E53, or, if you need multiple
files, a dot-subdirectory. (Files or directories whose names start with a dot are omitted from
directory listings by default.) Avoid creating multiple entries under N!E53, because this can get
very cluttered. Again, you can allow the user to override this location with an environment
variable. Programs should always behave sensibly if they fail to find any per-user configuration.
1.15 Why doesn't my process get SIG¦ P when its parent
dies?
Because it's not supposed to.

#BC!@D is a signal that means, by convention, "the terminal line got hung up". It has nothing to
do with parent processes, and is usually generated by the tty driver (and delivered to the
foreground process group).

However, as part of the session management system, there are exactly two cases where #BC!@D is
sent on the death of a process:

c When the process that dies is the session leader of a session that is attached to a terminal
device, #BC!@D is sent to all processes in the foreground process group of that terminal
device.
c When the death of a process causes a process group to become orphaned, and one or
more processes in the orphaned group are  ’, then #BC!@D and #BC/E?( are sent to
all members of the orphaned group. (An orphaned process group is one where no process
in the group has a parent which is part of the same session, but not the same process
group.)

1.16 ¦ow can I kill all descendents of a process?


There isn't a fully general approach to doing this. While you can determine the relationships
between processes by parsing output, this is unreliable in that it represents only a snapshot of
the system.

However, if you're lauching a subprocess that might spawn further subprocesses of its own, and
you want to be able to kill the entire spawned job at one go, the solution is to put the subprocess
into a new process group, and kill that process group if you need to.

The preferred function for creating process groups is  - . Use this if possible rather than
 -  because the latter differs between systems (on some systems G  - & is
equivalent to G  - *"*&, on others,  -  and  -  are identical).

See the job-control example in the examples section.

Putting a subprocess into its own process group has a number of effects. In particular, unless you
explicitly place the new process group in the foreground, it will be treated as a background job
with these consequences:

c it will be stopped with #BC((B? if it attempts to read from the terminal


c if p p is set in the terminal modes, it will be stopped with #BC((E@ if it attempts to
write to the terminal (attempting to change the terminal modes should also cause this,
independently of the current setting of p p )
c The subprocess will not receive keyboard signals from the terminal (e.g. #BCB?( or
#BCO@B()

In many applications input and output will be redirected anyway, so the most significant effect
will be the lack of keyboard signals. The parent application should arrange to catch at least
#BCB?( and #BCO@B( (and preferably #BC(345 as well) and clean up any background jobs as
necessary.

2. General File handling (including pipes and


sockets)
See also the Sockets FAQ, available at:

http://www.lcg.org/sock-faq/

2.1 ¦ow to manage multiple connections?


I have to monitor more than one (fd/connection/stream) at a time. How do I manage all of them?

Use   or p.

Note:   was introduced in BSD, whereas p is an artifact of SysV SToEAMS. As
such, there are portability issues; pure BSD systems may still lack p, whereas some older
SVo3 systems may not have  . SVo4 added  , and the Posix.1g standard
defines both.

  and p essentially do the same thing, just differently. Both of them examine a set
of file descriptors to see if specific events are pending on any, and then optionally wait for a
specified time for an event to happen.

[Important note: neither   nor p do anything useful when applied to plain files;
they are useful for sockets, pipes, ptys, ttys & possibly other character devices, but this is
system-dependent.]

There the similarity ends....

2.1.1 ¦ow do I use select()?

The interface to   is primarily based on the concept of an   , which is a set of FDs
(usually implemented as a bit-vector). In times past, it was common to assume that FDs were
smaller than 32, and just use an int to store the set, but these days, one usually has more FDs
available, so it is important to use the standard macros for manipulating fd_sets:

    
FIP34EK   $      
FI#3("K    FI p    
FI/94"K   $p FIp$    
FIB##3("K     FI      

In most cases, it is the system's responsibility to ensure that fdsets can handle the whole range of
file descriptors, but in some cases you may have to predefine the FI#3(#BP3 macro. · 
 ’’ ; check your   manpage. Also, some systems have problems handling
more than 1024 file descriptors in  .

The basic interface to select is simple:

      "     "


      "
   .  "   $ $p 

where


the number of FDs to examine; this must be greater than the largest FD in any of the
fdsets,  the actual number of FDs specified
 
the set of FDs to examine for readability
  
the set of FDs to examine for writability
. 
the set of FDs to examine for exceptional status (note: errors are  exceptional statuses)
$p
NULL for infinite timeout, or points to a timeval specifying the maximum wait time (if
  and   both equal zero, then the status of the FDs is polled, but the call
never blocks)

The call returns the number of `ready' FDs found, and the three fdsets are modified in-place, with
only the ready FDs left in the sets. Use the FIB##3( macro to test the returned sets.

Here's a simple example of testing a single FD for readability:

  
  

  
   
   $ 

FIP34EK 
FI#3("K 
      *

  A"K "?@99"?@99"K 
 *
 

 FIB##3("K ,*
2

Note that we can pass ?@99 for fdsets that we aren't interested in testing.

2.1.2 ¦ow do I use poll()?

p accepts a pointer to a list of   p, in which the descriptors and the events you
wish to poll for are stored. The events are specified via a bitwise mask in the events field of the
structure. The instance of the structure will later be filled in and returned to you with any events
which occured. Macros defined by G p& on SVo4 (probably older versions as well), are
used to specify the events in the field. A timeout may be specified in milliseconds, only the type
provided is an integer which is quite perplexing. A timeout of 0 causes p to return
immediately; a value of @math{-1} will suspend poll until an event is found to be true.

  p
   (  p 
 p   (       
 p   3 p  
2

A lot like  , the return value if positive reflects how many descriptors were found to
satisfy the events requested. A zero return value is returned if the timeout period is reached
before any of the events specified have occured. A negative value should immediately be
followed by a check of p, since it signifies an error.

If no events are found,  is cleared, so there's no need for you to do this yourself.

The returned events are tested to contain the event.

Here's an example:

Dpp p  p p?p$ "p! -  p


 
B
p p  p     p
  p
Ip&  $p "p
-   p"ppp 
  p -   

â   %
â   p

â 

 
â  p 
â  p

â  
â p
â   -

â ?E4589I8(8
â !BD4BI8(8;

  p pp$  "  ;

   p p :;>
   

 p :*>
 p :>;
 p :*> DE99B?QDE99D4B
 p :> DE99B?QDE99D4B

 

  p p " -p-;"
 4  
%-  *p    
# &p -  %p - 

  *

    "'3p  p -0 1'" pp
 
2

  p :*> KDE99!@DDE99!@DQQ
 p :*> KDE99344DE99344QQ
 p :*> KDE99?789DE99?789QQ
 p :> KDE99!@DDE99!@DQQ
 p :> KDE99344DE99344QQ
 p :> KDE99?789DE99?789
 *

  p :*> KDE99B?DE99B?
 p :*>"?E4589I8(8
  p :*> KDE99D4BDE99D4B
 p :*>"!BD4BI8(8
  p :> KDE99B?DE99B?
 p :>"?E4589I8(8
  p :> KDE99D4BDE99D4B
 p :>"!BD4BI8(8
2
2

2.1.3 Can I use SysV IPC at the same time as select or poll?

No. (Except on AIX, which has an incredibly ugly kluge to allow this.)

In general, trying to combine the use of   or p with using SysV message queues is
troublesome. SysV IPC objects are not handled by file descriptors, so they can't be passed to
  or p. There are a number of workarounds, of varying degrees of ugliness:
c Abandon SysV IPC completely. 
c p, and have the child process handle the SysV IPC, communicating with the parent
process by a pipe or socket, which the parent process can   on.
c As above, but have the child process do the  , and communicate with the parent
by message queue.
c Arrange for the process that sends messages to you to send a signal after each message.
Warning: handling this right is non-trivial; it's very easy to write code that can
potentially lose messages or deadlock using this method.

(Other methods exist.)

2.2 ¦ow can I tell when the other end of a connection shuts
down?
If you try to read from a pipe, socket, FIFO etc. when the writing end of the connection has been
closed, you get an end-of-file indication ( returns 0 bytes read). If you try and write to a
pipe, socket etc. when the reading end has closed, then a #BCDBD3 signal will be delivered to the
process, killing it unless the signal is caught. (If you ignore or block the signal, the   call
fails with 3DBD3.)

2.3 Best way to read directories?


While historically there have been several different interfaces for this, the only one that really
matters these days the the Posix.1 standard G  & functions.

The function p   opens a specified directory;   reads directory entries from it
in a standardised format; p   does the obvious. Also provided are   ,
  and   which should also be obvious.

If you are looking to expand a wildcard filename, then most systems have the -p% function;
also check out $  to match filenames against a wildcard, or   to traverse entire
directory trees.

2.4 ¦ow can I find out if someone else has a file open?
This is another candidate for `Frequently Unanswered Questions' because, in general, your
program should never be interested in whether someone else has the file open. If you need to
deal with concurrent access to the file, then you should be looking at advisory locking.

This is, in general, too hard to do anyway. Tools like   and  p that find out about open
files do so by grovelling through kernel data structures in a most unhealthy fashion. You can't
usefully invoke them from a program, either, because by the time you've found out that the file
is/isn't open, the information may already be out of date.
2.5 ¦ow do I `lock' a file?
There are three main file locking mechanisms available. All of them are `advisory'[*], which
means that they rely on programs co-operating in order to work. It is therefore vital that all
programs in an application should be consistent in their locking regime, and great care is
required when your programs may be sharing files with third-party software.

[*] Well, actually some Unices permit mandatory locking via the sgid bit -- oTFM for this hack.

Some applications use lock files -- something like GFB93?853p&. Simply testing for the
existence of such files is inadequate though, since a process may have been killed while holding
the lock. The method used by UUCP (probably the most notable example: it uses lock files for
controlling access to modems, remote systems etc.) is to store the PID in the lockfile, and test if
that pid is still running. Even this isn't enough to be sure (since PIDs are recycled); it has to have
a backstop check to see if the lockfile is old, which means that the process holding the lock must
update the file regularly. Messy.

The locking functions are:

p
p
 

p originates with BSD, and is now available in most (but not all) Unices. It is simple and
effective on a single host, but doesn't work at all with NFS. It locks an entire file. Perhaps rather
deceptively, the popular Perl programming language implements its own p where
necessary, conveying the illusion of true portability.

  is the only POSIX-compliant locking mechanism, and is therefore the only truly
portable lock. It is also the most powerful, and the hardest to use. For NFS-mounted file systems,
  requests are passed to a daemon ( p), which communicates with the lockd on
the server host. Unlike p it is capable of record-level locking.

p is merely a simplified programming interface to the locking functions of  .

Whatever locking mechanism you use, it is important to sync all your file IO while the lock is
active:

p
  p p$ pp
 p   p ?3734p p  $
%% 
p
p p$  -  p  p $ -     
p
 " p$ % pp  p   p   
p p$  - 

A few useful   locking recipes (error handling omitted for simplicity) are:

â  
â  

p    pp   

 "F#3(9MJ" pF4I9/M"#33M#3(
2

 p   . pp   

 "F#3(9MJ" pFJ49/M"#33M#3(
2

 p   pp p p 
 p  $
 . -p  

 "F#3(9MJ" pFJ49/M"#33M3?I
2

The function file_lock used by the above is

 p  p p 


" p 

    p 
 


   *
 
 *
  - 
 K 
2

2.6 ¦ow do I find out if a file has been updated by another


process?
This is close to being a Frequently Unanswered Question, because people asking it are often
looking for some notification from the system when a file or directory is changed, and there is no
portable way of getting this. (IoIX has a non-standard facility for monitoring file accesses, but
I've never heard of it being available in any other flavour.)

In general, the best you can do is to use    on the file. (Note: the overhead on    is
quite low, usually much lower than the overhead of  .) By watching the mtime and ctime
of the file, you can detect when it is modified, or deleted/linked/renamed. This is a bit kludgy, so
you might want to rethink ¬  you want to do it.

2.7 ¦ow does the `du' utility work?


 simply traverses the directory structure calling   (or more accurately,   ) on
every file and directory it encounters, adding up the number of blocks consumed by each.

If you want more detail about how it works, then the simple answer is:

Use the source, Luke!

Source for BSD systems (FreeBSD, NetBSD and OpenBSD) is available as unpacked source
trees on their FTP distribution sites; source for GNU versions of utilities is available from any of
the GNU mirrors, but you have to unpack the archives yourself.

2.8 ¦ow do I find the size of a file?


Use  , or    if you have the file open.

These calls fill in a data structure containing all the information about the file that the system
keeps track of; that includes the owner, group, permissions, size, last access time, last
modification time, etc.

The following routine illustrates how to use   to get the file size.

â   %
â   p

â 

 
â 
 

 -   +  "p  +

       

     "K   
 

 +     +
 *
2

2.9 ¦ow do I expand `~' in a filename like the shell does?


The standard interpretation for GR& at the start of a filename is: if alone or followed by a G &,
then substitute the current user's home directory; if followed by the name of a user, then
substitute that user's home directory. If no valid expansion can be found, then shells will leave
the filename unchanged.

Be wary, however, of filenames that actually start with the GR& character. Indiscriminate tilde-
expansion can make it very difficult to specify such filenames to a program; while quoting will
prevent the shell from doing the expansion, the quotes will have been removed by the time the
program sees the filename. As a general rule, do not try and perform tilde-expansion on
filenames that have been passed to the program on the command line or in environment
variables. (Filenames generated within the program, obtained by prompting the user, or obtained
from a configuration file, are good candidates for tilde-expansion.)

Here's a piece of C++ code (using the standard string class) to do the job:

 -.   p   -K  



   - *QQ  :*>)&R&
   

p  .?@99
  - +
 p      p& &

   - QQ p 

 .- '!E53'
 ) .

 D J& 
- p. R "% !E53 &   
     -  -  
  
 .   
2
2
 

  -   "" p   - p ,  - p  p 
     - $  
  
 .   
2

    p .  p"    -

 ) .
   

  -   .

  p   - p 
   

   - *QQ  :  - >)& &
  A& &

  A   %  p A

   
2

2.10 What can I do with named pipes (FIFOs)?


2.10.1 What is a named pipe?

A named pipe is a special file that is used to transfer data between unrelated processes. One (or
more) processes write to it, while another process reads from it. Named pipes are visible in the
file system and may be viewed with G & like any other file. (Named pipes are also called fifos;
this term stands for `First In, First Out'.)

Named pipes may be used to pass data between unrelated processes, while normal (unnamed)
pipes can only connect parent/child processes (unless you try  hard).

Named pipes are strictly unidirectional, even on systems where anonymous pipes are
bidirectional (full-duplex).

2.10.2 ¦ow do I create a named pipe?

To create a named pipe interactively, you'll use either $p or $ p. On some systems,
mknod will be found in /etc. In other words, it might not be on your path. See your man pages
for details.

To make a named pipe within a C program use $ p:

   $ .   
"
pp& p & % 
$ *
$ p'   p'"#B4@#4Q#BJ@#4Q#B4C4DQ#BJC4D

 p'$ p'
. 
2

If you don't have $ p, you'll have to use $p:

   $ .   
"
pp& p & % 
$ *
$p'   p'"
#BFBFEQ#B4@#4Q#BJ@#4Q#B4C4DQ#BJC4D"
*

 p'$p'
. 
2

2.10.3 ¦ow do I use a named pipe?

To use the pipe, you open it like a normal file, and use  and   just as though it was
a plain pipe.

However, the p  of the pipe may block. The following rules apply:

c If you open for both reading and writing (E4IJ4), then the open will not block.
c If you open for reading (E4IE?96), the open will block until another process opens the
FIFO for writing, unless E?E?S9E/M is specified, in which case the open succeeds.
c If you open for writing EJ4E?96, the open will block until another process opens the
FIFO for reading, unless E?E?S9E/M is specified, in which case the open fails.

When reading and writing the FIFO, the same considerations apply as for regular pipes and
sockets, i.e.  will return EOF when all writers have closed, and   will raise
#BCDBD3 when there are no readers. If #BCDBD3 is blocked or ignored, the call fails with 3DBD3.

2.10.4 Can I use a named pipe across NFS?

No, you can't. There is no facility in the NFS protocol to do this. (You may be able to use a
named pipe on an NFS-mounted filesystem to communicate between processes on the same
client, though.)

2.10.5 Can multiple processes write to the pipe simultaneously?

If each piece of data written to the pipe is less than DBD3S@F in size, then they will not be
interleaved. However, the boundaries of writes are not preserved; when you read from the pipe,
the read call will return as much data as possible, even if it originated from multiple writes.

The value of DBD3S@F is guaranteed (by Posix) to be at least 512. It may or may not be defined
in G $ &, but it can be queried for individual pipes using  p or   p.

2.10.6 sing named pipes in applications

How can I implement two way communication between one server and several clients?

It is possible that more than one client is communicating with your server at once. As long as
each command they send to the server is smaller than DBD3S@F (see above), they can all use the
same named pipe to send data to the server. All clients can easily know the name of the server's
incoming fifo.

However, the server can not use a single pipe to communicate with the clients. If more than one
client is reading the same pipe, there is no way to ensure that the appropriate client receives a
given response.

A solution is to have the client create its own incoming pipe before sending data to the server, or
to have the server create its outgoing pipes after receiving data from the client.

Using the client's process ID in the pipe's name is a common way to identify them. Using fifos
named in this manner, each time the client sends a command to the server, it can include its PID
as part of the command. Any returned data can be sent through the appropriately named pipe.

3. Terminal I/O
3.1 ¦ow can I make my program not echo input?
How can I make my program not echo input, like login does when asking for your password?

There is an easy way, and a slightly harder way:

The easy way, is to use -  , which is probably found on almost all Unices. It takes a
string to use as a prompt. It will read up to an 3EF or newline and returns a pointer to a static area
of memory holding the string typed in.

The harder way is to use -   and    , both use a   $ p to
manipulate the terminal. The following two routines should allow echoing, and non-echoing
mode.

â   %
â   p

â  $ p 
â   -

    $ p  p  - 

p ppp 

   $ p   - 
 -  *"K p  - 
  -  p  - 
  - -KR3/!E
    *"(/#8?EJ"K  - 
 
2

p ppp 

    *"(/#8?EJ"K p  - 
 
2

Both routines used, are defined by the POSIX standard.

3.2 ¦ow can I read single characters from the terminal?


How can I read single characters from the terminal? My program is always waiting for the user
to press 43(@4?.

Terminals are usually in canonical mode, where input is read in lines after it is edited. You may
set this into non-canonical mode, where you set how many characters should be read before input
is given to your program. You also may set the timer in non-canonical mode terminals to 0, this
timer flushs your buffer at set intervals. By doing this, you can use -  to grab the key
pressed immediately by the user. We use -   and     both of which are
defined by POSIX to manipulate the $ p structure.

â   %
â   p

â  $ p 
â   -

    $ p  p  - 

p   
 p 

   $ p   - 

 -  *"K p  - 

  -  p  - 

 I %p $p"  % + p%
 
  - -KRB/8?E?
  - :7(B53>*
  - :75B?>

    *"(/#8?EJ"K  - 
 
2

p   
 p 

    *"(/#8?EJ"K p  - 
 
2

3.3 ¦ow can I check and see if a key was pressed?


How can I check and see if a key was pressed? On DOS I use the %  function, but there
doesn't seem to be an equivalent?

If you set the terminal to single-character mode (see previous answer), then (on most systems)
you can use   or p to test for readability.

3.4 ¦ow can I move the cursor around the screen?


How can I move the cursor around the screen? I want to do full screen editing without using
curses.

Seriously, you probably don't want to do this. Curses knows about how to handle all sorts of
oddities that different terminal types exhibit; while the termcap/terminfo data will tell you
whether any given terminal type possesses any of these oddities, you will probably find that
correctly handling all the combinations is a huge job.
However, if you insist on getting your hands dirty (so to speak), look into the $ functions,
particularly  , $ and -p p.

3.5 What are pttys?


Pseudo-teletypes (pttys, ptys, other variant abbreviations) are pseudo-devices that have two
parts: the master side, which can be thought of as the `user', and the slave side, which behaves
like a standard tty device.

They exist in order to provide a means to emulate the behaviour of a serial terminal under the
control of a program. For example,  uses a pseudo-terminal on the remote system; the
remote login shell sees the behaviour it expects from a tty device, but the master side of the
pseudo-terminal is being controlled by a daemon that forwards all data over the network. They
are also used by programs such as . $, .  ,  , , $ , and many others.

3.6 ¦ow to handle a serial port or modem?


The handling of serial devices under Unix is heavily influenced by the traditional use of serial
terminals. Historically, various combinations of ioctls and other hacks were necessary to control
the precise behaviour of a serial device, but fortunately this is one of the areas that POSIX made
some efforts to standardise.

If you're using a system that doesn't understand  $ p ,     and related
functions, then you'll have to go elsewhere for information (or upgrade your system to something
less archaeological).

There are still significant differences between systems, however, mainly in the area of device
names, handling of hardware flow control, and modem signalling. (Whenever possible, leave the
device driver to do all the handshaking work, and don't attempt to manipulate handshaking
signals directly.)

The basic steps for opening and initialising a serial device are:

c p  the device; this may require the use of certain flags:

E?E?S9E/M
Opening a dial-in or modem-controlled device will block until carrier is present, unless this flag is
used. A nonblocking open gives you the opportunity to disable the modem controls (see CLOCAL
below) if necessary.

E?E/((6

On 4.4BSD-derived systems this is redundant, but on other systems it controls whether the
serial device can become a control terminal for the session. In most cases you probably ’ 
want to acquire a control terminal, and should therefore specify this flag, but there are
exceptions.

c se -   to retrieve the current device modes. While one will often ignore most or all
of the initial settings thus obtained, it's still a convenient way of initialising a   $ p .
c Set suitable values for  -, p-, -, -, and  in the termios
structure. (See below.)
c se    and   p  to set the desired baud rate. Very few systems
allow you to set differing input and output speeds, so as a general rule you should set both to
your desired speed.
c se     to set the device modes.
c †ou may wish, if you used E?E?S9E/M when opening the port, to use   to ensure that
E?E?S9E/M is turned off again. Systems seem to differ as to whether a nonblocking open on a
tty will affect subsequent  calls; better to be explicit.

Once you have opened and set up the port, you can then use  and   normally. Note
that the behaviour of  will be controlled by the flag settings you gave to    .

 ,  ,  % and p are additional useful functions that you
should be aware of.

When you're done with the port, and want to close it, be aware of a very nasty little hazard on
some systems; if there's any pending output waiting to be written to the device (e.g. if output
flow is stopped by hardware or software handshaking), your process can hang unkillably in the
p  call until the output drains. Calling   to discard any pending output is
probably a wise move.

(Blocked output on tty devices is by far the most common cause of "unkillable" processes in my
experience.)

3.6.1 Serial device names and types

The device names used for serial port devices vary quite widely between systems. Some
examples from different systems are:

c G 
:*T>:+>& for direct access devices, and G 
:*T>:8P>& for modem
control devices (e.g. SCO nix)
c G  :*T> :*T>& for direct access devices, G  :*T> :*T>& for dial-out
devices and G 
:*T> :*T>& for dial-in devices (e.g. HP- )
c G  :+>:*T>& for dial-out devices and G 
:+>:*T>& for dial-in devices
(e.g. FreeBSD)

The precise interaction between the device name used, and the effect on any hardware handshake
lines is system-, configuration- and hardware-dependant, but will usually follow approximately
these rules (assuming that the hardware is oS-232 DTE):
c A successful open of any device should assert DTR and RTS
c A blocking open of a modem-control or dial-in device will wait for DCD (and possibly also DSR
and/or CTS) to be raised, usually after asserting DTR/RTS.
c An open of a dial-out device while an open call to the corresponding dial-in device is blocked
waiting for carrier      cause the open of the dial-in port to complete. Some systems
implement a simple sharing scheme for dial-in and dial-out ports whereby the dial-in port is
effectively "put to sleep" while the dial-out port is in use; other systems do not do this, and
sharing the port between dial-in and dial-out on such systems requires external cooperation
(e.g. use of CP lockfiles) to avoid contention problems.

3.6.2 Setting up termios flags

Some hints on setting up the termios flags when using a serial device that you've opened yourself
(as opposed to using your existing control tty):

3.6.2.1 c_iflag

You probably want to set all the bits in  - to 0, unless you want to use software flow
control (ick) in which case you set BLE? and BLEFF.

3.6.2.2 c_oflag

Most of the bits of p- are hacks of one sort or another to make output to slow terminals
work, and as such some newer systems have dropped almost all of them as obsolete (especially
all the gory output-padding options). As with  -, setting everything to 0 is reasonable for
most applications.

3.6.2.3 c_cflag

When setting the character size, remember to mask using /#BP3 first; e.g. to set 8-bit characters,
use:

 -KR/#BP3
 -Q/#U

Other important flags found in - that you probably want to turn on and /438I and !@D/9.

If you need to generate even parity, then set D843?S and clear D84EII; if you need to generate
odd parity then set both D843?S and D84EII. If you don't want parity at all, then make sure
D843?S is clear.

Clear /#(EDS unless you actually need to generate two stop bits.

Flags for enabling hardware flow control may also be found in -, but they aren't
standardised (pity).
3.6.2.4 c_lflag

Most applications will probably want to turn off B/8?E? (canonical, i.e. line-based, input
processing), 3/!E, and B#BC.

B3L(3? is a more complex issue. If you don't turn it off, the implementation is allowed to do
nonstandard things (like define additional control characters in ) that might cause
unexpected results, but you might need to leave B3L(3? enabled on some systems to get useful
features like hardware flow control.

3.6.2.5 c_cc

This is an array of characters that have special meanings on input. These characters are given
names like 7B?(4, 7#(ED etc.; the names are indexes into the array.

(Two of these "characters" are not really characters at all, but control the behaviour of 
when B/8?E? is disabled; these are 75B? and 7(B53.)

The indexes are often referred to as though they were actual variables, e.g. "set VMIN to 1"
actually means "set c_cc[VMIN] to 1". The shorthand is useful and only occasionally confusing.

Many of the slots in  are only used if some other combination of flags is set:

sed only if B/8?E? is set

73EF, 73E9, 7348#3, 7MB99 (and also 73E9;, 7#(8(@# and 7J348#3 if defined and B3L(3? is
set)

sed only if B#BC is set

7B?(4, 7O@B(, 7#@#D (and also 7I#@#D if defined and B3L(3? is set)

sed only if BLE? or BLEFF is set

7#(ED, 7#(84(

sed only if B/8?E? is ›  set

75B?, 7(B53

Implementations may define additional entries in . It may be prudent to initialise all the
entries to DE#BL7IB#8S93 (the constant ?//# gives the array size) before setting the specific
values you wish to use.

75B? and 7(B53 (which may share slots with 73EF and 73E9 respectively, depending on the
implementation) have the following meaning. The value of 7(B53 is (if not 0) always interpreted
as a timer in tenths of seconds.
:75B?>*":7(B53>*

 will return when either VMIN bytes of input are available, or if at least one character
has been read and VTIME has expired between characters, or if interrupted by a signal.

:75B?>*":7(B53>*

 will return when VMIN bytes of input are available, or if interrupted. Otherwise it will
wait indefinitely.

:75B?>*":7(B53>*

 will return as soon as any input is available; if VTIME expires with no data arriving, it will
return with no characters read. (This conflicts slightly with the end-of-file indication received in
the event of modem hangup; using 1 for VMIN and either $ or   for a timeout
avoids this particular problem.)

:75B?>*":7(B53>*

 will always return immediately; if no data is available it will return with no characters
read (with the same problem as above).

4. System Information
4.1 ¦ow can I tell how much memory my system has?
This is another `Frequently Unanswered Question'. In most cases, you should not even   to
find out.

If you really must, then it can usually be done, but in a highly system-dependent fashion. For
example, on Solaris, you can use
p#/D!6#D8C3# and
p#/D8C3#BP3; on
FreeBSD, you can use
 ; on Linux you can read and parse G p $$ p& (being
careful to allow any of the historically valid formats for this file); other systems may have their
own methods. I'm not aware of any more portable methods.

For HP-UX (9 and 10), the following code has been contributed:

     

  -  K " +p " + "*)

   'D-# +01'"  - +
   'D
D- 01'"  
$$p

2

4.2 ¦ow do I check a user's password?


4.2.1 ¦ow do I get a user's password?

Traditionally user passwords were kept in the G    & file, on most UNIX flavours.
Which is usually of this format:

username:password:uid:gid:gecos field:home directory:login shell

Though this has changed with time, now user information may be kept on other hosts, or not
necessarily in the G    & file. Modern implementations also made use of `shadow'
password files which hold the password, along with sensitive information. This file would be
readable only by privileged users.

The password is usually not in clear text, but encrypted due to security concerns.

POSIX defines a suite of routines which can be used to access this database for queries. The
quickest way to get an individual record for a user is with the - $ and -  
routines. Both return a pointer to a struct passwd, which holds the users information in various
members. - $ accepts a string holding the user's name, -   accepts a uid (type
  as defined by POSIX). Both return NULL if they fail.

However, as explained earlier, a shadow database exists on most modern systems to hold
sensitive information, namely the password. Some systems only return the password if the
calling uid is of the superuser, others require you to use another suite of functions for the shadow
password database. If this is the case you need to make use of - $, which accepts a
username and returns a struct spwd. Again, in order to successfully do this, you will need to have
privileges. (On some systems, notably HP-UX and SCO, you may need to use -  $
instead.)

4.2.2 ¦ow do I get shadow passwords by uid?

My system uses the getsp* suite of routines to get the sensitive user information. However I do
not have -  , only - $. How do I work around this, and get by uid?

The work around is relatively painless. The following routine should go straight into your
personal utility library:

â   %
â   p

â  
â  p

   -      

    p
      

   -    ?@99
QQ p- $   $?@99
 ?@99

  p
2

The problem is, that some systems do not keep the uid, or other information in the shadow
database.

4.2.3 ¦ow do I verify a user's password?

The fundamental problem here is, that various authentication systems exist, and passwords aren't
always what they seem. Also with the traditional one way encryption method used by most
UNIX flavours (out of the box), the encryption algorithm may differ, some systems use a one
way DES encryption, others like the international release of FreeBSD use MD5.

The most popular way is to have a one way encryption algorithm, where the password cannot be
decrypted. Instead the password is taken in clear text from input, and encrypted and checked
against the encrypted password in the database. The details of how to encrypt should really come
from your man page for 
, but here's a usual version:

-    .   p
  p" 
  
$     
$ "*p  
 

   p    "p  


  $ 
   "
"
*
2

This works because the salt used in encrypting the password is stored as an initial substring of
the encrypted value.

d  on some systems, password encryption is actually done with a variant of crypt called
% -
.

5. Miscellaneous programming
5.1 ¦ow do I compare strings using wildcards?
The answer to  depends on what exactly you mean by `wildcards'.

There are two quite different concepts that qualify as `wildcards'. They are:

-   

These are what the shell uses for filename expansion (`globbing').
o  

These are used by editors, - , etc. for matching text, but they normally  applied to
filenames.

5.1.1 ¦ow do I compare strings using filename patterns?

Unless you are unlucky, your system should have a function $  to do filename
matching. This generally allows only the Bourne shell style of pattern; i.e. it recognises G &,
G:>& and G,&, but probably won't support the more arcane patterns available in the Korn
and Bourne-Again shells.

If you don't have this function, then rather than reinvent the wheel, you are probably better off
snarfing a copy from the BSD or GNU sources.

Also, for the common cases of matching actual filenames, look for -p%, which will find all
existing files matching a pattern.

5.1.2 ¦ow do I compare strings using regular expressions?

There are a number of slightly different syntaxes for regular expressions; most systems use at
least two: the one recognised by , sometimes known as `Basic oegular Expressions', and the
one recognised by - , `Extended oegular Expressions'. Perl has it's own slightly different
flavour, as does Emacs.

To support this multitude of formats, there is a corresponding multitude of implementations.


Systems will generally have regexp-matching functions (usually -p$  and -.)
supplied, but be wary; some systems have more than one implementation of these functions
available, with different interfaces. In addition, there are many library implementations available.
(It's common, BTW, for regexps to be compiled to an internal form before use, on the
assumption that you may compare several separate strings against the same regexp.)

One library available for this is the G.& library, available from the GNU mirrors. This seems to
be under active development, which may be a good or a bad thing depending on your point of
view :-)

5.2 What's the best way to send mail from a program?


There are several ways to send email from a Unix program. Which is the best method to use in a
given situation varies, so I'll present two of them. A third possibility, not covered here, is to
connect to a local SMTP port (or a smarthost) and use SMTP directly; see oFC 821.

5.2.1 The simple method: /bin/mail


For simple applications, it may be sufficient to invoke $  (usually G %  $ &, but could be
G   %  $ & on some systems).

WARNING: Some versions of UCB Mail may execute commands prefixed by GR)& or GRQ&
given in the message body even in non-interactive mode. This can be a security risk.

Invoked as G$  & %V &  & it will take a message body on
standard input, and supply a default header (including the specified subject), and pass the
message to $  for delivery.

This example mails a test message to pp on the local system:

â   p

â 58B9D4EC' %  $ '

 $ 

FB93 $  p 58B9D4EC' &( 5 -&pp '"''
 )$ 

 p' p '
. 
2

   $ "'(    1'

  p $ 

    "'$  )1'
. 
2
2

If the text to be sent is already in a file, then one can do:


$58B9D4EC' & p  &pp  $  $'

These methods can be extended to more complex cases, but there are many pitfalls to watch out
for:

c If using system() or popen(), you must be very careful about quoting arguments to protect them
from filename expansion or word splitting
c Constructing command lines from user-specified data is a common source of buffer-overrun
errors and other security holes
c This method does not allow for CC: or BCC: recipients to be specified (some versions of /bin/mail
may allow this, some do not)

5.2.2 Invoking the MTA directly: /usr/lib/sendmail


The $  program is an example of a Mail ser Agent, a program intended to be invoked by the
user to send and receive mail, but which does not handle the actual transport. A program for
transporting mail is called an MTA, and the most commonly found MTA on Unix systems is
called $ . There are other MTAs in use, such as 55IF, but these generally include a
program that emulates the usual behaviour of $ .

Historically, $  has usually been found in G    %&, but the current trend is to move
library programs out of G    %& into directories such as G   % & or G    %.&.
As a result, one normally invokes $  by its full path, which is system-dependent.

To understand how $  behaves, it's useful to understand the concept of an envelope. This
is very much like paper mail; the envelope defines who the message is to be delivered to, and
who it is from (for the purpose of reporting errors). Contained in the envelope are the headers,
and the body, separated by a blank line. The format of the headers is specified primarily by oFC
822; see also the MIME oFCs.

There are two main ways to use $  to originate a message: either the envelope recipients
can be explicitly supplied, or $  can be instructed to deduce them from the message
headers. Both methods have advantages and disadvantages.

5.2.2.1 Supplying the envelope explicitly

The recipients of a message can simply be specified on the command line. This has the drawback
that mail addresses can contain characters that give
$ and p  considerable grief,
such as single quotes, quoted strings etc. Passing these constructs successfully through shell
interpretation presents pitfalls. (One can do it by replacing any single quotes by the sequence
single-quote backslash single-quote single-quote, then surrounding the entire address with single
quotes. Ugly, huh?)

Some of this unpleasantness can be avoided by eschewing the use of


$ or p , and
resorting to p and . directly. This is sometimes necessary in any event; for example,
user-installed handlers for SIGCHLD will usually break p  to a greater or lesser extent.

Here's an example:

â 

 
â 
 
â  
â   %
â  
â 
. 
â     
p  

â D8(!#3?I58B9
â D8(!#3?I58B9'    % $ '
â 

p $ 'p    $ - $  p'
 $p"''  - 7U $ p   pp
        - 

 
p$ -   pp$ p p %
$ 
 

â #3?I58B9ED(#'p '"''

   $pp  - $%p$  
 

â p p +p +p:*>

  p  p  p p -pFI p 
          $ pp  4F/U;; 
 K%p
"      $  %
?@99 p    
  p  "p    p$ $ 
    
.  p p $ -. p 
 

  $ -  "p    

  p  -  :>D8(!#3?I58B9"#3?I58B9ED(#2
p  -?@99
  $ *
   
  
     

 p $%p   

   :$ >
AA$ 

 )$ 
 *   - pp      

 p p-$  p 

-$p +p  $ Ap p-  A
 )-
 

    -$  p 

$$
-"-  " +p-  
$$
-Ap p-  "
  "$ +p 
-:$ Ap p-  >?@99

 $
 p p$ -%p - 

 p 

   p

 *   

 D$% - 
 )#(IB?FB93?E
 ;"#(IB?FB93?E

   p  FI -$  
p H

 -pp  
.D8(!#3?I58B9"-
. 3LE#FB93

     

-
  "K   "*
 *
 
 JBF3LB(3I   
 J3LB(#(8(@#   
 

  p 
-
 
2
2

5.2.2.2 Allowing sendmail to deduce the recipients

The G & option to $  instructs $  to parse the headers of the message, and use
all the recipient-type headers (i.e. (p, / and S) to construct the list of envelope recipients.
This has the advantage of simplifying the $  command line, but makes it impossible to
specify recipients other than those listed in the headers. (This is not usually a problem.)

As an example, here's a program to mail a file on standard input to specified recipients as a


MIME attachment. Some error checks have been omitted for brevity. This requires the
G$ $p& program from the $ $  distribution.

â   p
â  
â  
â     
p  

â D8(!#3?I58B9
â D8(!#3?I58B9'    % $ '
â 

â #3?I58B9ED(#'p '
â p p +p +p:*>

  $:9 $ $>
p$$:;UA9 $ $>

p  p 

   $
2

 $   -" -

FB93 $ -
   

 -;

    "' -0   1'"-:*>
. ;
2

  $ $  $?@99
QQ$ -p   $"''?@99
. ;

 .  

p $ -
$ -p   $"''
 )$ -
. ;

 p      

   $ -"'(p0 '"-:>
p ; - AA
   $ -"'"11 0 '"-: >
  &1&"$ -

 #%V  

   $ -"'#%V    %
$ 1'

  $  & pFp$"I "5 -BI  

 5B53  

   $ -"'5B537 p*1'
   $ -"'/p  (
   p p   $1'
   $ -"'/p  ( 3p -% =W1'

 p    %  

  &1&"$ -
p $ -

  pp - p-$ 

   p$$"'$ $p%0 '"  $
 
$p$$
. 

  p$  

   p$$"'0 0  0 '"
D8(!#3?I58B9"#3?I58B9ED(#"  $
 
$p$$
. 

 *
2

6. se of tools
6.1 ¦ow can I debug the children after a fork?
Depending on the tools available there are various ways:

Your debugger may have options to select whether to follow the parent or the child process (or
both) after a p, which may be sufficient for some purposes.

Alternatively, your debugger may have an option which allows you to attach to a running
process. This can be used to attach to the child process after it has been started. If you don't need
to examine the very start of the child process, this is usually sufficient. Otherwise, you may wish
to insert a   call after the p in the child process, or a loop such as the following:


p   
 
2

which will hang the child process until you explicitly set  to 0 using the debugger.

oemember, too, that actively using a debugger isn't the only way to find errors in your program;
utilities are available to trace system calls and signals on many unix flavours, and verbose
logging is also often useful.

6.2 ¦ow to build library from other libraries?


Assuming we're talking about an archive (static) library, the easiest way is to explode all the
constituent libraries into their original objects using G.& in an empty directory, and combine
them all back together. Of course, there is the potential for collision of filenames, but if the
libraries are large, you probably don't want to be combining them in the first place....

6.3 ¦ow to create shared libraries / dlls?


The precise method for creating shared libraries varies between different systems. There are two
main parts to the process; firstly the objects to be included in the shared library must be
compiled, usually with options to indicate that the code is to be position-independent; secondly,
these objects are linked together to form the library.
Here's a trivial example that should illustrate the idea:

  p%V 

p  $


 '!pJp'
2

 p%V 

 p 

â   p

. p  $


$ 

   '0 1'"$

 *
2

p 

N-  p%V
N- p %  p p%Vp
N-p %  p
N p 
!pJp


By far the best method if you want the library and build procedure to be anything approaching
portable is to use GNU Libtool. This is a small suite of utilities which know about the platform-
dependent aspects of building shared libraries; you can distribute the necessary bits with your
program, so that when the installer configures the package, he or she can decide what libraries to
build. Libtool works fine on systems which do not support shared libraries. It also knows how to
hook into GNU Autoconf and GNU Automake (if you use those tools to manage your program's
build procedure).

If you don't want to use Libtool, then for compilers other than gcc, you should change the
compiler options as follows:

AIX 3.2 using xlc (unverified)


Drop the G &, and use G%5#43%3 % . & instead of G
&. You also need to create a file G % . & containing the list of
symbols to export, in this case G$
&. In addition, use Gp  & when
linking the library (on newer versions of AIX, I believe this changes to G%p 
&).
SCO OpenServer 5 using the SCO Development System (unverified)
Shared libraries are only available on OS5 if you compile to ELF format, which requires
the G%& option. Use GM & instead of G &, and G%C& for
the link step.
Solaris using SparcWorks compilers
Use G & instead of G &, and use GC& instead of G- &.

(Submission of additional entries for the above table is encouraged.)

Other issues to watch out for:

c AIX and (I believe) Digital Unix don't require the -fpic option, because all code is
position independent.
c AIX normally requires that you create an `export file', which is a list of symbols to be
exported from the shared library. Some versions of the linker (possibly only the SLHS
linker, svld?) have an option to export all symbols.
c If you want to refer to your shared library using the conventional G& parameter to the
linker, you will have to understand how shared libraries are searched for at runtime on
your system. The most common method is by using the 9I9BS4846D8(! environment
variable, but there is usually an additional option to specify this at link time.
c Most implementations record the expected runtime location of the shared library
internally. Thus, moving a library from one directory to another may prevent it from
working. Many systems have an option to the linker to specify the expected runtime
location (the G4& linker option on Solaris, for example, or the 9I4@?D8(!
environment variable).
c ELF and a.out implementations may have a linker option GS
$%p & which causes
internal references within the library to be resolved. Otherwise, on these systems, all
symbol resolution is deferred to the final link, and individual routines in the main
program can override ones in the library.

6.4 Can I replace objects in a shared library?


Generally, no.

On most systems (except AIX), when you link objects to form a shared library, it's rather like
linking an executable; the objects don't retain their individual identity. As a result, it's generally
not possible to extract or replace individual objects from a shared library.

6.5 ¦ow can I generate a stack dump from within a running


program?
Some systems provide library functions for unwinding the stack, so that you can (for example)
generate a stack dump in an error-handling function. However, these are highly system-specific,
and only a minority of systems have them.
A possible workaround is to get your program to invoke a debugger  
-- the details still
vary slightly between systems, but the general idea is to do this:

p $  p 



 :=*>

    "' %  p&1 &Q%.0'"- 

$ 

 
2

You will need to tweak the commands and parameters to dbx according to your system, or even
substitute another debugger such as -%, but this is still the most general solution to this
particular problem that I've ever seen. Kudos to oalph Corderoy for this one :-)

Here's a list of the command lines required for some systems:

Most systems using dbx


' %  p&1 &Q%.   p p-$0'
AIX
' %  p&1 &Q%.0'
IRIX
' %  p&1 &Q%. 0'

Examples
Catching SIGC¦
â 

     %p
p 
  
â 
  p  p $p  
â  - p - p  
â   p p    
â   pp 

p  -    p p
pp#BC/!9I 

 $ 

   - p 
   

 8 - - p#BC/!9I 
   -

 Jp&   p%p
p  -    .$  
 -$
 K  $ 

 
 J&p
        $  "p p 
  % p -   -p pP  $ 
 
  - #8?E/9I#(ED

 
 5    B -
    p"p p%%
  p  p
   -?@99
 
  - p#BC/!9I"K "?@99*

    "' - p 1'
 
2

 Fp 
   p

 
    "'p 1'
 

 *      - 
 
. X .    X 

     
  * -   $ p   
2

 *
2


 ( - pp
- #BC/!9I
   "   $   
 
p  -   -p

     " 

 J p
  p %p - 
  "K   "J?E!8?C*

 
  - B E p      
  - p p$$"%  p%%
EM
   p
 p-$    p
 
    "'  1'
 
2

 
 Jp  p &   &$    -
  $p   
 
 JBF3LB(3I      . p$
, 

 J3LB(#(8(@#    -  & .     
   ' & . p$
    01'" 
2
2

Reading the process table -- S NOS 4 version


â M535@#34
â 
p
â $
â  

-. :;<=>
â B?B(-  -. 
â C3(/ AA
â D33M/ 
â @?C3(/ 
â 43(@4? p    p  
â 344E4
â -. 

 
- %
$ $"    

$  
 -
  p
 $?@99
. %:;<=>
 $
   
     
   $
 
   p  p


 $p ?@99"?@99"?@99"E4IE?96"?@99?@99
 
2
   -. "'Y 0 N'"$
p$ ?@99". %". %A;<="&1*&

  p$. p
  p  
  $- " p)?@99
p$- $" p" "K-"?@99
 p
  p$$:*>)&1*&
 $ p$$
2
2
 
 $-:*>
2
2
  $
 ) $  $"$
 p)
-
2
   )KKp   
p 
2
 
p 
%
2
%
2
 
    $". %
 p)
-
2
%
2
2
2
 p)
-
2
 $?@99
2
$p 
  $)?@99
  
2
 
2

Reading the process table -- SYSV version


 
- %
$ $"    

IB4  
       
  p  
  
  p 

  p  ' p'?@99
 
2
 ' p'
     )?@99
   $:*>)&&
 p   $"E4IE?96)
  p "DBE/D#B?FE"K )
 ) $   $"$
p    p   $
   )KKp   
p 
2
 
p 
%
2
2
2
p 
2
2
2
p   
 p 
2

Reading the process table -- AIX 4.2 version


â   p
â  p p

 - p    p p "  "   p "
  "   "  

 - %
$ $"   . D 

   p p 
     
   

  . D 

 

 - p K " +p "*"*"K ")
%

 ) $ $"  p$$

    
 . D  
%
2
2

  
2

 $   -" -:>

  8-
   
  . D 

 -

   '
 .0  p-$: p-$>1'"-:*>
. 
2

p8-8--8-AA

   'Dp BI p0 1'"-:8->

p. D *" * )
  - %
$-:8->"K. D )
   '1 01'" 
2
2

Reading the process table using popen and ps


â   p FB93"   "- "   
â   %  p ". "3LB(#@//3## 
â   -   p" $  
â 

     
â 
  JBF3LB(3I"J3LB(#(8(@# 

 p$   

   :HH>"p$$:U*>"   " p" $
FB93  
     

 *   *

   p$$"'  0;  '" 
  p p$$"''
 FB93 *   *

    
  *-  " +p " 

 p  
  *
2

  -p  p$$$ p$ p$ - 
 S#I $     /E558?I  < p$" #
7
  $  p  /5Ip/E558?I  W p$
 
p      *

  * p  p  "'1 1'

 p  
  *
2
 * $ '/E558?I'" pQQ* $ '/5I'" p
 p /E558?Ip$ 
$ p
%
2
2

   p    
  *-  " +p " 

 p  
  *
2

 -% 'p'  p$$ - 
  * p  p$"'1 1'

 p  
  *
2

    p  
 )JBF3LB(3I   QQ*)J3LB(#(8(@#   
  *

  p
2

 $   -" -:>

   p$ p -:>
. 3LB(#@//3##
2

aemon utility functions


â  
â   %
â  
â  -
â 

 
â 
 
â p

p p FI     

p p   

   $ 
p#/ED3?58L

  $ 
p AA
2

$p  p p$     p %-p
   p "% 
p& p$. .     
  $

p(  % p S#I p"
  p   p %p  -   $ " 
 

%  pppDp .
$  

 $p  p "  pp 

  p

 *%
  
 . * .  p -  p  
2

   *  p&   
 

 
p      
p  pZ p p
  
   p p$
 %p$p  

  p

 *%
  
 . *
2

 )p 
 ' '

 )pp 

p *
p '  '"E4IJ4
 * *
2

 *
2

p; p"%   p   $$  
p 
 p& +p$%  . 
 4   p   "p 
$ - 
 (  p  p  p  &  
 

(  p $   
p & - p -p#BC/!9I 
B
p" 
p pV % -p  

 

 p;

   
  
     

 ) p

  p

 * *
 . p  $ p ;<= 
 . *
2
2

  *QQ  "K   "**
 

 JBF3LB(3I   
 J3LB(#(8(@#   *
 
 
pJ3LB(#(8(@#   
 
p3B?(4 " p p 

 
2

An example of using the above functions:

â 

 
â 
p 
â   
â   p
â   %
â 
p-
â p

 $p  "  
 p;p 
p p   

â (/DDE4(UUUU

p . p  


p-9ECB?FE"'0  00$'" "p
. 
2

p  p p  


p-9ECB?FE"'0  00$'" "p
2

    p   

p     p

FB93 p  p"''
FB93 p p  p"''
  

  % "?@99"BEFSF"*;W
  %p "?@99"BE9SF"*;W

 -  )3EF
   p "p 

p p 
2

(   $p& $ p pp p   

p  p 

   p 
   +p
   p p 8FB?3("#E/M#(4385"*
  -
    pp  p"#E9#E/M3("#E43@#38II4"
K-" +p-

 *
. '  pp '

 $ 
8FB?3(
  p  p (/DDE4(
  B?8II48?6

%  p"   p K"
 *
. '% '

  p"<
 *
. ' '

p

  p"   p K"K

 *
  p;

 *p  p . *
  p 'p;'p %
 p 
2
2
2

 $ 

 $p*"**

 p'$p'
. ;
2

p p-'  '"9ECDBI"9ECI835E?

 p 

 *
2

Modem handling example


  p$ $ $p$p$$ 
 Z   $p    %
 p  "
 pp$p$p p   p
 $ 
 B
pp&  p p   " $p/9E/89
  p/F98C#(E#3(  
 

â   p
â   %
â  
â  
â 

 
â 
$
â 
p  $
%
$   
â  $ p 
â p
â   -
â 


â /F98C#(E#3(/438IQ!@D/9
â /F98C#(E/9384/#(EDSQD843?SQ/9E/89

$p$p?pFp"!Fp"#p Fp2


$   
â /F98C#!84IF9EJ/4(#/(#

â 3L85D93S8@IST;**
â 3L85D93F9EJ!Fp

 p  p  $ -

    "'0 1'"$ -
. 
2

   p p$    "p  $ -"  

    "'0 0 1'"$ -" p
 *
p 
p
 
2

 p  p p  $"  %"$p$pp

  - 
   $ p  

  p $"E4IJ4QE?E?S9E/MQE?E/((6

 *
 p p$  "'p '"p

   -
  %  -  

  -  "K *
 p p$  "' -  '"p

 p     pp   p - 

  -p#p Fp,BLE?QBLEFF*
 p-*

   U%   +$ p p p$p  

 -KR/#BP3Q/F98C#(E/9384Q/F98C#!84IF9EJ
 -Q/#UQ/F98C#(E#3(
 p!Fp
 -Q/F98C#!84IF9EJ

 p$p  

 -KRB/8?E?Q3/!EQ3/!E3Q3/!EMQB#BC

     $p  %%
  p  - 

 


   
â DE#BL7IB#8S93
 :*>DE#BL7IB#8S93
â 
 :*>  p"D/7IB#8S93
â 
p  ?//# AA
 : > :*>
2

 :7#(84(>*.
 :7#(ED>*.H

  $ -p p p 

 :75B?>
 :7(B53>*

 %  

  K "%
  p K "%

    -  

     "(/#8?EJ"K *
 p p$  "'    '"p

  pE?E?S9E/M   $$%  

-  "FC3(F9"*
 - *
 p p$  "' C3(F9'"p
  "F#3(F9"- KRE?E?S9E/M*
 p p$  "' #3(F9'"p

 
2

 p$ $  $ -    

#3/#@#3/# p (7 

 p  $   $ "p-  "p-  

   A  
    A  ******

   A    ******
   0******
2
2

#  43# 8 S"  -  -p    

    $ %   $  "
p    $ "p    $ %

p-   %  
p-   %  

  *
 A******" 

    
    

  *, *KK *,*
2

  p &  
p    pp-   - -%%
  $p   $   
 8$p  p p    p $p  $p 
 ( .$ p   - -p $  
 p   
    p
 

 .    "p  "   $p

  $ *
    
   $p"" 
   


- $p
K"?@99
 $K" $p ***" $p0***

 $ 

- $p
Kp"?@99
  $ %K "K"Kp*
 

FIP34EK 
FI#3("K 
   A"K "?@99"?@99"K *
 

 "K")
 

     -QQ&1&QQ&1&
  
 
   '11.0*;.'"

  :$ >
AA$ 
 
$ *
2

 *
2

 $   -" -

  
 -

 -;
 'p p    '

  % p "?@99"BE?SF"*

p  p -:>"3L85D93S8@I"3L85D93F9EJ
 *
 'p p  p '

 "'8(1'"H
 .  "'EM'"<****

 "'8(1'"H
 .  "'EM'"<****

  "(/BEF9@#!
p 
 'p p  p8('
2
2

 "'8(BW1'"<
.  "'EM'"****

  &1&

  "(/BEF9@#!
p 

 *
2

´ob Control example



 p  p p-p %-pVp%  

â   p
â  
â   %
â  
â  -
â 

 
â 
 
â p

#p$p  p %p   p p
& %
 p "p   - p  &   p-pB 
    " $ -  p-p p   
 
p p   " p p " 3?E((6
    & B  p " 3D345 
 pp-p p  $  p   p$  -  p 
 p-p p%%
p
 p . p    
 pp-p 
 

 -  $ p p
 p    - (  
 p   -  p
% p. $%p-p
p 
   pDE#BLpp$ -
$  #(C((E@    -  
 p$pp-p p   $p   %
 
 8  $ p  p p 
pp$$p  
 

  - $   
"   - 

 -    - 
 -   p - 
  

 -$
 K - 
 -  K - "#BC((E@
 - p$ #BCS9E/M"K - "Kp - 

   - 
" - 

 - p$ #BC#3(58#M"Kp - "?@99

 
2

9 p"% p Vp%p pFC    
 
  p   p%   p-p(  $   
  
   - p   %-p" p p p
B E
  p -  DC4D  p Vp%"   
      p  - p Vp%"p    
 . -Vp%   $  pp$
 p
p  -
  pp % Z  p     

  Vp%  -"   - 

  

   

 B  -  p-pVp%"Z     p
 p  " p p  p p p
"  
    p    p-p
 E
pp p -
   -p-p
  p  . -Vp%
 8  p p p p
p
%-pVp% 
 

 -

   - 

  -  - - 
;*
KK -  - - 
**
KK -  - - 
*
 p3?E((6"  

  - *KK - )- - 
 p3D345"  
2

   p

  p  
  

 *   

  %  p -p "  p   
 p-p  

   pp   -   '&  '
 

  - *
 - - 

   - *" - *KK-
 - $ 
" - 

 *

     

  %   p -p  pp 

  - *
 -  

  -  " - 

  
2

 ?E(438/!3I 
2

M Vp%DC4D  -#BC?E 

  Vp%   - "   -p

   - " -p
2

# Vp%DC4D 

   Vp%   - 

  Vp% - "#BC#(ED
2

4 $Vp%DC4D %-p 

  $Vp%%-   - 

  Vp% - "#BC/E?(
2

 $Vp%DC4D p-p 

  $Vp%-   - 

   - 
  


  -  - - 
;*
KK -  - - 
**
KK -  - - 
*
 p3?E((6"  

  - )- - 
 p3D345"  

  - $ 
" - *
 

  Vp% - "#BC/E?(
2


  p    p-p"-    -p-p
 Vp%
 

 p-p 

   - 
  


  -  - - 
;*
KK -  - - 
**
KK -  - - 
*
 p3?E((6"  

  - $ 
"- - 
2

p p FI     

p p   

   $ 
p#/ED3?58L

  $ 
p AA
2

 
$"% .      p$$ %-p
 Vp%"  -  p   p    p  - 
 p Vp%"  %p Vp% 
 BB?FI"E@(FIp344FIp?@99"   %p 
   pp   p    p 
 B
p  ?@99" 
 %   p    
  
 8 pp  FI ;    p p ppp  
 

  %-pp$$p  $"
   "   p "   

  
    :H>:;>
  p*

 )$
 p3B?789"

  :*>:*>  :*>:>
  :>:*>  :>:>
  :;>:*>  :;>:>

  KK   :*>*
pp
  p KK   :>*
pp
  KK   :;>*
pp

 )pKK) KKp KK

p '  '"E4IJ4
 *
pp
2

 )p

    Vp%*"
   

  p  
pp
%

 *   p 

 ; ,  :*>:*>"*
 ;p ,  :>:>"
 ;,  :;>:>";
p H

.' %  '"' '"''"$" ?@99

. ;X

     p 

p 
  
p   :*>:*>"   :*>:>
 p 
p   :>:>" p   :>:*>
 
p   :;>:>"   :;>:*>

  
2
2

 p
 p 


   "V
p * HAA 
pV*V;AAV
   : >:V>*
p   : >:V>
2

 *
p 

 pp"  
2

 
( %   p$    .$ p - %p 

 %-Vp%
p    -p*

â J/E43I@5D
 BJ/E43I@5D $ -"
p$ -   p  
p 
   pp
p  p$    
   K*.U*% 
 p 
p      .$ %
 $ -pp$ 
 
â J/E43I@5D   *
â 

  

   
     
  p *

   "K   "J?E!8?CQJ@?(48/3I*

  %-Vp%KK)JBF#(EDD3I   
%-Vp%

AAp 

 JBF3LB(3I   
    "'Dp 0.   p01'"
p- "J3LB(#(8(@#   
  JBF#BC?893I   
    "'Dp 0 %
 -00 1'"
p- "J(345#BC   "
J/E43I@5D   ,'p$ '''
  JBF#(EDD3I   
    "'Dp 0 p %
 -01'"
p- "J#(ED#BC   
 
    "'@.      0"   *.0.1'"
p- "   
2

 p 
2

p  -   -

  -)#BC/!9I
 -p -
2

 $ 

   - p 
   -p *

   -
  - *
 -$
 K  $ 
 - p#BCB?("K "?@99
 - p#BCO@B("K "?@99
 - p#BC(345"K "?@99
 - p#BC(#(D"K "?@99
 - p#BC/!9I"K "?@99

    "'#  -%-pVp%&  =*&1'
%-Vp% %-pp$$'  =*'"?@99"?@99"?@99
 %-Vp%*

 p' %-pp$$'
. 
2
    "'S-pVp%    01'"p-%-Vp%
 %-Vp%*

  -p

    "'# -0- 1'" -p
  -p AA
 Vp%%-Vp%"#BCMB99
 

 Vp%%-Vp%"#BC(345
 Vp%%-Vp%"#BC/E?(
2
2

 ) 
  
2

    "'Ip. -1'
 *
2


You might also like