精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>网络与通讯>>Unix Programming FAQ

主题:Unix Programming FAQ
发信人: vmstat()
整理人: mrcloud(2000-08-24 02:27:03), 站内信件
发件人: Andrew Gierth <[email protected]>
主题: Unix Programming FAQ (v1.34)
日期: 2000年5月31日 2:40

Archive-Name: unix-faq/programmer/faq
Comp-unix-programmer-Archive-Name: faq
URL: http://www.erlenstar.demon.co.uk/unix/faq_toc.html
URL: http://www.whitefang.com/unix/faq_toc.html
Posting-Frequency: every 2 weeks
Copyright: Collection Copyright (C) 1997 Andrew Gierth.
Last-Modified: 1999/09/25 03:17:37
Version: 1.34

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

About this FAQ
**************

$Id: rawfaq.texi,v 1.34 1999/09/25 03:17:37 andrew Exp $

This FAQ was originally begun by Patrick Horgan in May 1996; I took it
 over
after it had been lying idle for several months.  I've reorganised it 
a bit
and added some stuff; I still regard it as `under development'.

Comments, suggestions, additions, corrections etc. should be sent to t
he
maintainer at: <[email protected]>.

A hypertext version of this document is available on the WWW. The home
 site
is located at `http://www.erlenstar.demon.co.uk/unix/faq_toc.html'. A 
US
mirror site is available at `http://www.whitefang.com/unix/faq_toc.htm
l'.

This document is available by FTP from the news.answers archives at
rtfm.mit.edu and its many mirror sites worldwide. The official archive
 name
is `unix-faq/programmer/faq'. Sites which also archive *.answers posts
 by
group should also carry the file under the `comp.unix.programmer' dire
ctory.

Other sources of information are not listed here. You can find pointer
s to
other FAQs, books, source code etc. in the regular [READ ME FIRST] pos
ting
that should appear weekly in comp.unix.programmer. Administrivia regar
ding
newsgroup conduct, etc., are also found there; I want to reserve this

document specifically for technical Q's and A's.

All contributions have been edited by the maintainer, therefore any er
rors
or omissions are my responsibility rather than that of the contributor
.

This FAQ is now maintained as Texinfo source; I'm generating a raw tex
t
version for Usenet using the `makeinfo' program, and an HTML version u
sing
`texi2html'.

Copyright (C) 1997, 1998, 1999 Andrew Gierth. This document may be
distributed freely on Usenet or by email; it may be archived on FTP or
 WWW
sites that mirror the news.answers archives, provided that all reasona
ble
efforts are made to ensure that the archive is kept up-to-date.  (This

permission may be withdrawn on an individual basis.)  It may not be
published in any other form, whether in print, on the WWW, on CD-ROM, 
or in
any other medium, without the express permission of the maintainer.

List of contributors in no particular order:

Andrew Gierth       <[email protected]>                    
        
Patrick J. Horgan   withheld                                          
        
Stephen Baynes      <[email protected]>             
        
James Raynard       withheld                                          
        
Michael F. Quigley  withheld                                          
        
Ken Pizzini         withheld                                          
        
Thamer Al-Herbish   withheld                                          
        
Nick Kew            <[email protected]>                              
        
Dan Abarbanel       withheld                                          
        
Billy Chambless     <[email protected]>                          
        
Walter Briscoe      <[email protected]>                     
        
Jim Buchanan        <[email protected]>                             
        
Dave Plonka         <[email protected]>                            
        
Daniel Stenberg     withheld                                          
        
Ralph Corderoy      <[email protected]>                     
        
Stuart Kemp         withheld                                          
        
Sergei Chernev      <[email protected]>                                      
        
Bjorn Reese         withheld                                          
        
Joe Halpin          <[email protected]>                               
        
Aaron Crane         <[email protected]>                                
        
Geoff Clare         <[email protected]>                                  
        

List of Questions
*****************

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

2. General File handling (including pipes and sockets)
  2.1 How to manage multiple connections?
    2.1.1 How do I use select()?
    2.1.2 How do I use poll()?
    2.1.3 Can I use SysV IPC at the same time as select or poll?
  2.2 How can I tell when the other end of a connection shuts down?
  2.3 Best way to read directories?
  2.4 How can I find out if someone else has a file open?
  2.5 How do I `lock' a file?
  2.6 How do I find out if a file has been updated by another process?

  2.7 How does the `du' utility work?
  2.8 How do I find the size of a file?
  2.9 How do I expand `~' in a filename like the shell does?
  2.10 What can I do with named pipes (FIFOs)?
    2.10.1 What is a named pipe?
    2.10.2 How do I create a named pipe?
    2.10.3 How do I use a named pipe?
    2.10.4 Can I use a named pipe across NFS?
    2.10.5 Can multiple processes write to the pipe simultaneously?
    2.10.6 Using named pipes in applications

3. Terminal I/O
  3.1 How can I make my program not echo input?
  3.2 How can I read single characters from the terminal?
  3.3 How can I check and see if a key was pressed?
  3.4 How can I move the cursor around the screen?
  3.5 What are pttys?
  3.6 How to handle a serial port or modem?
    3.6.1 Serial device names and types
    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

4. System Information
  4.1 How can I tell how much memory my system has?
  4.2 How do I check a user's password?
    4.2.1 How do I get a user's password?
    4.2.2 How do I get shadow passwords by uid?
    4.2.3 How do I verify a user's password?

