Løsningsforslag våren 2008 Unix og Operativsystemer

Oppgave 1 - Bash (10%)

a) chmod 640 fil.txt

b) Gir totalt antall filer, mapper og linker i mappen kommandoen kjøres. Gir lang listing, en infolinje for hver, pipes til wc som teller antallet. Overteller med en pga første linje med output(total ...).

c) ls -l /home | wc -l

d) Lister lang listing av alle prosesser, grep plukker ut alle linjer som ikke starter med root, wc teller antall linjer. Mao: teller antall prosesser som ikke er eid av root.

e) Flytter alle filer i mappen du står i som har fil-endelse .mp3 til mappen min_musikk.

f) Da ville alle mp3-filene slettes, untatt den siste mp3-filen som får navnet min_musikk (først endrer den første mp3-filen navn til min_musikk, så den neste samtidig som den eksisterende overskrives, og så videre til det kun er en igjen).

g) grep -v "#" code.txt > code_no_comments.txt
alternativt
cat code.txt | grep -v \# > code_no_comments.txt

Oppgave 2 - Prosesser (30%)

a) ps aux eller top

b)

c) På et Linux-system er det et antall root-prosesser som alltid skal kjøre og vanligvis er dette antallet forholdsvis konstant. Antall ikke-root prosesser er mer variabelt og endrer seg i større grad avhengig av hvor mange brukere som er innlogget og hva de gjør. Med tanke på å finne ut av unormale hendelser er det derfor fornuftig å overvåke disse gruppene av prosesser hver for seg.

d) CPU-scheduling går ut på at OS fordeler CPU-tid mellom alle prosessene på systemet ved å dele opp tiden i deler eller timeslices og sette alle kjørende prosesser inn i en Round Robin-kø. Prosessene kan prioriteres ulikt ved hvor mye tid de får tildelt for hver runde i RR-køen og når de får kjøre. OS får hjelp av en hardwaretimer som med faste intervaller (typisk 10 millisekunder) sender et interrupt som gir OS tilbake kontrollen.

e) Kommandoen renice kan endre prioriteten til en prosess som kjører. For eksempel vil kommandoen $ renice +19 25567 gi nice-verdi 19 til prosessen med PID lik 25567. Da endres prioriteten på en slik måte at den får hver runde i RR-køen får tildelt mindre CPU-tid. Nice-verdi 19 er den høyeste og gir laveste prioritet, 0 er standard verdi. Root kan gi sine prosesser negativ nice-verdi og dermed høyere prioritet.

f) Semaforer kan brukes til å synkronisere bruken av minneområder. En prosess som ønsker å bruke en bestemt del av minnet, varsler ved hjelp av semaforen at den går inn i kritisk avsnitt der minneområdet blir brukt. Før prosessen varsler at den er ferdig, vil andre prosesser som prøver å gå inn i kritisk avsnitt måtte vente. Semaforer kan implementeres i OS, av programmeringsspråket eller av programmereren selv. En mutex er en enklere løsning som kan brukes til det samme.

g) I første runde i for-løkken vil det når fork() kalles lages en ny prosess og denne skriver også ut "Starter P1". Etter 5 sekunder er begge ferdige og skriver omtrent samtidig ut "P1 ferdig". Begge prosessene utfører fork() i runde to i for-løkken og dermed er det 4 uavhengige prosesser som skriver ut "Starter P2" og 5 sekunder senere skriver alle de 4 prosessene ut "P2 ferdig" omtrent samtidig. Ved å la bare child-prosessen kalle prosess()-funksjonen vil man oppnå det ønskede resultat.

h)

#! /usr/bin/perl
for($i = 1;$i <= 2;$i++)
{
   $pid = fork();
   if($pid == 0)
   {
      # Dermed blir det bare de to child-prosessene
      # som kjører prosess()
      print "Starter P$i\n";
      prosess($i);
      exit; # Viktig for at child ikke skal ta en runde i for-løkken
   }
}
wait; # Ikke vesentlig, men gjør at shellets prompt ikke kommer 
      # før child er ferdig
sub prosess()
{
   sleep 5;
   print "P$_[0] ferdig\n";
}

Oppgave 3 - Munin (30%)

