===== Creating, opening and closing files ===== 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 [[https://en.cppreference.com/w/c/language/integer_constant|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 write * ''**O_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 created * ''**O_EXCL**'' (shall be used only in conjunction with ''O_CREAT'') makes open fail when the file exists * and at least a dozen of other flags For 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.#~~ Open a file with hardcoded filename, read its contents and write it to standard output. ~~Exercise.#~~ Open a file specified as the first argument of your program, read its contents and write it to standard output. ~~Exercise.#~~ 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.#~~ Implement a program that checks if two files have the same contents. \\ ''memcmp'' compares two memory areas. ~~Exercise.#~~ Implement a program that works as ''paste [//file//]...''. \\ Hint: the dirty solution reads single character a time. ===== Fork ===== === Forking === To create a new process, POSIX defines the ''fork'' function: Needs header:unistd.h ''pid_t **fork**()'' \\ **''fork'' creates a copy((Nowadays forking is considered cheap, for it uses [[https://en.wikipedia.org/wiki/Copy-on-write|copy-on-write]] to reduce costs.)) 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: * all stack and heap memory is copied * the list of open files is copied * memory mappings are copied (unless one provides an explicit flag not to copy a mapping upon creating it) * signal handlers are copied * pending signals and timers are **not** copied * threads are **not** copied \\ (but state of mutexes and values of semaphores are copied) \\ forking in a multithreaded application is dangerous === Learning one's own pid === 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**()'' === Waiting for a child === 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). === Exercises === ~~Exercise.#~~ 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 ''[[https://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html|nanosleep]]''; C standard includes now the equivalent ''[[https://en.cppreference.com/w/c/thread/thrd_sleep|thrd_sleep]]'') \\ To keep an eye on the application, either use ''htop'' / ''top'', or try ''watch -n 0.1 ps -lHC //executable_name//''. ~~Exercise.#~~ Fork and print the result of ''fork'', ''getpid'' and ''getppid''. ~~Exercise.#~~ Fork. Print ''child'' in the child process and ''parent'' in the parent process. ~~Exercise.#~~ 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''. ~~META: language = en ~~