[an error occurred while processing this directive]




Note: This is not the current faq for comp.unix. programmers.  It was the
first faq for cup.  It's presented here for historical purposes only.

This is still a work in progress, feel free to share any questions or answers.

comp.unix.programmer FAQ - Maintainer Patrick Horgan

Contributors:
    Patrick J. Horgan patrick at ootbcomp.com
    Stephen Baynes bay...@ukpsshp1.serigate.philips.nl
    James Raynard <jrayn...@dial.pipex.com>
    Michael F. Quigley (mich...@cybernetics.net)  
    Daniel Brandt dbra...@crl.com
    Steve Badrich sbadr...@mcimail.com                  

1)   How does fork work?
2)   How can I find out the value of/set an environment variable from a program?
3)   I have to monitor more than one (fd/connection/stream) at a time. How do
     I manage all of them?
4)   How can I tell when the other end of a connection shuts down?
     (question 1 of the sockets FAQ)
5)   How can I get a more precise timer?
     (question 4.6 of comp.unix.questions FAQ)
6)   How can a parent and child process communicate.
7)   My program generates a lot of zombie processes. How do I get rid of them?
     (question 3.13 of the comp.unix.questions FAQ)
8)   How do I find out the address of a remote site connected to me?
     (question IV.9 of the sockets FAQ)
9)   How do I find out the address of my socket?
10)  How do I get my program to act like a daemon?
11)  What books can I read to learn about Unix programming.
12)  Where can I get the source from these books?
13)  How can I look at process in the system like ps does?
14)  How can I debug the children after a fork?
15)  How can I tell how much memory my system has?
16)  Given a pid, how can I tell if it's a running program?
17)  After running my program once I can't run it again until some time
     out happens...The os complains about the port already being in use.
     (question II.7 in the sockets FAQ)
18)  system()/pclose()/waitpid() doesn't seem to return the exit value
     of my process...or the exit value is shifted left 16 bits...what's
     the deal?
19)  How can I make my program not echo input like login does when asking
     for your password?
20)  How can I check and see if a key was pressed?  I'm looking for
     something like the dos kbhit() command.
21)  How can I move the cursor around the screen, to do full screen
     editing without using curses?

~~~
1)   How does fork work?

     #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 existing
