Blame manual/job.texi

Packit Service 82fcde
@node Job Control, Name Service Switch, Inter-Process Communication, Top
Packit Service 82fcde
@c %MENU% All about process groups and sessions
Packit Service 82fcde
@chapter Job Control
Packit Service 82fcde
Packit Service 82fcde
@cindex process groups
Packit Service 82fcde
@cindex job control
Packit Service 82fcde
@cindex job
Packit Service 82fcde
@cindex session
Packit Service 82fcde
@dfn{Job control} refers to the protocol for allowing a user to move
Packit Service 82fcde
between multiple @dfn{process groups} (or @dfn{jobs}) within a single
Packit Service 82fcde
@dfn{login session}.  The job control facilities are set up so that
Packit Service 82fcde
appropriate behavior for most programs happens automatically and they
Packit Service 82fcde
need not do anything special about job control.  So you can probably
Packit Service 82fcde
ignore the material in this chapter unless you are writing a shell or
Packit Service 82fcde
login program.
Packit Service 82fcde
Packit Service 82fcde
You need to be familiar with concepts relating to process creation
Packit Service 82fcde
(@pxref{Process Creation Concepts}) and signal handling (@pxref{Signal
Packit Service 82fcde
Handling}) in order to understand this material presented in this
Packit Service 82fcde
chapter.
Packit Service 82fcde
Packit Service 82fcde
@menu
Packit Service 82fcde
* Concepts of Job Control::     Jobs can be controlled by a shell.
Packit Service 82fcde
* Job Control is Optional::     Not all POSIX systems support job control.
Packit Service 82fcde
* Controlling Terminal::        How a process gets its controlling terminal.
Packit Service 82fcde
* Access to the Terminal::      How processes share the controlling terminal.
Packit Service 82fcde
* Orphaned Process Groups::     Jobs left after the user logs out.
Packit Service 82fcde
* Implementing a Shell::        What a shell must do to implement job control.
Packit Service 82fcde
* Functions for Job Control::   Functions to control process groups.
Packit Service 82fcde
@end menu
Packit Service 82fcde
Packit Service 82fcde
@node Concepts of Job Control, Job Control is Optional,  , Job Control
Packit Service 82fcde
@section Concepts of Job Control
Packit Service 82fcde
Packit Service 82fcde
@cindex shell
Packit Service 82fcde
The fundamental purpose of an interactive shell is to read
Packit Service 82fcde
commands from the user's terminal and create processes to execute the
Packit Service 82fcde
programs specified by those commands.  It can do this using the
Packit Service 82fcde
@code{fork} (@pxref{Creating a Process}) and @code{exec}
Packit Service 82fcde
(@pxref{Executing a File}) functions.
Packit Service 82fcde
Packit Service 82fcde
A single command may run just one process---but often one command uses
Packit Service 82fcde
several processes.  If you use the @samp{|} operator in a shell command,
Packit Service 82fcde
you explicitly request several programs in their own processes.  But
Packit Service 82fcde
even if you run just one program, it can use multiple processes
Packit Service 82fcde
internally.  For example, a single compilation command such as @samp{cc
Packit Service 82fcde
-c foo.c} typically uses four processes (though normally only two at any
Packit Service 82fcde
given time).  If you run @code{make}, its job is to run other programs
Packit Service 82fcde
in separate processes.
Packit Service 82fcde
Packit Service 82fcde
The processes belonging to a single command are called a @dfn{process
Packit Service 82fcde
group} or @dfn{job}.  This is so that you can operate on all of them at
Packit Service 82fcde
once.  For example, typing @kbd{C-c} sends the signal @code{SIGINT} to
Packit Service 82fcde
terminate all the processes in the foreground process group.
Packit Service 82fcde
Packit Service 82fcde
@cindex session
Packit Service 82fcde
A @dfn{session} is a larger group of processes.  Normally all the
Packit Service 82fcde
processes that stem from a single login belong to the same session.
Packit Service 82fcde
Packit Service 82fcde
Every process belongs to a process group.  When a process is created, it
Packit Service 82fcde
becomes a member of the same process group and session as its parent
Packit Service 82fcde
process.  You can put it in another process group using the
Packit Service 82fcde
@code{setpgid} function, provided the process group belongs to the same
Packit Service 82fcde
session.
Packit Service 82fcde
Packit Service 82fcde
@cindex session leader
Packit Service 82fcde
The only way to put a process in a different session is to make it the
Packit Service 82fcde
initial process of a new session, or a @dfn{session leader}, using the
Packit Service 82fcde
@code{setsid} function.  This also puts the session leader into a new
Packit Service 82fcde
process group, and you can't move it out of that process group again.
Packit Service 82fcde
Packit Service 82fcde
Usually, new sessions are created by the system login program, and the
Packit Service 82fcde
session leader is the process running the user's login shell.
Packit Service 82fcde
Packit Service 82fcde
@cindex controlling terminal
Packit Service 82fcde
A shell that supports job control must arrange to control which job can
Packit Service 82fcde
use the terminal at any time.  Otherwise there might be multiple jobs
Packit Service 82fcde
trying to read from the terminal at once, and confusion about which
Packit Service 82fcde
process should receive the input typed by the user.  To prevent this,
Packit Service 82fcde
the shell must cooperate with the terminal driver using the protocol
Packit Service 82fcde
described in this chapter.
Packit Service 82fcde
Packit Service 82fcde
@cindex foreground job
Packit Service 82fcde
@cindex background job
Packit Service 82fcde
The shell can give unlimited access to the controlling terminal to only
Packit Service 82fcde
one process group at a time.  This is called the @dfn{foreground job} on
Packit Service 82fcde
that controlling terminal.  Other process groups managed by the shell
Packit Service 82fcde
that are executing without such access to the terminal are called
Packit Service 82fcde
@dfn{background jobs}.
Packit Service 82fcde
Packit Service 82fcde
@cindex stopped job
Packit Service 82fcde
If a background job needs to read from its controlling
Packit Service 82fcde
terminal, it is @dfn{stopped} by the terminal driver; if the
Packit Service 82fcde
@code{TOSTOP} mode is set, likewise for writing.  The user can stop
Packit Service 82fcde
a foreground job by typing the SUSP character (@pxref{Special
Packit Service 82fcde
Characters}) and a program can stop any job by sending it a
Packit Service 82fcde
@code{SIGSTOP} signal.  It's the responsibility of the shell to notice
Packit Service 82fcde
when jobs stop, to notify the user about them, and to provide mechanisms
Packit Service 82fcde
for allowing the user to interactively continue stopped jobs and switch
Packit Service 82fcde
jobs between foreground and background.
Packit Service 82fcde
Packit Service 82fcde
@xref{Access to the Terminal}, for more information about I/O to the
Packit Service 82fcde
controlling terminal.
Packit Service 82fcde
Packit Service 82fcde
@node Job Control is Optional, Controlling Terminal, Concepts of Job Control , Job Control
Packit Service 82fcde
@section Job Control is Optional
Packit Service 82fcde
@cindex job control is optional
Packit Service 82fcde
Packit Service 82fcde
Not all operating systems support job control.  @gnusystems{} do
Packit Service 82fcde
support job control, but if you are using @theglibc{} on some other
Packit Service 82fcde
system, that system may not support job control itself.
Packit Service 82fcde
Packit Service 82fcde
You can use the @code{_POSIX_JOB_CONTROL} macro to test at compile-time
Packit Service 82fcde
whether the system supports job control.  @xref{System Options}.
Packit Service 82fcde
Packit Service 82fcde
If job control is not supported, then there can be only one process
Packit Service 82fcde
group per session, which behaves as if it were always in the foreground.
Packit Service 82fcde
The functions for creating additional process groups simply fail with
Packit Service 82fcde
the error code @code{ENOSYS}.
Packit Service 82fcde
Packit Service 82fcde
The macros naming the various job control signals (@pxref{Job Control
Packit Service 82fcde
Signals}) are defined even if job control is not supported.  However,
Packit Service 82fcde
the system never generates these signals, and attempts to send a job
Packit Service 82fcde
control signal or examine or specify their actions report errors or do
Packit Service 82fcde
nothing.
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Controlling Terminal, Access to the Terminal, Job Control is Optional, Job Control
Packit Service 82fcde
@section Controlling Terminal of a Process
Packit Service 82fcde
Packit Service 82fcde
One of the attributes of a process is its controlling terminal.  Child
Packit Service 82fcde
processes created with @code{fork} inherit the controlling terminal from
Packit Service 82fcde
their parent process.  In this way, all the processes in a session
Packit Service 82fcde
inherit the controlling terminal from the session leader.  A session
Packit Service 82fcde
leader that has control of a terminal is called the @dfn{controlling
Packit Service 82fcde
process} of that terminal.
Packit Service 82fcde
Packit Service 82fcde
@cindex controlling process
Packit Service 82fcde
You generally do not need to worry about the exact mechanism used to
Packit Service 82fcde
allocate a controlling terminal to a session, since it is done for you
Packit Service 82fcde
by the system when you log in.
Packit Service 82fcde
@c ??? How does GNU system let a process get a ctl terminal.
Packit Service 82fcde
Packit Service 82fcde
An individual process disconnects from its controlling terminal when it
Packit Service 82fcde
calls @code{setsid} to become the leader of a new session.
Packit Service 82fcde
@xref{Process Group Functions}.
Packit Service 82fcde
Packit Service 82fcde
@c !!! explain how it gets a new one (by opening any terminal)
Packit Service 82fcde
@c ??? How you get a controlling terminal is system-dependent.
Packit Service 82fcde
@c We should document how this will work in the GNU system when it is decided.
Packit Service 82fcde
@c What Unix does is not clean and I don't think GNU should use that.
Packit Service 82fcde
Packit Service 82fcde
@node Access to the Terminal, Orphaned Process Groups, Controlling Terminal, Job Control
Packit Service 82fcde
@section Access to the Controlling Terminal
Packit Service 82fcde
@cindex controlling terminal, access to
Packit Service 82fcde
Packit Service 82fcde
Processes in the foreground job of a controlling terminal have
Packit Service 82fcde
unrestricted access to that terminal; background processes do not.  This
Packit Service 82fcde
section describes in more detail what happens when a process in a
Packit Service 82fcde
background job tries to access its controlling terminal.
Packit Service 82fcde
Packit Service 82fcde
@cindex @code{SIGTTIN}, from background job
Packit Service 82fcde
When a process in a background job tries to read from its controlling
Packit Service 82fcde
terminal, the process group is usually sent a @code{SIGTTIN} signal.
Packit Service 82fcde
This normally causes all of the processes in that group to stop (unless
Packit Service 82fcde
they handle the signal and don't stop themselves).  However, if the
Packit Service 82fcde
reading process is ignoring or blocking this signal, then @code{read}
Packit Service 82fcde
fails with an @code{EIO} error instead.
Packit Service 82fcde
Packit Service 82fcde
@cindex @code{SIGTTOU}, from background job
Packit Service 82fcde
Similarly, when a process in a background job tries to write to its
Packit Service 82fcde
controlling terminal, the default behavior is to send a @code{SIGTTOU}
Packit Service 82fcde
signal to the process group.  However, the behavior is modified by the
Packit Service 82fcde
@code{TOSTOP} bit of the local modes flags (@pxref{Local Modes}).  If
Packit Service 82fcde
this bit is not set (which is the default), then writing to the
Packit Service 82fcde
controlling terminal is always permitted without sending a signal.
Packit Service 82fcde
Writing is also permitted if the @code{SIGTTOU} signal is being ignored
Packit Service 82fcde
or blocked by the writing process.
Packit Service 82fcde
Packit Service 82fcde
Most other terminal operations that a program can do are treated as
Packit Service 82fcde
reading or as writing.  (The description of each operation should say
Packit Service 82fcde
which.)
Packit Service 82fcde
Packit Service 82fcde
For more information about the primitive @code{read} and @code{write}
Packit Service 82fcde
functions, see @ref{I/O Primitives}.
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Orphaned Process Groups, Implementing a Shell, Access to the Terminal, Job Control
Packit Service 82fcde
@section Orphaned Process Groups
Packit Service 82fcde
@cindex orphaned process group
Packit Service 82fcde
Packit Service 82fcde
When a controlling process terminates, its terminal becomes free and a
Packit Service 82fcde
new session can be established on it.  (In fact, another user could log
Packit Service 82fcde
in on the terminal.)  This could cause a problem if any processes from
Packit Service 82fcde
the old session are still trying to use that terminal.
Packit Service 82fcde
Packit Service 82fcde
To prevent problems, process groups that continue running even after the
Packit Service 82fcde
session leader has terminated are marked as @dfn{orphaned process
Packit Service 82fcde
groups}.
Packit Service 82fcde
Packit Service 82fcde
When a process group becomes an orphan, its processes are sent a
Packit Service 82fcde
@code{SIGHUP} signal.  Ordinarily, this causes the processes to
Packit Service 82fcde
terminate.  However, if a program ignores this signal or establishes a
Packit Service 82fcde
handler for it (@pxref{Signal Handling}), it can continue running as in
Packit Service 82fcde
the orphan process group even after its controlling process terminates;
Packit Service 82fcde
but it still cannot access the terminal any more.
Packit Service 82fcde
Packit Service 82fcde
@node Implementing a Shell, Functions for Job Control, Orphaned Process Groups, Job Control
Packit Service 82fcde
@section Implementing a Job Control Shell
Packit Service 82fcde
Packit Service 82fcde
This section describes what a shell must do to implement job control, by
Packit Service 82fcde
presenting an extensive sample program to illustrate the concepts
Packit Service 82fcde
involved.
Packit Service 82fcde
Packit Service 82fcde
@iftex
Packit Service 82fcde
@itemize @bullet
Packit Service 82fcde
@item
Packit Service 82fcde
@ref{Data Structures}, introduces the example and presents
Packit Service 82fcde
its primary data structures.
Packit Service 82fcde
Packit Service 82fcde
@item
Packit Service 82fcde
@ref{Initializing the Shell}, discusses actions which the shell must
Packit Service 82fcde
perform to prepare for job control.
Packit Service 82fcde
Packit Service 82fcde
@item
Packit Service 82fcde
@ref{Launching Jobs}, includes information about how to create jobs
Packit Service 82fcde
to execute commands.
Packit Service 82fcde
Packit Service 82fcde
@item
Packit Service 82fcde
@ref{Foreground and Background}, discusses what the shell should
Packit Service 82fcde
do differently when launching a job in the foreground as opposed to
Packit Service 82fcde
a background job.
Packit Service 82fcde
Packit Service 82fcde
@item
Packit Service 82fcde
@ref{Stopped and Terminated Jobs}, discusses reporting of job status
Packit Service 82fcde
back to the shell.
Packit Service 82fcde
Packit Service 82fcde
@item
Packit Service 82fcde
@ref{Continuing Stopped Jobs}, tells you how to continue jobs that
Packit Service 82fcde
have been stopped.
Packit Service 82fcde
Packit Service 82fcde
@item
Packit Service 82fcde
@ref{Missing Pieces}, discusses other parts of the shell.
Packit Service 82fcde
@end itemize
Packit Service 82fcde
@end iftex
Packit Service 82fcde
Packit Service 82fcde
@menu
Packit Service 82fcde
* Data Structures::             Introduction to the sample shell.
Packit Service 82fcde
* Initializing the Shell::      What the shell must do to take
Packit Service 82fcde
				 responsibility for job control.
Packit Service 82fcde
* Launching Jobs::              Creating jobs to execute commands.
Packit Service 82fcde
* Foreground and Background::   Putting a job in foreground of background.
Packit Service 82fcde
* Stopped and Terminated Jobs::  Reporting job status.
Packit Service 82fcde
* Continuing Stopped Jobs::     How to continue a stopped job in
Packit Service 82fcde
				 the foreground or background.
Packit Service 82fcde
* Missing Pieces::              Other parts of the shell.
Packit Service 82fcde
@end menu
Packit Service 82fcde
Packit Service 82fcde
@node Data Structures, Initializing the Shell,  , Implementing a Shell
Packit Service 82fcde
@subsection Data Structures for the Shell
Packit Service 82fcde
Packit Service 82fcde
All of the program examples included in this chapter are part of
Packit Service 82fcde
a simple shell program.  This section presents data structures
Packit Service 82fcde
and utility functions which are used throughout the example.
Packit Service 82fcde
Packit Service 82fcde
The sample shell deals mainly with two data structures.  The
Packit Service 82fcde
@code{job} type contains information about a job, which is a
Packit Service 82fcde
set of subprocesses linked together with pipes.  The @code{process} type
Packit Service 82fcde
holds information about a single subprocess.  Here are the relevant
Packit Service 82fcde
data structure declarations:
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{A process is a single process.}  */
Packit Service 82fcde
typedef struct process
Packit Service 82fcde
@{
Packit Service 82fcde
  struct process *next;       /* @r{next process in pipeline} */
Packit Service 82fcde
  char **argv;                /* @r{for exec} */
Packit Service 82fcde
  pid_t pid;                  /* @r{process ID} */
Packit Service 82fcde
  char completed;             /* @r{true if process has completed} */
Packit Service 82fcde
  char stopped;               /* @r{true if process has stopped} */
Packit Service 82fcde
  int status;                 /* @r{reported status value} */
Packit Service 82fcde
@} process;
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{A job is a pipeline of processes.}  */
Packit Service 82fcde
typedef struct job
Packit Service 82fcde
@{
Packit Service 82fcde
  struct job *next;           /* @r{next active job} */
Packit Service 82fcde
  char *command;              /* @r{command line, used for messages} */
Packit Service 82fcde
  process *first_process;     /* @r{list of processes in this job} */
Packit Service 82fcde
  pid_t pgid;                 /* @r{process group ID} */
Packit Service 82fcde
  char notified;              /* @r{true if user told about stopped job} */
Packit Service 82fcde
  struct termios tmodes;      /* @r{saved terminal modes} */
Packit Service 82fcde
  int stdin, stdout, stderr;  /* @r{standard i/o channels} */
Packit Service 82fcde
@} job;
Packit Service 82fcde
Packit Service 82fcde
/* @r{The active jobs are linked into a list.  This is its head.}   */
Packit Service 82fcde
job *first_job = NULL;
Packit Service 82fcde
@end group
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
Here are some utility functions that are used for operating on @code{job}
Packit Service 82fcde
objects.
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Find the active job with the indicated @var{pgid}.}  */
Packit Service 82fcde
job *
Packit Service 82fcde
find_job (pid_t pgid)
Packit Service 82fcde
@{
Packit Service 82fcde
  job *j;
Packit Service 82fcde
Packit Service 82fcde
  for (j = first_job; j; j = j->next)
Packit Service 82fcde
    if (j->pgid == pgid)
Packit Service 82fcde
      return j;
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Return true if all processes in the job have stopped or completed.}  */
Packit Service 82fcde
int
Packit Service 82fcde
job_is_stopped (job *j)
Packit Service 82fcde
@{
Packit Service 82fcde
  process *p;
Packit Service 82fcde
Packit Service 82fcde
  for (p = j->first_process; p; p = p->next)
Packit Service 82fcde
    if (!p->completed && !p->stopped)
Packit Service 82fcde
      return 0;
Packit Service 82fcde
  return 1;
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Return true if all processes in the job have completed.}  */
Packit Service 82fcde
int
Packit Service 82fcde
job_is_completed (job *j)
Packit Service 82fcde
@{
Packit Service 82fcde
  process *p;
Packit Service 82fcde
Packit Service 82fcde
  for (p = j->first_process; p; p = p->next)
Packit Service 82fcde
    if (!p->completed)
Packit Service 82fcde
      return 0;
Packit Service 82fcde
  return 1;
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Initializing the Shell, Launching Jobs, Data Structures, Implementing a Shell
Packit Service 82fcde
@subsection Initializing the Shell
Packit Service 82fcde
@cindex job control, enabling
Packit Service 82fcde
@cindex subshell
Packit Service 82fcde
Packit Service 82fcde
When a shell program that normally performs job control is started, it
Packit Service 82fcde
has to be careful in case it has been invoked from another shell that is
Packit Service 82fcde
already doing its own job control.
Packit Service 82fcde
Packit Service 82fcde
A subshell that runs interactively has to ensure that it has been placed
Packit Service 82fcde
in the foreground by its parent shell before it can enable job control
Packit Service 82fcde
itself.  It does this by getting its initial process group ID with the
Packit Service 82fcde
@code{getpgrp} function, and comparing it to the process group ID of the
Packit Service 82fcde
current foreground job associated with its controlling terminal (which
Packit Service 82fcde
can be retrieved using the @code{tcgetpgrp} function).
Packit Service 82fcde
Packit Service 82fcde
If the subshell is not running as a foreground job, it must stop itself
Packit Service 82fcde
by sending a @code{SIGTTIN} signal to its own process group.  It may not
Packit Service 82fcde
arbitrarily put itself into the foreground; it must wait for the user to
Packit Service 82fcde
tell the parent shell to do this.  If the subshell is continued again,
Packit Service 82fcde
it should repeat the check and stop itself again if it is still not in
Packit Service 82fcde
the foreground.
Packit Service 82fcde
Packit Service 82fcde
@cindex job control, enabling
Packit Service 82fcde
Once the subshell has been placed into the foreground by its parent
Packit Service 82fcde
shell, it can enable its own job control.  It does this by calling
Packit Service 82fcde
@code{setpgid} to put itself into its own process group, and then
Packit Service 82fcde
calling @code{tcsetpgrp} to place this process group into the
Packit Service 82fcde
foreground.
Packit Service 82fcde
Packit Service 82fcde
When a shell enables job control, it should set itself to ignore all the
Packit Service 82fcde
job control stop signals so that it doesn't accidentally stop itself.
Packit Service 82fcde
You can do this by setting the action for all the stop signals to
Packit Service 82fcde
@code{SIG_IGN}.
Packit Service 82fcde
Packit Service 82fcde
A subshell that runs non-interactively cannot and should not support job
Packit Service 82fcde
control.  It must leave all processes it creates in the same process
Packit Service 82fcde
group as the shell itself; this allows the non-interactive shell and its
Packit Service 82fcde
child processes to be treated as a single job by the parent shell.  This
Packit Service 82fcde
is easy to do---just don't use any of the job control primitives---but
Packit Service 82fcde
you must remember to make the shell do it.
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
Here is the initialization code for the sample shell that shows how to
Packit Service 82fcde
do all of this.
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
/* @r{Keep track of attributes of the shell.}  */
Packit Service 82fcde
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
#include <termios.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
Packit Service 82fcde
pid_t shell_pgid;
Packit Service 82fcde
struct termios shell_tmodes;
Packit Service 82fcde
int shell_terminal;
Packit Service 82fcde
int shell_is_interactive;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* @r{Make sure the shell is running interactively as the foreground job}
Packit Service 82fcde
   @r{before proceeding.} */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
init_shell ()
Packit Service 82fcde
@{
Packit Service 82fcde
Packit Service 82fcde
  /* @r{See if we are running interactively.}  */
Packit Service 82fcde
  shell_terminal = STDIN_FILENO;
Packit Service 82fcde
  shell_is_interactive = isatty (shell_terminal);
Packit Service 82fcde
Packit Service 82fcde
  if (shell_is_interactive)
Packit Service 82fcde
    @{
Packit Service 82fcde
      /* @r{Loop until we are in the foreground.}  */
Packit Service 82fcde
      while (tcgetpgrp (shell_terminal) != (shell_pgid = getpgrp ()))
Packit Service 82fcde
        kill (- shell_pgid, SIGTTIN);
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Ignore interactive and job-control signals.}  */
Packit Service 82fcde
      signal (SIGINT, SIG_IGN);
Packit Service 82fcde
      signal (SIGQUIT, SIG_IGN);
Packit Service 82fcde
      signal (SIGTSTP, SIG_IGN);
Packit Service 82fcde
      signal (SIGTTIN, SIG_IGN);
Packit Service 82fcde
      signal (SIGTTOU, SIG_IGN);
Packit Service 82fcde
      signal (SIGCHLD, SIG_IGN);
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Put ourselves in our own process group.}  */
Packit Service 82fcde
      shell_pgid = getpid ();
Packit Service 82fcde
      if (setpgid (shell_pgid, shell_pgid) < 0)
Packit Service 82fcde
        @{
Packit Service 82fcde
          perror ("Couldn't put the shell in its own process group");
Packit Service 82fcde
          exit (1);
Packit Service 82fcde
        @}
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Grab control of the terminal.}  */
Packit Service 82fcde
      tcsetpgrp (shell_terminal, shell_pgid);
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Save default terminal attributes for shell.}  */
Packit Service 82fcde
      tcgetattr (shell_terminal, &shell_tmodes);
