1) How many times does the program below print Hello ? #include int main() { fork(); fork(); fork(); printf( "Hello\n" ); } || 8 times ----------------------------------------------------------------------------- 2) Consider the following code fragments, existing separately in different user programs. Provide the simplest correct boolean expression to complete the fragments. a) if( ) printf( "I am not an orphan process\n" ); || if ( getppid() != 1 ) printf( "I am not an orphan process\n" ); b) if( ) printf( "I am not a zombie process\n" ); ----------------------------------------------------------------------------- 3) The command more /etc/passwd produces the line --More--(2%) at the bottom of the first screen, whereas the sequence cat /etc/passwd | more produces --More-- Explain the difference in the output. || In the first case more can check the size of the file using stat(), and hence || knows how far it is throught eh file. In the second case it is reading from stdin, and cannot || determine the size of the file in advance ----------------------------------------------------------------------------- 4) Write a C function int myStrLen( const char *s ) that returns the number of bytes in "s", not including the terminating null character. You are NOT permitted to use any system calls or standard library function calls, which includes any of the "str" string handling functions. ----------------------------------------------------------------------------- 5) Consider this UNIX shell command line: a.out > temp What is the purpose of the symbol ">" ? || It re-directs stdout for a.out into the file "temp". ----------------------------------------------------------------------------- 6) Describe the shell commands necessary to do the following: a) run a program at the lowest priority and in the background || nice -127 & b) list all processes owned by the user || ps -ux c) create a soft link "slink" that points to the file "/u/blah" || ln -s /u/blah slink d) place the currently running foreground job in the background || ^Z || bg ----------------------------------------------------------------------------- 7) Write a C function "cleanup(char *s)" that takes a sentence "s" as input and eliminates extra spaces and tabs between words, makes sure that the first letter is capitalized, and makes sure that there is a period at the end. An example of the input and output is as follows: char sentence[] = " the sky had a \t strange green tint "; cleanup( sentence ); printf( "%s\n", sentence ); produces: The sky had a strange green tint. ----------------------------------------------------------------------------- 8) Write a csh script called "prargs" that prints out a numbered list of its arguments in the following format: $ prargs a 'b c' 0: "prargs" 1: "a" 2: "b c" #!/bin/csh # echo 0: $0 set argNum = 1 foreach word ( $argv ) echo ${argNum}: $word @ argNum = $argNum + 1 end ----------------------------------------------------------------------------- 9) In the current working directory, there is a file called "data". If we display the contents of the file, along with the line numbers, by using "cat -n", here is the output: 1 This is a data file 2 I know my abc's 3 Of course I read the 4 man page for grep Which line(s) of data will the program grep match and display in response to the following commands from the UNIX shell? (example) grep This data Matches: line 1 (a) grep 'a.a' data Matches: _1____________ (b) grep 'a.*a' data Matches: _1_4_________ (c) grep '^...[cn]' data Matches: _2_3_________ ----------------------------------------------------------------------------- Question 10 ---------------------- Write a csh script called "tiny", which lists all regular files in the current directory that are smaller than 100 bytes. ||| set list = `ls` ||| foreach file ( $list ) ||| set size = `wc -c $file` ||| if( (-f $file) && ($size[1] < 100) ) echo $file ||| end Question 1 --------------------- Describe the steps necessary to make the above script executable. ||| 1) chmod u+rx tiny (or just chmod u+x tiny) ||| 2) set 1st line as "#!/usr/bin/csh" Question 12 --------------------- Consider the following program, named "args.c", compiled with "gcc args.c -o args": #include void main( int argc, char *argv[] ) { printf( "%d\n", argc ); } What is the output for each of the following invocations: ||| ./args a b ANSWER: 3 ||| ./args "a b" ANSWER: 2 ||| ./args < /etc/passwd ANSWER: 1 Question 13 ---------------------- Below is an interactive session using the csh shell. For each of the six "Output" lines below, give the output that the previous "echo" command would produce. % set colours = ( red yellow green red ) % echo $colours[3-] ||| Output1: green red % echo $#colours ||| Output2: 4 % echo $?colours ||| Output3: 1 % set colours = ( red yellow green ) % set colours[4] = pink % echo $colours ||| Output4: red yellow green % set colours = ( red yellow green ) % set colours = ( $colours blue ) % echo $colours ||| Output5: red yellow green blue % set colours = ( red yellow green ) % set colours = $colours black % echo $colours ||| Output6: red Question 14 ---------------------- ||| How many times does the program below print "hi" ? ANSWER: 0 ||| How many times does the program below print "bye" ? ANSWER: 4 #include void main( int argc, char *argv[] ) { if( argc == 0 ) { printf( "bye\n" ); exit(); } fork(); fork(); execlp( argv[0], (char *) 0 ); printf( "hi\n" ); } Question 15 --------------------- Write a C function void Expand( FILE *in, FILE *out )that reads data from the file stream "in", replace all occurrences of tabs ('\t') with 8 spaces, and writes the resulting data to the file stream "out". It should continue to read until the end-of-file has been reached. Assume that "in" has already been successfully opened for reading, and "out" has already been successfully opened for writing. ||| void Expand( FILE *in, FILE *out ) ||| { ||| int ch; ||| while( (ch=fgetc( in )) != (int) EOF ) ||| if( ch == '\t' ) ||| fprintf( out, " " ); ||| else ||| fputc( ch, out ); ||| } Question 16 ---------------------- Write a C function int *PackedInts( char *fileName ) that opens the text file "fileName", which contains a single positive integer per line. After each integer is read, it should be appended to an integer array of type "int*" that the PackedInts() function will return. Once you reach the end of the data file, you should append a "-1" to the integer array. Since you don't know in advance how many integers are contained in the data file, you will need to use dynamic memory allocation to create space for the integer array. As a hint, the synopsis for the system call malloc() is: "void *malloc(int size);" and the synopsis for the system call realloc() is: "void *realloc(void *ptr, int size);". Below is a program showing a sample invocation of the PackedInts() function. void main() { int i=0, *vals = PackedInts( "input" ); while( vals[i] != -1 ) printf( "%d\n", vals[i++] ); } ||| int *PackedInts( char *file ) ||| { ||| char line[12]; ||| int cnt = 0, *array = (int*) malloc( 1*sizeof(int) ); ||| FILE *fp = fopen( file, "r" ); ||| assert( fp != (FILE *) NULL ); ||| ||| while( fgets(line,12,fp) != (char *) NULL ) ||| { ||| array[cnt++] = atoi(line); ||| realloc( array, (cnt+1)*sizeof(int) ); ||| } ||| array[cnt] = -1; ||| fclose( fp ); ||| return( array ); ||| } ----------------------------- 1. What is the name of the operating system being discussed in this course? UNIX 2. What is the output of: echo good morning hello goodbye | grep good 2. good morning hello goodbye > Remember that grep processes input line by line and echo normally > outputs everything on one line. [1] 3. Can you run a shell script if you have execute permission but no read permission? Answer yes or no. 3. No. > The UNIX kernel sees a shell script, starts a shell process with the > script as the argument. The shell must then open the file for read > in order to process the script. 4. Can you run a machine-code executable if you have execute permission but no read permission? Answer yes or no. Ans: Yes > Unlike question #3, a binary executable is run directly. Only the > kernel needs to be able to read it and the kernel can do anything. The following is used for questions 5 and 6. You are in a directory and the output of "ls -la" is: total 306 drwxr-xr-x 2 ruhtra devlp 512 Jun 29 23:17 . drwxr-xr-x 41 ruhtra devlp 3584 Jun 29 23:18 .. -rw-r--r-- 1 ruhtra devlp 18 Jun 29 23:18 .foorc -rw-r--r-- 1 ruhtra devlp 135816 Jun 29 23:18 bigfile -rw-r--r-- 1 ruhtra devlp 26 Jun 29 23:18 fubar -rw-r--r-- 1 ruhtra devlp 72 Jun 29 23:18 snafu -rw-r--r-- 1 ruhtra devlp 4 Jun 29 23:18 test 5. Show the output of "echo *" Ans: bigfile fubar snafu test > .foorc is a dotfile and by convention is not expanded by *. 6. /bin/ls is a C program. If you type "ls *", what is the value of argc in main() that ls sees? Show the contents of the argv array. (Remember that argv is declared as "char *argv[]".) Ans: argc equals 5. argv[0] = "ls" argv[1] = "bigfile" argv[2] = "fubar" argv[3] = "snafu" argv[4] = "test" > Other straightforward representations of the array will suffice. 7. How many times does the following program print "Hello"? #include main() { fork(); printf("Hello\n"); fork(); printf("Hello\n"); fork(); printf("Hello\n"); } Ans: 14 > If you don't understand, Compile it and play with it. 8. Give a Bourne shell example that would demonstrate that variable substitution occurs before filename expansion. Ans: FOO="*" echo $FOO > This will echo the same thing as "echo *" thus showing that $FOO > is replaced by * before the * argument is expanded into filenames. > While glancing through the finished tests, I came across a clever > solution which is concise and correct. > echo $HOME/* The following set of commands apply to questions 9, 10 and 11. $ cat /etc/hosts /etc/termcap > foo $ ln -s foo symlink_to_foo $ ln foo hardlink_to_foo 9. How many copies of the contents of file "foo" exist? Ans: one > The hard link and symlink do not create a copy of the contents of > file foo. 10. How many inodes were allocated by running the above commands. Ans: two > One for foo. > One for the symlink which needs a file to hold the location that the > symlink points to. 11. If I remove foo, the file still exists because of the hard link. Can I access it by opening "symlink_to_foo"? Answer yes or no. Ans: No. > The symlink is pointing to "foo" and that file path is gone. 12. Explain why the "cd" command to change the current directory of your shell must be a builtin shell command instead of being a Unix utility program. Ans: Changing directory in a child can't influence the parent process. Therefore, you cannot fork and exec a program to change your directory. 13. State one difference between the standard library and the system call interface to read files. ie Using fopen()/fread() vs. open()/read(). Recall that the C prototypes for fopen and open are: FILE *fopen(const char *filename, const char *type); int open(const char *path, int oflag); Ans: The Standard I/O Library does buffering on top of the system calls. > There are several valid answers here. 14. Explain what "rwho | grep a209abcd" does. Ans: It lists machines on the local network that a209abcd has logged into. > Directly related to the work you did for assignment #2. 15. The Bourne Shell processes redirection arguments from left to right. Explain the difference between the following two shell inputs. cmd >file.out 2>&1 cmd 2>&1 >file.out Ans: cmd >file.out 2>&1 Standard output and standard error are written to file.out from cmd. cmd 2>&1 >file.out Standard error goes standard output *was* going. Standard output goes to file file.out. 16. Given the following program, #include main() { int pid; printf("ORIGINAL: PID=%d PPID=%d\n", getpid(), getppid()); pid = fork; if (pid) printf("PARENT: PID=%d PPID=%d pid=%d\n", get pid(), getppid(), pid); else printf("CHILD: PID=%d PPID=%d pid=%d\n", get pid(), getppid(), pid); } the output will look something like: ORIGINAL: PID=_A_ PPID=_B_ CHILD: PID=_C_ PPID=_D_ pid=_E_ PARENT: PID=_F_ PPID=_G_ pid=_H_ where A to H are numbers. Let A and B be as follows. A = 99 B = 42 Give example numbers for C to H which could occur (ie are consistent with the operation of fork()). C = D = E = F = G = H = Ans: C = 100 D = 99 E = 0 F = 99 G = 42 H = 100 > I warned you in class this makes an excellent test question! > Anyway, the parent and original are the same process. So A=F and > B=G. The pid of the child is almost arbitrary. It can't be zero. > It also can't be 1 because that's the init process. It also can't be > 99 or 42 because they're still live processes presumably and pids > are unique. So I have C=H=100 an arbitrary number consistent with > other information. E must be zero because that's what the return > code for fork() will give to the child. D=A=F=99 because that is the > pid of the parent. 17. Write a C program that opens a pathname given as a command line argument and outputs the file to standard output until End-of-File is reached. You must use the following library calls. FILE *fopen(const char *filename, const char *type); int getc(FILE *stream); int putc(int c, FILE *stream); int fclose(FILE *stream); Ans: > My standard solution. #include int main(int argc, char *argv[]) { FILE *fp; int c; if (argc != 2) exit(1); fp = fopen(argv[1], "r"); if (!fp) exit(1); while( (c=getc(fp)) != EOF) putc(c, stdout); fclose(fp); exit(0); } > This is a bit modified from the one I wrote during the class. > During the test, I decided that you can assume the command is run > with a correct argument and the file exists and is readable. > I don't know if I will be as lenient on the exam. It seems a shame > to leave out an opportunity to decide part marks.