process is called the parent.  You can tell which is which by checking
the return value from fork().  The parent gets the childs pid returned
to him, but the child gets 0 returned to him.  Thus this simple code
illustrate's the basics of it.

    main()
    {
        int pid;

        if((pid=fork())>0){
            /* pid greater than zero is parent getting the child's pid */
            printf("Child's pid is %d\n",pid);
        }
        else if(!pid){
            /* pid of zero is the child */
            /* Here we're the child...what should we do? */
        }
        else{
            /* 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!");
        }
    }

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.

Note that the following two sections talk about the usual state of affairs,
it can vary between OSs.

Inherited by the child from the parent:

    o real user ID, real group ID, effective user ID, effective group ID.
    o supplementary group IDs
    o environment
    o stack
    o memory
    o open file descriptors
    o close-on-exec flags
    o signal handling settings
    o set-user-ID and set-group-ID mode bits
    o nice value
    o scheduler class
    o process group ID
    o session ID
    o current working directory
    o root directory
    o file mode creation mask (umask)
    o resource limits
    o controlling terminal
    o saved user ID and group ID

Unique to the child:

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

~~~
2)   How can I find out the value of/set an environment variable from a program?

Getting the value of an environment variable is done by using getenv(3C).

    #include <stdlib.h>

    char *getenv(const char *name);

Setting the value of an environment variable is done by using putenv(3C).

     #include <stdlib.h>

     int putenv(char *string);

Suppose you wanted to get the value for the TERM environment variable.
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 MYVAR,
with a value of MYVAL.  This is how you'd do it.

    char envbuf[256];

    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 */
    }

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

The answer to this one can vary depending on whether you're using system V
or bsd derived unix.  BSD derivative will use select() and SYSV derivatives
will use poll().  Note that SVR4 supports select() as well.  For portability,
it might very well be the best to stick with select(), but don't be afraid
to go with poll() if you're sure that you won't need to port.

Note that the particular fds that work as expected with this can vary
by OS.

We'll cover each.  First, for each, you may want to put the
file descriptor in non-blocking mode.  You do this in a variety of ways.
If you're using open() to get a file descriptor, you can use the
O_NONBLOCK flag to put the stream in non-blocking mode.

    fd=open("our/file",O_RDWR|O_NONBLOCK);

If one is already open, we can use fcntl() to put it in non-blocking mode.

    int flags;

    if((flags=fcntl(fd,F_GETFL,0))!=-1){
        if(fcntl(fd,F_SETFL,(flags|O_NONBLOCK))==-1){
            fprintf(stderr,"fcntl(fd,O_NONBLOCK) failed with errno %d",errno);
        }
    }

We can also use an ioctl() to put the stream in non-blocking mode.

    const int one=1;

    if(ioctl(fd,FIONBIO,&one)==-1){
       fprintf(stderr,"ioctl(fd,FIONBIO,1) failed with errno %d",errno);
    }

As you can see the ioctl() is simpler, but the choice is up to you.
Either method works with socket under BSD or SYSV.

Now assume that you've got two file descriptors, fd1, and fd2.  Whether
these file descriptors came from socket() call, or open() is immaterial,
we'll just call them file descriptors, and assume that you've put each
of them in non-blocking mode.

BSD (actually works with SVR4 as well.)

The first thing we'll do is learn about the fd_set.  An fd_set is
essentially an array of bits, with each bit position corresponding
to a file descriptor number, with bit 0 corresponding to fd number 0,
etc...
          fd0 fd1 fd2
         +---+---+---+-------------------------+
         | 0 | 0 | 0 | . . .                   |
         +---+---+---+-------------------------+

We know something is true about an fd if the corresponding bit is turned
on.

          fd0 fd1 fd2
         +---+---+---+-------------------------+
         | 0 | 1 | 0 | . . .                   |
         +---+---+---+-------------------------+
so in this case, we'd know that something, (depending on context,) was
true about fd1, but not about fd0 or fd2.

If you #include <sys/types.h> you'll get access to several macros that
make dealing with fd_set's easier.

The first one is FD_ZERO, and is used to set all the bits to zero.

    fd_set myfds;

    int fd1,fd2;

    FD_ZERO(&myfds);

Then we can use another macro, FD_SET, to pull up the bits that
we're interested in.

    FD_SET(fd1,&myfds);
    FD_SET(fd2,&myfds);

Now before using select we only need one more thing.  select will want
an argument that says the number of file descriptors we care about in
the fd_set.  You have to start from zero, and go up to the highest
file descriptor number you have.  The usual thing is to use the maximum
of the fd numbers, (plus one to make it a number instead of an offset.)

    int fd_max;

    fd_max = 1+ fd1<fd2?fd2:fd1;

Now we can tell select about what we want to do:

    if(select(fd_max,&myfds,(fd_set *)0,(fd_set *)0, (struct timeval *)0)<0){
        if(errno!=EINTR){
            /* Here you had some failure other than an expected one.
             * You might want to abort execution.
             * an EINTR just means that some interrupt happened...in this
             * case we usually just start over.
             */
        }
        else{
            continue;
        }
    }

Now we want to be able to tell if something is available for reading,
so we use another macro, FD_ISSET, to check.

    if(FD_ISSET(fd1,&myfds)){
        /* Something available from fd1, read it and process it. */
    }
    if(FD_ISSET(fd2,&myfds)){
        /* Something available from fd2, read it and process it. */
    }

Now I'm sure that you noticed that there were some other unused arguments
to the select call.

~~~
6)   How can a parent and child process communicate.

A parent and child can communicate through any of the normal inter-process
communication schemes, 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 the the file descriptor returned from popen() and
the child process sees it as its stdin, and you can read from the
file descriptor and see what the program wrote to it's stdout.

~~~

7)   My program generates a lot of zombie processes. How do I get rid
of them?

7a) What is a zombie?

When a program forks and the child finishes before the parent, the
kernel still keeps some of its information about the child in case the
parent might need it - for example, the parent may need to check the
child's exit status. To be able to get this information, the parent
calls 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 some system resources; in
particular an entry in the process table.

This is not good, as the process table has a fixed number of entries
and it is possible for the system to run out of them. Even if the
system doesn't run out, there is a limit on the number of processes
each user can run, which is usually smaller than the system's
limit. This is one of the reasons why you should always check if 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 first program to run after the system boots up).

7b) How do get rid of zombies?