Packit Service 82fcde
    @}
Packit Service 82fcde
@}
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Launching Jobs, Foreground and Background, Initializing the Shell, Implementing a Shell
Packit Service 82fcde
@subsection Launching Jobs
Packit Service 82fcde
@cindex launching jobs
Packit Service 82fcde
Packit Service 82fcde
Once the shell has taken responsibility for performing job control on
Packit Service 82fcde
its controlling terminal, it can launch jobs in response to commands
Packit Service 82fcde
typed by the user.
Packit Service 82fcde
Packit Service 82fcde
To create the processes in a process group, you use the same @code{fork}
Packit Service 82fcde
and @code{exec} functions described in @ref{Process Creation Concepts}.
Packit Service 82fcde
Since there are multiple child processes involved, though, things are a
Packit Service 82fcde
little more complicated and you must be careful to do things in the
Packit Service 82fcde
right order.  Otherwise, nasty race conditions can result.
Packit Service 82fcde
Packit Service 82fcde
You have two choices for how to structure the tree of parent-child
Packit Service 82fcde
relationships among the processes.  You can either make all the
Packit Service 82fcde
processes in the process group be children of the shell process, or you
Packit Service 82fcde
can make one process in group be the ancestor of all the other processes
Packit Service 82fcde
in that group.  The sample shell program presented in this chapter uses
Packit Service 82fcde
the first approach because it makes bookkeeping somewhat simpler.
Packit Service 82fcde
Packit Service 82fcde
@cindex process group leader
Packit Service 82fcde
@cindex process group ID
Packit Service 82fcde
As each process is forked, it should put itself in the new process group
Packit Service 82fcde
by calling @code{setpgid}; see @ref{Process Group Functions}.  The first
Packit Service 82fcde
process in the new group becomes its @dfn{process group leader}, and its
Packit Service 82fcde
process ID becomes the @dfn{process group ID} for the group.
Packit Service 82fcde
Packit Service 82fcde
@cindex race conditions, relating to job control
Packit Service 82fcde
The shell should also call @code{setpgid} to put each of its child
Packit Service 82fcde
processes into the new process group.  This is because there is a
Packit Service 82fcde
potential timing problem: each child process must be put in the process
Packit Service 82fcde
group before it begins executing a new program, and the shell depends on
Packit Service 82fcde
having all the child processes in the group before it continues
Packit Service 82fcde
executing.  If both the child processes and the shell call
Packit Service 82fcde
@code{setpgid}, this ensures that the right things happen no matter which
Packit Service 82fcde
process gets to it first.
Packit Service 82fcde
Packit Service 82fcde
If the job is being launched as a foreground job, the new process group
Packit Service 82fcde
also needs to be put into the foreground on the controlling terminal
Packit Service 82fcde
using @code{tcsetpgrp}.  Again, this should be done by the shell as well
Packit Service 82fcde
as by each of its child processes, to avoid race conditions.
Packit Service 82fcde
Packit Service 82fcde
The next thing each child process should do is to reset its signal
Packit Service 82fcde
actions.
Packit Service 82fcde
Packit Service 82fcde
During initialization, the shell process set itself to ignore job
Packit Service 82fcde
control signals; see @ref{Initializing the Shell}.  As a result, any child
Packit Service 82fcde
processes it creates also ignore these signals by inheritance.  This is
Packit Service 82fcde
definitely undesirable, so each child process should explicitly set the
Packit Service 82fcde
actions for these signals back to @code{SIG_DFL} just after it is forked.
Packit Service 82fcde
Packit Service 82fcde
Since shells follow this convention, applications can assume that they
Packit Service 82fcde
inherit the correct handling of these signals from the parent process.
Packit Service 82fcde
But every application has a responsibility not to mess up the handling
Packit Service 82fcde
of stop signals.  Applications that disable the normal interpretation of
Packit Service 82fcde
the SUSP character should provide some other mechanism for the user to
Packit Service 82fcde
stop the job.  When the user invokes this mechanism, the program should
Packit Service 82fcde
send a @code{SIGTSTP} signal to the process group of the process, not
Packit Service 82fcde
just to the process itself.  @xref{Signaling Another Process}.
Packit Service 82fcde
Packit Service 82fcde
Finally, each child process should call @code{exec} in the normal way.
Packit Service 82fcde
This is also the point at which redirection of the standard input and
Packit Service 82fcde
output channels should be handled.  @xref{Duplicating Descriptors},
Packit Service 82fcde
for an explanation of how to do this.
Packit Service 82fcde
Packit Service 82fcde
Here is the function from the sample shell program that is responsible
Packit Service 82fcde
for launching a program.  The function is executed by each child process
Packit Service 82fcde
immediately after it has been forked by the shell, and never returns.
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
void
Packit Service 82fcde
launch_process (process *p, pid_t pgid,
Packit Service 82fcde
                int infile, int outfile, int errfile,
Packit Service 82fcde
                int foreground)
