\chapter{Procesbeheer}
\label{process}

In dit hoofdstuk zullen we leren hoe processen zowel interactief als
niet interactief te besturen. Het is zeer belangrijk de besturing over
je systeem te onderhouden en lastige processen te beheren.

\section{Voorgrond- en achtergrondprocessen aanmaken}

\term{Procesbeheer} refereert naar de mogelijkheid processen zowel
in de \term{voorgrond} als \term{achtergrond} van de shell te besturen.
Een \term{voorgrond} proces is een proces dat interactief in je shell
draait, en dit zijn de meeste processen die we tot dusverre hebben
besproken. Je kunt een \term{voorgrond} proces onderbreken met behulp
van de toetsencombinatie \program{Ctrl-Z} 
(uitgesproken als ``control z'', druk de \lt{}Ctrl\gt\ en \term{z} toets
tegelijkertijd in). Om dat proces nu weer terug in de \term{voorgrond}
te plaatsen, gebruik je de (bash) opdracht \program{fg}. 

Als contrast is een \term{achtergrond} proces een proces waarbij geen
directe interactie met je shell is. Het blijft op zichzelf en draait in stilte.
Om in plaats daarvan een proces in de achtergrond te plaatsen gebruik je
de interne opdracht \program{bg}. 
Vanuit de shell gezien, hebben alle processen een
\term{job} nummer. Vanuit het systeem gezien, hebben alle
processen een \term{proces ID}, vaak een \term{PID} genoemd (zie de
opdracht \program{ps}).

Om echt een van deze processen af te vangen, moeten we naar een opdracht
op zoek gaan welke langer duurt dan even (zoals \program{date}).
Laten we met de opdracht \program{xterm} werken waarmee een X-terminal
venster wordt gecreeerd:

\begin{alltt}
\bash{xterm}            # Start een nieuwe \program{xterm}
\unshell{Ctrl-Z}        # Je drukte \term{Ctrl-Z} in en stelde het uit!
\unshell{[1]+ Stopped   xterm}

\bash{fg}                # Herstartte het met \program{fg}
\unshell{xterm}
\unshell{Ctrl-Z}         # Je stelde het weer uit.. goed..
\unshell{[1]+ Stopped   xterm}

\bash{jobs}              # Zoek naar het nummer van de job.
\unshell{[3]+ Stopped  xterm}
\bash{}

\bash{bg \%3}            # Plaats xterm in de achtergrond.
\unshell{[3]    xterm &}
\bash{}
\end{alltt}

Als het goed is heb je nu een \program{xterm} die normaal functioneert.
De laatst getoonde [3] geeft aan dat dit \term{Job Number} 3 is.
Je kunt dat nummer gebruiken om ernaar te refereren met behulp van
\program{fg} als in

\begin{alltt}
\bash{fg \%3}               # plaats het op de voorgrond met \\program{fg}
\unshell{Ctrl-Z}            # Stel de uitvoering ervan weer uit.
\unshell{[3]+ Stopped  xterm}

\bash{bg \%3}                # Plaats het met \\program{bg} in de achtergrond
[3]    xterm &
\bash{jobs}
[1]    Running                       xterm -cr red -ms >&
[2]    Running                       xclock
[3]    Running                       xterm
\bash{kill -9 %3}
\bash{jobs}
[1]    Running                       xterm -cr red -ms >&
[2]    Running                       xclock
[3]-   Terminated                    xterm
\end{alltt}

Het programma \program{jobs} toont alle jobs en het bijbehorende nummer
en de status. De opdracht \program{kill -9 \%N} verwijdert jobnummer $N$. 
De vlag (-9) is nodig om een ``echte kill'' te forceren, wat soms nodig is.
Het ampersand symbool (\&) is wat je zou gebruiken om een opdracht direct
in de achtergrond te plaatsen, zoals in \program{xterm \&}.

Wees voorzichtig, want een aantal opdrachten willen fouten wegschrijven naar
standaarduitvoer \term{stdout} en dat zou vreemde resultaten op je scherm
op kunnen leveren. Om dit te voorkomen, kun je \term{stdout} omleiden naar
\file{/dev/null} (of een logbestand) EN het in een keer in de achtergrond
kunnen plaatsen:

\begin{alltt}
\bash{xterm \gt\& /dev/null \&}
of
\bash{xterm \gt\& /tmp/xterm-log \&}
\end{alltt}

Dit is aan te raden als je van plan bent de opdrachten in een script te
plaatsen, omdat de \term{stdout} die nergens heen kan, je script kan stoppen.
Ervaring heeft aangetoond van te voren altijd gebruik te maken van 
/dev/null.
 