5. Miscellaneous programming
  5.1 How do I compare strings using wildcards?
    5.1.1 How do I compare strings using filename patterns?
    5.1.2 How do I compare strings using regular expressions?
  5.2 What's the best way to send mail from a program?
    5.2.1 The simple method: /bin/mail
    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

6. Use of tools
  6.1 How can I debug the children after a fork?
  6.2 How to build library from other libraries?
  6.3 How to create shared libraries / dlls?
  6.4 Can I replace objects in a shared library?
  6.5 How can I generate a stack dump from within a running program?

1. Process Control
******************

1.1 Creating new processes: fork()
==================================

1.1.1 What does fork() do?
--------------------------

     #include <sys/types.h>
     #include <unistd.h>
     
     pid_t fork(void);

The `fork()' function is used to create a new process from an existing

process.  The new process is called the child process, and the existin
g
process is called the parent.  You can tell which is which by checking
 the
return value from `fork()'.  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.

     pid_t pid;
     
     switch (pid = fork())
     {
     case -1:
         /* Here pid is -1, the fork failed */
         /* Some possible reasons are that you're */
         /* out of process slots or virtual memory */
         perror("The fork failed!");
         break;
     
     case 0:
         /* pid of zero is the child */
         /* Here we're the child...what should we do? */
         /* ... */
         /* but after doing it, we should do something like: */
         _exit(0);
     
     default:
         /* pid greater than zero is parent getting the child's pid */

         printf("Child's pid is %d\n",pid);
     }

Of course, one can use `if()... else...' instead of `switch()', but th
e
above form is a useful idiom.

Of help when doing this is knowing just what is and is not inherited b
y the
child.  This list can vary depending on Unix implementation, so take i
t
with a grain of salt.  Note that the child gets *copies* of these thin
gs,
not the real thing.

Inherited by the child from the parent:

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

   * environment

   * stack

   * memory

   * open file descriptors (note that the underlying file positions ar
e
     shared between the parent and child, which can be confusing)

   * close-on-exec flags

   * signal handling settings

   * nice value

   * scheduler class

   * process group ID

   * session ID

   * current working directory

   * root directory

   * file mode creation mask (umask)

   * resource limits

   * controlling terminal

Unique to the child:

   * process ID

   * different parent process ID

   * Own copy of file descriptors and directory streams.

   * process, text, data and other memory locks are NOT inherited.

   * process times, in the tms struct

   * resource utilizations are set to 0

   * pending signals initialized to the empty set

   * timers created by timer_create not inherited

   * asynchronous input or output operations not inherited

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

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

*However*, since `vfork()' was introduced, the implementation of `fork
()'
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 t
he
justification for `vfork()'; indeed, a large proportion of systems now
 lack
the original functionality of `vfork()' completely. For compatibility,

though, there may still be a `vfork()' call present, that simply calls

`fork()' without attempting to emulate all of the `vfork()' semantics.


As a result, it is *very* unwise to actually make use of any of the
differences between `fork()' and `vfork()'. Indeed, it is probably unw
ise
to use `vfork()' at all, unless you know exactly *why* you want to.

The basic difference between the two is that when a new process is cre
ated
with `vfork()', the parent process is temporarily suspended, and the c
hild
process might borrow the parent's address space. This strange state of

affairs continues until the child process either exits, or calls
`execve()', at which point the parent process continues.

This means that the child process of a `vfork()' must be careful to av
oid
unexpectedly modifying variables of the parent process. In particular,
 the
child process must *not* return from the function containing the `vfor
k()'
call, and it must *not* call `exit()' (if it needs to exit, it should 
use
`_exit()'; actually, this is also true for the child of a normal `fork
()').

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

There are a few differences between `exit()' and `_exit()' that become

significant when `fork()', and especially `vfork()', is used.

The basic difference between `exit()' and `_exit()' 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 `fork()', it is normally incorrect to use
`exit()', 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 *parent* should
 call
`_exit()' rather than the child; the basic rule, applicable in the
overwhelming majority of cases, is that `exit()' should be called only
 once
for each entry into `main'.)

In the child branch of a `vfork()', the use of `exit()' is even more
dangerous, since it will affect the state of the *parent* process.

1.2 Environment variables
=========================

1.2.1 How can I get/set an environment variable from a program?
---------------------------------------------------------------

Getting the value of an environment variable is done by using `getenv(
)'.

     #include <stdlib.h>
     
     char *getenv(const char *name);

Setting the value of an environment variable is done by using `putenv(
)'.

     #include <stdlib.h>
     
     int putenv(char *string);

The string passed to putenv must *not* be freed or made invalid, since
 a
pointer to it is kept by `putenv()'.  This means that it must either b
e a
static buffer or allocated off the heap.  The string can be freed if t
he
environment variable is redefined or deleted via another call to `pute
nv()'.

Remember that environment variables are inherited; each process has a

separate copy of the environment. As a result, you can't change the va
lue
of an environment variable in another process, such as the shell.