Packit Service 82fcde
@{
Packit Service 82fcde
  pid_t pid;
Packit Service 82fcde
Packit Service 82fcde
  if (shell_is_interactive)
Packit Service 82fcde
    @{
Packit Service 82fcde
      /* @r{Put the process into the process group and give the process group}
Packit Service 82fcde
         @r{the terminal, if appropriate.}
Packit Service 82fcde
         @r{This has to be done both by the shell and in the individual}
Packit Service 82fcde
         @r{child processes because of potential race conditions.}  */
Packit Service 82fcde
      pid = getpid ();
Packit Service 82fcde
      if (pgid == 0) pgid = pid;
Packit Service 82fcde
      setpgid (pid, pgid);
Packit Service 82fcde
      if (foreground)
Packit Service 82fcde
        tcsetpgrp (shell_terminal, pgid);
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Set the handling for job control signals back to the default.}  */
Packit Service 82fcde
      signal (SIGINT, SIG_DFL);
Packit Service 82fcde
      signal (SIGQUIT, SIG_DFL);
Packit Service 82fcde
      signal (SIGTSTP, SIG_DFL);
Packit Service 82fcde
      signal (SIGTTIN, SIG_DFL);
Packit Service 82fcde
      signal (SIGTTOU, SIG_DFL);
Packit Service 82fcde
      signal (SIGCHLD, SIG_DFL);
Packit Service 82fcde
    @}