\section{Processen met \program{\Large kill} verwijderen}
Nu zullen we procesnummers met de opdracht \program{ps} laten zien.

\normalsize
\begin{Verbatim}[fontfamily=tt,frame=single,commandchars=\\\{\}]
\bash{ps}
  PID TTY          TIME CMD
  683 ttyp1    00:00:00 bash
31666 ttyp1    00:00:00 xterm
32716 ttyp1    00:00:00 xclock
  698 ttyp1    00:00:00 ps
\bash{ps -agl}                # Haal een uitgebreide lijst op met \program{ps}
  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  STAT TTY        TIME COMMAND
000   501   683   672  13   0  2220  804 rt_sig S    ttyp1      0:01 [bash]
000   501 31666   683   0   0  3012 1900 wait4  S    ttyp1      0:00 xterm -cr r
000   501 32716   683   0   0  2572 1304 do_sel S    ttyp1      0:00 xclock
000   501   464   683   0   0  8540 5936 do_sel S    ttyp1      0:03 /home/carin

\bash{top}
42 processes: 40 sleeping, 2 running, 0 zombie, 0 stopped
CPU states:  2.3% user,  0.7% system,  0.0% nice, 96.8% idle
Mem:   63484K av,  52328K used,  11156K free,  18020K shrd,   2896K buff
Swap: 220316K av,   4964K used, 215352K free                 28804K cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT  LIB %CPU %MEM   TIME COMMAND
  664 root      18   0 14824  14M  1540 R       0  1.1 22.7  18:21 X
31797 carinhas   9   0  7060 7060  3276 S       0  0.0 11.1   0:16 xemacs
  464 carinhas   0   0  6020 6020  3596 S       0  0.0  9.4   0:03 netscapex
31666 carinhas   0   0  1900 1900  1440 S       0  0.0  2.9   0:00 xterm
32716 carinhas   0   0  1304 1304  1096 S       0  0.0  2.0   0:00 xclock
  587 carinhas   0   0  1104 1104   728 S       0  0.0  1.7   0:00 bash
... <Shift-M> Sorted by memory usage....
Ctrl-C <quit>
\end{Verbatim}
\large

Ik heb nu een afvallig proces met de naam \program{xclock} opgezocht wat volgens
het \program{top} utility veel te veel geheugen verbruikt. Je wilt dit
proces verwijderen door het uitvoeren van

\begin{alltt}
\bash{kill -9 32716}
\bash{}
[3]    Terminated                    xclock
\end{alltt}

Bestudeer voor de LPI-examens ook de man pages van \program{pstree} en 
\term{proc}.

Hierna komt een verkorte manual page van \program{kill}, maar denk erom dat
de meeste shells een eigen ingebouwde versie hebben van \program{kill}. 

\newpage
\normalsize
\begin{alltt}
\hrulefill
KILL(1)             Linux Programmer's Manual             KILL(1)
NAME
       kill - terminate a process
SYNOPSIS
       \command{kill}\option{ [ -s signal ] \%job \pipe{} pid ...}
       \command{kill} \option{ -l [ signal ]}
OPTIONS
       pid .. Specify the list of processes.
       -s     Specify  the  signal name or number to  send.
       -l     Print a list of signal names. See \term{signal(7)} 
\hrulefill
\end{alltt}
\vspace{-10truept}

\large
Hier is de relevante en verkorte man sectie van signal(7):

\normalsize
\vspace{-19truept}
\begin{alltt}
\hrulefill
SIGNAL(7)           Linux Programmer's Manual           SIGNAL(7)
NAME       signal - list of available signals

      Signal       Value     Action   Comment
       ----------------------------------------------------------
       SIGHUP        1        A      Hangup detected on controlling terminal
       SIGINT        2        A      Interrupt from keyboard
       SIGQUIT       3        A      Quit from keyboard
       SIGILL        4        A      Illegal Instruction
       SIGABRT       6        C      Abort signal from abort(3)
       SIGFPE        8        C      Floating point exception
       SIGKILL       9       AEF     Kill signal
       SIGSEGV      11        C      Invalid memory reference
       SIGPIPE      13        A      Broken pipe: write to pipe with no readers
       SIGALRM      14        A      Timer signal from alarm(2)
       SIGTERM      15        A      Termination signal
       SIGUSR1   30,10,16     A      User-defined signal 1
       SIGUSR2   31,12,17     A      User-defined signal 2
       SIGCHLD   20,17,18     B      Child stopped or terminated
       SIGCONT   19,18,25            Continue if stopped
       SIGSTOP   17,19,23    DEF     Stop process
       SIGTSTP   18,20,24     D      Stop typed at tty
       SIGTTIN   21,21,26     D      tty input for background process
       SIGTTOU   22,22,27     D      tty output for background process

       The letters in the "Action" column have the following meanings:

       A      Default  action is to terminate the process.
       B      Default action is to ignore the signal.
       C      Default action is to dump core.
       D      Default action is to stop the process.
       E      Signal cannot be caught.
       F      Signal cannot be ignored.
       G      Not a POSIX.1 conformant signal.
