Out: March 30, 2021 Due: Wed Apr 14, 2021

There are 30 marks. Please keep and submit a time log to account for what you’ve done.

CENG251: Assignment #5

Part I: C Language Features (8 marks)

In class we demonstrated re-entrant code by comparing the use of ctime vs ctime_r. We showed that ctime always returned the same memory location and that ctime_r avoided this problem by passing the memory to be filled which was then returned with a different result;

Write a single small C program that

1. Demonstrates that getpwuid and getpwnam are not reentrant by calling each of these twice with different valid arguments and displaying the return address and the content of the passwd structure returned. Prepare your output string using fmemopen and then writing the output to a string using a file pointer before writing the string to the terminal. An example of using fmemopen can be found in the example program stringIODemo.c (3)

2. Continue the program and call getpwuid_r and getpwnam_r with correct arguments. Prepare your output string using sprintf and then display the string to the terminal. Examples of long structured format strings can be seen in the example program stringIODemo.c (3)

3. In ctimeDemo.c we demonstrated the use of strdup to preserve the result of ctime from one function call to the next. Use malloc and memcpy to do the same for getpwuid and show that this worked displaying the values from the copy. (2)

Part II: Signals (8 marks)

The following exercises should be done as a single program. Show that your program works by sending it signals using from the shell.

1. Create a program that reacts to 2 different signals, SIGCHLD and one of the unused realtime signals and then goes into a forever loop. Have each output a unique message. (2)

2. Add a signal handler that responds to SIGUSR1 by listing all the C files in a specified directory using a readdir loop. The directory should be specified using either an environment variable or through the command line. Document which you do. (3)

3. Add a signal handler that responds to SIGURS2 by listing then names of all executable files a specified directory sorted by inode number using a call to scandir. After scandir returns display the list of files along with their inode #s and permissions. (3 marks)

Part III: Multitasking using fork (14 marks)

1. In class we demonstrated 3 different styles of forking a were used. Use a different style for each experiment a-c. Use a separate program for each of a-c.

a. Creating an : (2 marks)

A ’s parent has died is known as an orphan process. Write a short program that creates a single child. Have the main process die right away but leave the child still executing in an infinite loop.

When the main program has completed:

Run the shell command: -u $USER –O ppid What is the process id of this child’s parent? What is the State of the child? Kill the child when you are done.

b. Creating a : (2 marks)

When a child process completes a record is kept in the system’s process table. A zombie process is a child process that has died without it’s code being picked up by the parent. Write a short program that creates a single child. Have the child process die right away but leave the parent running either in a loop or an extended . Do not use a statement to wait for the child.

Run the command: ps -u $USER –O ppid (type in the letters ppid literally, not a id) and examine the column headings:

What is the process id of the child’s parent? What is the State of the child?

c. Reaping a process: (2 marks)

Write a short program that creates a single child. i. The child should output its process id and exit with a non-zero exit code. ie: exit(17)

The parent should wait for the child to complete and report the pid of the child and the reason (status code) that it exited by recovering it from the status variable passed to the wait function call. Use the macro WEXITSTATUS to obtain the status. The wait function itself returns the pid of the child.

2. exec and forking with signals (8 marks)

A key safeguard in forking a process is that the child process must immediately branch away from the parent and never return. One method to ensure this is that the child uses an exec function call, one of execvp, execl, execlp, execle, execve or execvpe - all of which, if successful, launch a new process. (Using strace we can demonstrate that every program launched from the bash shell used execve.) (8 marks)

Write a single program that launches 3 child programs each using a different forking style. At the top of the program use code from sigIgnoreDemo.c to make sure that all realtime signals are initially set to SIG_IGN.

a. The 1st child program should run your getopt or getopt_long program from an earlier assignment. Supply the flags and supplemental non flag arguments using a call to an exec function. This should be done either by passing a null terminate array of arguments or a null terminated list.

By observing the behaviour of your getopt program explain that you were able to prove that your call to exec succeeded in passing different arguments to the child, or why it did not? (2 marks)

b. In the parent process, before any fork, create a completely new set of environment variables and then exec the program showEnvp or your correctly modified version of the program from Assignment #1. You can do this in any of 3 ways: (2 marks)

i. Use execle which takes a null terminated list of environment variable definitions. ii. Use execve or execvpe which takes a null terminated array of environment variable def’ns. iii. Use clearenv to remove all environment variable definitions, then putenv or setenv to define 3 or 4 variables then call either execv, execl or execvp, neither of which directly pass any environment variables but cause the child to inherit the environment of the parent. iv. Write up whether or not it worked.

c. Create an execMyTask function that runs as the 3rd child of your parent process. (4)

i. before launching the child set up signal handler for an unused realtime signal that outputs a unique message. ii. Have the child process set up a signal handler for another unused realtime signal that outputs a different unique message. iii. The child process should announce that it is a child, what its pid and parent id are and then go into an infinite loop.

iv. After the child process is launched let the parent process sleep for a short while to make absolutely sure that the child is established. Then set up a 3rd signal handler for the main program using a 3rd unused realtime signal that prints a 3rd unique message.

v. Have the parent process send all 3 signals to itself using raise to prove that the parent only reacts to its own signals and not the one in the child.

vi. Have the parent process use kill to send a signal 0 to the child to prove that the child is still running. (It should be because it has an infinite loop)

vii. Have the parent process use kill to send all 3 realtime signals to the child to prove that the child inherits the signal handler created before it was launched, recognizes the signal handler created in the child and ignores the one after it was launched.

viii. Have the parent kill the child and reap the child id and the signal # used to kill it.

ix. Send a signal of 0 to the child to prove that the child is no longer running.

Summary: Launch a child process and send the child a bunch of signals to figure out what it inherits, what it knows about and whether its still running.

x. Summarize the results: 1. Did the child inherit signal handlers from the parent? 2. Did the parent inherit signal handler from the child? 3. Can the parent detect if the child is still running, recover the signal used to terminate it and detect when it is no longer running?