1 Problembeskrivning Uppgiften var att skriva ett program, digenv för att visa miljövariabler. programmet vara ekvivalent med att köra: Kört utan argument så skulle printenv sort pager och kört med argument så skulle det vara ekvivalent med att köra: printenv grep args sort pager där pager väljs som den först tillgängliga av $PAGER less more. 2 Programbeskrivning Programmet är relativt simpelt. Vi skapar pipes, sedan forkar vi de andra programmen (printenv, grep, sort och $PAGER) ett efter ett. Om vi inte får in några argument till programmet så kör vi grep ändå, fast utan argument. Detta ger lite sämre prestanda, men å andra sidan blir programmet mer uniformt. Egentligen borde flagorna till grep kontrolleras, så de inte innehåller -f eller file, eftersom dessa flaggor är korrekta, men förstör pipen. Men eftersom programmet skulle vara ekvivalent med att köra en viss pipe, så har vi inte implementerat den checken. Kdoen finns i appendix. 3 Kompilering och exekvering Programmet kompileras tex med kommandot: gcc -Wall hacked_digenv.c -o digenv Programmet kan köras utan argument, med argument och med miljövariabeln PAGER satt till det man vill. Till exempel:./digenv PAGER=more./digenv./digenv term PAGER=cat./digenv -i term Följande är ett exempel på en körning utan argument. ALTERNATE_EDITOR= COLORFGBG=12;default;8 COLORTERM=rxvt-xpm COLUMNS=134 DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-78isgF0B4Y,guid=1f2122f416aa0f3d7874ec9352d2643a DESKTOP_STARTUP_ID=i3/urxvtc/317-0-joakim-nb_TIME39735 DISPLAY=:0.0 EMACS=24.3.1 (term:0.96) GTK_MODULES=canberra-gtk-module HOME=/home/joakim 1
_=/home/joakim/skola/os/kompl_lab1/./digenv INSIDE_EMACS=24.3.1,term:0.96 JAVA_HOME=/usr/lib/jvm/java-7-openjdk KRB5_CONFIG=/home/joakim/pdckrb/krb5.conf LANG=en_US.UTF-8 LINES=77 LOGNAME=joakim MAIL=/var/mail/joakim MOZ_PLUGIN_PATH=/usr/lib/mozilla/plugins OLDPWD=/home/joakim/skola/os/kompl_lab1 PAGER=cat PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/vendor_perl:/usr/bin/core_perl PWD=/home/joakim/skola/os/kompl_lab1 SERV=85.229.180.20 SHELL=/bin/zsh SHLVL=3 SKOLAN=jjalap@u-shell.csc.kth.se TERMCAP=eterm-color:li#78:co#131:cl=\E[H\E[J:cd=\E[J:bs:am:xn:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:ce=\E[K:ho= TERMINFO=/usr/share/emacs/24.3/etc/ TERM=xterm-256color TEXINPUTS=.:/home/joakim/.emacs.d/elpa/auctex-11.87.2/latex: USER=joakim WINDOWID=16777222 XAUTHORITY=/home/joakim/.Xauthority XDG_RUNTIME_DIR=/run/user/1000 XDG_SEAT=seat0 XDG_SESSION_ID=1 XDG_VTNR=7 Följande är ett exempel på en körning med argument -i term. COLORTERM=rxvt-xpm EMACS=24.3.1 (term:0.96) INSIDE_EMACS=24.3.1,term:0.96 TERMCAP=eterm-color:li#78:co#131:cl=\E[H\E[J:cd=\E[J:bs:am:xn:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:ce=\E[K:ho= TERMINFO=/usr/share/emacs/24.3/etc/ TERM=xterm-256color 4 Verksamhetsberättelse Laborationen tog kanske 10 timmar att genomföra. Den första implementationen blev inte godkänd på grund av att vi skapade en temporär fil, vilket man inte fick. Vi missade delen av labblydelsen där det står att man inte får skapa temporära filer (åtminstone delvis på grund av att den inte existerar). 5 Svar på frågor 1. init 2. Barnprocessen ärver sin förälders miljö, så det går att kommunicera åt ena hållet men inte åt andra. 3. Det går inte att fånga SIGKILL och SIGSTOP. Som det står i mansidorna: the system silently enforces this. 2
4. Därför att det finns en biblioteksfunction som returnerar processens egen pid (getpid(3)) men ingen som returnerar barns pid. 5. Nej. Till exempel så implementeras reference counting i kärnans File Table, så att en fil stängs först när ingen process har den öppen, istället för när den första processen stänger den. Flera entries i olika processers File descriptor tables kan ju peka på samma entry i kärnans File Table. 6. Nej, det kan man inte. Programmet avslutas inte då. 7. Om de tex delar en pipe så kommer den andra processen få en SIGPIPE signal skickad till sig. 8. Exitstatusen är 0 om något hittades, 1 om inget hittades men allt gick bra i övrigt och större än 1 om något gick snett. 1 Kod / NAME: digenv - A program to show envorinment variables SYNTAX: digenv [args] DESCRIPTION digenv without options is equivalent to: printenv sort pager, where pager is either the program by the environment variable PAGER, or if no such variable is set, less(1). digenv args is equivalent to: printenv grep args sort pager, with pager set as above. OPTIONS Any options will be interpreted as options to grep(1), see above. EXAMPLES Without options:./digenv With more(1) as the pager: PAGER=more./digenv With options:./digenv -i term ENVIRONMENT The program indicated by the environment variable PAGER, will be used as the pager in the final step of the pipeline. If PAGER is not set, less(1) will be used. If less(1) failes to execute more(1) wil be tried. SEE ALSO printenv(1), grep(1), sort(1), less(1), more(1) AUTHOR This program was written by Joakim Jalap (jjalap@kth.se) and Daniel Schiess (schiess@kth.se) 3
/ #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h> #include <stdlib.h> int pipes[3][2]; void err(char msg) { perror(msg); exit(exit_failure); void mkpipes(void) { int i; for (i=0; i<3; i++) if (pipe(pipes[i])) err("failed making pipes"); void close_or_die(int fd) { if (close(fd) == -1) err("failed closing a file descriptor"); void close_pipes(int stage) { switch(stage) { case 1: case 2: 4
case 3: err("invalid argument to close_pipes(int)"); void dup_pipes(int stage) { switch(stage) { if (dup2(pipes[0][1], STDOUT_FILENO) == -1) err("failed to dup stdout in printenv"); case 1: if (dup2(pipes[0][0], STDIN_FILENO) == -1) err("failed to dup stdin in grep"); if (dup2(pipes[1][1], STDOUT_FILENO) == -1) err("failed to dup stdout in grep"); case 2: if (dup2(pipes[1][0], STDIN_FILENO) == -1) err("failed to dup stdin in sort"); if (dup2(pipes[2][1], STDOUT_FILENO) == -1) err("failed to dup stdout in sort"); case 3: if (dup2(pipes[2][0], STDIN_FILENO) == -1) err("failed to dup stdin in pager"); err("illegal arguments to dup_pipes(int)"); int main(int argc, char argv) { int pids[4]; int stat; mkpipes(); switch(pids[0] = fork()) { err("failed to fork printenv"); dup_pipes(0); close_pipes(0); execlp("printenv", "printenv", NULL); err("failed to exec printenv"); 5
switch(pids[1] = fork()) { err("failed to fork grep"); dup_pipes(1); close_pipes(1); if (argc == 1) execlp("grep", "grep", "", NULL); else {argv[0] = "grep"; execvp("grep", argv); err("failed to exec grep"); switch(pids[2] = fork()) { err("failed to fork sort"); dup_pipes(2); close_pipes(2); execlp("sort", "sort", NULL); err("failed to exec sort"); switch(pids[3] = fork()) { err("failed to fork pager"); { char pager; dup_pipes(3); close_pipes(3); if ((pager = getenv("pager"))) execlp(pager, pager, NULL); else { execlp("less", "less", NULL); execlp("more", "more", NULL); err("failed to exec pager"); close_pipes(-1); int i; for (i=0; i<4; i++) { 6
if (waitpid(pids[i], &stat, 0) == -1) err("failed to wait"); fprintf(stderr, "Process nr %d exited with status %d, and the result of wexitstatus is %d\n", i, sta if ((i == 1 && WEXITSTATUS(stat) > 1) (i!= 1 && WEXITSTATUS(stat)!= 0)) { fprintf(stderr, "Process %d exited abnormally, killing rest of chain\n", i); int f; for (f=i+1; f<4; f++) { fprintf(stderr, "sending SIGKILL to process %d\n", f); if (kill(pids[f], SIGKILL) == -1) err("couldn t even kill a process, dying"); return EXIT_FAILURE; return EXIT_SUCCESS; 7