\hrulefill
\end{alltt}
\large

\newpage
\section{Beheren van procesprioriteiten}
Onder Linux en Unix hebben alle processen een belangrijke factor genaamd
de \term{prioriteit}. De \term{prioriteit} vertelt de systeem \term{kernel}
hoe vaak service te verlenen aan dat proces. Uiteraard zijn een aantal 
processen veel kritischer voor het systeem dan anderen.
Toegang tot de hardware is veel belangrijker dan email. Hoe kleiner de waarde
van de prioriteit hoe meer belang aan het proces is gegeven.
Prioriteitswaarden vari\"eren van -20 tot 20, waar -20 
de hoogste prioriteit is en 20 de laagste.

Je kunt de prioriteit van je processen zien door het lezen van de kolom
\term{PRI} in de opdracht \program{ps -xl}:

{\normalsize
\begin{alltt}
\bash{ps -xl}

  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  STAT TTY        TIME COMMAND
000   501   617   612   0   0  2032  504 do_sel S    ?          0:03 fvwm
000   501   622   617   0   0  3144  872 do_sel S    ?          0:01 xterm -cr r
....etc....
\end{alltt}
}

Er zijn twee belangrijke tools voor het manipuleren van procesprioriteiten,
\program{nice} en \program{renice}. \program{nice} laat je de prioriteit
voor een opdracht aanvankelijk opgeven, en \program{renice} geeft je de
mogelijkheid de prioriteit te wijzigen nadat het proces is gestart. 
Hier is een oefening voor je:

{\normalsize
\begin{alltt}
\bash{man nice}
----------------------------------------------------------------
NICE(1)                                                   NICE(1)
       nice - run a program with modified scheduling priority
SYNOPSIS
       \command{nice} \option{ -n priority command [arguments]}
----------------------------------------------------------------
\end{alltt}
}

\subsection{Oefeningen}

{\normalsize
\begin{alltt}
\bash{xclock -rv}
\bash{nice -10 xclock -rv}
\bash{/bin/nice -n 10 xclock -rv}         # Hetzelfde als boven
\bash{ps -xl}

  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  STAT TTY        TIME COMMAND
000   501   617   612   0   0  2032  504 do_sel S    ?          0:03 fvwm
000   501   622   617   0   0  3144  872 do_sel S    ?          0:01 xterm -cr r
000   501  2855  1321   8   4  2568 1300 do_sel SN   ttyp2      0:00 xclock

\bash{renice 20 2855}                     # Renice de xclock job, ok?
\unshell{2855: old priority 4, new priority 20}# Don't worry if numbers don't jive.

\bash{renice  5 2855}                          # renice naar LOWER # ?
{\bf renice: 2855: setpriority: Permission denied} # Kan niet, alleen HOGER # is
toegestaan.

\bash{ps -xl}

  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  STAT TTY        TIME COMMAND
000   501   617   612   0   0  2032  504 do_sel S    ?          0:03 fvwm
000   501   622   617   0   0  3144  872 do_sel S    ?          0:01 xterm -cr r
000   501  2937  1321  19  19  2568 1300 do_sel SN   ttyp2      0:00 xclock
\end{alltt}
}

Je kunt renice alleen met een hoger nummer gebruiken (dus lagere prioriteit)
daarom geeft het systeem een foutmelding. 
Ook duurt het even eer de weergegeven \term{PRI} zich heeft aangepast tot
de \term{NI} (\program{nice}) waarde. 

\vspace{10pt}
{\normalsize
\begin{alltt}
{\large LINUX WAARSCHUWING! 
\program{tcsh} definieert een EIGEN ingebouwde versie van nice:}
\hrulefill
TCSH(1)                                                   TCSH(1)
   Builtin commands
       \command{nice} \option{ [+priority] [command]}
\hrulefill
\end{alltt}
}

\newpage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Cron}
\label{crontab}
\term{Cron} is een \term{daemon} waarmee taken 
kunnen worden geautomatiseerd door ze op basis van een tijdschema
periodiek uit te voeren. Het is erg handig voor beheertaken.
\term{Cron} neemt een bestandsnaam als een script voor de invoer
die het intern indeelt en periodiek controleert.
Het bestand wordt een \term{crontab} bestand genoemd.