a) Munin er et overvåkningsverktøy som brukes til å lage oversiktlige grafer over alt som foregår på en datamaskin. Spesielt kan Munin lage statistikk over egenskaper som antall prosesser, CPU-bruk, interrupts, context switcher, etc. ved å sammle inn data hvert femte minutt.

b) For hvert graf med Munin-statistikk, ligger det et script i mappen /etc/munin/plugins. Dette er "munin script" som kjøres regelmessig for å samle inn data. Hvis munin-scriptet kjøres med argumentet config, gir det opplysninger om hvordan dataene skal samles inn, tittel på grafen, hva som skal stå på akser og så videre.

c) Hvis scriptet kalles med argumentet config vil det skrive ut de fire linjene med info om hvordan grafen skal se ut og deretter avslutte. Hvis scriptet kjøres uten argumenter, vil det bare avslutte uten å gjøre noe. Det som mangler er kode som genererer mem-data og skriver det ut.

d)

# Settes inn etter fi ...

mem=`getmem | cut -d ' ' -f 3`
echo "getmem.value $mem"
# Alternativt: 
#  echo "getmem.value $(getmem | (read a b c; echo $c))"

# .... og før exit 0

e)

$mem = `getmem`;
$mem =~ /(\d+)/;
print "getmem.value $1\n";
Alternativt:
open(MEM,"getmem|");
($value) = <MEM> =~ /(\d+)MB/;
close(MEM);
print "getmem.value $value\n";

f) Hvis vi definerer de to variablene som getmemR og getmemNR kan config-delen endres slik.

    echo "graph_title Results of getmem";
    echo "graph_vlabel getmem";
    echo "graph_info Sum of memory used by root and non-root processes";
    echo "getmemR.label Root-mem";      # Må være med
    echo "getmemNR.label Non-root mem";# Må være med
For å informere mer i detalj kan man legge til:
    echo "getmemR.info Memory used owned by root";
    echo "getmemNR.info Memory used not owned by root";

g)

echo "getmemR.value `getmem | grep -v not | cut -d ' ' -f 5`"
echo "getmemNR.value `getmem | grep not | cut -d ' ' -f 6`"
Alternativt, om man vil unngå at getmem må kjøres to ganger:
getmem | 
while read a b c d e f
do
   if [ $b = 'not' ]; then
      echo "getmemNR.value $f"
   else
      echo "getmemR.value $e"
   fi
done

h) Man kunne forvente at minnebruk av prosesser som blir eid av root er forholdsvis konstant mens minnebruken for prosesser som ikke blir eid av root kan forventes å øke og minke i takt med at vanlige brukere logger seg inn og jobber. I noen grad vil student-gruppene gjøre ukeoppgaver som root, noe som vil lede til tilsvarende variasjoner for root-minnebruk.

Oppgave 4 - Perl sockets (30%)

#! /usr/bin/perl
use IO::Socket::INET; 
$serverPort = 4949;

# Oppretter et socket-objekt
$socket = IO::Socket::INET->new(LocalPort => $serverPort,
                                Listen    => 5)
        or die "Can't start tcp-server at port $serverPort ($!)\n";
$host = `hostname`;
while ($socketConnection = $socket->accept())        # Venter på tilkobling
{
    # Ny tilkobling
    print $socketConnection "# munin node at $host";
    while($received = <$socketConnection>)
    {
         chomp($received);
         last if $received =~ /^quit/;
         @arr = split(" ",$received);
         $com = $arr[0];
         $plugin = $arr[1];

         if($com eq "fetch")
         {
             $res = `/etc/munin/plugins/$plugin`;
             print $socketConnection "$res.\n";
         }
         elsif($com eq "config")
         {
             $res = `/etc/munin/plugins/$plugin config`;
             print $socketConnection "$res.\n";
         }
         elsif($com eq "list")
         {
             $res = `/bin/ls /etc/munin/plugins`;
             print $socketConnection $res;
         }
         else
         {
             print $socketConnection "# Unknown command. Try list, config, fetch or quit\n";
         }
    }
    close($socketConnection); # Kobler ned forbindelsen for å vente på en ny
}



haugerud 2008-07-01