Apart from hoping the parent will call wait(), or rebooting the
system, there isn't any way to get rid of them. A much better strategy
is to prevent them happening in the first place.

This is discussed in detail in the unix questions FAQ. Here's some
sample code for the POSIX way of doing this:-

#include <sys/types.h>  /* must include this before any other sys headers */
#include <sys/wait.h>   /* header for waitpid() and various macros */
#include <signal.h>     /* header for signal functions */
#include <stdio.h>      /* header for fprintf() */
#include <unistd.h>     /* header for fork() */

void sig_chld(int);     /* prototype for our SIGCHLD handler */

int main() {
    struct sigaction act;
    pid_t pid;

    /* Assign sig_chld as our SIGCHLD handler */
    act.sa_handler = sig_chld;

    /* We don't want to block any other signals in this example */
    sigemptyset(&act.sa_mask);

    /*
     * 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 */
    if ((pid = fork()) < 0) {       /* always check this! */
        fprintf(stderr, "fork failed\n");
        return 1;
    } else if (pid == 0)            /* child - finish straight away */
        return 7;                   /* exit status = 7 */
    else {                          /* 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;

    /* Wait for any child without blocking */
    if (waitpid(-1, &status, WNOHANG) < 0) {

        /*
         * calling standard I/O functions like fprintf() in a
         * signal handler is not recommended, but probably OK
         * in toy programs like this one.
         */
        fprintf(stderr, "waitpid failed\n");
    }

    /*
     * 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);

}

(Hmm, maybe that's a bit long for a short answer 8-)

-- 
James Raynard, Edinburgh, Scotland

~~~
10)  How do I get my program to act like a daemon?

Entering Daemon Mode by Patrick J. Horgan (patr...@amdahl.com)

Here's the steps to become a daemon.

(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.
(2) setsid() to become a process group and session group leader. Since a
   controlling terminal is associated with a session, and this new session
   has not yet acquired a controlling terminal our process now has no
   controlling terminal, (a good thing.)
(3) fork() again so the parent, (the session group leader,) can exit. This
   means that we, as a non-session group leader, can never regain a
   controlling terminal.
(4) chdir("/") to ensure that our process doesn't keep any directory in use.
   Failure to do this could make it so that an administrator couldn't unmount
   a slice, because it was our current directory.
(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.
(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.
   See NOTE below.
(7) Create a new stdout, an example might be: open("/dev/console",O_RDWR).
(8) dup2() twice to duplicate the fd for standard out for standard in and
   standard error.

NOTE:  If you're started from inetd some of this is a little different, you
   don't have to do the first fork, and fds 0, 1, and 2 are set up to be
   the connected socket.  That means you should probably skip steps 6, 7
   and 8.

~~~
11)  What books can I read to learn about Unix programming.

        "Unix Network Programming"
        W. Richard Stevens
        (c) Prentice Hall, 1990
        ISBN 0-13-949876-1
            [This is frequently recomemended. I have just got a copy, but
            not had time to read it.]

        "Advanced Programming in the Unix Environment"
        W. Richard Stevens
        (c) Addison-Wesley, 1992
        ISBN 0-201-56317-7

        "Internetworking with TCP/IP Volume III"
        Douglas E. Comer / David L. Stevens
        (c) Prentice Hall, 1993
        ISBN 0-13-474222-2

    The O'Reily Nutshell book on Make. [Recomended. Its a good series too]

    There is also Valhalia's (may have the spelling wrong) book on
    the unix operating system varients. "Unix the new frontiers" if I recall
    the title right. I am reading it at the moment at home and can check the
    details if you need it. It is very good if you want to know more about
    what goes on under the bonnett of different unix versions.

Also check the archives for misc.books.technical A Concise Guide to UNIX books
~~~
12)  Where can I get the source from these books?

For Stevens,
ftp://ftp.uu.net./published/books/stevens.advprog.tar

~~~
13)  How can I look at process in the system like ps does?

The answer is that this is system dependent...I thought you wouldn't
like that.  I'll show you how to write the same routine, one to return
a pid given a name using two systems...

The first one uses the privileged kvm SunOS4 routines to walk through
system structures and pull information out of the process table.

The second one uses the /proc process file system available on many SYSV
sytems to do the same thing.

Each of them has the ability to skip the FIRST match found if the skipit
arg is set to the pid of the first one.

The SunOS4 version requires root permissions to run.  The SYSV version
uses file permissions.  Generally /proc permissions are set so that
only the owner of the process has read permission.  That means that
most of the time you want to be running as root.

SUNOS 4 version

#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;
    struct user * cur_user;
    struct user myuser;
    struct proc * cur_proc;

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

}

SYSV version

pid_t
getpidbyname(char *name,pid_t skipit)
{
    DIR  *dp;
    struct dirent *dirp;
    prpsinfo_t retval;
    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;
}

~~~
14)  How can I debug the children after a fork?

There are several answers to this, some modern debuggers, like Sun's
dbx and debugger, let you tell the debugger to follow the child, the
parent, both, or ask you what to do during a fork().  Sometimes though
you just have to be able to grab the process.  The process won't
wait for you to grab it though, so if it's a short lived process, you
might want to either have it sleep for 30 seconds, or try this
great idea from James Raynard:

int pause_mode = 1;

...

if ((pid = fork()) > 0)      {       /* child */
        while (pause_mode)
                sleep(5);

        ...
}

...

and then set pause_mode equal to 0 after you have attached to the
child, and debug in the usual way!

Once you have it waiting for you, gdb lets you say "attach <pid>" to
start debugging the pid.  dbx and kin expect "debug - <pid>".  From
the command line you can start dbx to attach to a running process
by dbx - <pid>

~~~
16)  Given a pid, how can I tell if it's a running program?

