Sie sind auf Seite 1von 7

Lab 1: Process Management

Computer Systems DV1


Autumn 2003

Lab Assistant

John Håkansson
www.docs.uu.se/˜johnh
email: johnh@docs.uu.se
room: 1442
postbox: 136 (4th floor, building 1)
phone: 018 - 471 6225

The lab package is located in /stud/docs/kurs/os and is called OSLab.lab1.SunOS.tgz. Un-


pack it in an appropriate directory by tar zxf OSLab.lab1.SunOS.tgz. Begin with this.
There is a FAQ (frequently asked question) at the end of this assignment, have a look at it.

1 Getting Started

1.1 ps(1)

In this part of the assignment you will learn how to use the ps command to see what processes
are running. Start by reading the manual page for ps(1), (do: man -s 1 ps in your shell) 1 .
Use the ps command to see what processes are running on your machine. Try using different
options to see what they do. In particular, run ps with:

• no options • -l

• -e • -u

Q1 What does ps do with no option and with these options?


Q2 Explain what happens when you use -el?
Try top and get familiar with pstree2.
Q3 Explain what the -s flag, that you gave to man command above, actually does.
Q4 Which section of the manual holds documentation for the UNIX system calls?
Q5 And shortly, what is the difference between wait(1) and wait(2)?
A useful command when looking for manual pages is apropos. It looks at the indexes of the
manual pages and sorts out the occurences of what you are looking for. Try apropos wait.
There is also a graphical tool for displaying manual pages called xman. Write xman & in your shell
1 man 1 ps on Linux
2 pstree is in the lab package, run it with ./pstree
and familiarise yourself with it. It may not work depending on your system setup, in this case
check your PATH environment variable that should include /usr/sup/X11/bin. In the worst case
use /usr/sup/X11/bin/xman with full path.

1.2 fork(2) and wait(2)

In this part you will learn how processes are created, and how to avoid defunct processes. Begin
with reading the manual pages for fork(2) and wait(2).
P1 Write a simple program that uses the fork(2) system call. Start with simplefork.c and
complete it. Do not forget to wait for the spawned child : use the wait(2), in order to avoid
defunct processes.

Compile: type make and all your programs will be compiled.


This is the standard way to use fork(2) to create a single child process:

/* parent creates a process */


pid=fork();

/* the return value is a process ID, and


* has the following meaning (always test these): */
switch (pid) {
case -1:
/* error: fork was unsuccessful */
case 0:
/* this is the child process */
/* no process ID */
/* ... do something ... */
default:
/* this is the parent process */
/* pid=process ID of the child */
/* ... */
}

/* both processes continue here */

Note that both processes will run the code that follows the switch statement. Normally this is
undesirable, and by forcing the child to terminate after it has done its “useful work”, we can
prevent it. Pay attention to the switch command, you may want to use exit or break. The code
shown above can be modified as follows:

case 0:
/* this is the child process */
/* ... */
exit(0);

You see some printouts in the program (simplefork.c),


Q6 what do pid,ppid and pgid stand for?
You may look at the manual pages of getpid(2),getppid(2) and getpgrp(2). The function
sleep(3C) is used to delay the processes.
2 Process Management
This assignment will demonstrate to you a more advanced use of fork(2) and wait(2) through
a client-server program. The files you have to look at are server.c and netstuff.h.

• Begin with compiling the server (normally already done, with make that you used for the
previous exercise). Try xterm -e ./client & and xterm -e ./server & 3 to get a feeling
of what the programs do.
• Start several clients and observe the problem : the server can handle only one client at a
time. The other ones have to wait.

The client is used as follows : it waits for a string, so you enter one at the prompt, and it sends it
to the server which does some useful job, in this case it returns the reversed string. The client has
an auto mode, to activate it enter auto at the prompt. To stop the client press Ctrl-D or Ctrl-C.
Now you have a feeling of your task : make the server handle several clients at the same time. To
achieve this, you will have to use fork(2). You will proceed in two steps :

1. add a fork()
2. handle the generated zombies

2.1 Accepting Several Clients

The server works as follows :

1. initServer() which initializes network stuff, you are not supposed to look at this, and you
do not have the sources either.
2. for(;;) infinite loop where the server
(a) listens to the network and accept a new connection with acceptConnection() which
returns 0 in case of success.
(b) handle the connection with connectionJob(pid)