Packit Service 82fcde
Packit Service 82fcde
  /* @r{Set the standard input/output channels of the new process.}  */
Packit Service 82fcde
  if (infile != STDIN_FILENO)
Packit Service 82fcde
    @{
Packit Service 82fcde
      dup2 (infile, STDIN_FILENO);
Packit Service 82fcde
      close (infile);
Packit Service 82fcde
    @}
Packit Service 82fcde
  if (outfile != STDOUT_FILENO)
Packit Service 82fcde
    @{
Packit Service 82fcde
      dup2 (outfile, STDOUT_FILENO);
Packit Service 82fcde
      close (outfile);
Packit Service 82fcde
    @}
Packit Service 82fcde
  if (errfile != STDERR_FILENO)
Packit Service 82fcde
    @{
Packit Service 82fcde
      dup2 (errfile, STDERR_FILENO);
Packit Service 82fcde
      close (errfile);
Packit Service 82fcde
    @}
Packit Service 82fcde
Packit Service 82fcde
  /* @r{Exec the new process.  Make sure we exit.}  */
Packit Service 82fcde
  execvp (p->argv[0], p->argv);
Packit Service 82fcde
  perror ("execvp");
Packit Service 82fcde
  exit (1);
Packit Service 82fcde
@}
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
If the shell is not running interactively, this function does not do
Packit Service 82fcde
anything with process groups or signals.  Remember that a shell not
Packit Service 82fcde
performing job control must keep all of its subprocesses in the same
Packit Service 82fcde
process group as the shell itself.
Packit Service 82fcde
Packit Service 82fcde
Next, here is the function that actually launches a complete job.
Packit Service 82fcde
After creating the child processes, this function calls some other
Packit Service 82fcde
functions to put the newly created job into the foreground or background;
Packit Service 82fcde
these are discussed in @ref{Foreground and Background}.
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
void
Packit Service 82fcde
launch_job (job *j, int foreground)
Packit Service 82fcde
@{
Packit Service 82fcde
  process *p;
Packit Service 82fcde
  pid_t pid;
Packit Service 82fcde
  int mypipe[2], infile, outfile;
Packit Service 82fcde
Packit Service 82fcde
  infile = j->stdin;
Packit Service 82fcde
  for (p = j->first_process; p; p = p->next)
Packit Service 82fcde
    @{
Packit Service 82fcde
      /* @r{Set up pipes, if necessary.}  */
Packit Service 82fcde
      if (p->next)
Packit Service 82fcde
        @{
Packit Service 82fcde
          if (pipe (mypipe) < 0)
Packit Service 82fcde
            @{
Packit Service 82fcde
              perror ("pipe");
Packit Service 82fcde
              exit (1);
Packit Service 82fcde
            @}
Packit Service 82fcde
          outfile = mypipe[1];
Packit Service 82fcde
        @}
Packit Service 82fcde
      else
Packit Service 82fcde
        outfile = j->stdout;
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Fork the child processes.}  */
Packit Service 82fcde
      pid = fork ();
Packit Service 82fcde
      if (pid == 0)
Packit Service 82fcde
        /* @r{This is the child process.}  */
Packit Service 82fcde
        launch_process (p, j->pgid, infile,
Packit Service 82fcde
                        outfile, j->stderr, foreground);
Packit Service 82fcde
      else if (pid < 0)
Packit Service 82fcde
        @{
Packit Service 82fcde
          /* @r{The fork failed.}  */
Packit Service 82fcde
          perror ("fork");
Packit Service 82fcde
          exit (1);
Packit Service 82fcde
        @}
Packit Service 82fcde
      else
Packit Service 82fcde
        @{
Packit Service 82fcde
          /* @r{This is the parent process.}  */
Packit Service 82fcde
          p->pid = pid;
Packit Service 82fcde
          if (shell_is_interactive)
Packit Service 82fcde
            @{
Packit Service 82fcde
              if (!j->pgid)
Packit Service 82fcde
                j->pgid = pid;
Packit Service 82fcde
              setpgid (pid, j->pgid);
Packit Service 82fcde
            @}
Packit Service 82fcde
        @}
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Clean up after pipes.}  */
Packit Service 82fcde
      if (infile != j->stdin)
