Unix Programming FAQ (v1
Unix Programming FAQ (v1
37)
Search FAQs
2 Like 461 Unix Programming FAQ (v1.37)
3ABC DEFGHIJKLM
Font: Monospace
NOPQRSTUVWXYZ
[ Usenet FAQs | Web FAQs | Documents | RFC Index | Counties ]
ArchiveName: unixfaq/programmer/faq
CompunixprogrammerArchiveName: faq
URL: http://www.erlenstar.demon.co.uk/unix/faq_toc.html
URL: http://www.whitefang.com/unix/faq_toc.html
PostingFrequency: every 2 weeks
Copyright: Collection Copyright (C) 19972000 Andrew Gierth.
LastModified: 2000/09/01 06:34:57
Version: 1.37
See reader questions & answers on this topic! Help others by sharing your knowledge
==============================================================================
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'.
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.html'.
Other sources of information are not listed here. You can find pointers to
other FAQs, books, source code etc. in the regular [READ ME FIRST] posting
that should appear weekly in comp.unix.programmer. Administrivia regarding
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 errors
or omissions are my responsibility rather than that of the contributor.
This FAQ is now maintained as Texinfo source; I'm generating a raw text
version for Usenet using the `makeinfo' program, and an HTML version using
`texi2html'.
Copyright (C) 1997, 1998, 1999, 2000 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 reasonable
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 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?
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 2/56
3/13/2017 Unix Programming FAQ (v1.37)
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
******************
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
pid_t pid;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 3/56
3/13/2017 Unix Programming FAQ (v1.37)
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 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 *copies* of these things,
not the real thing.
* environment
* stack
* memory
* open file descriptors (note that the underlying file positions are
shared between the parent and child, which can be confusing)
* close‐on‐exec flags
* nice value
* scheduler class
* process group ID
* session ID
* root directory
* resource limits
* controlling terminal
* process ID
* process, text, data and other memory locks are NOT inherited.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 4/56
3/13/2017 Unix Programming FAQ (v1.37)
Some systems have a system call `vfork()', which was originally designed 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).
The basic difference between the two is that when a new process is created
with `vfork()', 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
`execve()', at which point the parent process continues.
This means that the child process of a `vfork()' 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 `vfork()'
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.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 5/56
3/13/2017 Unix Programming FAQ (v1.37)
#include <stdlib.h>
#include <stdlib.h>
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 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 `putenv()'.
Suppose you wanted to get the value for the `TERM' environment variable.
You would use this code:
char *envvar;
envvar=getenv("TERM");
Now suppose you wanted to create a new environment variable called `MYVAR',
with a value of `MYVAL'. This is how you'd do it.
sprintf(envbuf,"MYVAR=%s","MYVAL");
if(putenv(envbuf))
{
printf("Sorry, putenv() couldn't find the memory for %s\n",envbuf);
/* Might exit() or something here if you can't live without it */
}
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 deeper
into how the environment is stored.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 6/56
3/13/2017 Unix Programming FAQ (v1.37)
#include <stdio.h>
int main()
{
char **ep = environ;
char *p;
while ((p = *ep++))
printf("%s\n", p);
return 0;
}
#include <stdio.h>
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:
* If your system has itimers (most do), you can roll your own `usleep()'
using them (see the BSD sources for `usleep()' for how to do this)
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 7/56
3/13/2017 Unix Programming FAQ (v1.37)
`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 having
been present since 4.2BSD. The POSIX realtime extensions define some
similar, but different, functions.
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
`popen()' routine to run another program from within yours, i.e. you can
write to the file descriptor returned from `popen()' 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 `popen()' 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 `/dev/zero') by the parent; these shared memory
segments are not accessible from unrelated processes.
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 `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 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,
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 8/56
3/13/2017 Unix Programming FAQ (v1.37)
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!
You need to ensure that your parent process calls `wait()' (or `waitpid()',
`wait3()', etc.) for every child process that terminates; or, on some
systems, you can instruct the system that you are uninterested in child
exit states.
To ignore child exit states, you need to do the following (check your
system's manpages to see if this works):
The other technique is to catch the SIGCHLD signal, and have the signal
handler call `waitpid()' or `wait3()'. See the examples section for a
complete program.
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 *itself* into the background.
1. `fork()' 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, `setsid()', fails if you're a process group leader.
3. `fork()' again so the parent, (the session group leader), can exit.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 9/56
3/13/2017 Unix Programming FAQ (v1.37)
This means that we, as a non‐session group leader, can never regain a
controlling terminal.
6. `close()' 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 `sysconf()' to determine the limit `_SC_OPEN_MAX'. `_SC_OPEN_MAX'
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 `/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.
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 another
for SVR4 systems (including SunOS 5), which uses the `/proc' filesystem.
* `kill()' returns 0
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 10/56
3/13/2017 Unix Programming FAQ (v1.37)
‐ 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.
‐ 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 *anybody*).
An alternative exists, if you are writing specifically for a system (or all
those systems) that provide a `/proc' filesystem: checking for the
existence of `/proc/PID' may work.
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 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 `wait()' or `wstat'.
Macros defined for the purpose (in `<sys/wait.h>') include (stat is the
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
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 11/56
3/13/2017 Unix Programming FAQ (v1.37)
`WCOREDUMP(stat)'
If `WIFSIGNALED(stat)' is non‐zero, this is non‐zero if the process
left behind a core dump.
When you free memory back to the heap with `free()', on almost all systems
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 used 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 unmapped,
the memory really is released back to the system. Certain implementations
of `malloc()' (e.g. in the GNU C Library) automatically use `mmap()' where
available to perform large allocations; these blocks are then returned to
the system on `free()'.
On BSDish systems, the `ps' program actually looks into the address space
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 BSD
behaviour. On these systems, if you change `argv[]', then the BSD version
of `ps' will reflect the change, and the SysV version won't.
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 does
not, then you can mimic the shell's search of the `PATH' variable, looking
for the program. However, success is not guaranteed, since it is possible
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.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 12/56
3/13/2017 Unix Programming FAQ (v1.37)
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 *nothing* except
executables, and administrative requirements often make it desirable for
configuration files to be located on different filesystems to executables.
The correct directory for this usually depends on the particular flavour of
Unix you're using; `/var/opt/PACKAGE', `/usr/local/lib', `/usr/local/etc',
or any of several other possibilities. User‐specific configuration files
are usually hidden `dotfiles' under `$HOME' (e.g. `$HOME/.exrc').
1.15 Why doesn't my process get SIGHUP when its parent dies?
============================================================
`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 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 `SIGHUP' is sent on the death of a process:
* When the process that dies is the session leader of a session that is
attached to a terminal device, `SIGHUP' is sent to all processes in
the foreground process group of that terminal device.
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.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 13/56
3/13/2017 Unix Programming FAQ (v1.37)
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.
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:
* The subprocess will not receive keyboard signals from the terminal
(e.g. `SIGINT' or `SIGQUIT')
`http://www.lcg.org/sock‐faq/'
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 14/56
3/13/2017 Unix Programming FAQ (v1.37)
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:
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 */
where
`nfds'
the number of FDs to examine; this must be greater than the largest 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 are
*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, 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
`FD_ISSET' macro to test the returned sets.
FD_ZERO(&fds);
FD_SET(fd,&fds);
tv.tv_sec = tv.tv_usec = 0;
return FD_ISSET(fd,&fds) ? 1 : 0;
}
Note that we can pass `NULL' for fdsets that we aren't interested in
testing.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 15/56
3/13/2017 Unix Programming FAQ (v1.37)
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 events
specified have occured. A negative value should immediately be followed by
a check of `errno', since it signifies an error.
Here's an example:
#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
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 case.
Since we're doing it while blocking */
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 16/56
3/13/2017 Unix Programming FAQ (v1.37)
if(retval < 0)
{
fprintf(stderr,"Error while polling: %s\n",strerror(errno));
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.)
‐ `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.
‐ 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.
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 (`read()'
returns 0 bytes read). If you try and write to a pipe, socket etc. when the
reading end has closed, then a `SIGPIPE' signal will be delivered to the
process, killing it unless the signal is caught. (If you ignore or block
the signal, the `write()' call fails with `EPIPE'.)
While historically there have been several different interfaces for this,
the only one that really matters these days the the Posix.1 standard
`<dirent.h>' functions.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 17/56
3/13/2017 Unix Programming FAQ (v1.37)
If you are looking to expand a wildcard filename, then most systems have
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, in general, too hard to do anyway. Tools like `fuser' and `lsof'
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.
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 ‐
RTFM for this hack.
flock();
lockf();
fcntl();
`flock()' 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 `flock()' where
necessary, conveying the illusion of true portability.
Whatever locking mechanism you use, it is important to sync all your file
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 18/56
3/13/2017 Unix Programming FAQ (v1.37)
lock(fd);
write_to(some_function_of(fd));
flush_output_to(fd); /* NEVER unlock while output may be buffered */
unlock(fd);
do_something_else; /* another process might update it */
lock(fd);
seek(fd, somewhere); /* because our old file pointer is not safe */
do_something_with(fd);
...
#include <fcntl.h>
#include <unistd.h>
2.6 How do I find out if a file has been updated by another process?
====================================================================
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 overhead 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 you
might want to rethink *why* you want to do it.
`du' simply traverses the directory structure calling `stat()' (or more
accurately, `lstat()') on every file and directory it encounters, adding up
the number of blocks consumed by each.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 19/56
3/13/2017 Unix Programming FAQ (v1.37)
If you want more detail about how it works, then the simple answer is:
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 `stat()' to get the file size.
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
if(stat(path,&file_stats))
return ‐1;
*size = file_stats.st_size;
return 0;
}
The standard interpretation for `~' at the start of a filename is: if alone
or followed by a `/', 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 `~' 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:
if (path.length() == 1 || pos == 1)
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 20/56
3/13/2017 Unix Programming FAQ (v1.37)
{
pfx = getenv("HOME");
if (!pfx)
{
// Punt. We're trying to expand ~/, but HOME isn't set
struct passwd *pw = getpwuid(getuid());
if (pw)
pfx = pw‐>pw_dir;
}
}
else
{
string user(path,1,(pos==string::npos) ? string::npos : pos‐1);
struct passwd *pw = getpwnam(user.c_str());
if (pw)
pfx = pw‐>pw_dir;
}
if (!pfx)
return path;
string result(pfx);
if (pos == string::npos)
return result;
result += path.substr(pos+1);
return result;
}
Named pipes may be used to pass data between unrelated processes, while
normal (unnamed) pipes can only connect parent/child processes (unless you
try *very* hard).
/* 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))
{
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 21/56
3/13/2017 Unix Programming FAQ (v1.37)
perror("mkfifo");
exit(1);
}
/* 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);
}
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 open
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' is
specified, in which case the open succeeds.
* If you open for writing `O_WRONLY', the open will block until another
process opens the FIFO for reading, unless `O_NONBLOCK' 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. `read()' will return EOF when all writers
have closed, and `write()' will raise `SIGPIPE' when there are no readers.
If `SIGPIPE' is blocked or ignored, the call fails with `EPIPE'.
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.)
If each piece of data written to the pipe is less than `PIPE_BUF' 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.
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
`PIPE_BUF' (see above), they can all use the same named pipe to send data
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 22/56
3/13/2017 Unix Programming FAQ (v1.37)
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.
3. Terminal I/O
***************
How can I make my program not echo input, like login does when asking
for your password?
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 `EOF'
or newline and returns a pointer to a static area of memory holding the
string typed in.
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <string.h>
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;
}
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 23/56
3/13/2017 Unix Programming FAQ (v1.37)
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 `getc()' to
grab the key pressed immediately by the user. We use `tcgetattr()' and
`tcsetattr()' both of which are defined by POSIX to manipulate the
`termios' structure.
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <string.h>
void set_keypress(void)
{
struct termios new_settings;
tcgetattr(0,&stored_settings);
new_settings = stored_settings;
tcsetattr(0,TCSANOW,&new_settings);
return;
}
void reset_keypress(void)
{
tcsetattr(0,TCSANOW,&stored_settings);
return;
}
How can I check and see if a key was pressed? On DOS I use the
`kbhit()' function, but there doesn't seem to be an equivalent?
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 `termcap' functions, particularly `tputs()', `tparm()' and `tgoto()'.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 24/56
3/13/2017 Unix Programming FAQ (v1.37)
The basic steps for opening and initialising a serial device are:
* `open()' the device; this may require the use of certain flags:
`O_NONBLOCK'
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.
`O_NOCTTY'
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 *don't* want
to acquire a control terminal, and should therefore specify this
flag, but there are exceptions.
* Use `tcgetattr()' 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 `struct termios'.
* You may wish, if you used `O_NONBLOCK' when opening the port, to use
`fcntl()' to ensure that `O_NONBLOCK' is turned off again. Systems
seem to differ as to whether a nonblocking open on a tty will affect
subsequent `read()' calls; better to be explicit.
Once you have opened and set up the port, you can then use `read()' and
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 25/56
3/13/2017 Unix Programming FAQ (v1.37)
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 `close()'
call until the output drains. Calling `tcflush()' to discard any pending
output is probably a wise move.
The device names used for serial port devices vary quite widely between
systems. Some examples from different systems are:
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 RS‐232 DTE):
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 `c_iflag' to 0, unless you want
to use software flow control (ick) in which case you set `IXON' and `IXOFF'.
3.6.2.2 c_oflag
...............
Most of the bits of `c_oflag' are hacks of one sort or another to make
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 26/56
3/13/2017 Unix Programming FAQ (v1.37)
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 `c_iflag', setting everything to 0 is reasonable for most
applications.
3.6.2.3 c_cflag
...............
When setting the character size, remember to mask using `CSIZE' first; e.g.
to set 8‐bit characters, use:
attr.c_cflag &= ~CSIZE;
attr.c_cflag |= CS8;
Other important flags found in `c_cflag' that you probably want to turn
*on* and `CREAD' and `HUPCL'.
If you need to generate even parity, then set `PARENB' and clear `PARODD';
if you need to generate odd parity then set both `PARENB' and `PARODD'. If
you don't want parity at all, then make sure `PARENB' is clear.
Clear `CSTOPB' unless you actually need to generate two stop bits.
Flags for enabling hardware flow control may also be found in `c_cflag',
but they aren't standardised (pity).
3.6.2.4 c_lflag
...............
Most applications will probably want to turn off `ICANON' (canonical, i.e.
line‐based, input processing), `ECHO', and `ISIG'.
3.6.2.5 c_cc
............
(Two of these "characters" are not really characters at all, but control
the behaviour of `read()' when `ICANON' is disabled; these are `VMIN' and
`VTIME'.)
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 `c_cc' are only used if some other combination of
flags is set:
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 27/56
3/13/2017 Unix Programming FAQ (v1.37)
`VMIN' and `VTIME' (which may share slots with `VEOF' and `VEOL'
respectively, depending on the implementation) have the following meaning.
The value of `VTIME' is (if not 0) always interpreted as a timer in tenths
of seconds.
4. System Information
*********************
For HP‐UX (9 and 10), the following code has been contributed:
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 28/56
3/13/2017 Unix Programming FAQ (v1.37)
Though this has changed with time, now user information may be kept on
other hosts, or not necessarily in the `/etc/passwd' 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 `getpwnam()' and `getpwuid()' routines. Both return a pointer to a
struct passwd, which holds the users information in various members.
`getpwnam()' accepts a string holding the user's name, `getpwuid()' accepts
a uid (type `uid_t' as defined by POSIX). Both return NULL if they fail.
My system uses the getsp* suite of routines to get the sensitive user
information. However I do not have `getspuid()', only `getspnam()'.
How do I work around this, and get by uid?
#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <shadow.h>
return shadow;
}
The problem is, that some systems do not keep the uid, or other information
in the shadow database.
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
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 29/56
3/13/2017 Unix Programming FAQ (v1.37)
database. The details of how to encrypt should really come from your man
page for `crypt()', but here's a usual version:
This works because the salt used in encrypting the password is stored as an
initial substring of the encrypted value.
5. Miscellaneous programming
****************************
There are two quite different concepts that qualify as `wildcards'. They
are:
*Filename patterns*
These are what the shell uses for filename expansion (`globbing').
*Regular Expressions*
These are used by editors, `grep', etc. for matching text, but they
normally *aren't* applied to filenames.
Unless you are unlucky, your system should have a function `fnmatch()' to
do filename matching. This generally allows only the Bourne shell style of
pattern; i.e. it recognises `*', `[...]' and `?', 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 `glob()',
which will find all existing files matching a pattern.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 30/56
3/13/2017 Unix Programming FAQ (v1.37)
One library available for this is the `rx' 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 :‐)
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 RFC 821.
*WARNING:* Some versions of UCB Mail may execute commands prefixed by `~!'
or `~|' given in the message body even in non‐interactive mode. This can be
a security risk.
#include <stdio.h>
int main()
{
FILE *mail = popen(MAILPROG " ‐s 'Test Message' root", "w");
if (!mail)
{
perror("popen");
exit(1);
}
if (pclose(mail))
{
fprintf(stderr, "mail failed!\n");
exit(1);
}
}
These methods can be extended to more complex cases, but there are many
pitfalls to watch out for:
* This method does not allow for CC: or BCC: recipients to be specified
(some versions of /bin/mail may allow this, some do not)
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 31/56
3/13/2017 Unix Programming FAQ (v1.37)
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
There are two main ways to use `sendmail' to originate a message: either
the envelope recipients can be explicitly supplied, or `sendmail' can be
instructed to deduce them from the message headers. Both methods have
advantages and disadvantages.
Here's an example:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sysexits.h>
/* #include <paths.h> if you have it */
#ifndef _PATH_SENDMAIL
#define _PATH_SENDMAIL "/usr/lib/sendmail"
#endif
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 32/56
3/13/2017 Unix Programming FAQ (v1.37)
while (recipients[num_recip])
++num_recip;
if (!num_recip)
return 0; /* sending to no recipients is successful */
/* fork */
/* Plumbing */
if (fd != STDIN_FILENO)
dup2(fd, STDIN_FILENO);
/* go for it: */
execv(_PATH_SENDMAIL, argvec);
_exit(EX_OSFILE);
default: /* parent */
free(argvec);
rc = waitpid(pid, &status, 0);
if (rc < 0)
return ‐1;
if (WIFEXITED(status))
return WEXITSTATUS(status);
return ‐1;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 33/56
3/13/2017 Unix Programming FAQ (v1.37)
free(argvec);
return ‐1;
}
}
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
/* #include <paths.h> if you have it */
#ifndef _PATH_SENDMAIL
#define _PATH_SENDMAIL "/usr/lib/sendmail"
#endif
char tfilename[L_tmpnam];
char command[128+L_tmpnam];
void cleanup(void)
{
unlink(tfilename);
}
if (argc < 2)
{
fprintf(stderr, "usage: %s recipients...\n", argv[0]);
exit(2);
}
if (tmpnam(tfilename) == NULL
|| (msg = fopen(tfilename,"w")) == NULL)
exit(2);
atexit(cleanup);
fclose(msg);
msg = fopen(tfilename,"a");
if (!msg)
exit(2);
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 34/56
3/13/2017 Unix Programming FAQ (v1.37)
/* Subject */
/* MIME stuff */
fputc('\n',msg);
fclose(msg);
/* invoke mailer */
return 0;
}
6. Use of tools
***************
Your debugger may have options to select whether to follow the parent or
the child process (or both) after a `fork()', 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 `sleep()' call after the `fork()' in the child process, or a loop
such as the following:
{
volatile int f = 1;
while(f);
}
which will hang the child process until you explicitly set `f' to 0 using
the debugger.
Remember, 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.
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 35/56
3/13/2017 Unix Programming FAQ (v1.37)
Assuming we're talking about an archive (static) library, the easiest way
is to explode all the constituent libraries into their original objects
using `ar x' 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....
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.
/* file shrobj.c */
/* end shrobj.c */
/* file hello.c */
#include <stdio.h>
main()
{
printf("%s\n", myfunc());
return 0;
}
/* end hello.c */
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:
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 36/56
3/13/2017 Unix Programming FAQ (v1.37)
* AIX and (I believe) Digital Unix don't require the ‐fpic option,
because all code is position independent.
* 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.
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 How 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.
void dump_stack(void)
{
char s[160];
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 37/56
3/13/2017 Unix Programming FAQ (v1.37)
return;
}
You will need to tweak the commands and parameters to dbx according to your
system, or even substitute another debugger such as `gdb', but this is
still the most general solution to this particular problem that I've ever
seen. Kudos to Ralph Corderoy for this one :‐)
AIX
`"/bin/echo 'where\ndetach' | dbx ‐a %d"'
IRIX
`"/bin/echo 'where\ndetach' | dbx ‐p %d"'
Examples
********
Catching SIGCHLD
================
int main()
{
struct sigaction act;
pid_t pid;
/*
* We're only interested in children that have terminated, not ones
* which have been stopped (eg user pressing control‐Z at terminal)
*/
act.sa_flags = SA_NOCLDSTOP;
/*
* Make these values effective. If we were writing a real
* application, we would probably save the old value instead of
* passing NULL.
*/
if (sigaction(SIGCHLD, &act, NULL) < 0)
{
fprintf(stderr, "sigaction failed\n");
return 1;
}
/* Fork */
switch (pid = fork())
{
case ‐1:
fprintf(stderr, "fork failed\n");
return 1;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 38/56
3/13/2017 Unix Programming FAQ (v1.37)
default: /* parent */
sleep(10); /* give child time to finish */
}
return 0;
}
/*
* The signal handler function ‐‐ only gets called when a SIGCHLD
* is received, ie when a child terminates
*/
void sig_chld(int signo)
{
int status, child_val;
/*
* We now have the info in 'status' and can manipulate it using
* the macros in wait.h.
*/
if (WIFEXITED(status)) /* did child exit normally? */
{
child_val = WEXITSTATUS(status); /* get child's exit status */
printf("child's exited normally with status %d\n", child_val);
}
}
#define _KMEMUSER
#include <sys/proc.h>
#include <kvm.h>
#include <fcntl.h>
char regexpstr[256];
#define INIT register char *sp=regexpstr;
#define GETC() (*sp++)
#define PEEKC() (*sp)
#define UNGETC(c) (‐‐sp)
#define RETURN(pointer) return(pointer);
#define ERROR(val)
#include <regexp.h>
pid_t
getpidbyname(char *name,pid_t skipit)
{
kvm_t *kd;
char **arg;
int error;
char *p_name=NULL;
char expbuf[256];
char **freeme;
int curpid;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 39/56
3/13/2017 Unix Programming FAQ (v1.37)
if((kd=kvm_open(NULL,NULL,NULL,O_RDONLY,NULL))==NULL){
return(‐1);
}
sprintf(regexpstr,"^.*/%s$",name);
compile(NULL,expbuf,expbuf+256,'\0');
while(cur_proc=kvm_nextproc(kd)){
curpid = cur_proc‐>p_pid;
if((cur_user=kvm_getu(kd,cur_proc))!=NULL){
error=kvm_getcmd(kd,cur_proc,cur_user,&arg,NULL);
if(error==‐1){
if(cur_user‐>u_comm[0]!='\0'){
p_name=cur_user‐>u_comm;
}
}
else{
p_name=arg[0];
}
}
if(p_name){
if(!strcmp(p_name,name)){
if(error!=‐1){
free(arg);
}
if(skipit!=‐1 && ourretval==skipit){
ourretval=‐1;
}
else{
close(fd);
break;
}
break;
}
else{
if(step(p_name,expbuf)){
if(error!=‐1){
free(arg);
}
break;
}
}
}
if(error!=‐1){
free(arg);
}
p_name=NULL;
}
kvm_close(kd);
if(p_name!=NULL){
return(curpid);
}
return (‐1);
}
pid_t
getpidbyname(char *name,pid_t skipit)
{
DIR *dp;
struct dirent *dirp;
prpsinfo_t retval;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 40/56
3/13/2017 Unix Programming FAQ (v1.37)
int fd;
pid_t ourretval=‐1;
if((dp=opendir("/proc"))==NULL){
return ‐1;
}
chdir("/proc");
while((dirp=readdir(dp))!=NULL){
if(dirp‐>d_name[0]!='.'){
if((fd=open(dirp‐>d_name,O_RDONLY))!=‐1){
if(ioctl(fd,PIOCPSINFO,&retval)!=‐1){
if(!strcmp(retval.pr_fname,name)){
ourretval=(pid_t)atoi(dirp‐>d_name);
if(skipit!=‐1 && ourretval==skipit){
ourretval=‐1;
}
else{
close(fd);
break;
}
}
}
close(fd);
}
}
}
closedir(dp);
return ourretval;
}
#include <stdio.h>
#include <procinfo.h>
pid = *nextPid;
while(1)
{
if(getprocs(&pi, sizeof pi, 0, 0, &pid, 1) != 1)
break;
if(!strcmp(name, pi.pi_comm))
{
retval = pi.pi_pid;
*nextPid = pid;
break;
}
}
return retval;
}
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 41/56
3/13/2017 Unix Programming FAQ (v1.37)
if(argc == 1)
{
printf("syntax: %s <program> [program ...]\n",argv[0]);
exit(1);
}
/* figure out where the command name is from the column headings.
* (BSD‐ish machines put the COMMAND in the 5th column, while SysV
* seems to put CMD or COMMAND in the 4th column.)
*/
for (linep = line; ; linep = (char *)0)
{
if ((char *)0 == (token = strtok(linep, " \t\n")))
{
pclose(fp);
return (char *)0;
}
if (0 == strcmp("COMMAND", token) || 0 == strcmp("CMD", token))
{ /* we found the COMMAND column */
cmd = token;
break;
}
}
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 42/56
3/13/2017 Unix Programming FAQ (v1.37)
status = pclose(fp);
if (!WIFEXITED(status) || 0 != WEXITSTATUS(status))
return (char *)0;
return token;
}
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
/* daemon() ‐ detach process from user and disappear into the background
* returns ‐1 on failure, but you can't do much except exit in that case
* since we may already have forked. This is based on the BSD version,
* so the caller is responsible for things like the umask, etc.
*/
switch (fork())
{
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 43/56
3/13/2017 Unix Programming FAQ (v1.37)
case 0: break;
case ‐1: return ‐1;
default: _exit(0);
}
if (!nochdir)
chdir("/");
if (!noclose)
{
closeall(0);
open("/dev/null",O_RDWR);
dup(0); dup(0);
}
return 0;
}
int fork2()
{
pid_t pid;
int rc;
int status;
if (!(pid = fork()))
{
switch (fork())
{
case 0: return 0;
case ‐1: _exit(errno); /* assumes all errnos are <256 */
default: _exit(0);
}
}
if (WIFEXITED(status))
if (WEXITSTATUS(status) == 0)
return 1;
else
errno = WEXITSTATUS(status);
else
errno = EINTR; /* well, sort of :‐) */
return ‐1;
}
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
int daemon(int,int);
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 44/56
3/13/2017 Unix Programming FAQ (v1.37)
int fork2(void);
void closeall(int);
fclose(out);
}
/* This is the daemon's main work ‐‐ listen for connections and spawn */
void process()
{
struct sockaddr_in addr;
int addrlen = sizeof(addr);
int sock = socket(AF_INET, SOCK_STREAM, 0);
int flag = 1;
int rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
&flag, sizeof(flag));
if (rc < 0)
errexit("setsockopt");
addr.sin_family = AF_INET;
addr.sin_port = htons(TCP_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
rc = listen(sock, 5);
if (rc < 0)
errexit("listen");
for (;;)
{
rc = accept(sock, (struct sockaddr *) &addr, &addrlen);
if (rc >= 0)
switch (fork2())
{
case 0: close(sock); run_child(rc); _exit(0);
case ‐1: errreport("fork2"); close(rc); break;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 45/56
3/13/2017 Unix Programming FAQ (v1.37)
default: close(rc);
}
}
}
int main()
{
if (daemon(0,0) < 0)
{
perror("daemon");
exit(2);
}
process();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h> /* maybe; system‐dependent */
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
/* system‐dependent */
#define CFLAGS_HARDFLOW (CRTSCTS)
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 46/56
3/13/2017 Unix Programming FAQ (v1.37)
if (fd < 0)
return close_and_complain(‐1, "open", errno);
/* local modes */
{
int i;
#ifdef _POSIX_VDISABLE
attr.c_cc[0] = _POSIX_VDISABLE;
#else
attr.c_cc[0] = fpathconf(fd, _PC_VDISABLE);
#endif
for (i = 1; i < NCCS; i++)
attr.c_cc[i] = attr.c_cc[0];
}
attr.c_cc[VSTART] = 0x11;
attr.c_cc[VSTOP] = 0x13;
attr.c_cc[VMIN] = 1;
attr.c_cc[VTIME] = 0;
/* baud rate */
cfsetispeed(&attr, baud);
cfsetospeed(&attr, baud);
/* write settings */
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 47/56
3/13/2017 Unix Programming FAQ (v1.37)
if (flags < 0)
return close_and_complain(fd, "fcntl(GETFL)", errno);
if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0)
return close_and_complain(fd, "fcntl(SETFL)", errno);
return fd;
}
if (usec < 0)
usec += 1000000, ‐‐sec;
res‐>tv_sec = sec;
res‐>tv_usec = usec;
/* this doesn't try and cope with pathological strings (e.g. ababc)
* timeout is in millisecs
* A more usual approach to this is to use alarm() for the timeout.
* This example avoids signal handling for simplicity and to illustrate
* an alternative approach
*/
gettimeofday(&end, NULL);
timeradd(&end, timeo/1000, timeo%1000);
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (select(fd+1, &fds, NULL, NULL, &left) <= 0)
return ‐1;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 48/56
3/13/2017 Unix Programming FAQ (v1.37)
if (read(fd, &c, 1) != 1)
return ‐1;
if (c == str[matchlen])
++matchlen;
else
matchlen = 0;
}
return 0;
}
if (argc < 2)
die("no port specified");
putchar('\n');
tcflush(fd, TCIOFLUSH);
close(fd);
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 49/56
3/13/2017 Unix Programming FAQ (v1.37)
#include <sys/wait.h>
#include <errno.h>
sigemptyset(&sigs);
sigaddset(&sigs,SIGTTOU);
sigprocmask(SIG_BLOCK, &sigs, &oldsigs);
rc = tcsetpgrp(ctty, pgrp);
return rc;
}
if (fg)
{
pid_t curpgrp;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 50/56
3/13/2017 Unix Programming FAQ (v1.37)
case 0: /* child */
if (pgrp < 0)
pgrp = getpid();
return 0;
default: /* parent */
if (pgrp < 0)
pgrp = pid;
setpgid(pid, pgrp);
return pid;
}
/*NOTREACHED*/
}
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 51/56
3/13/2017 Unix Programming FAQ (v1.37)
if (curpgrp != getpgrp())
return errno = EPERM, (pid_t)‐1;
int foreground_self()
{
pid_t curpgrp;
int ctty;
if (!cmd)
return errno = EINVAL, ‐1;
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 52/56
3/13/2017 Unix Programming FAQ (v1.37)
if (!error)
{
pid_t pid = spawn_job(0, ‐1);
switch (pid)
{
case ‐1: /* fork failure */
error = errno;
break;
execl("/bin/sh","sh","‐c",cmd,(char*)NULL);
_exit(127);
close(nullfd);
if (infd)
close(pipefds[0][0]), *infd = pipefds[0][1];
if (outfd)
close(pipefds[1][1]), *outfd = pipefds[1][0];
if (errfd)
close(pipefds[2][1]), *errfd = pipefds[2][0];
return pid;
}
}
{
int i,j;
for (i = 0; i < 3; ++i)
for (j = 0; j < 2; ++j)
if (pipefds[i][j] >= 0)
close(pipefds[i][j]);
}
if (nullfd >= 0)
close(nullfd);
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 53/56
3/13/2017 Unix Programming FAQ (v1.37)
/*‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐*/
/* This bit is a somewhat trivial example of using the above. */
#ifndef WCOREDUMP
/* If WCOREDUMP is missing, you might want to supply a correct
* definition for your platform (this is usually (status & 0x80) but
* not always) or punt (as in this example) by assuming no core dumps.
*/
# define WCOREDUMP(status) (0)
#endif
int check_children()
{
pid_t pid;
int status;
int count = 0;
++count;
if (WIFEXITED(status))
fprintf(stderr,"Process %ld exited with return code %d\n",
(long)pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
fprintf(stderr,"Process %ld killed by signal %d%s\n",
(long)pid, WTERMSIG(status),
WCOREDUMP(status) ? " (core dumped)" : "");
else if (WIFSTOPPED(status))
fprintf(stderr,"Process %ld stopped by signal %d\n",
(long)pid, WSTOPSIG(status));
else
fprintf(stderr,"Unexpected status ‐ pid=%ld, status=0x%x\n",
(long)pid, status);
}
return count;
}
int main()
{
struct sigaction act;
int sigcount = 0;
act.sa_handler = sighandler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGTERM,&act,NULL);
sigaction(SIGTSTP,&act,NULL);
sigaction(SIGCHLD,&act,NULL);
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 54/56
3/13/2017 Unix Programming FAQ (v1.37)
if (!check_children())
pause();
}
fprintf(stderr,"Done ‐ exiting\n");
return 0;
}
==============================================================================
‐‐
Andrew.
User Contributions:
Comment about this article, ask questions, or add new information about this topic:
Send
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 55/56
3/13/2017 Unix Programming FAQ (v1.37)
http://www.faqs.org/faqs/unixfaq/programmer/faq/ 56/56