├── .gitignore ├── Makefile ├── README.md ├── bucaneer.txt ├── malloc-usable.c └── src ├── atexit-example.c ├── block-count.c ├── calloc.c ├── custom-pidof.c ├── daemon.c ├── eject.c ├── fake-system.c ├── filesize.c ├── filetype.c ├── find-file-in-dir.c ├── getaffinity.c ├── getscheduler.c ├── getsid-example.c ├── harakiri.c ├── how-many-hz.c ├── inotify-q-size.c ├── map-example.c ├── more-signals.c ├── naive_writev.c ├── poll-example.c ├── print-inode.c ├── readv.c ├── rlim.c ├── schedulerpriorities.c ├── select-example.c ├── setaffinity.c ├── setscheduler.c ├── sigint.c ├── stop-all-the-clocks.c ├── thread-example.c ├── wait-example.c └── writev.c /.gitignore: -------------------------------------------------------------------------------- 1 | /out/ 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS?=-Wall -Werror -g 3 | AWK?=awk 4 | SORT?=sort 5 | PR?=pr 6 | VPATH?=src 7 | 8 | # daemon not included yet due to undefined NR_COUNT compiler error 9 | SOURCES=atexit-example block-count custom-pidof fake-system filesize filetype 10 | SOURCES+=getaffinity getscheduler getsid-example map-example naive_writev 11 | SOURCES+=poll-example print-inode readv rlim schedulerpriorities select-example 12 | SOURCES+=setaffinity setscheduler wait-example writev daemon find-file-in-dir 13 | SOURCES+=eject inotify-q-size calloc sigint more-signals harakiri malloc-usable 14 | SOURCES+=how-many-hz 15 | 16 | all: $(SOURCES) thread 17 | 18 | $(SOURCES): %: %.c 19 | $(CC) $(CFLAGS) $< -o out/$@ 20 | 21 | thread: thread-example.c 22 | $(CC) $(CFLAGS) -pthread $< -o out/$@ 23 | 24 | # The book says that linking to librt is required for this example although I 25 | # encountered no compiler, linker warnings, and the program output remains the 26 | # same 27 | stop-all-the-clocks: stop-all-the-clocks.c 28 | $(CC) $(CFLAGS) -lrt $< -o out/$@ 29 | 30 | .PHONY: clean 31 | clean: 32 | rm -f out/* 33 | 34 | .PHONY: help 35 | help: 36 | @$(MAKE) --print-data-base --question | \ 37 | $(AWK) '/^[^.%][-A-Za-z0-9_]*:/ \ 38 | { print substr($$1,1,length($$1)-1) }' | \ 39 | $(SORT) | \ 40 | $(PR) --omit-pagination --width=80 --columns=4 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux Systems Programming 2 | 3 | Following along with the examples from the [Linux Systems Programming](http://www.amazon.co.uk/Linux-System-Programming-Talking-Directly/dp/1449339530/) 4 | book by [Robert Love](https://www.rlove.org/). 5 | 6 | Copyright 2007 O’Reilly Media, Inc., ISBN 978-0-596-00958-8. 7 | 8 | Not all of the examples are verbatim, and I have annotated where I encountered 9 | specific issues on my system. I am running an up-to-date arch linux system. 10 | 11 | Current versions: 12 | ``` 13 | gcc (GCC) 4.8.2 20140206 (prerelease) 14 | Linux 3.13.6-1-ARCH #1 SMP PREEMPT x86_64 GNU/Linux 15 | glibc 2.19-3 16 | ``` 17 | 18 | I combined several snippets to improve my own understanding and added makefiles 19 | to aid with building and to get to grips with those aspects of system 20 | programming. 21 | -------------------------------------------------------------------------------- /bucaneer.txt: -------------------------------------------------------------------------------- 1 | The term buccaneer comes from the word boucan. 2 | A boucan is a wooden frame used for cooking meat. 3 | Buccaneer is the West Indies name for a pirate. 4 | -------------------------------------------------------------------------------- /malloc-usable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main (void) 6 | { 7 | size_t requested = 21; 8 | size_t actual; 9 | char *buf; 10 | 11 | buf = malloc (requested); 12 | if (!buf) { 13 | perror ("malloc"); 14 | return 1; 15 | } 16 | 17 | actual = malloc_usable_size (buf); 18 | 19 | printf ("%ld bytes actually available in buf\n", actual); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/atexit-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void out (void) 5 | { 6 | printf ("atexit() succeeded!\n"); 7 | } 8 | 9 | 10 | int main (void) 11 | { 12 | if (atexit (out)) { 13 | fprintf (stderr, "atexit(0 failed!\n"); 14 | return 1; 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/block-count.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int get_block (int fd, int logical_block) 10 | { 11 | int ret; 12 | 13 | ret = ioctl (fd, FIBMAP, &logical_block); 14 | if (ret < 0) { 15 | perror ("ioctl"); 16 | return -1; 17 | } 18 | 19 | return logical_block; 20 | } 21 | 22 | int get_nr_blocks (int fd) 23 | { 24 | struct stat buf; 25 | int ret; 26 | 27 | ret = fstat (fd, &buf); 28 | if (ret < 0) { 29 | perror ("fstat"); 30 | return 1; 31 | } 32 | 33 | return buf.st_blocks; 34 | } 35 | 36 | void print_blocks (int fd) 37 | { 38 | int nr_blocks, i; 39 | 40 | nr_blocks = get_nr_blocks (fd); 41 | if (nr_blocks < 0) { 42 | fprintf (stderr, "get_nr_blocks failed!\n"); 43 | return; 44 | } 45 | 46 | if (nr_blocks == 0) { 47 | printf ("no allocated blocks\n"); 48 | return; 49 | } else if (nr_blocks == 1) { 50 | printf ("1 block\n\n"); 51 | } else { 52 | printf ("%d blocks\n\n", nr_blocks); 53 | } 54 | 55 | for (i = 0; i < nr_blocks; i++) { 56 | int phys_block; 57 | 58 | phys_block = get_block (fd, i); 59 | if (phys_block < 0) { 60 | fprintf (stderr, "get_block failed!\n"); 61 | return; 62 | } 63 | if (!phys_block) 64 | continue; 65 | 66 | printf ("(%u, %u) ", i, phys_block); 67 | } 68 | 69 | putchar ('\n'); 70 | } 71 | 72 | int main (int argc, char *argv[]) 73 | { 74 | int fd; 75 | 76 | if (argc < 2) { 77 | fprintf (stderr, "usage: %s \n", argv[0]); 78 | return 1; 79 | } 80 | 81 | fd = open (argv[1], O_RDONLY); 82 | if (fd < 0) { 83 | perror ("open"); 84 | return 1; 85 | } 86 | 87 | print_blocks (fd); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /src/calloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void print_chars (int n, char c) 5 | { 6 | int i; 7 | 8 | for (i = 0; i < n; i++) { 9 | char *s; 10 | int j; 11 | 12 | s = calloc (i + 2, 1); 13 | if (!s) { 14 | perror ("calloc"); 15 | exit(1); 16 | } 17 | 18 | for (j = 0; j < i + 1; j++) { 19 | s[j] = c; 20 | } 21 | 22 | printf ("%s\n", s); 23 | 24 | free (s); 25 | } 26 | } 27 | 28 | int main (void) 29 | { 30 | print_chars (5, 'X'); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /src/custom-pidof.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main (int argc, char *argv[]) 7 | { 8 | printf ("My pid is %jd\n", (intmax_t) getpid ()); 9 | printf ("Parent pid is %jd\n", (intmax_t) getppid ()); 10 | 11 | return 0; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/daemon.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | /* 10 | *On my system linux/fs.h undefs NR_OPEN and linux/limits.h defines it. 11 | *No matter whether I include limits after fs or not gcc errors with a warning 12 | *saying NR_OPEN is undefined (gcc 4.8.2 / kernel 3.13.8-1-ARCH) so we must 13 | *define it here 14 | */ 15 | #define NR_OPEN 1024 16 | 17 | int main (void) 18 | { 19 | pid_t pid; 20 | int i; 21 | 22 | /* create new process */ 23 | pid = fork (); 24 | if (pid == -1) { 25 | return -1; 26 | } else if (pid != 0) { 27 | exit (EXIT_SUCCESS); 28 | } 29 | 30 | if (setsid () == -1) { 31 | return -1; 32 | } 33 | 34 | if (chdir ("/") == -1) { 35 | return -1; 36 | } 37 | 38 | for (i = 0; i < NR_OPEN; i++) 39 | close (i); 40 | 41 | open ("/dev/null", O_RDWR); 42 | dup (0); 43 | dup (0); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/eject.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main (int argc, char *argv[]) 10 | { 11 | int fd, ret; 12 | 13 | if (argc < 2) { 14 | fprintf(stderr, "Usage: %s \n", argv[0]); 15 | return 1; 16 | } 17 | 18 | fd = open (argv[1], O_RDONLY | O_NONBLOCK); 19 | if (fd < 0) { 20 | perror ("open"); 21 | return 1; 22 | } 23 | 24 | ret = ioctl(fd, CDROMEJECT, 0); 25 | if (ret) { 26 | perror ("ioctl"); 27 | return 1; 28 | } 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/fake-system.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int my_system (char *command) 9 | { 10 | int fd, execret, status; 11 | pid_t pid, waited_pid; 12 | char *argv[4]; 13 | 14 | if (command == NULL) { 15 | fd = open ("/bin/sh", O_RDONLY); 16 | if (fd < 0) { 17 | perror ("open"); 18 | return 0; 19 | } 20 | 21 | fprintf(stderr, "Command was NULL\n"); 22 | return -1; 23 | } 24 | 25 | pid = fork (); 26 | if (pid < 0) { 27 | perror("fork"); 28 | return -1; 29 | } 30 | 31 | if (!pid) { 32 | /* Child process */ 33 | argv[0] = "sh"; 34 | argv[1] = "-c"; 35 | argv[2] = command; 36 | argv[3] = NULL; 37 | 38 | execret = execvp ("sh", argv); 39 | if (execret < 0) { 40 | perror ("exec"); 41 | return execret; 42 | } 43 | } 44 | 45 | waited_pid = wait(&status); 46 | if (waited_pid == -1) { 47 | perror ("wait"); 48 | return -1; 49 | } 50 | 51 | if (WIFEXITED (status)) 52 | return status; 53 | 54 | return -1; 55 | } 56 | 57 | int main (void) 58 | { 59 | return my_system("echo foo"); 60 | } 61 | -------------------------------------------------------------------------------- /src/filesize.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main (int argc, char *argv[]) 7 | { 8 | struct stat sb; 9 | int ret; 10 | 11 | if (argc < 2) { 12 | fprintf(stderr, "usage: %s \n", argv[0]); 13 | return 1; 14 | } 15 | 16 | ret = stat (argv[1], &sb); 17 | if (ret) { 18 | perror ("stat"); 19 | return 1; 20 | } 21 | 22 | printf ("%s is %ld bytes\n", argv[1], sb.st_size); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/filetype.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main (int argc, char *argv[]) 7 | { 8 | struct stat sb; 9 | int ret; 10 | 11 | if (argc < 2) { 12 | fprintf(stderr, "usage: %s \n", argv[0]); 13 | return 1; 14 | } 15 | 16 | ret = stat (argv[1], &sb); 17 | if (ret) { 18 | perror ("stat"); 19 | return 1; 20 | } 21 | 22 | printf ("File type: "); 23 | switch (sb.st_mode & S_IFMT) { 24 | case S_IFBLK: 25 | printf ("block device node\n"); 26 | break; 27 | case S_IFCHR: 28 | printf ("character device node\n"); 29 | break; 30 | case S_IFDIR: 31 | printf ("directory\n"); 32 | break; 33 | case S_IFIFO: 34 | printf ("FIFO\n"); 35 | break; 36 | case S_IFLNK: 37 | printf ("symbolic link\n"); 38 | break; 39 | case S_IFREG: 40 | printf ("regular file\n"); 41 | break; 42 | case S_IFSOCK: 43 | printf ("socket\n"); 44 | break; 45 | default: 46 | printf ("unknown\n"); 47 | break; 48 | } 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /src/find-file-in-dir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main (int argc, char *argv[]) 10 | { 11 | struct dirent *entry; 12 | struct stat buf; 13 | int ret; 14 | DIR *dir; 15 | 16 | if (argc < 3) { 17 | fprintf (stderr, "Usage: %s \n", argv[0]); 18 | return 1; 19 | } 20 | 21 | ret = stat (argv[1], &buf); 22 | if (ret < 0) { 23 | perror ("stat"); 24 | return 1; 25 | } 26 | 27 | if (S_ISDIR(buf.st_mode)) { 28 | ret = 1; 29 | dir = opendir (argv[1]); 30 | 31 | errno = 0; 32 | while ((entry = readdir (dir)) != NULL) { 33 | if (strcmp (entry->d_name, argv[2]) == 0) { 34 | ret = 0; 35 | break; 36 | } 37 | } 38 | 39 | if (errno && !entry) { 40 | perror ("readdir"); 41 | return 1; 42 | } 43 | 44 | closedir (dir); 45 | return ret; 46 | } 47 | 48 | fprintf(stderr, "%s is not a directory\n", argv[1]); 49 | return 1; 50 | } 51 | -------------------------------------------------------------------------------- /src/getaffinity.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | 5 | #define MAX_CPU 8 6 | 7 | int main (void) 8 | { 9 | cpu_set_t set; 10 | int ret, i; 11 | 12 | CPU_ZERO (&set); 13 | ret = sched_getaffinity (0, sizeof (cpu_set_t), &set); 14 | if (ret == -1) { 15 | perror ("sched_getaffinity"); 16 | return -1; 17 | } 18 | 19 | for (i = 0; i < MAX_CPU; i++) { 20 | int cpu; 21 | 22 | cpu = CPU_ISSET (i, &set); 23 | printf ("cpu=%i is %s\n", i, 24 | cpu ? "set" : "unset"); 25 | } 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/getscheduler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main (void) 5 | { 6 | int policy; 7 | 8 | policy = sched_getscheduler (0); 9 | 10 | switch (policy) { 11 | case SCHED_OTHER: 12 | printf ("policy is normal\n"); 13 | break; 14 | case SCHED_RR: 15 | printf ("policy is round-robin\n"); 16 | break; 17 | case SCHED_FIFO: 18 | printf ("policy is first-in, first-out\n"); 19 | break; 20 | case -1: 21 | perror ("sched_getscheduler"); 22 | break; 23 | default: 24 | fprintf (stderr, "Unknown policy!\n"); 25 | } 26 | 27 | return 0; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/getsid-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main (void) 5 | { 6 | pid_t sid; 7 | 8 | sid = getsid (0); 9 | if (sid == -1) { 10 | perror ("getsid"); 11 | return 1; 12 | } 13 | 14 | printf ("My session id=%d\n", sid); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/harakiri.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static void signal_handler (int signo) 7 | { 8 | /* We shouldn't be using printf here because of reentrancy. */ 9 | printf("Caught %s\n", sys_siglist[signo]); 10 | exit (EXIT_SUCCESS); 11 | } 12 | 13 | int main (void) 14 | { 15 | if (signal (SIGINT, signal_handler) == SIG_ERR) { 16 | fprintf (stderr, "Cannot handle SIGINT\n"); 17 | exit (EXIT_FAILURE); 18 | } 19 | 20 | if (signal (SIGTERM, signal_handler) == SIG_ERR) { 21 | fprintf (stderr, "Cannot handle SIGTERM\n"); 22 | exit (EXIT_FAILURE); 23 | } 24 | 25 | kill (getpid (), SIGINT); 26 | /* or we could do this but we won't reach here */ 27 | raise (SIGTERM); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/how-many-hz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main (void) 6 | { 7 | long hz; 8 | 9 | hz = sysconf (_SC_CLK_TCK); 10 | if (hz == -1) { 11 | perror ("sysconf"); 12 | exit (EXIT_FAILURE); 13 | } 14 | 15 | printf ("There are %ld ticks per second\n", hz); 16 | exit (EXIT_SUCCESS); 17 | } 18 | -------------------------------------------------------------------------------- /src/inotify-q-size.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // On my system the inotify header is in sys unlike in the book 4 | #include 5 | #include 6 | #include 7 | // The attributed form in the book wouldn't work for me and was missing 8 | // the constants needed to initialise the buffers. 9 | // Love's article on linuxjournal provides the necessary info: 10 | // http://www.linuxjournal.com/article/8478?page=0,1 11 | #define NAME_MAX 16 12 | #define EVENT_SIZE (sizeof(struct inotify_event)) 13 | #define BUF_LEN (1024 * (EVENT_SIZE + NAME_MAX)) 14 | 15 | int main (void) 16 | { 17 | unsigned int queue_len; 18 | int ret, fd; 19 | char buf[BUF_LEN]; 20 | ssize_t len, i = 0; 21 | 22 | fd = inotify_init (); 23 | if (fd < 0) { 24 | perror ("inotify_init"); 25 | return 1; 26 | } 27 | 28 | ret = inotify_add_watch (fd, "./", IN_ACCESS | IN_MODIFY); 29 | if (ret < 0) { 30 | perror ("inotify_add_watch"); 31 | return 1; 32 | } 33 | 34 | len = read (fd, buf, BUF_LEN); 35 | while (i < len) { 36 | struct inotify_event *event = 37 | (struct inotify_event *) &buf[i]; 38 | 39 | printf ("wd=%d mask=%d cookie=%d len=%d dir=%s\n", 40 | event->wd, event->mask, event->cookie, event->len, 41 | (event->mask & IN_ISDIR) ? "yes" : "no"); 42 | 43 | if (event->len) { 44 | printf ("name=%s\n", event->name); 45 | } 46 | 47 | i += sizeof (struct inotify_event) + event->len; 48 | } 49 | 50 | 51 | ret = ioctl (fd, FIONREAD, &queue_len); 52 | if (ret < 0) { 53 | perror ("ioctl"); 54 | return 1; 55 | } 56 | 57 | printf ("%u bytes pending in queue\n", queue_len); 58 | 59 | ret = close (fd); 60 | if (fd == -1) { 61 | perror ("close"); 62 | return 1; 63 | } 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /src/map-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main (int argc, char *argv[]) 9 | { 10 | struct stat sb; 11 | off_t len; 12 | char *p; 13 | int fd; 14 | 15 | if (argc < 2) { 16 | fprintf (stderr, "usage: %s \n", argv[0]); 17 | return 1; 18 | } 19 | 20 | fd = open (argv[1], O_RDONLY); 21 | if (fd == -1) { 22 | perror("open"); 23 | return 1; 24 | } 25 | 26 | if (fstat (fd, &sb) == -1) { 27 | perror ("fstat"); 28 | return 1; 29 | } 30 | 31 | if (!S_ISREG (sb.st_mode)) { 32 | fprintf (stderr, "%s is not a file\n", argv[1]); 33 | return 1; 34 | } 35 | 36 | p = mmap (0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); 37 | if (p == MAP_FAILED) { 38 | perror ("mmap"); 39 | return 1; 40 | } 41 | 42 | if (close (fd) == -1) { 43 | perror ("close"); 44 | return 1; 45 | } 46 | 47 | for (len = 0; len < sb.st_size; len++) 48 | putchar (p[len]); 49 | 50 | if (munmap(p, sb.st_size) == -1) { 51 | perror ("munmap"); 52 | return 1; 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /src/more-signals.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static void signal_handler (int signo) 7 | { 8 | /* We shouldn't be using printf here because of reentrancy. */ 9 | if (signo == SIGINT) 10 | printf ("Caught SIGINT!\n"); 11 | else if (signo == SIGTERM) 12 | printf ("Caught SIGTERM!\n"); 13 | else { 14 | fprintf(stderr, "Unexpected signal\n"); 15 | exit (EXIT_FAILURE); 16 | } 17 | 18 | exit (EXIT_SUCCESS); 19 | } 20 | 21 | int main (void) 22 | { 23 | if (signal (SIGINT, signal_handler) == SIG_ERR) { 24 | fprintf (stderr, "Cannot handle SIGINT\n"); 25 | exit (EXIT_FAILURE); 26 | } 27 | 28 | if (signal (SIGTERM, signal_handler) == SIG_ERR) { 29 | fprintf (stderr, "Cannot handle SIGTERM\n"); 30 | exit (EXIT_FAILURE); 31 | } 32 | 33 | if (signal (SIGPROF, SIG_DFL) == SIG_ERR) { 34 | fprintf (stderr, "Cannot reset SIGPROF\n"); 35 | exit (EXIT_FAILURE); 36 | } 37 | 38 | if (signal (SIGHUP, SIG_IGN) == SIG_ERR) { 39 | fprintf (stderr, "Cannot ignore SIGHUP\n"); 40 | exit (EXIT_FAILURE); 41 | } 42 | 43 | for (;;) 44 | pause (); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /src/naive_writev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | ssize_t naive_writev (int fd, const struct iovec *iov, int count) 11 | { 12 | ssize_t ret = 0; 13 | int i; 14 | 15 | for (i = 0; i < count; i++) { 16 | ssize_t nr; 17 | 18 | errno = 0; 19 | nr = write (fd, iov[i].iov_base, iov[i].iov_len); 20 | if (nr == -1) { 21 | if (errno == EINTR) 22 | continue; 23 | 24 | ret = -1; 25 | break; 26 | } 27 | ret += nr; 28 | } 29 | 30 | return ret; 31 | } 32 | 33 | int main () 34 | { 35 | struct iovec iov[3]; 36 | ssize_t nr; 37 | int fd, i; 38 | 39 | char *buf[] = { 40 | "The term buccaneer comes from the word boucan.\n", 41 | "A boucan is a wooden frame used for cooking meat.\n", 42 | "Buccaneer is the West Indies name for a pirate.\n" }; 43 | 44 | fd = open ("bucaneer.txt", O_WRONLY| O_CREAT | O_TRUNC); 45 | if (fd == -1) { 46 | perror ("open"); 47 | return 1; 48 | } 49 | 50 | for (i = 0; i < 3; i++) { 51 | iov[i].iov_base = buf[i]; 52 | iov[i].iov_len = strlen (buf[i]) + 1; 53 | } 54 | 55 | nr = naive_writev (fd, iov, 3); 56 | if (nr == -1) { 57 | perror ("writev"); 58 | return 1; 59 | } 60 | printf("wrote %ld bytes\n", nr); 61 | 62 | if (close (fd)) { 63 | perror ("close"); 64 | return 1; 65 | } 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /src/poll-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define TIMEOUT 5 6 | 7 | int main (void) 8 | { 9 | struct pollfd fds[2]; 10 | int ret; 11 | 12 | /* watch stdin for input */ 13 | fds[0].fd = STDIN_FILENO; 14 | fds[0].events = POLLIN; 15 | 16 | /* watch stdout for ability to write */ 17 | fds[1].fd = STDOUT_FILENO; 18 | fds[1].events = POLLOUT; 19 | 20 | ret = poll(fds, 2, TIMEOUT * 1000); 21 | 22 | if (ret == -1) { 23 | perror ("poll"); 24 | return 1; 25 | } 26 | 27 | if (!ret) { 28 | printf ("%d seconds elapsed.\n", TIMEOUT); 29 | return 0; 30 | } 31 | 32 | if (fds[0].revents & POLLIN) 33 | printf ("stdin is readable\n"); 34 | 35 | if (fds[1].revents & POLLOUT) 36 | printf ("stdout is writable\n"); 37 | 38 | return 0; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/print-inode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int get_inode (int fd) 8 | { 9 | struct stat buf; 10 | int ret; 11 | 12 | ret = fstat (fd, &buf); 13 | if (ret < 0) { 14 | perror ("fstat"); 15 | return -1; 16 | } 17 | 18 | return buf.st_ino; 19 | } 20 | 21 | int main (int argc, char *argv[]) 22 | { 23 | int fd, inode; 24 | 25 | if (argc < 2) { 26 | fprintf (stderr, "usage: %s \n", argv[0]); 27 | return 1; 28 | } 29 | 30 | fd = open (argv[1], O_RDONLY); 31 | if (fd < 0) { 32 | perror ("open"); 33 | return 1; 34 | } 35 | 36 | inode = get_inode (fd); 37 | printf ("%d\n", inode); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/readv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() 9 | { 10 | char foo[48], bar[51], baz[49]; 11 | struct iovec iov[3]; 12 | ssize_t nr; 13 | int fd, i; 14 | 15 | fd = open ("bucaneer.txt", O_RDONLY); 16 | if (fd == -1) { 17 | perror ("open"); 18 | return 1; 19 | } 20 | 21 | iov[0].iov_base = foo; 22 | iov[0].iov_len = sizeof (foo); 23 | iov[1].iov_base = bar; 24 | iov[1].iov_len = sizeof (bar); 25 | iov[2].iov_base = baz; 26 | iov[2].iov_len = sizeof (baz); 27 | 28 | nr = readv (fd, iov, 3); 29 | if (nr == -1) { 30 | perror ("readv"); 31 | return 1; 32 | } 33 | 34 | for (i = 0; i < 3; i++) 35 | printf ("%d: %s", i, (char *)iov[i].iov_base); 36 | 37 | if (close (fd)) { 38 | perror ("close"); 39 | return 1; 40 | } 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /src/rlim.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main (void) 6 | { 7 | struct rlimit rlim; 8 | int ret; 9 | 10 | ret = getrlimit (RLIMIT_FSIZE, &rlim); 11 | if (ret == -1) { 12 | perror ("getrlimit"); 13 | return 1; 14 | } 15 | 16 | printf ("File size resource soft limit is %ld and hard limit is %ld\n", 17 | rlim.rlim_cur, 18 | rlim.rlim_max); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/schedulerpriorities.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main (void) 5 | { 6 | int min, max; 7 | 8 | min = sched_get_priority_min (SCHED_RR); 9 | if (min == -1) { 10 | perror ("sched_get_priority_min"); 11 | return 1; 12 | } 13 | 14 | max = sched_get_priority_max (SCHED_RR); 15 | if (max == -1) { 16 | perror ("sched_get_priority_max"); 17 | return 1; 18 | } 19 | 20 | printf ("SCHED_RR priority range is %d - %d\n", min, max); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/select-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define TIMEOUT 5 7 | #define BUF_LEN 1024 8 | 9 | int main (void) 10 | { 11 | struct timeval tv; 12 | fd_set readfds; 13 | int ret; 14 | 15 | /* Wait on stdin for input. */ 16 | FD_ZERO(&readfds); 17 | FD_SET(STDIN_FILENO, &readfds); 18 | 19 | /* Wait up to five seconds */ 20 | tv.tv_sec = TIMEOUT; 21 | tv.tv_usec = 0; 22 | 23 | ret = select (STDIN_FILENO + 1, 24 | &readfds, 25 | NULL, 26 | NULL, 27 | &tv); 28 | 29 | if (ret == -1) { 30 | perror("select"); 31 | return 1; 32 | } else if (!ret) { 33 | printf("%d seconds elapsed.\n", TIMEOUT); 34 | return 0; 35 | } 36 | 37 | if (FD_ISSET(STDIN_FILENO, &readfds)) { 38 | char buf[BUF_LEN + 1]; 39 | int len; 40 | 41 | len = read (STDIN_FILENO, buf, BUF_LEN); 42 | if (len == -1) { 43 | perror ("read"); 44 | return 1; 45 | } 46 | 47 | if (len) { 48 | buf[len] = '\0'; 49 | printf("read: %s\n", buf); 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | fprintf (stderr, "This should not happen!\n"); 56 | return 1; 57 | } 58 | -------------------------------------------------------------------------------- /src/setaffinity.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | 5 | #define MAX_CPU 8 6 | 7 | int main (void) 8 | { 9 | cpu_set_t set; 10 | int ret, i; 11 | 12 | CPU_ZERO (&set); 13 | CPU_SET (0, &set); 14 | CPU_CLR (1, &set); 15 | ret = sched_setaffinity (0, sizeof (cpu_set_t), &set); 16 | if (ret == -1) { 17 | perror ("sched_setaffinity"); 18 | return -1; 19 | } 20 | 21 | for (i = 0; i < MAX_CPU; i++) { 22 | int cpu; 23 | 24 | cpu = CPU_ISSET (i, &set); 25 | printf ("cpu=%i is %s\n", i, 26 | cpu ? "set" : "unset"); 27 | } 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/setscheduler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main (void) 5 | { 6 | int policy; 7 | struct sched_param sp = { .sched_priority = 1 }; 8 | struct timespec tp; 9 | int ret; 10 | 11 | ret = sched_setscheduler (0, SCHED_RR, &sp); 12 | if (ret == -1) { 13 | perror ("sched_setscheduler"); 14 | return 1; 15 | } 16 | 17 | policy = sched_getscheduler (0); 18 | 19 | switch (policy) { 20 | case SCHED_OTHER: 21 | printf ("policy is normal\n"); 22 | break; 23 | case SCHED_RR: 24 | printf ("policy is round-robin\n"); 25 | break; 26 | case SCHED_FIFO: 27 | printf ("policy is first-in, first-out\n"); 28 | break; 29 | case -1: 30 | perror ("sched_getscheduler"); 31 | break; 32 | default: 33 | fprintf (stderr, "Unknown policy!\n"); 34 | } 35 | 36 | ret = sched_getparam (0, &sp); 37 | if (ret == -1) { 38 | perror ("sched_getparam"); 39 | return 1; 40 | } 41 | 42 | printf ("Our priority is %d\n", sp.sched_priority); 43 | 44 | ret = sched_rr_get_interval (0, &tp); 45 | if (ret == -1) { 46 | perror ("sched_rr_get_interval"); 47 | return 1; 48 | } 49 | 50 | printf ("Our time quantum is %.2lf milliseconds\n", 51 | (tp.tv_sec * 1000.0f) + (tp.tv_nsec / 1000000.0f)); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/sigint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static void sigint_handler (int signo) 7 | { 8 | /* We shouldn't be using printf here because of reentrancy. */ 9 | printf ("Caught SIGINT!\n"); 10 | exit (EXIT_SUCCESS); 11 | } 12 | 13 | int main (void) 14 | { 15 | if (signal (SIGINT, sigint_handler) == SIG_ERR) { 16 | fprintf (stderr, "Cannot handle SIGINT\n"); 17 | exit (EXIT_FAILURE); 18 | } 19 | 20 | for (;;) 21 | pause (); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/stop-all-the-clocks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main (void) 8 | { 9 | clockid_t clocks[] = { 10 | CLOCK_REALTIME, 11 | CLOCK_MONOTONIC, 12 | CLOCK_PROCESS_CPUTIME_ID, 13 | CLOCK_THREAD_CPUTIME_ID, 14 | CLOCK_MONOTONIC_RAW, 15 | (clockid_t) -1 16 | }; 17 | int i, ret; 18 | time_t now; 19 | struct timeval time_of_day; 20 | 21 | printf ("Getting clock resolutions and times of various clocks:\n"); 22 | 23 | for (i = 0; clocks[i] != -1; i++) { 24 | struct timespec res, ts; 25 | 26 | printf ("Clock: %d\n", clocks[i]); 27 | ret = clock_getres(clocks[i], &res); 28 | if (ret) { 29 | perror ("clock_getres"); 30 | exit (EXIT_FAILURE); 31 | } else 32 | printf ("Resolution: sec=%ld nsec=%ld\n", 33 | res.tv_sec, res.tv_nsec); 34 | 35 | ret = clock_gettime(clocks[i], &ts); 36 | if (ret) { 37 | perror ("clock_gettime"); 38 | exit (EXIT_FAILURE); 39 | } else 40 | printf ("Time: sec=%ld nsec=%ld\n", 41 | ts.tv_sec, ts.tv_nsec); 42 | } 43 | 44 | now = time (&now); 45 | if (now == -1) { 46 | /* This should only happen if &now is an invlid pointer */ 47 | perror ("time"); 48 | exit (EXIT_FAILURE); 49 | } 50 | 51 | printf ("Current time in seconds since the epoch: %ld\n", now); 52 | 53 | printf ("Getting more accurate time:\n"); 54 | ret = gettimeofday (&time_of_day, NULL); 55 | if (ret == -1) { 56 | perror ("gettimeofday"); 57 | exit (EXIT_FAILURE); 58 | } 59 | 60 | printf ("\tseconds=%ld, useconds=%ld\n", 61 | (long)time_of_day.tv_sec, (long)time_of_day.tv_usec); 62 | exit (EXIT_SUCCESS); 63 | } 64 | -------------------------------------------------------------------------------- /src/thread-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void * start_thread (void *message) 6 | { 7 | printf ("%s\n", (const char *) message); 8 | return message; 9 | } 10 | 11 | int main (void) 12 | { 13 | pthread_t thing1, thing2; 14 | const char *message1 = "thing 1"; 15 | const char *message2 = "thing 2"; 16 | 17 | pthread_create (&thing1, NULL, start_thread, (void *) message1); 18 | pthread_create (&thing2, NULL, start_thread, (void *) message2); 19 | 20 | /* We must join here to wait for the threads to exit or the main thread may 21 | * terminate first */ 22 | pthread_join (thing1, NULL); 23 | pthread_join (thing2, NULL); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/wait-example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main (void) 7 | { 8 | int status; 9 | pid_t pid; 10 | 11 | if (!fork ()) { 12 | return 1; 13 | } 14 | 15 | pid = wait (&status); 16 | if (pid == -1) 17 | perror ("wait"); 18 | 19 | printf ("pid=%d\n", pid); 20 | 21 | if (WIFEXITED (status)) 22 | printf ("Normal termination with exit status=%d\n", 23 | WEXITSTATUS (status)); 24 | 25 | if (WIFSIGNALED (status)) 26 | printf ("Killed by signal=%d%s\n", 27 | WTERMSIG (status), 28 | WCOREDUMP (status) ? " (dumped core)" : ""); 29 | 30 | if (WIFSTOPPED (status)) 31 | printf ("Stopped by signal=%d\n", 32 | WSTOPSIG (status)); 33 | 34 | if (WIFCONTINUED (status)) 35 | printf ("Continued\n"); 36 | 37 | return 0; 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/writev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main () 10 | { 11 | struct iovec iov[3]; 12 | ssize_t nr; 13 | int fd, i; 14 | 15 | char *buf[] = { 16 | "The term buccaneer comes from the word boucan.\n", 17 | "A boucan is a wooden frame used for cooking meat.\n", 18 | "Buccaneer is the West Indies name for a pirate.\n" }; 19 | 20 | fd = open ("bucaneer.txt", O_WRONLY| O_CREAT | O_TRUNC); 21 | if (fd == -1) { 22 | perror ("open"); 23 | return 1; 24 | } 25 | 26 | for (i = 0; i < 3; i++) { 27 | iov[i].iov_base = buf[i]; 28 | iov[i].iov_len = strlen (buf[i]) + 1; 29 | } 30 | 31 | nr = writev (fd, iov, 3); 32 | if (nr == -1) { 33 | perror ("writev"); 34 | return 1; 35 | } 36 | printf("wrote %ld bytes\n", nr); 37 | 38 | if (close (fd)) { 39 | perror ("close"); 40 | return 1; 41 | } 42 | 43 | return 0; 44 | } 45 | --------------------------------------------------------------------------------