Packit Service 82fcde
        close (infile);
Packit Service 82fcde
      if (outfile != j->stdout)
Packit Service 82fcde
        close (outfile);
Packit Service 82fcde
      infile = mypipe[0];
Packit Service 82fcde
    @}
Packit Service 82fcde
Packit Service 82fcde
  format_job_info (j, "launched");
Packit Service 82fcde
Packit Service 82fcde
  if (!shell_is_interactive)
Packit Service 82fcde
    wait_for_job (j);
Packit Service 82fcde
  else if (foreground)
Packit Service 82fcde
    put_job_in_foreground (j, 0);
Packit Service 82fcde
  else
Packit Service 82fcde
    put_job_in_background (j, 0);
Packit Service 82fcde
@}
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Foreground and Background, Stopped and Terminated Jobs, Launching Jobs, Implementing a Shell
Packit Service 82fcde
@subsection Foreground and Background
Packit Service 82fcde
Packit Service 82fcde
Now let's consider what actions must be taken by the shell when it
Packit Service 82fcde
launches a job into the foreground, and how this differs from what
Packit Service 82fcde
must be done when a background job is launched.
Packit Service 82fcde
Packit Service 82fcde
@cindex foreground job, launching
Packit Service 82fcde
When a foreground job is launched, the shell must first give it access
Packit Service 82fcde
to the controlling terminal by calling @code{tcsetpgrp}.  Then, the
Packit Service 82fcde
shell should wait for processes in that process group to terminate or
Packit Service 82fcde
stop.  This is discussed in more detail in @ref{Stopped and Terminated
Packit Service 82fcde
Jobs}.
Packit Service 82fcde
Packit Service 82fcde
When all of the processes in the group have either completed or stopped,
Packit Service 82fcde
the shell should regain control of the terminal for its own process
Packit Service 82fcde
group by calling @code{tcsetpgrp} again.  Since stop signals caused by
Packit Service 82fcde
I/O from a background process or a SUSP character typed by the user
Packit Service 82fcde
are sent to the process group, normally all the processes in the job
Packit Service 82fcde
stop together.
Packit Service 82fcde
Packit Service 82fcde
The foreground job may have left the terminal in a strange state, so the
Packit Service 82fcde
shell should restore its own saved terminal modes before continuing.  In
Packit Service 82fcde
case the job is merely stopped, the shell should first save the current
Packit Service 82fcde
terminal modes so that it can restore them later if the job is
Packit Service 82fcde
continued.  The functions for dealing with terminal modes are
Packit Service 82fcde
@code{tcgetattr} and @code{tcsetattr}; these are described in
Packit Service 82fcde
@ref{Terminal Modes}.
Packit Service 82fcde
Packit Service 82fcde
Here is the sample shell's function for doing all of this.
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Put job @var{j} in the foreground.  If @var{cont} is nonzero,}
Packit Service 82fcde
   @r{restore the saved terminal modes and send the process group a}