(This is an ambiguous question. I'll assume it means "given a pid, how
can I tell if there's a process with that pid?", rather than "is it
stopped/a zombie, etc")

Use kill with 0 for the signal number:-

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
        pid_t pid;

        if (argc != 2) {
                fprintf(stderr, "usage: ./a.out <process ID>\n");
                return -1;
        }

        pid = atol(argv[1]);

        if (kill(pid, 0) == 0)
                printf("process with ID %ld is running\n", pid);
        else
                printf("no process with ID %ld\n", pid);

        return 0;

}

This works from the command line as well:-

$ kill -0 3120  # Process 3120 is running - nothing happens
$ kill -0 9999  # Process 9999 is not running - complain and return 1
kill: (9999) - No such pid
$ echo $?
1
$

~~~
18)  system()/pclose()/waitpid() doesn't seem to return the exit value
     of my process...or the exit value is shifted left 16 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 "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 defined by wstat(5).

Macros defined by wstat(5) 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
WCOREDUMP(stat)         - If WIFSIGNALED(stat) non-zero this is non-zero if
                          core dumped

~~~
19)  How can I make my program not echo input like login does when asking
     for your password?

The first answer is to call getpass(3C) if you want to get a password.  If
you need a more general understanding of how to do this an example
implementation of getpass illustrates the technique.

Adapted from Stevens' Advanced Programming In The Unix Environment

#include <signal.h>
#include <stdio.h>
#include <termios.h>

#define MAX_PASS_LEN 18

char *
getpass(const char *prompt)
{
    static char     buf[MAX_PASS_LEN + 1 ];
    char            *ptr;
    sigset_t        sig,sigsave;
    struct termios  term, termsave;
    FILE            *fp;
    int             c;

    if((fp=fopen(ctermid(NULL),"r+")) == NULL)
        return NULL;
    setbuf(fp,NULL);

    sigemptyset(&sig);              /* block SIGINT & SIGTSTP, save signal mask */
    sigaddset(&sig,SIGINT);
    sigaddset(&sig,SIGTSTP);
    sigprocmask(SIG_BLOCK,&sig, &sigsave);

    tcgetattr(fileno(fp),&termsave);
    term=termsave;
    term.c_lflag&= ~(ECHO | ECHOE | ECHOK | ECHONL);
    tcsetattr(fileno(fp),TCSAFLUSH,&term);

    fputs(prompt,fp);

    ptr=buf;
    while((c=getc(fp)) !=EOF && c!='\n'){
        if(ptr&lt;&buf[MAX_PASS_LEN])
            *ptr++=c;
    }
    *ptr=0;
    putc('\n',fp);
    tcsetattr(fileno(fp),TCSAFLUSH,&termsave);
    sigprocmask(SIG_SETMASK,&sigsave,NULL);
    fclose(fp);
    return buf;

}

~~~
20)  How can I check and see if a key was pressed?  I'm looking for
     something like the dos kbhit() command.

I have several answers here, from several folks.