Suppose you wanted to get the value for the `TERM' environment variabl
e.
You would use this code:

     char *envvar;
     
     envvar=getenv("TERM");
     
     printf("The value for the environment variable TERM is ");
     if(envvar)
     {
         printf("%s\n",envvar);
     }
     else
     {
         printf("not set.\n");
     }

Now suppose you wanted to create a new environment variable called `MY
VAR',
with a value of `MYVAL'.  This is how you'd do it.

     static char envbuf[256];
     
     sprintf(envbuf,"MYVAR=%s","MYVAL");
     
     if(putenv(envbuf))
     {
         printf("Sorry, putenv() couldn't find the memory for %s\n",en
vbuf);
         /* Might exit() or something here if you can't live without i
t */
     }

1.2.2 How can I read the whole environment?
-------------------------------------------

If you don't know the names of the environment variables, then the
`getenv()' function isn't much use. In this case, you have to dig deep
er
into how the environment is stored.

A global variable, `environ', holds a pointer to an array of pointers 
to
environment strings, each string in the form `"NAME=value"'. A `NULL'

pointer is used to mark the end of the array. Here's a trivial program
 to
print the current environment (like `printenv'):

     #include <stdio.h>
     
     extern char **environ;
     
     int main()
     {
         char **ep = environ;
         char *p;
         while ((p = *ep++))
             printf("%s\n", p);
         return 0;
     }

In general, the `environ' variable is also passed as the third, option
al,
parameter to `main()'; that is, the above could have been written:

     #include <stdio.h>
     
     int main(int argc, char **argv, char **envp)
     {
         char *p;
         while ((p = *envp++))
             printf("%s\n", p);
         return 0;
     }

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

1.3 How can I sleep for less than a second?
===========================================

The `sleep()' 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:

   * Many systems have a function `usleep()'

   * You can use `select()' or `poll()', specifying no file descriptor
s to
     test; a common technique is to write a `usleep()' function based 
on
     either of these (see the comp.unix.questions FAQ for some example
s)

   * If your system has itimers (most do), you can roll your own `usle
ep()'
     using them (see the BSD sources for `usleep()' for how to do this
)

   * If you have POSIX realtime, there is a `nanosleep()' function

Of the above, `select()' is probably the most portable (and strangely,
 it
is often much more efficient than `usleep()' or an itimer-based method
).
However, the behaviour may be different if signals are caught while as
leep;
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 `sleep()', the 
delay
you specify is only a *minimum* value; after the specified period elap
ses,
there will be an indeterminate delay before your process next gets
scheduled.

1.4 How can I get a finer-grained version of alarm()?
=====================================================

Modern Unixes tend to implement alarms using the `setitimer()' functio
n,
which has a higher resolution and more options than the simple `alarm(
)'
function. One should generally assume that `alarm()' and
`setitimer(ITIMER_REAL)' may be the same underlying timer, and accessi
ng 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:

`ITIMER_REAL'
     counts real (wall clock) time, and sends the `SIGALRM' signal

`ITIMER_VIRTUAL'
     counts process virtual (user CPU) time, and sends the `SIGVTALRM'

     signal

`ITIMER_PROF'
     counts user and system CPU time, and sends the `SIGPROF' signal; 
it is
     intended for interpreters to use for profiling.

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

1.5 How can a parent and child process communicate?
===================================================

A parent and child can communicate through any of the normal inter-pro
cess
communication schemes (pipes, sockets, message queues, shared memory),
 but
also have some special ways to communicate that take advantage of thei
r
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 t
he
`popen()' routine to run another program from within yours, i.e. you c
an
write to the file descriptor returned from `popen()' and the child pro
cess
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 `popen()' defi
nes
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 `/dev/zero') by the parent; these shared mem
ory
segments are not accessible from unrelated processes.

1.6 How 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 ker
nel
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 `wait()'
;
when this happens, the kernel can discard the information.

In the interval between the child terminating and the parent calling
`wait()', the child is said to be a `zombie'.  (If you do `ps', the ch
ild
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 a
nd it
is possible for the system to run out of them. Even if the system does
n'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 `fork()' failed, by the way!

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

1.6.2 How do I prevent them from occuring?
------------------------------------------

You need to ensure that your parent process calls `wait()' (or `waitpi
d()',
`wait3()', etc.) for every child process that terminates; or, on some

systems, you can instruct the system that you are uninterested in chil
d
exit states.

Another approach is to `fork()' *twice*, 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 c
ode
to do this, see the function `fork2()' 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):

         struct sigaction sa;
         sa.sa_handler = SIG_IGN;
     #ifdef SA_NOCLDWAIT
         sa.sa_flags = SA_NOCLDWAIT;
     #else
         sa.sa_flags = 0;
     #endif
         sigemptyset(&sa.sa_mask);
         sigaction(SIGCHLD, &sa, NULL);

If this is successful, then the `wait()' functions are prevented from

working; if any of them are called, they will wait until *all* child
processes have terminated, then return failure with `errno == ECHILD'.


The other technique is to catch the SIGCHLD signal, and have the signa
l
handler call `waitpid()' or `wait3()'. See the examples section for a

complete program.

1.7 How do I get my program to act like a daemon?
=================================================

A "daemon" process is usually defined as a background process that doe
s 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 starti
ng
daemons is simply to issue the command manually or from an rc script; 
the
daemon is expected to put *itself* into the background.

Here are the steps to become a daemon:

  1. `fork()' so the parent can exit, this returns control to the comm
and
     line or shell invoking your program.  This step is required so th
at
     the new process is guaranteed not to be a process group leader. T
he
     next step, `setsid()', fails if you're a process group leader.

  2. `setsid()' to become a process group and session group leader. Si
nce a
     controlling terminal is associated with a session, and this new
     session has not yet acquired a controlling terminal our process n
ow
     has no controlling terminal, which is a Good Thing for daemons.

  3. `fork()' again so the parent, (the session group leader), can exi
t.
     This means that we, as a non-session group leader, can never rega
in a
     controlling terminal.

  4. `chdir("/")' to ensure that our process doesn't keep any director
y in
     use. Failure to do this could make it so that an administrator
     couldn't unmount a filesystem, because it was our current directo
ry.

     [Equivalently, we could change to any directory containing files

     important to the daemon's operation.]

  5. `umask(0)' 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. `close()' fds 0, 1, and 2. This releases the standard in, out, an
d
     error we inherited from our parent process. We have no way of kno
wing
     where these fds might have been redirected to. Note that many dae
mons
     use `sysconf()' to determine the limit `_SC_OPEN_MAX'.  `_SC_OPEN
_MAX'
     tells you the maximun open files/process. Then in a loop, the dae
mon
     can close all possible file descriptors. You have to decide if yo
u
     need to do this or not.  If you think that there might be
     file-descriptors open you should close them, since there's a limi
t 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 stde
rr,
     and open `/dev/null' as stdin; alternatively, you could open
     `/dev/console' as stderr and/or stdout, and `/dev/null' 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 bein
g
started by `inetd'.  In that case, stdin, stdout and stderr are all se
t up
for you to refer to the network connection, and the `fork()'s and sess
ion
manipulation should *not* be done (to avoid confusing `inetd').  Only 
the
`chdir()' and `umask()' steps remain as useful.

1.8 How can I look at process in the system like ps does?
=========================================================

You really *don't* want to do this.

The most portable way, by far, is to do `popen(pscmd, "r")' and parse 
the
output. (pscmd should be something like `"ps -ef"' 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 `kvm_*'
routines to read the information from kernel data structures; and anot
her
for SVR4 systems (including SunOS 5), which uses the `/proc' filesyste
m.

It's even easier on systems with an SVR4.2-style `/proc'; just read a

psinfo_t structure from the file `/proc/PID/psinfo' for each PID of
interest. However, this method, while probably the cleanest, is also
perhaps the least well-supported. (On FreeBSD's `/proc', you read a
semi-undocumented printable string from `/proc/PID/status'; Linux has

something similar.)

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

Use `kill()' with 0 for the signal number.

There are four possible results from this call:

   * `kill()' returns 0

        - this implies that a process exists with the given PID, and t
he
          system would allow you to send signals to it. It is
          system-dependent whether the process could be a zombie.

   * `kill()' returns -1, `errno == ESRCH'

        - 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.)

   * `kill()' returns -1, `errno == EPERM'

        - the system would not allow you to kill the specified process
.
          This means that either the process exists (again, it could b
e a
          zombie) or draconian security enhancements are present (e.g.
 your
          process is not allowed to send signals to *anybody*).

   * `kill()' returns -1, with some other value of `errno'

        - you are in trouble!

The most-used technique is to assume that success or failure with `EPE
RM'
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 (o
r all
those systems) that provide a `/proc' filesystem: checking for the
existence of `/proc/PID' may work.

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

     The return value of `system()', `pclose()', or `waitpid()' 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
`waitpid()' you'll find that the return code for the process is encode
d.
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 prov
ided.
These are usually documented under `wait()' or `wstat'.

Macros defined for the purpose (in `<sys/wait.h>') include (stat is th
e
value returned by `waitpid()'):

`WIFEXITED(stat)'
     Non zero if child exited normally.

`WEXITSTATUS(stat)'
     exit code returned by child

`WIFSIGNALED(stat)'
     Non-zero if child was terminated by a signal

`WTERMSIG(stat)'
     signal number that terminated child

`WIFSTOPPED(stat)'
     non-zero if child is stopped

`WSTOPSIG(stat)'
     number of signal that stopped child

`WIFCONTINUED(stat)'
     non-zero if status was for continued child

`WCOREDUMP(stat)'
     If `WIFSIGNALED(stat)' is non-zero, this is non-zero if the proce
ss
     left behind a core dump.

1.11 How do I find out about a process' memory usage?
=====================================================

Look at `getrusage()', if available.

1.12 Why do processes never decrease in size?
=============================================

When you free memory back to the heap with `free()', on almost all sys
tems
that *doesn't* reduce the memory usage of your program.  The memory
`free()'d is still part of the process' address space, and will be use
d to
satisfy future `malloc()' requests.

If you really need to free memory back to the system, look at using
`mmap()' to allocate private anonymous mappings.  When these are unmap
ped,
the memory really is released back to the system.  Certain implementat
ions
of `malloc()' (e.g. in the GNU C Library) automatically use `mmap()' w
here
available to perform large allocations; these blocks are then returned
 to
the system on `free()'.

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 u
nused
memory not being freed.

1.13 How do I change the name of my program (as seen by `ps')?
==============================================================

On BSDish systems, the `ps' program actually looks into the address sp
ace
of the running process to find the current `argv[]', and displays that
.
That enables a program to change its `name' simply by modifying `argv[
]'.

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 `exec()', or write into kernel

memory (dangerous, and only possible if running as root).

Some systems (notably Solaris) may have two separate versions of `ps',
 one
in `/usr/bin/ps' with SysV behaviour, and one in `/usr/ucb/ps' with BS
D
behaviour. On these systems, if you change `argv[]', then the BSD vers
ion
of `ps' will reflect the change, and the SysV version won't.

Check to see if your system has a function `setproctitle()'.

1.14 How 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 `argv[0]'.  If 
this
contains a `/', then it is probably the absolute or relative (to the
current directory at program start) path of the executable.  If it doe
s
not, then you can mimic the shell's search of the `PATH' variable, loo
king
for the program.  However, success is not guaranteed, since it is poss
ible
to invoke programs with arbitrary values of `argv[0]', 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 `main()' save the va
lue
of `argv[0]' in a global variable for use by the entire program.  Whil
e
there is no guarantee whatsoever that the value in `argv[0]' 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 f
orm;
directories containing executables should contain *nothing* except
executables, and administrative requirements often make it desirable f
or
configuration files to be located on different filesystems to executab
les.

A less common, but more legitimate, reason to do this is to allow the

program to call `exec()' *on itself*; this is a method used (e.g. by s
ome
versions of `sendmail') to completely reinitialise the process (e.g. i
f a
daemon receives a `SIGHUP').

1.14.1 So where do I put my configuration files then?
-----------------------------------------------------

The correct directory for this usually depends on the particular flavo
ur of
Unix you're using; `/var/opt/PACKAGE', `/usr/local/lib', `/usr/local/e
tc',
or any of several other possibilities.  User-specific configuration fi
les
are usually hidden `dotfiles' under `$HOME' (e.g. `$HOME/.exrc').

From the point of view of a package that is expected to be usable acro
ss a
range of systems, this usually implies that the location of any sitewi
de
configuration files will be a compiled-in default, possibly using a
`--prefix' option on a configure script (Autoconf scripts do this).  Y
ou
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 defau
lt in
the Makefile as a `-D' option on compiles, or put it in a `config.h' h
eader
file, or something similar.)

User-specific configuration should be either a single dotfile under
`$HOME', or, if you need multiple files, a dot-subdirectory.  (Files o
r
directories whose names start with a dot are omitted from directory
listings by default.) Avoid creating multiple entries under `$HOME',
because this can get very cluttered. Again, you can allow the user to

override this location with an environment variable. Programs should a
lways
behave sensibly if they fail to find any per-user configuration.

1.15 Why doesn't my process get SIGHUP when its parent dies?
============================================================

Because it's not supposed to.

`SIGHUP' is a signal that means, by convention, "the terminal line got
 hung
up".  It has nothing to do with parent processes, and is usually gener
ated
by the tty driver (and delivered to the foreground process group).

However, as part of the session management system, there are exactly t
wo
cases where `SIGHUP' is sent on the death of a process:

   * When the process that dies is the session leader of a session tha
t is
     attached to a terminal device, `SIGHUP' is sent to all processes 
in
     the foreground process group of that terminal device.

   * When the death of a process causes a process group to become orph
aned,
     and one or more processes in the orphaned group are *stopped*, th
en
     `SIGHUP' and `SIGCONT' are sent to all members of the orphaned gr
oup.
     (An orphaned process group is one where no process in the group h
as a
     parent which is part of the same session, but not the same proces
s
     group.)

1.16 How 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 `ps' 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 sp
awned
job at one go, the solution is to put the subprocess into a new proces
s
group, and kill that process group if you need to.

The preferred function for creating process groups is `setpgid()'.  Us
e
this if possible rather than `setpgrp()' because the latter differs be
tween
systems (on some systems `setpgrp();' is equivalent to `setpgid(0,0);'
, on
others, `setpgrp()' and `setpgid()' are identical).

See the job-control example in the examples section.

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

   * it will be stopped with `SIGTTIN' if it attempts to read from the

     terminal

   * if `tostop' is set in the terminal modes, it will be stopped with

     `SIGTTOU' if it attempts to write to the terminal (attempting to

     change the terminal modes should also cause this, independently o
f the
     current setting of `tostop')

   * The subprocess will not receive keyboard signals from the termina
l
     (e.g. `SIGINT' or `SIGQUIT')

In many applications input and output will be redirected anyway, so th
e
most significant effect will be the lack of keyboard signals. The pare
nt
application should arrange to catch at least `SIGINT' and `SIGQUIT' (a
nd
preferably `SIGTERM' as well) and clean up any background jobs as nece
ssary.

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

See also the Sockets FAQ, available at:

`http://www.ibrado.com/sock-faq/'

`http://kipper.york.ac.uk/~vic/sock-faq/'

`ftp://rtfm.mit.edu/pub/usenet/news.answers/unix-faq/socket'

2.1 How 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 `select()' or `poll()'.

Note: `select()' was introduced in BSD, whereas `poll()' is an artifac
t of
SysV STREAMS. As such, there are portability issues; pure BSD systems 
may
still lack `poll()', whereas some older SVR3 systems may not have
`select()'. SVR4 added `select()', and the Posix.1g standard defines b
oth.

`select()' and `poll()' essentially do the same thing, just differentl
y.
Both of them examine a set of file descriptors to see if specific even
ts
are pending on any, and then optionally wait for a specified time for 
an
event to happen.

[Important note: neither `select()' nor `poll()' do anything useful wh
en
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 How do I use select()?
----------------------------

The interface to `select()' is primarily based on the concept of an
`fd_set', 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 manipulat
ing
fd_sets:

     fd_set set;
     FD_ZERO(&set);      /* empties the set */
     FD_SET(fd,&set);    /* adds FD to the set */
     FD_CLR(fd,&set);    /* removes FD from the set */
     FD_ISSET(fd,&set)   /* true if FD is in the set */

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 `FD_SETSIZE' macro.  *This is system-dependent*; chec
k
your `select()' manpage. Also, some systems have problems handling mor
e
than 1024 file descriptors in `select()'.

The basic interface to select is simple:

     int select(int nfds, fd_set *readset,
                          fd_set *writeset,
                          fd_set *exceptset, struct timeval *timeout);


where

`nfds'
     the number of FDs to examine; this must be greater than the large
st FD
     in any of the fdsets, *not* the actual number of FDs specified

`readset'
     the set of FDs to examine for readability

`writeset'
     the set of FDs to examine for writability

`exceptfds'
     the set of FDs to examine for exceptional status (note: errors ar
e
     *not* exceptional statuses)

`timeout'
     NULL for infinite timeout, or points to a timeval specifying the

     maximum wait time (if `tv_sec' and `tv_usec' both equal zero, the
n 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
`FD_ISSET' macro to test the returned sets.

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

     int isready(int fd)
     {
         int rc;
         fd_set fds;
         struct timeval tv;
     
         FD_ZERO(&fds);
         FD_SET(fd,&fds);
         tv.tv_sec = tv.tv_usec = 0;
     
         rc = select(fd+1, &fds, NULL, NULL, &tv);
         if (rc < 0)
return -1;

return FD_ISSET(fd,&fds) ? 1 : 0;
}

Note that we can pass `NULL' for fdsets that we aren't interested in
testing.

2.1.2 How do I use poll()?
--------------------------

`poll()' accepts a pointer to a list of `struct pollfd', in which the

descriptors and the events you wish to poll for are stored. The event
s are
specified via a bitwise mask in the events field of the structure. Th
e
instance of the structure will later be filled in and returned to you
with
any events which occured. Macros defined by `poll.h' on SVR4 (probabl
y
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 `poll()' to

return immediately; a value of -1 will suspend poll until an event is
found
to be true.

struct pollfd {
int fd; /* The descriptor. */
short events; /* The event(s) is/are specified here. */
short revents; /* Events found are returned here. */
};

A lot like `select()', 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 e
vents
specified have occured. A negative value should immediately be follow
ed by
a check of `errno', since it signifies an error.

If no events are found, `revents' is cleared, so there's no need for y
ou to
do this yourself.

The returned events are tested to contain the event.

Here's an example:

/* Poll on two descriptors for Normal data, or High priority data
.
If any found call function handle() with appropriate descripto
r
and priority. Don't timeout, only give up if error, or one of
the
descriptors hangs up. */

#include <stdlib.h>
     #include <stdio.h>
     
     #include <sys/types.h>
     #include <stropts.h>
     #include <poll.h>
     
     #include <unistd.h>
     #include <errno.h>
     #include <string.h>
     
     #define NORMAL_DATA 1
     #define HIPRI_DATA 2
     
     int poll_two_normal(int fd1,int fd2)
     {
         struct pollfd poll_list[2];
         int retval;
     
         poll_list[0].fd = fd1;
         poll_list[1].fd = fd2;
         poll_list[0].events = POLLIN|POLLPRI;
         poll_list[1].events = POLLIN|POLLPRI;
     
         while(1)
         {
             retval = poll(poll_list,(unsigned long)2,-1);
             /* Retval will always be greater than 0 or -1 in this cas
e.
                Since we're doing it while blocking */
     
             if(retval < 0)
{
fprintf(stderr,"Error while polling: %s\n",strerror(e
rrno));
return -1;
}

if(((poll_list[0].revents&POLLHUP) == POLLHUP) ||
((poll_list[0].revents&POLLERR) == POLLERR) ||
((poll_list[0].revents&POLLNVAL) == POLLNVAL) ||
((poll_list[1].revents&POLLHUP) == POLLHUP) ||
((poll_list[1].revents&POLLERR) == POLLERR) ||
((poll_list[1].revents&POLLNVAL) == POLLNVAL))
return 0;

if((poll_list[0].revents&POLLIN) == POLLIN)
handle(poll_list[0].fd,NORMAL_DATA);
if((poll_list[0].revents&POLLPRI) == POLLPRI)
handle(poll_list[0].fd,HIPRI_DATA);
if((poll_list[1].revents&POLLIN) == POLLIN)
handle(poll_list[1].fd,NORMAL_DATA);
if((poll_list[1].revents&POLLPRI) == POLLPRI)
handle(poll_list[1].fd,HIPRI_DATA);
}
}

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 `select()' or `poll()' with u
sing
SysV message queues is troublesome. SysV IPC objects are not handled b
y
file descriptors, so they can't be passed to `select()' or `poll()'. T
here
are a number of workarounds, of varying degrees of ugliness:

- Abandon SysV IPC completely. :-)

- `fork()', and have the child process handle the SysV IPC,
communicating with the parent process by a pipe or socket, which
the
parent process can `select()' on.

- As above, but have the child process do the `select()', and
communicate with the parent by message queue.

- Arrange for the process that sends messages to you to send a sign
al
after each message. *Warning:* handling this right is non-trivial
;
it's very easy to write code that can potentially lose messages o
r
deadlock using this method.

(Other methods exist.)

2.2 How 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 (`re
ad()'
returns 0 bytes read). If you try and write to a pipe, socket etc. whe
n the
reading end has closed, then a `SIGPIPE' signal will be delivered to t
he
process, killing it unless the signal is caught. (If you ignore or blo
ck
the signal, the `write()' call fails with `EPIPE'.)

2.3 Best way to read directories?
=================================

While historically there have been several different interfaces for th
is,
the only one that really matters these days the the Posix.1 standard
`<dirent.h>' functions.

The function `opendir()' opens a specified directory; `readdir()' read
s
directory entries from it in a standardised format; `closedir()' does 
the
obvious. Also provided are `rewinddir()', `telldir()' and `seekdir()' 
which
should also be obvious.

If you are looking to expand a wildcard filename, then most systems ha
ve
the `glob()' function; also check out `fnmatch()' to match filenames
against a wildcard, or `ftw()' to traverse entire directory trees.

2.4 How can I find out if someone else has a file open?
=======================================================

This is another candidate for `Frequently Unanswered Questions' becaus
e, in
general, your program should never be interested in whether someone el
se
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 `fuser' and `ls
of'
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 How do I `lock' a file?
===========================

There are three main file locking mechanisms available. All of them ar
e
`advisory'[*], which means that they rely on programs co-operating in 
order
to work.  It is therefore vital that all programs in an application sh
ould
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 b
it -
RTFM for this hack.

Some applications use lock files - something like `FILENAME.lock'.  Si
mply
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 contro
lling
access to modems, remote systems etc.) is to store the PID in the lock
file,
and test if that pid is still running.  Even this isn't enough to be s
ure
(since PIDs are recycled); it has to have a backstop check to see if t
he
lockfile is old, which means that the process holding the lock must up
date
the file regularly.  Messy.

The locking functions are:

         flock();
         lockf();
         fcntl();

`flock()' originates with BSD, and is now available in most (but not a
ll)
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, th
e
popular Perl programming language implements its own `flock()' where
necessary, conveying the illusion of true portability.

`fcntl()' is the only POSIX-compliant locking mechanism, and is theref
ore
the only truly portable lock.  It is also the most powerful, and the
hardest to use.  For NFS-mounted file systems, `fcntl()' requests are

passed to a daemon (`rpc.lockd'), which communicates with the lockd on
 the
server host.  Unlike `flock()' it is capable of record-level locking.


`lockf()' is merely a simplified programming interface to the locking

functions of `fcntl()'.

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

         lock(fd);
         write_to(some_function_of(fd));
         flush_output_to(fd); /* NEVER unlock while output may be buff
ered */
         unlock(fd);
         do_something_else;   /* another process might update it */
         lock(fd);
         seek(fd, somewhere); /* because our old file pointer is not s
afe */
         do_something_with(fd);
         ...

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

     #include <fcntl.h>
     #include <unistd.h>
     
     read_lock(int fd)   /* a shared lock on an entire file */
     {
         fcntl(fd, F_SETLKW, file_lock(F_RDLCK, SEEK_SET));
     }
     
     write_lock(int fd)  /* an exclusive lock on an entire file */
     {
         fcntl(fd, F_SETLKW, file_lock(F_WRLCK, SEEK_SET));
     }
     
     append_lock(int fd) /* a lock on the _end_ of a file -- other
                            processes may access existing records */
     {
         fcntl(fd, F_SETLKW, file_lock(F_WRLCK, SEEK_END));
     }

The function file_lock used by the above is

     struct flock* file_lock(short type, short whence)
     {
         static struct flock ret ;
         ret.l_type = type ;
         ret.l_start = 0 ;
         ret.l_whence = whence ;
         ret.l_len = 0 ;
         ret.l_pid = getpid() ;
         return &ret ;
     }

2.6 How do I find out if a file has been updated by another process?
====================================================================

This is close to being a Frequently Unanswered Question, because peopl
e
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.
(IRIX 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 `fstat()' on the file. (Note
: the
overhead on `fstat()' is quite low, usually much lower than the overhe
ad of
`stat()'.) 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 yo
u
might want to rethink *why* you want to do it.

2.7 How does the `du' utility work?
===================================

`du' simply traverses the directory structure calling `stat()' (or mor
e
accurately, `lstat()') on every file and directory it encounters, addi
ng 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 yo
u
have to unpack the archives yourself.

2.8 How do I find the size of a file?
=====================================

Use `stat()', or `fstat()' if you have the file open.

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

The following routine illustrates how to use `stat()' to get the file 
size.

     #include <stdlib.h>
     #include <stdio.h>
     
     #include <sys/types.h>
     #include <sys/stat.h>
     
     int get_file_size(char *path,off_t *size)
     {
       struct stat file_stats;
     
       if(stat(path,&file_stats))
         return -1;
     
       *size = file_stats.st_size;
       return 0;
     }

2.9 How do I expand `~' in a filename like the shell does?
==========================================================

The standard interpretation for `~' at the start of a filename is: if 
alone
or followed by a `/', then substitute the current user's home director
y; if
followed by the name of a user, then substitute that user's home direc
tory.
If no valid expansion can be found, then shells will leave the filenam
e
unchanged.

Be wary, however, of filenames that actually start with the `~' charac
ter.
Indiscriminate tilde-expansion can make it very difficult to specify s
uch
filenames to a program; while quoting will prevent the shell from doin
g the
expansion, the quotes will have been removed by the time the program s
ees
the filename. As a general rule, do not try and perform tilde-expansio
n on
filenames that have been passed to the program on the command line or 
in
environment variables. (Filenames generated within the program, obtain
ed 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:

     string expand_path(const string& path)
     {
         if (path.length() == 0 || path[0] != '~')
           return path;
     
         const char *pfx = NULL;
         string::size_type pos = path.find_first_of('/');
     
         if (path.length() == 1 || pos == 1)
         {
             pfx = getenv("HOME");
             if (!pfx)
             {
                 // Punt. We're trying to expand ~/, but HOME isn't se
t
                 struct passwd *pw = getpwuid(getuid());
                 if (pw)
                   pfx = pw->pw_dir;
             }
         }
         else
         {
             string user(path,1,(pos==string::npos) ? string::npos : p
os-1);
             struct passwd *pw = getpwnam(user.c_str());
             if (pw)
               pfx = pw->pw_dir;
         }
     
         // if we failed to find an expansion, return the path unchang
ed.
     
         if (!pfx)
           return path;
     
         string result(pfx);
     
         if (pos == string::npos)
           return result;
     
         if (result.length() == 0 || result[result.length()-1] != '/')

           result += '/';
     
         result += path.substr(pos+1);
     
         return result;
     }

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 anoth
er
process reads from it.  Named pipes are visible in the file system and
 may
be viewed with `ls' like any other file.  (Named pipes are also called

"fifo"s; this term stands for `First In, First Out'.)

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

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

2.10.2 How do I create a named pipe?
------------------------------------

To create a named pipe interactively, you'll use either `mknod' or
`mkfifo'. 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 `mkfifo()':

     /* set the umask explicitly, you don't know where it's been */
     umask(0);
     if (mkfifo("test_fifo", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP))
     {
         perror("mkfifo");
         exit(1);
     }

If you don't have `mkfifo()', you'll have to use `mknod()':

     /* set the umask explicitly, you don't know where it's been */
     umask(0);
     if (mknod("test_fifo",
                 S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
                0))
     {
         perror("mknod");
         exit(1);
     }

2.10.3 How do I use a named pipe?
---------------------------------

To use the pipe, you open it like a normal file, and use `read()' and

`write()' just as though it was a plain pipe.

However, the `open()' of the pipe may block. The following rules apply
:

   * If you open for both reading and writing (`O_RDWR'), then the ope
n
     will not block.

   * If you open for reading (`O_RDONLY'), the open will block until
     another process opens the FIFO for writing, unless `O_NONBLOCK' i
s
     specified, in which case the open succeeds.

   * If you open for writing `O_WRONLY', the open will block until ano
ther
     process opens the FIFO for reading, unless `O_NONBLOCK' is specif
ied,
     in which case the open fails.

When reading and writing the FIFO, the same considerations apply as fo
r
regular pipes and sockets, i.e. `read()' will return EOF when all writ
ers
have closed, and `write()' will raise `SIGPIPE' when there are no read
ers.
If `SIGPIPE' is blocked or ignored, the call fails with `EPIPE'.

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 commun
icate
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 `PIPE_BUF' in s
ize,
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 `PIPE_BUF' is guaranteed (by Posix) to be at least 512.  
It
may or may not be defined in `<limits.h>', but it can be queried for
individual pipes using `pathconf()' or `fpathconf()'.

2.10.6 Using 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 se
rver
at once.  As long as each command they send to the server is smaller t
han
`PIPE_BUF' (see above), they can all use the same named pipe to send d
ata
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 n
o 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 How can I make my program not echo input?
=============================================

     How can I make my program not echo input, like login does when as
king
     for your password?

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

The easy way, is to use `getpass()', which is probably found on almost
 all
Unices. It takes a string to use as a prompt. It will read up to an `E
OF'
or newline and returns a pointer to a static area of memory holding th
e
string typed in.

The harder way is to use `tcgetattr()' and `tcsetattr()', both use a
`struct termios' to manipulate the terminal. The following two routine
s
should allow echoing, and non-echoing mode.

     #include <stdlib.h>
     #include <stdio.h>
     
     #include <termios.h>
     #include <string.h>
     
     static struct termios stored_settings;
     
     void echo_off(void)
     {
         struct termios new_settings;
         tcgetattr(0,&stored_settings);
         new_settings = stored_settings;
         new_settings.c_lflag &= (~ECHO);
         tcsetattr(0,TCSANOW,&new_settings);
         return;
     }
     
     void echo_on(void)
     {
         tcsetattr(0,TCSANOW,&stored_settings);
         return;
     }

Both routines used, are defined by the POSIX standard.

3.2 How can I read single characters from the terminal?
=======================================================

     How can I read single characters from the terminal? My program is

[关闭][返回]