Packit Service 82fcde
   @r{@code{SIGCONT} signal to wake it up before we block.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
put_job_in_foreground (job *j, int cont)
Packit Service 82fcde
@{
Packit Service 82fcde
  /* @r{Put the job into the foreground.}  */
Packit Service 82fcde
  tcsetpgrp (shell_terminal, j->pgid);
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
  /* @r{Send the job a continue signal, if necessary.}  */
Packit Service 82fcde
  if (cont)
Packit Service 82fcde
    @{
Packit Service 82fcde
      tcsetattr (shell_terminal, TCSADRAIN, &j->tmodes);
Packit Service 82fcde
      if (kill (- j->pgid, SIGCONT) < 0)
Packit Service 82fcde
        perror ("kill (SIGCONT)");
Packit Service 82fcde
    @}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
  /* @r{Wait for it to report.}  */
Packit Service 82fcde
  wait_for_job (j);
Packit Service 82fcde
Packit Service 82fcde
  /* @r{Put the shell back in the foreground.}  */
Packit Service 82fcde
  tcsetpgrp (shell_terminal, shell_pgid);
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
  /* @r{Restore the shell's terminal modes.}  */
Packit Service 82fcde
  tcgetattr (shell_terminal, &j->tmodes);
Packit Service 82fcde
  tcsetattr (shell_terminal, TCSADRAIN, &shell_tmodes);
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
@cindex background job, launching
Packit Service 82fcde
If the process group is launched as a background job, the shell should
Packit Service 82fcde
remain in the foreground itself and continue to read commands from
Packit Service 82fcde
the terminal.
Packit Service 82fcde
Packit Service 82fcde
In the sample shell, there is not much that needs to be done to put
Packit Service 82fcde
a job into the background.  Here is the function it uses:
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
/* @r{Put a job in the background.  If the cont argument is true, send}
Packit Service 82fcde
   @r{the process group a @code{SIGCONT} signal to wake it up.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
put_job_in_background (job *j, int cont)
Packit Service 82fcde
@{
Packit Service 82fcde
  /* @r{Send the job a continue signal, if necessary.}  */
Packit Service 82fcde
  if (cont)
Packit Service 82fcde
    if (kill (-j->pgid, SIGCONT) < 0)
Packit Service 82fcde
      perror ("kill (SIGCONT)");
Packit Service 82fcde
@}
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Stopped and Terminated Jobs, Continuing Stopped Jobs, Foreground and Background, Implementing a Shell
Packit Service 82fcde
@subsection Stopped and Terminated Jobs
Packit Service 82fcde
Packit Service 82fcde
@cindex stopped jobs, detecting
Packit Service 82fcde
@cindex terminated jobs, detecting
Packit Service 82fcde
When a foreground process is launched, the shell must block until all of
Packit Service 82fcde
the processes in that job have either terminated or stopped.  It can do
Packit Service 82fcde
this by calling the @code{waitpid} function; see @ref{Process
Packit Service 82fcde
Completion}.  Use the @code{WUNTRACED} option so that status is reported
Packit Service 82fcde
for processes that stop as well as processes that terminate.
Packit Service 82fcde
Packit Service 82fcde
The shell must also check on the status of background jobs so that it
Packit Service 82fcde
can report terminated and stopped jobs to the user; this can be done by
Packit Service 82fcde
calling @code{waitpid} with the @code{WNOHANG} option.  A good place to
Packit Service 82fcde
put a such a check for terminated and stopped jobs is just before
Packit Service 82fcde
prompting for a new command.
Packit Service 82fcde
Packit Service 82fcde
@cindex @code{SIGCHLD}, handling of
Packit Service 82fcde
The shell can also receive asynchronous notification that there is
Packit Service 82fcde
status information available for a child process by establishing a
Packit Service 82fcde
handler for @code{SIGCHLD} signals.  @xref{Signal Handling}.
Packit Service 82fcde
Packit Service 82fcde
In the sample shell program, the @code{SIGCHLD} signal is normally
Packit Service 82fcde
ignored.  This is to avoid reentrancy problems involving the global data
Packit Service 82fcde
structures the shell manipulates.  But at specific times when the shell
Packit Service 82fcde
is not using these data structures---such as when it is waiting for
Packit Service 82fcde
input on the terminal---it makes sense to enable a handler for
Packit Service 82fcde
@code{SIGCHLD}.  The same function that is used to do the synchronous
Packit Service 82fcde
status checks (@code{do_job_notification}, in this case) can also be
Packit Service 82fcde
called from within this handler.
Packit Service 82fcde
Packit Service 82fcde
Here are the parts of the sample shell program that deal with checking
Packit Service 82fcde
the status of jobs and reporting the information to the user.
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Store the status of the process @var{pid} that was returned by waitpid.}
Packit Service 82fcde
   @r{Return 0 if all went well, nonzero otherwise.}  */
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
mark_process_status (pid_t pid, int status)
Packit Service 82fcde
@{
Packit Service 82fcde
  job *j;
Packit Service 82fcde
  process *p;
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
  if (pid > 0)
Packit Service 82fcde
    @{
Packit Service 82fcde
      /* @r{Update the record for the process.}  */
Packit Service 82fcde
      for (j = first_job; j; j = j->next)
Packit Service 82fcde
        for (p = j->first_process; p; p = p->next)
Packit Service 82fcde
          if (p->pid == pid)
Packit Service 82fcde
            @{
Packit Service 82fcde
              p->status = status;
Packit Service 82fcde
              if (WIFSTOPPED (status))
Packit Service 82fcde
                p->stopped = 1;
Packit Service 82fcde
              else
Packit Service 82fcde
                @{
Packit Service 82fcde
                  p->completed = 1;
Packit Service 82fcde
                  if (WIFSIGNALED (status))
Packit Service 82fcde
                    fprintf (stderr, "%d: Terminated by signal %d.\n",
Packit Service 82fcde
                             (int) pid, WTERMSIG (p->status));
Packit Service 82fcde
                @}
Packit Service 82fcde
              return 0;
Packit Service 82fcde
             @}
Packit Service 82fcde
      fprintf (stderr, "No child process %d.\n", pid);
Packit Service 82fcde
      return -1;
Packit Service 82fcde
    @}
Packit Service 82fcde
@end group
Packit Service 82fcde
@group
Packit Service 82fcde
  else if (pid == 0 || errno == ECHILD)
Packit Service 82fcde
    /* @r{No processes ready to report.}  */
Packit Service 82fcde
    return -1;
Packit Service 82fcde
  else @{
Packit Service 82fcde
    /* @r{Other weird errors.}  */
Packit Service 82fcde
    perror ("waitpid");
Packit Service 82fcde
    return -1;
Packit Service 82fcde
  @}
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Check for processes that have status information available,}
Packit Service 82fcde
   @r{without blocking.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
update_status (void)
Packit Service 82fcde
@{
Packit Service 82fcde
  int status;
Packit Service 82fcde
  pid_t pid;
Packit Service 82fcde
Packit Service 82fcde
  do
Packit Service 82fcde
    pid = waitpid (WAIT_ANY, &status, WUNTRACED|WNOHANG);
Packit Service 82fcde
  while (!mark_process_status (pid, status));
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Check for processes that have status information available,}
Packit Service 82fcde
   @r{blocking until all processes in the given job have reported.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
wait_for_job (job *j)
Packit Service 82fcde
@{
Packit Service 82fcde
  int status;
Packit Service 82fcde
  pid_t pid;
Packit Service 82fcde
Packit Service 82fcde
  do
Packit Service 82fcde
    pid = waitpid (WAIT_ANY, &status, WUNTRACED);
Packit Service 82fcde
  while (!mark_process_status (pid, status)
Packit Service 82fcde
         && !job_is_stopped (j)
Packit Service 82fcde
         && !job_is_completed (j));
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Format information about job status for the user to look at.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
format_job_info (job *j, const char *status)
Packit Service 82fcde
@{
Packit Service 82fcde
  fprintf (stderr, "%ld (%s): %s\n", (long)j->pgid, status, j->command);
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Notify the user about stopped or terminated jobs.}
Packit Service 82fcde
   @r{Delete terminated jobs from the active job list.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
do_job_notification (void)
Packit Service 82fcde
@{
Packit Service 82fcde
  job *j, *jlast, *jnext;
Packit Service 82fcde
  process *p;
Packit Service 82fcde
Packit Service 82fcde
  /* @r{Update status information for child processes.}  */
Packit Service 82fcde
  update_status ();
Packit Service 82fcde
Packit Service 82fcde
  jlast = NULL;
Packit Service 82fcde
  for (j = first_job; j; j = jnext)
Packit Service 82fcde
    @{
Packit Service 82fcde
      jnext = j->next;
Packit Service 82fcde
Packit Service 82fcde
      /* @r{If all processes have completed, tell the user the job has}
Packit Service 82fcde
         @r{completed and delete it from the list of active jobs.}  */
Packit Service 82fcde
      if (job_is_completed (j)) @{
Packit Service 82fcde
        format_job_info (j, "completed");
Packit Service 82fcde
        if (jlast)
Packit Service 82fcde
          jlast->next = jnext;
Packit Service 82fcde
        else
Packit Service 82fcde
          first_job = jnext;
Packit Service 82fcde
        free_job (j);
Packit Service 82fcde
      @}
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Notify the user about stopped jobs,}
Packit Service 82fcde
         @r{marking them so that we won't do this more than once.}  */
Packit Service 82fcde
      else if (job_is_stopped (j) && !j->notified) @{
Packit Service 82fcde
        format_job_info (j, "stopped");
Packit Service 82fcde
        j->notified = 1;
Packit Service 82fcde
        jlast = j;
Packit Service 82fcde
      @}
Packit Service 82fcde
Packit Service 82fcde
      /* @r{Don't say anything about jobs that are still running.}  */
Packit Service 82fcde
      else
Packit Service 82fcde
        jlast = j;
Packit Service 82fcde
    @}
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
@node Continuing Stopped Jobs, Missing Pieces, Stopped and Terminated Jobs, Implementing a Shell
Packit Service 82fcde
@subsection Continuing Stopped Jobs
Packit Service 82fcde
Packit Service 82fcde
@cindex stopped jobs, continuing
Packit Service 82fcde
The shell can continue a stopped job by sending a @code{SIGCONT} signal
Packit Service 82fcde
to its process group.  If the job is being continued in the foreground,
Packit Service 82fcde
the shell should first invoke @code{tcsetpgrp} to give the job access to
Packit Service 82fcde
the terminal, and restore the saved terminal settings.  After continuing
Packit Service 82fcde
a job in the foreground, the shell should wait for the job to stop or
Packit Service 82fcde
complete, as if the job had just been launched in the foreground.
Packit Service 82fcde
Packit Service 82fcde
The sample shell program handles both newly created and continued jobs
Packit Service 82fcde
with the same pair of functions, @w{@code{put_job_in_foreground}} and
Packit Service 82fcde
@w{@code{put_job_in_background}}.  The definitions of these functions
Packit Service 82fcde
were given in @ref{Foreground and Background}.  When continuing a
Packit Service 82fcde
stopped job, a nonzero value is passed as the @var{cont} argument to
Packit Service 82fcde
ensure that the @code{SIGCONT} signal is sent and the terminal modes
Packit Service 82fcde
reset, as appropriate.
Packit Service 82fcde
Packit Service 82fcde
This leaves only a function for updating the shell's internal bookkeeping
Packit Service 82fcde
about the job being continued:
Packit Service 82fcde
Packit Service 82fcde
@smallexample
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Mark a stopped job J as being running again.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
mark_job_as_running (job *j)
Packit Service 82fcde
@{
Packit Service 82fcde
  Process *p;
Packit Service 82fcde
Packit Service 82fcde
  for (p = j->first_process; p; p = p->next)
Packit Service 82fcde
    p->stopped = 0;
Packit Service 82fcde
  j->notified = 0;
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
Packit Service 82fcde
@group
Packit Service 82fcde
/* @r{Continue the job J.}  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
continue_job (job *j, int foreground)
Packit Service 82fcde
@{
Packit Service 82fcde
  mark_job_as_running (j);
Packit Service 82fcde
  if (foreground)
Packit Service 82fcde
    put_job_in_foreground (j, 1);
Packit Service 82fcde
  else
Packit Service 82fcde
    put_job_in_background (j, 1);
Packit Service 82fcde
@}
Packit Service 82fcde
@end group
Packit Service 82fcde
@end smallexample
Packit Service 82fcde
Packit Service 82fcde
@node Missing Pieces,  , Continuing Stopped Jobs, Implementing a Shell
Packit Service 82fcde
@subsection The Missing Pieces
Packit Service 82fcde
Packit Service 82fcde
The code extracts for the sample shell included in this chapter are only
Packit Service 82fcde
a part of the entire shell program.  In particular, nothing at all has
Packit Service 82fcde
been said about how @code{job} and @code{program} data structures are
Packit Service 82fcde
allocated and initialized.
Packit Service 82fcde
Packit Service 82fcde
Most real shells provide a complex user interface that has support for
Packit Service 82fcde
a command language; variables; abbreviations, substitutions, and pattern
Packit Service 82fcde
matching on file names; and the like.  All of this is far too complicated
Packit Service 82fcde
to explain here!  Instead, we have concentrated on showing how to
Packit Service 82fcde
implement the core process creation and job control functions that can
Packit Service 82fcde
be called from such a shell.
Packit Service 82fcde
Packit Service 82fcde
Here is a table summarizing the major entry points we have presented:
Packit Service 82fcde
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item void init_shell (void)
Packit Service 82fcde
Initialize the shell's internal state.  @xref{Initializing the
Packit Service 82fcde
Shell}.
Packit Service 82fcde
Packit Service 82fcde
@item void launch_job (job *@var{j}, int @var{foreground})
Packit Service 82fcde
Launch the job @var{j} as either a foreground or background job.
Packit Service 82fcde
@xref{Launching Jobs}.
Packit Service 82fcde
Packit Service 82fcde
@item void do_job_notification (void)
Packit Service 82fcde
Check for and report any jobs that have terminated or stopped.  Can be
Packit Service 82fcde
called synchronously or within a handler for @code{SIGCHLD} signals.
Packit Service 82fcde
@xref{Stopped and Terminated Jobs}.
Packit Service 82fcde
Packit Service 82fcde
@item void continue_job (job *@var{j}, int @var{foreground})
Packit Service 82fcde
Continue the job @var{j}.  @xref{Continuing Stopped Jobs}.
Packit Service 82fcde
@end table
Packit Service 82fcde
Packit Service 82fcde
Of course, a real shell would also want to provide other functions for
Packit Service 82fcde
managing jobs.  For example, it would be useful to have commands to list
Packit Service 82fcde
all active jobs or to send a signal (such as @code{SIGKILL}) to a job.
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Functions for Job Control,  , Implementing a Shell, Job Control
Packit Service 82fcde
@section Functions for Job Control
Packit Service 82fcde
@cindex process group functions
Packit Service 82fcde
@cindex job control functions
Packit Service 82fcde
Packit Service 82fcde
This section contains detailed descriptions of the functions relating
Packit Service 82fcde
to job control.
Packit Service 82fcde
Packit Service 82fcde
@menu
Packit Service 82fcde
* Identifying the Terminal::    Determining the controlling terminal's name.
Packit Service 82fcde
* Process Group Functions::     Functions for manipulating process groups.
Packit Service 82fcde
* Terminal Access Functions::   Functions for controlling terminal access.
Packit Service 82fcde
@end menu
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Identifying the Terminal, Process Group Functions,  , Functions for Job Control
Packit Service 82fcde
@subsection Identifying the Controlling Terminal
Packit Service 82fcde
@cindex controlling terminal, determining
Packit Service 82fcde
Packit Service 82fcde
You can use the @code{ctermid} function to get a file name that you can
Packit Service 82fcde
use to open the controlling terminal.  In @theglibc{}, it returns
Packit Service 82fcde
the same string all the time: @code{"/dev/tty"}.  That is a special
Packit Service 82fcde
``magic'' file name that refers to the controlling terminal of the
Packit Service 82fcde
current process (if it has one).  To find the name of the specific
Packit Service 82fcde
terminal device, use @code{ttyname}; @pxref{Is It a Terminal}.
Packit Service 82fcde
Packit Service 82fcde
The function @code{ctermid} is declared in the header file
Packit Service 82fcde
@file{stdio.h}.
Packit Service 82fcde
@pindex stdio.h
Packit Service 82fcde
Packit Service 82fcde
@deftypefun {char *} ctermid (char *@var{string})
Packit Service 82fcde
@standards{POSIX.1, stdio.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{@mtsposix{/!string}}@assafe{}@acsafe{}}
Packit Service 82fcde
@c This function is a stub by default; the actual implementation, for
Packit Service 82fcde
@c posix systems, returns a pointer to a string literal if passed a NULL
Packit Service 82fcde
@c string.  It's not clear we want to commit to being MT-Safe in the
Packit Service 82fcde
@c !string case, so maybe add mtasurace{:ctermid/!string} when we take
Packit Service 82fcde
@c prelim out, to make room for using a static buffer in the future.
Packit Service 82fcde
The @code{ctermid} function returns a string containing the file name of
Packit Service 82fcde
the controlling terminal for the current process.  If @var{string} is
Packit Service 82fcde
not a null pointer, it should be an array that can hold at least
Packit Service 82fcde
@code{L_ctermid} characters; the string is returned in this array.
Packit Service 82fcde
Otherwise, a pointer to a string in a static area is returned, which
Packit Service 82fcde
might get overwritten on subsequent calls to this function.
Packit Service 82fcde
Packit Service 82fcde
An empty string is returned if the file name cannot be determined for
Packit Service 82fcde
any reason.  Even if a file name is returned, access to the file it
Packit Service 82fcde
represents is not guaranteed.
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypevr Macro int L_ctermid
Packit Service 82fcde
@standards{POSIX.1, stdio.h}
Packit Service 82fcde
The value of this macro is an integer constant expression that
Packit Service 82fcde
represents the size of a string large enough to hold the file name
Packit Service 82fcde
returned by @code{ctermid}.
Packit Service 82fcde
@end deftypevr
Packit Service 82fcde
Packit Service 82fcde
See also the @code{isatty} and @code{ttyname} functions, in
Packit Service 82fcde
@ref{Is It a Terminal}.
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Process Group Functions, Terminal Access Functions, Identifying the Terminal, Functions for Job Control
Packit Service 82fcde
@subsection Process Group Functions
Packit Service 82fcde
Packit Service 82fcde
Here are descriptions of the functions for manipulating process groups.
Packit Service 82fcde
Your program should include the header files @file{sys/types.h} and
Packit Service 82fcde
@file{unistd.h} to use these functions.
Packit Service 82fcde
@pindex unistd.h
Packit Service 82fcde
@pindex sys/types.h
Packit Service 82fcde
Packit Service 82fcde
@deftypefun pid_t setsid (void)
Packit Service 82fcde
@standards{POSIX.1, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c This is usually a direct syscall, but if a syscall is not available,
Packit Service 82fcde
@c we use a stub, or Hurd- and BSD-specific implementations.  The former
Packit Service 82fcde
@c uses a mutex and a hurd critical section, and the latter issues a few
Packit Service 82fcde
@c syscalls, so both seem safe, the locking on Hurd is safe because of
Packit Service 82fcde
@c the critical section.
Packit Service 82fcde
The @code{setsid} function creates a new session.  The calling process
Packit Service 82fcde
becomes the session leader, and is put in a new process group whose
Packit Service 82fcde
process group ID is the same as the process ID of that process.  There
Packit Service 82fcde
are initially no other processes in the new process group, and no other
Packit Service 82fcde
process groups in the new session.
Packit Service 82fcde
Packit Service 82fcde
This function also makes the calling process have no controlling terminal.
Packit Service 82fcde
Packit Service 82fcde
The @code{setsid} function returns the new process group ID of the
Packit Service 82fcde
calling process if successful.  A return value of @code{-1} indicates an
Packit Service 82fcde
error.  The following @code{errno} error conditions are defined for this
Packit Service 82fcde
function:
Packit Service 82fcde
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item EPERM
Packit Service 82fcde
The calling process is already a process group leader, or there is
Packit Service 82fcde
already another process group around that has the same process group ID.
Packit Service 82fcde
@end table
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypefun pid_t getsid (pid_t @var{pid})
Packit Service 82fcde
@standards{SVID, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c Stub or direct syscall, except on hurd, where it is equally safe.
Packit Service 82fcde
Packit Service 82fcde
The @code{getsid} function returns the process group ID of the session
Packit Service 82fcde
leader of the specified process.  If a @var{pid} is @code{0}, the
Packit Service 82fcde
process group ID of the session leader of the current process is
Packit Service 82fcde
returned.
Packit Service 82fcde
Packit Service 82fcde
In case of error @code{-1} is returned and @code{errno} is set.  The
Packit Service 82fcde
following @code{errno} error conditions are defined for this function:
Packit Service 82fcde
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item ESRCH
Packit Service 82fcde
There is no process with the given process ID @var{pid}.
Packit Service 82fcde
@item EPERM
Packit Service 82fcde
The calling process and the process specified by @var{pid} are in
Packit Service 82fcde
different sessions, and the implementation doesn't allow to access the
Packit Service 82fcde
process group ID of the session leader of the process with ID @var{pid}
Packit Service 82fcde
from the calling process.
Packit Service 82fcde
@end table
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypefun pid_t getpgrp (void)
Packit Service 82fcde
@standards{POSIX.1, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
The @code{getpgrp} function returns the process group ID of
Packit Service 82fcde
the calling process.
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypefun int getpgid (pid_t @var{pid})
Packit Service 82fcde
@standards{POSIX.1, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c Stub or direct syscall, except on hurd, where it is equally safe.
Packit Service 82fcde
Packit Service 82fcde
The @code{getpgid} function
Packit Service 82fcde
returns the process group ID of the process @var{pid}.  You can supply a
Packit Service 82fcde
value of @code{0} for the @var{pid} argument to get information about
Packit Service 82fcde
the calling process.
Packit Service 82fcde
Packit Service 82fcde
In case of error @code{-1} is returned and @code{errno} is set.  The
Packit Service 82fcde
following @code{errno} error conditions are defined for this function:
Packit Service 82fcde
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item ESRCH
Packit Service 82fcde
There is no process with the given process ID @var{pid}.
Packit Service 82fcde
The calling process and the process specified by @var{pid} are in
Packit Service 82fcde
different sessions, and the implementation doesn't allow to access the
Packit Service 82fcde
process group ID of the process with ID @var{pid} from the calling
Packit Service 82fcde
process.
Packit Service 82fcde
@end table
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypefun int setpgid (pid_t @var{pid}, pid_t @var{pgid})
Packit Service 82fcde
@standards{POSIX.1, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c Stub or direct syscall, except on hurd, where it is equally safe.
Packit Service 82fcde
The @code{setpgid} function puts the process @var{pid} into the process
Packit Service 82fcde
group @var{pgid}.  As a special case, either @var{pid} or @var{pgid} can
Packit Service 82fcde
be zero to indicate the process ID of the calling process.
Packit Service 82fcde
Packit Service 82fcde
This function fails on a system that does not support job control.
Packit Service 82fcde
@xref{Job Control is Optional}, for more information.
Packit Service 82fcde
Packit Service 82fcde
If the operation is successful, @code{setpgid} returns zero.  Otherwise
Packit Service 82fcde
it returns @code{-1}.  The following @code{errno} error conditions are
Packit Service 82fcde
defined for this function:
Packit Service 82fcde
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item EACCES
Packit Service 82fcde
The child process named by @var{pid} has executed an @code{exec}
Packit Service 82fcde
function since it was forked.
Packit Service 82fcde
Packit Service 82fcde
@item EINVAL
Packit Service 82fcde
The value of the @var{pgid} is not valid.
Packit Service 82fcde
Packit Service 82fcde
@item ENOSYS
Packit Service 82fcde
The system doesn't support job control.
Packit Service 82fcde
Packit Service 82fcde
@item EPERM
Packit Service 82fcde
The process indicated by the @var{pid} argument is a session leader,
Packit Service 82fcde
or is not in the same session as the calling process, or the value of
Packit Service 82fcde
the @var{pgid} argument doesn't match a process group ID in the same
Packit Service 82fcde
session as the calling process.
Packit Service 82fcde
Packit Service 82fcde
@item ESRCH
Packit Service 82fcde
The process indicated by the @var{pid} argument is not the calling
Packit Service 82fcde
process or a child of the calling process.
Packit Service 82fcde
@end table
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypefun int setpgrp (pid_t @var{pid}, pid_t @var{pgid})
Packit Service 82fcde
@standards{BSD, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c Direct syscall or setpgid wrapper.
Packit Service 82fcde
This is the BSD Unix name for @code{setpgid}.  Both functions do exactly
Packit Service 82fcde
the same thing.
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
@node Terminal Access Functions,  , Process Group Functions, Functions for Job Control
Packit Service 82fcde
@subsection Functions for Controlling Terminal Access
Packit Service 82fcde
Packit Service 82fcde
These are the functions for reading or setting the foreground
Packit Service 82fcde
process group of a terminal.  You should include the header files
Packit Service 82fcde
@file{sys/types.h} and @file{unistd.h} in your application to use
Packit Service 82fcde
these functions.
Packit Service 82fcde
@pindex unistd.h
Packit Service 82fcde
@pindex sys/types.h
Packit Service 82fcde
Packit Service 82fcde
Although these functions take a file descriptor argument to specify
Packit Service 82fcde
the terminal device, the foreground job is associated with the terminal
Packit Service 82fcde
file itself and not a particular open file descriptor.
Packit Service 82fcde
Packit Service 82fcde
@deftypefun pid_t tcgetpgrp (int @var{filedes})
Packit Service 82fcde
@standards{POSIX.1, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c Stub, or ioctl on BSD and GNU/Linux.
Packit Service 82fcde
This function returns the process group ID of the foreground process
Packit Service 82fcde
group associated with the terminal open on descriptor @var{filedes}.
Packit Service 82fcde
Packit Service 82fcde
If there is no foreground process group, the return value is a number
Packit Service 82fcde
greater than @code{1} that does not match the process group ID of any
Packit Service 82fcde
existing process group.  This can happen if all of the processes in the
Packit Service 82fcde
job that was formerly the foreground job have terminated, and no other
Packit Service 82fcde
job has yet been moved into the foreground.
Packit Service 82fcde
Packit Service 82fcde
In case of an error, a value of @code{-1} is returned.  The
Packit Service 82fcde
following @code{errno} error conditions are defined for this function:
Packit Service 82fcde
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item EBADF
Packit Service 82fcde
The @var{filedes} argument is not a valid file descriptor.
Packit Service 82fcde
Packit Service 82fcde
@item ENOSYS
Packit Service 82fcde
The system doesn't support job control.
Packit Service 82fcde
Packit Service 82fcde
@item ENOTTY
Packit Service 82fcde
The terminal file associated with the @var{filedes} argument isn't the
Packit Service 82fcde
controlling terminal of the calling process.
Packit Service 82fcde
@end table
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypefun int tcsetpgrp (int @var{filedes}, pid_t @var{pgid})
Packit Service 82fcde
@standards{POSIX.1, unistd.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c Stub, or ioctl on BSD and GNU/Linux.
Packit Service 82fcde
This function is used to set a terminal's foreground process group ID.
Packit Service 82fcde
The argument @var{filedes} is a descriptor which specifies the terminal;
Packit Service 82fcde
@var{pgid} specifies the process group.  The calling process must be a
Packit Service 82fcde
member of the same session as @var{pgid} and must have the same
Packit Service 82fcde
controlling terminal.
Packit Service 82fcde
Packit Service 82fcde
For terminal access purposes, this function is treated as output.  If it
Packit Service 82fcde
is called from a background process on its controlling terminal,
Packit Service 82fcde
normally all processes in the process group are sent a @code{SIGTTOU}
Packit Service 82fcde
signal.  The exception is if the calling process itself is ignoring or
Packit Service 82fcde
blocking @code{SIGTTOU} signals, in which case the operation is
Packit Service 82fcde
performed and no signal is sent.
Packit Service 82fcde
Packit Service 82fcde
If successful, @code{tcsetpgrp} returns @code{0}.  A return value of
Packit Service 82fcde
@code{-1} indicates an error.  The following @code{errno} error
Packit Service 82fcde
conditions are defined for this function:
Packit Service 82fcde
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item EBADF
Packit Service 82fcde
The @var{filedes} argument is not a valid file descriptor.
Packit Service 82fcde
Packit Service 82fcde
@item EINVAL
Packit Service 82fcde
The @var{pgid} argument is not valid.
Packit Service 82fcde
Packit Service 82fcde
@item ENOSYS
Packit Service 82fcde
The system doesn't support job control.
Packit Service 82fcde
Packit Service 82fcde
@item ENOTTY
Packit Service 82fcde
The @var{filedes} isn't the controlling terminal of the calling process.
Packit Service 82fcde
Packit Service 82fcde
@item EPERM
Packit Service 82fcde
The @var{pgid} isn't a process group in the same session as the calling
Packit Service 82fcde
process.
Packit Service 82fcde
@end table
Packit Service 82fcde
@end deftypefun
Packit Service 82fcde
Packit Service 82fcde
@deftypefun pid_t tcgetsid (int @var{fildes})
Packit Service 82fcde
@standards{Unix98, termios.h}
Packit Service 82fcde
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
Packit Service 82fcde
@c Ioctl call, if available, or tcgetpgrp followed by getsid.
Packit Service 82fcde
This function is used to obtain the process group ID of the session
Packit Service 82fcde
for which the terminal specified by @var{fildes} is the controlling terminal.
Packit Service 82fcde
If the call is successful the group ID is returned.  Otherwise the
Packit Service 82fcde
return value is @code{(pid_t) -1} and the global variable @var{errno}
Packit Service 82fcde
is set to the following value:
Packit Service 82fcde
@table @code
Packit Service 82fcde
@item EBADF
Packit Service 82fcde
The @var{filedes} argument is not a valid file descriptor.
Packit Service 82fcde
Packit Service 82fcde
@item ENOTTY
Packit Service 82fcde
The calling process does not have a controlling terminal, or the file
Packit Service 82fcde
is not the controlling terminal.
Packit Service 82fcde
@end table
Packit Service 82fcde
@end deftypefun