\subsection{Een Crontab bestand aanmaken}
Het \term{crontab} bestand is standaard een \term{bash} script. Het heeft
extra parameters die \term{cron} vertellen wanneer de uitvoering moet
beginnen. Hier is het formaat:


\begin{figure}[h]
 \begin{alltt}
\Large
\begin{center}
mm  hh  dd  MM  D  COMMAND
\end{center}
\end{alltt}
\begin{center}
\vskip-40truept
{
\normalsize
\hspace{-20pt}
\rotate{320}{\large--minute}\endrotate 
\hspace{28truept}
\rotate{320}{\large--hour}\endrotate 
\hspace{28truept}
\rotate{320}{\large--day}\endrotate 
\hspace{25truept}
\rotate{320}{\large--Month}\endrotate 
\hspace{23truept}
\rotate{320}{\large--Weekday}\endrotate 
\hspace{40truept}
\rotate{320}{\large--Executable}\endrotate 
\vspace{30truept}
} 
\end{center}
\caption{\large Crontab File Specification Format}
\end{figure}

Sterretjes (*) zijn jokertekens die met alles overeenkomen, en
op de andere parameters afgaan om \term{cron} timing queues te geven.
Als je de taak elke dag uit wilt laten voeren, plaats je gewoon
een * in de kolom `day'.

Een simpel voorbeeld hiervan zou zijn ons bovenstaande script elke
nacht om 12 uur middernacht uit te laten voeren:

\begin{alltt}
# File: crontab-file. Start me ELKE DAG om 00.00 uur op!
  0 0 * * * /home/\user/bin/backup >& /home/\user/backup-log & 
\end{alltt}

Merk op dat we \stdout zorgvuldig om hebben geleid naar een logbestand,
anders zou \term{cron} de taak kunnen laten hangen, of ons alle foutmeldingen
per mail toe kunnen zenden.

Een ander interessante eigenschap van de \term{cron} time spec is de 
mogelijkheid een nummer op te geven op een \term{modulus} manier. 
Deel een * door een nummer om cron periodiek een opdracht uit te laten
voeren:

\begin{alltt}
# File: crontab-file. Voer elke vier uur een backup uit.
  * */4 * * * /home/\user/bin/backup >> /home/\user/backup-log 2>&1 
\end{alltt}


\subsection{Aanleveren van Cron Jobs}
Zodra we een \term{crontab} bestand hebben geschreven, kunnen we het
aanleveren met de opdracht \program{crontab \file{crontab-bestand}}. 
\program{crontab -l} geeft een opsomming van de huidige crontab records.


\begin{alltt}
\bash{crontab crontab-file}
\bash{crontab -l}
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (crontabs installed on Mon Feb  7 00:13:36 2000)
# (Cron version -- $Id: process.tex,v 1.1.1.1 2004/03/21 21:02:25 cor Exp $)
# Execute the job every four hours.
# /home/\user/crontab-file
  * * * * * /home/\user/bin/backup >> /home/\user/backup-log 2>&1 
\end{alltt}

\subsection{Cron taken verwijderen}
Met behulp van de (-r) vlaggen kun je de \program{cron} taken verwijderen:

\begin{alltt}
\bash{crontab -r}
\bash{crontab -l}
\end{alltt}

\subsection{Oefeningen}

\subsubsection{Oefening 1:}

Maak een simpel script met de naam \file{hello} dat ``hallo \user'' afdrukt''.
Er hoeven slechts twee regels in te staan:

\begin{alltt}
#!/bin/bash
echo Hallo \user jij slacker...
\end{alltt}

Dit bestand zou worden geplaatst in je persoonlijke \file{\tilde/bin} directory,
en hiervoor zouden de juiste bestandsmodi voor uitvoering moeten zijn
ingesteld (hint: chmod). Zorg dat je dit script met de hand test voordat
je verdergaat.

\subsubsection{Oefening 2:}

Maak nu een crontab bestand aan met de naam \file{crontab-file} dat elke
2 minuten \file{hallo} uit zal voeren. Lever dit crontab bestand zoals
hierboven besproken aan en controleer elke even minuut om te zien of de
scripts werken.

Noot: Cron's standaardfunctioneren is alle onbehandelde uitvoer via mail
naar je toe te sturen. Als mail om wat voor reden dan ook niet werkt, kun
je de uitvoer naar een bestand of naar het scherm laten sturen.