You see in the code closeAccept(pid) which is to close the accepted connection, got from
acceptConnection(). The problem is : when the server is in connectionJob(pid) it does
not listen to the network. The function connectionJob returns only when the connection is
closed. And that’s the reason why clients have to wait.
P2 Copy server.c to server1.c 4 and modify server1.c so that it can accept several connections
at the same time. The main process will do acceptConnection, fork, closeAccept while the
spawned children will do connectionJob, exit. Do not care (yet) to the function childHandler.
Figure 1 illustrates the programs.
Note : you must get rid of error messages if you get any during execution.
Q7 How are multiple connections handled now?
Open and close some connection and use ps(1) with the right options to visualize zombies. They
are marked <defunct>.
Q8 How do the zombies appear and why can’t you kill them by using kill or kill -9?
3 the & is used to start the programs in the background.
4 cp server.c server1.c
client requests client requests

listens listens
acceptConnection acceptConnection

handle the connection fork handle the connection


connectionJob fork connectionJob

close the connection close the connection terminate


closeAccept closeAccept exit

server.c server1.c

Figure 1: Structure of server.c(given) and server1.c(your task)


.

2.2 Getting Rid Of The Zombies - 1

Normally one would use signals to take care of the zombies: when a child exits, the main process
is interrupted, calls the wait(2) function and returns to its job. To try this (not compulsory, this
is for your culture), activate the code in server.c by replacing #define PART 1 by #define PART
2. The zombies will disappear. Notice the call to the function sigaction(2) that installs our
signal handler. However in the lab we are supposed to study the fork function, so we will skip this
solution and use another, heavier, not so clean, but very nice for lab purposes.

2.3 Getting Rid Of The Zombies - 2

When you use pstree, you notice that the first process at the root is init and has process ID 1.
This is the first process created when your machine is booted. As you see this process has many
children. Do you think that this process has created all these children? Think about it . . . .
Here is the secret : the init process adopts orphan processes. When the parent of a process dies,
it is impossible that it will wait for its children, isn’t it? And you have children processes that
may terminate . . . which is not good. So init adopts these children, which is it takes them in the
process hierarchy (that you get with pstree) as its descendant. This is why init has so many
process children. So you are going to use this!
To make the process handling a connection be adopted by init, you have to let its parent process
die, but of course it can’t be the main process! The solution is to use two consecutive forks, the
second one handles the connection, the first one exits to let the second child be adopted by init.
P3 Copy server1.c to server2.c and implement the solution. Be careful not to have zombies
left. Check this with ps or pstree.
Now you have a question which is : why all this pain about zombies if init solves the problem
eventually? The answer is : your server process is going to run a long time, and if you have
zombies, it will be unable to fork after a while, and your server is “dead”.

3 Process Communication
In this part of the assignment you will learn how processes can communicate with each other. You
will write a program that consists of two processes that communicate through a pipe to solve a
problem.
Pipes

A pipe is a mechanism provided by the operating system that lets one process send a stream of
bytes to another one. Since a child process inherits all open descriptors from the parent when it is
created, we can create a pipe (which is a pair of connected descriptors) before creating the child
process, thus allowing both processes access to the same pipe.

0 1 0 1 0 1 0 1

Pipe Pipe Pipe

0 1 0 1

(i) (ii) (iii) (iv)

Figure 2: (i) Before the call to pipe(). (ii) After the call to pipe(). (iii) After the call to fork().
(iv) After each of the processes closes one of the descriptors.

In figure 2, we see how an empty array of 2 descriptors is passed to pipe(2), and a pipe object
is created to connect them. After the call to fork(2), both parent and child processes share the
same pipe object through their own copies of the descriptors. Both processes can now write to
and read from the pipe. After one of the processes closes the write descriptor and the other closes
the read descriptor, the two processes share a one-way communication channel.

Problem description

The problem you will solve is this: while working for Intrusions AB (security consultants) you
have come across a file containing userids and passwords for the employees at Victims-R-Us. You
need to show the management of Victims-R-Us that their system is insecure, by cracking all the
passwords in the file. Write a program to do so.
Since the users at Victims-R-Us are very naive, they have all chosen ordinary English words for
passwords. In the course directory, /stud/docs/kurs/os you will find a pair of of files containing
English words, process mgmt/words1 and process mgmt/words2. You should not copy the files
to your local directory, instead, give the whole path as argument, (like /stud/docs/kurs/os/pro-
cess mgmt/words1) or see section 4 on how to make soft links to files.

Assignment

Begin by reading the manual pages for pipe(2), read(2), write(2) and close(2).
The model your program should use is as follows:

• A main program that sets up communication, then starts two other processes to do the
actual work. The first argument to the program should be the name of a file containing
words to try.
The main program should use the pipe(2) system call to create a pipe. Then it should start
two child processes (a producer and a consumer) and wait for both of them to finish.
• A producer that “generates” passwords to try, one at a time. An argument to the producer
indicates the name of a word file. The producer should open this file, send the words one at a
time through the pipe to the consumer until the end of the file is reached or the consumer is
finished, then close the file and exit. The producer shall use non-buffered I/O, (ie. write(2),
to send words to the consumer.
The producer shall count the words it reads from the file, and print the total number od
read words just before exiting. If you have doubts on how the code works, have a look at
the manual pages for fopen(3S), fgets(3S) and scanf(3S).
• A consumer that gets words from the producer and tests each of them on all the uncracked
accounts.
The consumer should read one word at a time from the pipe, (using read(2)), and test
it, until there are no more words to read, or until all the accounts have been successfully
cracked.
The consumer shall, just before it exits, print the number of words it read from the pipe and
the number of remaining (uncracked) accounts.

You have the most part of this program in crack.c. You just have to complete the main
function.
P4 Complete the main function of crack.c to make the program work as described. Note that
the skeleton handles errors and looks at the exit status of the processes, so be strict with error
handling and do not return 0 in case of error, also no exit(0) but exit(1) in case of an error.
Furthermore, you will have to use kill(2) to kill the first process if you cannot create the second
one. Be careful with the pipe : do not forget to close it where appropriate. You may want to
test your program on words3, which is faster than words1 words2 for debugging.
Either the producer or the consumer will finish first, depending on what words are in the file and
what passwords the employees have chosen. Your code deals with this situation in a reasonable
manner, and without the use of special messages though the pipe.
Q9 Explain how the pipe behaves. Your answer should cover the different cases when the pipe is
closed by one/all processe(s) at one/both ends, and what happens in these cases. You can make
an analogy to the files to explain the result when reading a closed pipe.

4 Miscellanous
• Read the manual pages for pipe(2), read(2) and write(2).
• The function strlen(3C) returns the number of bytes in a string, (without including the
terminating null character, ’\0’). It is used in the cracker program.
• Always check return values. Most system calls return a value to indicate if they were suc-
cessful, and if not, the reason for failure. They do fail sometimes! In these cases you should
use perror(3) to print a message describing the failure.
• perror(3C) is a special message function that understands the error values returned by most
system calls. Use it! But note also that perror(3C) is not a general purpose function, it
will only indicate the status of system calls, not C library functions and other functions. Use
fprintf(stderr,...) when these fail.
• Leave no zombies. If you create a process, you need to wait for it too (with wait(2)). All
processes should exit properly, and the main process must clean up after them. This means
that the main process must keep track of how many processes have been successfully started,
and never exit without waiting for each of them.
• Compile with: make. The given Makefile contains appropriate rules and options for com-
pilation. Warnings are signs of deficiencies in the code and are treated as errors!

4.1 FAQ

How to print? Use a2ps -Ppr1411 yourfile.c.

I got segmentation fault, what is that? Your program tried to read/write in forbidden
memory zones. It is typical from a pointer not initialized.

Bus error Fatal error, typically you tried wait(2) in your program and you did not notice that
wait(2) meant look at wait in the section 2 of the man pages.
What does kill do? It sends a signal to a process, to terminate it generally (depends on the
options), it is similar to clicking to the close button of a window. kill -9 is a nasty signal which
cannot be ignored and that always kills a running or sleeping process, i.e. not a zombie. See the
manual pages on kill for complete information.

Why compilation uses -Wall -Werror? To warn on all possible errors and treat them as
errors. . . to force you to have some discipline with C because it is a rather permissive language.

What is make? It is an utility widely used in programming: it takes a file (Makefile most
often) in a special format, which contains dependency rules, then it calls the proper programs to
build the targets. The result is that you type make and depending on your last modifications,
the right programs are rebuilt. It is very convenient to use it, that’s why a Makefile is provided
in the lab. You may have a look at it if you are curious. Have a look at the manual and
www.csd.uu.se/documentation/programming/make for more information.

Binding error? Address in use error? Are there client/server options? When you
start the server on a machine it needs a “port” to listen to. It takes by default 5000. If another
server is already running, it cannot take it, and you may have an error. It is possible to bypass
this by giving another port. Of course, if you do this, the client has to know it. The client may
take as an argument, the name of a machine (useful if you run the server on a different machine)
or a port number. The client may take both argument in the order server name port number.

How do these programs communicate? The programs use sockets to communicate over the
network by using the TCP/IP stack. Go to the computer network course to know more, it is very
interesting.

Command not found? You are trying pstree (for example) and you expect it work, but you
get an error. Check that you are in the right directory (pwd) and try ./pstree. The error comes
from the fact that “.” (your current directory is not in your path: echo $PATH to check this).

Das könnte Ihnen auch gefallen