Data Structures for the Shell
-----------------------------
All of the program examples included in this chapter are part of a
simple shell program. This section presents data structures and
utility functions which are used throughout the example.
The sample shell deals mainly with two data structures. The `job'
type contains information about a job, which is a set of subprocesses
linked together with pipes. The `process' type holds information about
a single subprocess. Here are the relevant data structure declarations:
/* A process is a single process. */
typedef struct process
{
struct process *next; /* next process in pipeline */
char **argv; /* for exec */
pid_t pid; /* process ID */
char completed; /* true if process has completed */
char stopped; /* true if process has stopped */
int status; /* reported status value */
} process;
/* A job is a pipeline of processes. */
typedef struct job
{
struct job *next; /* next active job */
char *command; /* command line, used for messages */
process *first_process; /* list of processes in this job */
pid_t pgid; /* process group ID */
char notified; /* true if user told about stopped job */
struct termios tmodes; /* saved terminal modes */
int stdin, stdout, stderr; /* standard i/o channels */
} job;
/* The active jobs are linked into a list. This is its head. */
job *first_job = NULL;
Here are some utility functions that are used for operating on `job'
objects.
/* Find the active job with the indicated PGID. */
job *
find_job (pid_t pgid)
{
job *j;
for (j = first_job; j; j = j->next)
if (j->pgid == pgid)
return j;
return NULL;
}
/* Return true if all processes in the job have stopped or completed. */
int
job_is_stopped (job *j)
{
process *p;
for (p = j->first_process; p; p = p->next)
if (!p->completed && !p->stopped)
return 0;
return 1;
}
/* Return true if all processes in the job have completed. */
int
job_is_completed (job *j)
{
process *p;
for (p = j->first_process; p; p = p->next)
if (!p->completed)
return 0;
return 1;
}