Oppgave 1 - Kommandolinjen (10%)
a) Det skal ikke være dollartegn når en variabel initialiseres og ikke mellomrom før og etter likhetstegnet. Kommandoen må ha backticks eller $()
rundt seg. Riktig kommando er filinfo=$(ls -l fil.txt)
eller filinfo=`ls -l fil.txt`
b) Eier hh
har lese og skriverettigheter. Medlemmene av gruppen staff
har kun leserettigheter, det samme har alle andre brukere.
c) chmod 644 h2.tex
d) en to tre
e) 12345
f) Den gir hvilke metoder og properties fil-objektet fil.txt
har.
Oppgave 2 - Prosesser og scheduling (20%)
a) Hvis prosesser skal kunne kjøre direkte på CPU'en, kan de ikke tvinges til å avbryte for eksempel en evig løkke uten hjelp fra hardware . Timer-interruptet gjør at neste instruksjon er et hopp til kjernekode som gir OS kontrollen slik at det kan vurdere hvilken prosess som skal slippe til neste gang.
b) Ved å variere størrelsen på antall jiffies som tildeles hver prosess(timeslice) vil noen prosesser prioriteres høyere enn andre ved at de får mer CPU-tid.
Tre 100% CPU-avhengige prosesser A, B og C kjører på en Linux-PC med kun én CPU. Ved starten av en epoke er alle tre klare til å kjøre og de er de eneste prosessene i ready-list. Prosess A har en tildelt timeslice på 30 ticks/jiffies, B har 20 og C har 10.
c) Prosess A starter og kjører til alle dens 30 jiffies er brukt opp. Så skjer det en context switch og B starter og kjører til alle sine 20 ticks er brukt opp. Ny context switch og C bruker opp sine 10. Da er epoken over.
d) Det vil være 30+20+10 = 60 timer-interrupts, ett for hvert tick, og to context switches som forklart i forrige delspørsmål.
e) Når epoken er over tildeles nye ticks. Antall tick beregnes ut fra en grunntildeling (som blant annet avhenger av nice-verdi) og en dynamisk del som avhenger av hvor stor del av tildelte ticks som blir brukt opp. Brukes alle opp kan de ble tildelt færre ved neste epoke.
f) En interaktiv prosess vil få mange ticks hver epoke og komme i en høy prioritetsklasse.
Dermed vil den alltid velges før CPU-intensive prosesser etter en context switch. Men om ikke need_resched
ble satt ved et interrupt
fra for eksempel tastaturet, ville den interaktive prosessen som skulle hatt og prosessert dette tegnet måtte vente helt til en
kjørende CPU-intensiv prosess var ferdig med alle sine tick i en epoke, før den slapp til etter en contex switch. At need_resched
settes
gjør at det skjer en context switch med en gang ved neste timer tick og interaktive prosesser får dermed en mye bedre responstid.
g) Det er rimelig å anta at teksteditoren har høyest prioritet av de som ønsker å kjøre. Da vil det maksimalt ta en tick før tegnet vises på skjermen. Om det finnes kjerne-prosesser eller andre prosesser med høyere prioritet, vil disse normalt bruke lite CPU-tid før de avslutter eller selv venter på I/O, da vil tiden det tar kunne bli litt mer enn en jiffy. Tiden det tar vil øke proposjonalt med lengden på en jiffy. Vanligvis vil tegnet vises når neste tick inntreffer, i gjennomsnitt en halv jiffy.
h) Om need_resched
ikke brukes vil etter et trykk på tastaturet den CPU-intensive jobben
bruke opp alle sine tick før det skjer en context og teksteditoren tar over. I snitt vil det derfor ta en halv timeslice = 50 ms.
Hvis need_resched
brukes, vil det i snitt ta en halv tick = 5ms.
Oppgave 3 - Prosesser og CPUer (25%)
sum1.pl
starter først run()
, venter til den er ferdig og starter så en ny run()
. Kjører to run()
sekvensielt.
sum2.pl
gjør først en fork og starter derfor run()
i hver sin uavhengige prosess, slik at de kjøres i parallell.
sum3.pl
gjør først en fork og deretter gjør child en fork. Dermed kjøres run()
i tre uavhengige prosesser, alle kjøres i parallell.
a) sum3.pl kjørt på B. På B bruker en run()
4.9s på én CPU. Darwin fordeler de 3 prosessene jevnt utover de to CPU'ene, alle blir ferdig samtidig. 3x4.9s/2 = 7.35s.
b) sum1.pl kjørt på B. To run()
kjøres etter hverandre; sekvensielt. Siste ferdig etter ca 2x4.9 = 9.8s.
c) sum3.pl kjørt på A. Tre run()
deler den ene CPU'en og kjøres i Round Robin, ferdig etter ca 3x6.2s = 18.6s.
d) sum1.pl kjørt på C. På C bruker run()
ca 4s. To run()
kjøres etter hverandre; sekvensielt. Siste ferdig etter ca 2x4 = 8s.
e) sum2.pl kjørt på A. To run()
kjøres i parallell og deler én CPU. Ferdig samtidig etter ca 2x6.2 = 12.4s.
f) sum2.pl kjørt på B. To run()
kjøres i parallell på hver sin CPU.
g) sum3.pl kjørt på C. Tre run()
kjøres i parallell på hver sin CPU.
h) sum2.pl kjørt på C. To run()
kjøres i parallell på hver sin CPU.
i) sum1.pl kjørt på A. På A bruker run()
ca 6.2s. To run()
kjøres etter hverandre; sekvensielt. Siste ferdig etter ca 2x6.2 = 12.4s.
Oppgave 4 - Scripting og internminne (30%)
a) Kolonnen free
er minne som ikke er i bruk, mens buffers + cached
er minne som kjernen
dynamisk gir tilbake til prosesser som måtte trenge det. Dermed er denne summen totalt tilgjengelig minne
for andre applikasjoner enn de som kjører og bruker det som står i used
, 260MBytes i dette tilfellet.
b)
#! /usr/bin/perl open(FREE,"free |"); <FREE>; <FREE>; $line = <FREE>; @arr = split(/\s+/,$line); #@arr = split(" ",$line); # virker også i dette tilfellet print "$arr[3]"; #$line =~ /\d+\s+(\d+)/; # alternativ #print "$1"; close(FREE); # print `free -m | grep "buffers/cache" | cut -d' ' -f 3`; # Virker ikke pga mellomrom
c)
#! /bin/bash mem1=$(./free.pl) for i in $(seq 1 10) do xcalc& sleep 10 mem2=$(./free.pl) ((mem = ($mem1 - $mem2) )) echo "$mem MBytes er brukt siden scriptet startet" done killall xcalcHvis det er stor forskjell på hvor mye minnet som brukes opp når den første instansen starter i forhold til de tidligere, vil det tyde på at de bruker noe felles applikasjonsminne. I det følgende reele eksempelet ser man at det brukes mer enn 1 MByte når første instans av xcalc startes og deretter ca en halv MByte for hver ny prosess. Det tyder på at prosessene bruker omtrent en halv MByte i felles minne. (I eksempelet gis resultatet i KBytes og ikke i MBytes som spesifisert i oppgaveteksten).
1136 KBytes er brukt siden scriptet startet 1508 KBytes er brukt siden scriptet startet 2128 KBytes er brukt siden scriptet startet 2748 KBytes er brukt siden scriptet startet 3244 KBytes er brukt siden scriptet startet 3740 KBytes er brukt siden scriptet startet 4484 KBytes er brukt siden scriptet startet 4980 KBytes er brukt siden scriptet startet 5604 KBytes er brukt siden scriptet startet 6100 KBytes er brukt siden scriptet startet
d)
foreach ($ps in ps){ $ws += $ps.WS $pm += $ps.PM } "WS: $ws" "PM: $pm"
e) Working set er den delen av sitt minne, det sett av pages, som en prosess har brukt nylig. Total WS er 257 MBytes og det er omtrent to tredjedeler av det totale minnet og dermed ikke et problem. PM er ca 500MBytes som er mer enn det totale minnet. Det er ikke et problem om total PM er større enn internminnet, for dette ligger i swap-området på disk. Men det ville vært et problem om summen av alle prosessers Working Set var større enn totalt minnet, fordi det ville betydd at det var for lite minne til å ha de sidene som brukes mest samtidig i minnet. Som kunne ført til at sider ofte må lastes inn og ut fra disk.
Oppgave 5 - Perl sockets (15%)
a)
#! /usr/bin/perl use IO::Socket::INET; $port = 9999; $socket = IO::Socket::INET->new(LocalPort=>$port,Listen=>5) or die "Can't open socket on port $port\n"; while ($newsocket = $socket->accept()){ $string = <$newsocket>; $string =~ /GET \/(.*?) HTTP/; $command = $1; $res = `$command`; print $newsocket "$res"; close($newsocket); }
b)
while ($newsocket = $socket->accept()){ $string = <$newsocket>; $string =~ s/%20/ /g; $string =~ s/%22/"/g; $string =~ s/%3E/>/g; $string =~ s/%3C/</g; $string =~ s/%27/'/g; $string =~ /GET \/(.*?) HTTP/; $command = $1; $res = `$command`; print $newsocket "Webshell\$ $command\n$res"; close($newsocket); }Ved å bruke echo til å skrive til en fil og så sette kjørerettigheter, kan man skrive et script linje for linje som vist under:
echo "ls" > script.bash echo "whoami" >> script.bash chmod 700 script.bash script.bash
c) Å gjøre det mulig for hvem som helst å kjøre en vilkårlig shell-kommando på
en server fra en browser er en meget stor sikkerhetsrisiko. Det tilsvarer å ikke bruke
brukernavn og passord, alle har tilgang. Det eneste som hjelper litt er at man
ikke bruker portnummer 80, slik at muligheten ikke er så lett å oppdage.
Metoden vist under gjør at man ikke får kjørt kommandoer med mindre man
skriver hemmeligPASS
etterfulgt av kommandoen. Serveren tolker da
hemmelig
som et passord som man må kjenne for å kunne gi kommandoer.
while ($newsocket = $socket->accept()){ $string = <$newsocket>; $string =~ /GET \/(.*?)PASS(.*?) HTTP/; $pass = $1; $command = $2; if($pass eq "hemmelig"){ $res = `$command`; print $newsocket "$res"; } close($newsocket); }