Teaching:
Feedback
To create or open a file, POSIX defines:
Needs header:fcntl.h
int open(const char *pathname, int flags)
int open(const char *pathname, int flags, mode_t mode)
and a creat
function that is a shorthand to open(pathname, O_WRONLY|O_CREAT|O_TRUNC, mode)
.
pathname
is a path.
mode
is used only if open
creates a new file, and it defines its
permissions. Either use octal
number, or use symbolic constants described in the manual.
flags
is a rat's nest.
flags
must contain exactly one of the following flags: O_RDONLY
, O_WRONLY
, or O_RDWR
that choose whether file is opened for reading, writing or both.
flags
may additionally contain other flags, including the following:
O_APPEND
sets file position to the end of a file before every writeO_TRUNC
(shall be used only in conjunction with O_WRONLY
or O_RDWR
) truncates the file (sets its size to 0)O_CREAT
tells open
that if the file does not exist, it should be createdO_EXCL
(shall be used only in conjunction with O_CREAT
) makes open fail when the file existsFor example:
int fd1 = open("/tmp/foo", O_RDONLY); if (fd1 == -1) perror("Opening /tmp/foo for reading failed"); int fd2 = open("/tmp/baz", O_WRONLY|O_APPEND); if (fd2 == -1) perror("Opening /tmp/baz for appending (write-only) failed"); int fd3 = open("/tmp/bar", O_RDWR|O_CREAT|O_EXCL, 0600); if (fd3 == -1) perror("Creating a new file /tmp/bar failed"); // if open succeeds, the file is open for reading and writing and has permissions of 0600
To close a file, POSIX defines:
Needs header:unistd.h
int close(int filedes)
that closes a file number filedes
.
On Linux, invoking close(fd)
always closes fd
, even if close
returns -1
.
Exercise 1 Open a file with hardcoded filename, read its contents and write it to standard output.
Exercise 2 Open a file specified as the first argument of your program, read its contents and write it to standard output.
Exercise 3 Open a file specified as the first argument of your program, read
its contents and write it to standard output with line numbers (just like
cat -n file
).
memchr
looks up a character (e.g., \n
) in memory.
Exercise 4 Implement a program that checks if two files have the same contents.
memcmp
compares two memory areas.
Exercise 5 Implement a program that works as paste [file]...
.
Hint: the dirty solution reads single character a time.
To create a new process, POSIX defines the fork
function:
Needs header:unistd.h
pid_t fork()
fork
creates a copy1)
of the running process.
Upon success, fork
returns the pid of the child process in the parent
process, and the value of 0
in the the child process.
Fork may fail if the resource limits are exhausted, and in such case the
expected -1
is returned.
There is a list of things that fork
does not clone or that are reset for the
child process upon fork
. See POSIX standard or Linux manual on fork for details.
Notice that:
To learn its own process identifier, the process can execute
Needs header: unistd.h
pid_t getpid()
To learn the process identifier of its parent, the process can execute
Needs header: unistd.h
pid_t getppid()
The parent process shall care for its child processes once they terminate.
The programmer may either:
1) wait for the child to terminate,
2) set up a signal handler for SIGCHILD (it suffices to ignore the signal),
3) force the child out of the parent processes session (by using
setsid()
or double fork
).
To wait for the termination of any child, one can call wait
. To wait for the
termination of a specific pid, one can call waitpid
:
Needs header:sys/wait.h
pid_t wait(int *stat_loc)
pid_t waitpid(pid_t pid, int *stat_loc, int options)
These functions return the process identifier of the child process which
terminated.
The functions write the status of the termination to the memory pointed by
stat_loc
(provided it's not NULL
) .
The status provides information whether the process terminated normally (by
calling exit
or returning from main
) and if it did, then which value
it returned.
See the documentation for a list of macros that extract the information.
If the pid
in waitpid
is positive, then it is considered the pid
of the child to wait for. Non-positive values have special meanings. Among
others, -1
waits for any child.
The options
argument of waitpid
is a combination of flags.
The value of 0
simply waits until the pid terminates.
The flag WNOHANG
makes waitpid
return immediately (and the return value
indicates whether a child has terminated).
Exercise 6 Write a program that:
1. sleeps five seconds,
2. prints a text with write
,
3. forks,
4. prints another text with write
,
5. sleeps another five seconds.
Run the program and observe it in a live process viewer.
sleep(int sec)
sleeps with second resolution. (The other POSIX sleep function is
nanosleep
;
C standard includes now the equivalent thrd_sleep
)
To keep an eye on the application, either use htop
/ top
, or try watch -n 0.1 ps -lHC executable_name
.
Exercise 7 Fork and print the result of fork
, getpid
and getppid
.
Exercise 8 Fork. Print child
in the child process and parent
in the
parent process.
Exercise 9 Fork. In the child process, exit immediately. In the parent,
wait for input (e.g., do a read
from 0 or invoke getchar
).
Run the program and observe the zombie using htop
/ top
/ ps
.