Basically, there are two modes in which Unix terminals operate,
canonical and non-canonical mode.(*) In canonical mode, input is
processed line by line; this is how a terminal is set up by
default. Under most circumstances, input is not passed to the
application until the user presses the return key.

In non-canonical mode, input is not read on a line-by-line
basis. There are several ways to specify how it is read; either by
waiting a given amount of time, asking for a certain number of
characters to be entered, or a combination of the two, or just by
reading all the characters that happen to be immediately available.

It is possible to change the terminal mode from the command line by
using stty(1). From within a program, this is done by using
tcsetattr() to set the terminal attributes (if the system doesn't
support tcsetattr(), there are certain arguments to ioctl() that can
do this).

When changing the terminal mode, it is important to reset the terminal
to its original mode before terminating the program, as leaving it in
a strange mode will be very annoying to the user!

This should be done by saving the original mode. A common mistake is
something like the following:-

struct termios myterm;

...

tcgetattr(STDIN_FILENO, &myterm); /* get terminal input attributes */

my_term.c_lflag &= ~ECHO;     /* turn off input echoing */

tcsetattr(fd, TCSAFLUSH, &myterm); /* set new attributes */

...                                /* do something here */

my_term.c_lflag |= ECHO;           /* turn echoing back on */
tcsetattr(fd, TCSAFLUSH, &myterm);

The problem is that echoing may have already been turned off for some
reason, and something else may be depending on it being turned
off. This scenario is unlikely, but not impossible. The correct way to
reset the terminal mode is to save the original attributes in a safe
place and use those attributes to reset the terminal.

Here's the solution to the question, which turns line-buffering off,
by putting the terminal into non-canonical mode:-

#include <termios.h>
#include <unistd.h>

int get_a_char(void) {
        struct termios oldterm, newterm;
        char c;

        /* Get the current terminal state and save it in oldterm*/
        if (tcgetattr(STDIN_FILENO, &oldterm) < 0) {
                error("tcgetattr failed");
                return -1;
        }

        /*
         * structure copy the terminal state into newterm - have to
         * do this member by member if you don't have ANSI C compiler!*/
        newterm = oldterm;

        /* prepare to put terminal into CBREAK mode */
        newterm.c_lflag &= ~(ECHO | ICANON);
        newterm.c_cc[VMIN] = 1;
        newterm.c_cc[VTIME] = 0;

        /*
         * Put terminal in CBREAK mode - this will turn off echo
         * and line buffering.
         */
        if (tcsetattr(STDIN_FILENO, &newterm) < 0) {
                error("tcsetattr failed");
                return -1;
        }

        /* read a character from the terminal */
        if (read(STDIN_FILENO, &c, 1) != 1) {
                error("read failed");
                return -1;
        }

        /* Leave terminal as how we found it */
        if (tcsetattr(STDIN_FILENO, &oldterm) < 0) {
                error("tcsetattr failed");
                return -1;
        }

        /* Return the character read to the caller */
        return c;

}

/*
 * Simplistic test program for the above.
 * It just reads a charcter from the terminal, until the user types
 * 'Q' or 'q'.
 */
int main() {
        int c;

        while ((c = get_a_char()) != -1) {
                if (c == 'Q' || c == 'q')
                        break;

                printf("You pressed %c!\n", c);
        }

        return 0;

}

(*) Some systems, mainly BSD ones, have three modes, known as cooked,
cbreak (or half-cooked) and raw. Cooked mode is the same as canonical,
cbreak and raw are the same as non-canonical but differ in the way
control characters are handled (cbreak handles some of them, raw
doesn't).

-- 
James Raynard, Edinburgh, Scotland

/*
This is one way to detect keystrokes in the input stream, similar
to the combination of kbhit() and getch() in the DOS compiler. It
should work on many flavors of Unix. Many programmers who are
familiar with DOS are frustrated when they discover that getc()
and getchar() don't even see any input until the user hits the
RETURN key. This means the program is hung there forever if the
user falls asleep. It's a showstopper for those who like to execute
code between keystrokes in order to accomplish a variety of stupid
programming tricks.

If your compiler is POSIX-compliant, as it would be if you are
using the GCC compiler, for example, the following code should
work. It compiles under GCC on a SunOS and also under Linux. It
works by changing how the port is read, whereas curses actually
takes over the terminal and therefore needs all sorts of terminal
definitions. This POSIX-compliant code should work with any sort
of terminal, and even works on a remote terminal if you redirect
the stdin and stdout to a port.
*/

#define _POSIX_SOURCE 1    /* forces POSIX definitions to be used in
                              all header files */

#include <termios.h>
#include <stdio.h>
#include <unistd.h>

struct termios systerm;     /* declare our name "systerm" as structure */

int charin( void );           /* declare function */

int main( int argc, char *argv[] )             /* start main function */
{
   int inp;                                 /* local integer */

 /* As best as I can understand it, the following five lines read the
 port attributes, and set the minimum characters to zero and the time to
 one-tenth second. By reading in the port attributes, you can then
 reset them before exiting so that everything is restored to normal.
 The echo is turned off and the keyboard buffering is set to non-canonical
 (raw) mode. Setting the VTIME to one-tenth second, as in this case,
 makes the input loop 200% less processor-intensive. */

   tcgetattr( STDIN_FILENO, &systerm );
   systerm.c_lflag &= ~( ICANON | ECHO );
   systerm.c_cc[ VMIN ] = 0;
   systerm.c_cc[ VTIME ] = 1;
   tcsetattr( STDIN_FILENO, TCSAFLUSH, &systerm );

   printf( "\n\n\nEnter Q to Quit\n\n" );
   printf( "The periods prove that we really ARE\n" );
   printf( "executing code between keystrokes.\n\n" );
   printf( "Input: " );
   fflush( stdout );              /* in this raw mode, any output that
                          doesn't end in \n must be explicitly flushed */
   while( 1 )
   {
      inp = charin();          /* call the character input function */
      if( inp == (int)'Q' || inp == (int)'q' )    /* if request to exit */
      {
         printf( "\n" );
         systerm.c_lflag |= ICANON | ECHO;
         tcsetattr( STDIN_FILENO, TCSANOW, &systerm );
                    /* the above three lines should precede any exit,
                  so that the terminal is restored to its normal mode */
         exit( 0 );
      }
   }

}

int charin( void )
{
   int w;
   char wus;

   w = read( STDIN_FILENO, &wus, 1 );
   if( w != 0 )
   {
      printf( "%c", wus );          /* we do our own echo here */
   }
   else
   {
      printf( "." );    /* if this executes, it means the read
                       timed out and returned 0. in other words,
                       this is where you can execute code between
                       the keystrokes.  */
   }
   fflush( stdout );                /* flush is required */
   return (int)wus;

}

/*
=====================================================================
Public Information Research, PO Box 680635, San Antonio TX 78268, USA
Tel:210-509-3160  Fax:210-509-3161    Nonprofit publisher of NameBase
Daniel Brandt:            dbra...@crl.com                 [president]
Steve Badrich:         sbadr...@mcimail.com         [NewsLine editor]
=====================================================================
*/

From: michael@ws0 (Michael Quigley)

I found this code snipped in NCSA httpd 1.4.  It looks like the authors
borrowed it from other sources. ;)

--8<--

extern char** environ;

/* taken from bdflush-1.5 for Linux source code */
void inststr(char *dst[], int argc, char *src)
{
    if (strlen(src) <= strlen(dst[0]))
    {
        char *ptr;

        for (ptr = dst[0]; *ptr; *(ptr++) = '\0');

        strcpy(dst[0], src);
    } else
    {
        /* stolen from the source to perl 4.036 (assigning to $0) */
        char *ptr, *ptr2;
        int count;
        ptr = dst[0] + strlen(dst[0]);
        for (count = 1; count < argc; count++) {
            if (dst[count] == ptr + 1)
                ptr += strlen(++ptr);
        }
        if (environ[0] == ptr + 1) {
            for (count = 0; environ[count]; count++)
                if (environ[count] == ptr + 1)
                    ptr += strlen(++ptr);
        }
        count = 0;
        for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) {
            *ptr2 = '\0';
            count++;
        }
        strncpy(dst[0], src, count);
    }

}  

--8<--

And the following stub:

/* it.c */
main(int argc, char **argv)
{
        inststr(argv, argc, "Hello world!");
        while(1);

}

produces the output:

 6063 p0  Ss     0:00.71 -tcsh (tcsh)
 6481 p0  R      0:01.49 Hello world! (it)
 6482 p0  R+     0:00.01 ps -ax

I'm going to look around to see if I can find any other implementations.

- Mike