37 | int main(void)
38 | {
39 | printf("Hello, world!\n");
40 | return 0;
41 | }
42 | ```
43 |
44 | ### Code in Action
45 | Click on following link to see the Code in Action:
46 |
47 | [Youtube link](https://bit.ly/39ovGd6)
48 |
49 | **Following is what you need for this book:**
50 | This book is for anyone who wants to develop system programs for Linux and gain a deeper understanding of the Linux system. The book is beneficial for anyone who is facing issues related to a particular part of Linux system programming and is looking for specific recipes or solutions.
51 |
52 | With the following software and hardware list you can run all code files present in the book (Chapter 1-12).
53 |
54 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](http://www.packtpub.com/sites/default/files/downloads/9781789951288_ColorImages.pdf).
55 |
56 | ### Related products
57 | * Mastering Linux Device Driver Development [[Packt]](https://www.packtpub.com/product/mastering-linux-device-driver-development/9781789342048?utm_source=github&utm_medium=repository&utm_campaign=9781789342048) [[Amazon]](https://www.amazon.in/Mastering-Linux-Device-Driver-Development-ebook/dp/B08M6G6Q4N)
58 |
59 | * Linux Kernel Programming [[Packt]](https://www.packtpub.com/product/linux-kernel-programming/9781789953435?utm_source=github&utm_medium=repository&utm_campaign=9781789953435) [[Amazon]](https://www.amazon.in/Linux-Kernel-Development-Cookbook-programming-ebook/dp/B07RW915K4/ref=sr_1_2?dchild=1&keywords=Linux+Kernel+Programming&qid=1617710161&s=digital-text&sr=1-2)
60 |
61 | ## Get to Know the Author
62 | **Jack-Benny Persson**
63 | is a consultant and author based in Sweden. He has written several books about Linux and programming. His passion for Linux and other Unix-like systems started as a hobby more than 20 years ago. Since then, he has spent most of his spare time reading about Linux, tinkering with Linux servers, and writing about Linux administration. Today he has his own IT and media company in Sweden that focuses on Linux.
64 | Jack-Benny holds an Advanced Higher Vocational Education Diploma as a Linux system specialist. He has also studied electronics, networking, and security.
65 |
66 | ## Other books by the authors
67 | * [Hands-On Linux System Administration [Video]](https://www.packtpub.com/product/hands-on-linux-system-administration-video/9781789133219?utm_source=github&utm_medium=repository&utm_campaign=9781789133219)
68 |
69 |
70 | ### Download a free PDF
71 |
72 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
73 | https://packt.link/free-ebook/9781789951288
--------------------------------------------------------------------------------
/ch1/first-example.c:
--------------------------------------------------------------------------------
1 | #include
2 | int main(void)
3 | {
4 | printf("Hello, world!\n");
5 | return 0;
6 | }
7 |
--------------------------------------------------------------------------------
/ch1/new-sum.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 500
2 | #include
3 | #include
4 | #include
5 | void printhelp(char progname[]);
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | int i, opt, sum;
10 |
11 | /* Simple sanity check */
12 | if (argc == 1)
13 | {
14 | printhelp(argv[0]);
15 | return 1;
16 | }
17 |
18 | /* Parse command-line options */
19 | while ((opt = getopt(argc, argv, "smh")) != -1)
20 | {
21 | switch (opt)
22 | {
23 | case 's': /* sum the integers */
24 | sum = 0;
25 | for (i=2; i
2 | #include
3 | void printhelp(char progname[]);
4 |
5 | int main(int argc, char *argv[])
6 | {
7 | int i;
8 | int sum = 0;
9 |
10 | /* Simple sanity check */
11 | if (argc == 1)
12 | {
13 | printhelp(argv[0]);
14 | return 1;
15 | }
16 |
17 | for (i=1; i
2 |
3 | int main(void)
4 | {
5 | FILE *fp;
6 | signed char c;
7 | const char fifoname[] = "/tmp/my-2nd-fifo";
8 | if ( (fp = fopen(fifoname, "r")) == NULL )
9 | {
10 | perror("Can't open FIFO");
11 | return 1;
12 | }
13 | while ( (c = getc(fp)) != EOF )
14 | putchar(c);
15 | fclose(fp);
16 | return 0;
17 | }
18 |
--------------------------------------------------------------------------------
/ch10/fifo-sender.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 700
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | void cleanUp(int signum);
13 |
14 | int fd; /* the FIFO file descriptor */
15 | const char fifoname[] = "/tmp/my-2nd-fifo";
16 |
17 | int main(int argc, char *argv[])
18 | {
19 | struct sigaction action; /* for sigaction */
20 | if ( argc != 2 )
21 | {
22 | fprintf(stderr, "Usage: %s 'the message'\n",
23 | argv[0]);
24 | return 1;
25 | }
26 |
27 | /* prepare for sigaction and register signals
28 | * (for cleanup when we exit) */
29 | action.sa_handler = cleanUp;
30 | sigfillset(&action.sa_mask);
31 | action.sa_flags = SA_RESTART;
32 | sigaction(SIGTERM, &action, NULL);
33 | sigaction(SIGINT, &action, NULL);
34 | sigaction(SIGQUIT, &action, NULL);
35 | sigaction(SIGABRT, &action, NULL);
36 | sigaction(SIGPIPE, &action, NULL);
37 |
38 | if ( (mkfifo(fifoname, 0644)) != 0 )
39 | {
40 | perror("Can't create FIFO");
41 | return 1;
42 | }
43 |
44 | if ( (fd = open(fifoname, O_WRONLY)) == -1)
45 | {
46 | perror("Can't open FIFO");
47 | return 1;
48 | }
49 | while(1)
50 | {
51 | dprintf(fd, "%s\n", argv[1]);
52 | sleep(1);
53 | }
54 | /* just in case, but we shouldn't reach this */
55 | close(fd);
56 | unlink(fifoname);
57 | return 0;
58 | }
59 |
60 | void cleanUp(int signum)
61 | {
62 | if (signum == SIGPIPE)
63 | printf("The receiver stopped receiving\n");
64 | else
65 | printf("Aborting...\n");
66 | if ( (close(fd)) == -1 )
67 | perror("Can't close file descriptor");
68 | if ( (unlink(fifoname)) == -1)
69 | {
70 | perror("Can't remove FIFO");
71 | exit(1);
72 | }
73 | exit(0);
74 | }
75 |
--------------------------------------------------------------------------------
/ch10/msg-reveiver.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | int main(void)
10 | {
11 | int md; /* msg queue descriptor */
12 | char *buffer;
13 | struct mq_attr msgattr;
14 | md = mq_open("/my_queue", O_RDONLY);
15 | if (md == -1 )
16 | {
17 | perror("Open message queue");
18 | return 1;
19 | }
20 | if ( (mq_getattr(md, &msgattr)) == -1 )
21 | {
22 | perror("Get message attribute");
23 | return 1;
24 | }
25 | buffer = calloc(msgattr.mq_msgsize,
26 | sizeof(char));
27 | if (buffer == NULL)
28 | {
29 | fprintf(stderr, "Couldn't allocate memory");
30 | return 1;
31 | }
32 | printf("%ld messages in queue\n",
33 | msgattr.mq_curmsgs);
34 | for (int i = 0; i
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #define MAX_MSG_SIZE 2048
8 |
9 | int main(int argc, char *argv[])
10 | {
11 | int md; /* msg queue descriptor */
12 | /* attributes for the message queue */
13 | struct mq_attr msgattr;
14 | msgattr.mq_maxmsg = 10;
15 | msgattr.mq_msgsize = MAX_MSG_SIZE;
16 |
17 | if ( argc != 2)
18 | {
19 | fprintf(stderr, "Usage: %s 'my message'\n",
20 | argv[0]);
21 | return 1;
22 | }
23 | md = mq_open("/my_queue", O_CREAT|O_RDWR, 0644,
24 | &msgattr);
25 | if ( md == -1 )
26 | {
27 | perror("Creating message queue");
28 | return 1;
29 | }
30 | if ( (mq_send(md, argv[1], strlen(argv[1]), 1))
31 | == -1 )
32 | {
33 | perror("Message queue send");
34 | return 1;
35 | }
36 | mq_close(md);
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/ch10/my-daemon-ctl.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 500
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | void printUsage(char progname[], FILE *fp);
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | FILE *fp;
14 | FILE *procfp;
15 | int pid, opt;
16 | int killit = 0;
17 | char procpath[PATH_MAX] = { 0 };
18 | char cmdline[PATH_MAX] = { 0 };
19 | const char pidfile[] = "/var/run/my-daemon.pid";
20 | const char daemon[] = "my-daemon-v2";
21 |
22 | /* Parse command-line options */
23 | while ((opt = getopt(argc, argv, "kh")) != -1)
24 | {
25 | switch (opt)
26 | {
27 | case 'k': /* kill the daemon */
28 | killit = 1;
29 | break;
30 | case 'h': /* help */
31 | printUsage(argv[0], stdout);
32 | return 0;
33 | default: /* in case of invalid options */
34 | printUsage(argv[0], stderr);
35 | return 1;
36 | }
37 | }
38 |
39 | if ( (fp = fopen(pidfile, "r")) == NULL )
40 | {
41 | perror("Can't open PID-file (daemon isn't "
42 | "running?)");
43 | return 1;
44 | }
45 | /* read the pid (and check if we could read an
46 | * integer) */
47 | if ( (fscanf(fp, "%d", &pid)) != 1 )
48 | {
49 | fprintf(stderr, "Can't read PID from %s\n",
50 | pidfile);
51 | return 1;
52 | }
53 |
54 | /* build the /proc path */
55 | sprintf(procpath, "/proc/%d/cmdline", pid);
56 |
57 | /* open the /proc path */
58 | if ( (procfp = fopen(procpath, "r")) == NULL )
59 | {
60 | perror("Can't open /proc path"
61 | " (no /proc or wrong PID?)");
62 | return 1;
63 | }
64 | /* read the cmd line path from proc */
65 | fscanf(procfp, "%s", cmdline);
66 |
67 | /* check the PID against the cmd line */
68 | if ( (strstr(cmdline, daemon)) == 0 )
69 | {
70 | fprintf(stderr, "PID %d doesn't belong "
71 | "to %s\n", pid, daemon);
72 | return 1;
73 | }
74 |
75 | if ( killit == 1 )
76 | {
77 | if ( (kill(pid, SIGTERM)) == 0 )
78 | {
79 | printf("Successfully terminated "
80 | "daemon\n");
81 | }
82 | else
83 | {
84 | perror("Couldn't terminate daemon");
85 | return 1;
86 | }
87 |
88 | }
89 | else
90 | {
91 | printf("The daemon is running with PID %d "
92 | "and cmdline %s\n", pid, cmdline);
93 | }
94 | return 0;
95 | }
96 |
97 | void printUsage(char progname[], FILE *fp)
98 | {
99 | fprintf(fp, "Usage: %s [-k] [-h]\n", progname);
100 | fprintf(fp, "If no options are given, a status "
101 | "message is displayed.\n"
102 | "-k will terminate the daemon.\n"
103 | "-h will display this usage help.\n");
104 | }
105 |
--------------------------------------------------------------------------------
/ch10/my-daemon-v2.c:
--------------------------------------------------------------------------------
1 | #define _POSIX_C_SOURCE 200809L
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | void sigHandler(int sig);
12 |
13 | /* moved these variables to the global scope
14 | since they need to be access/deleted/closed
15 | from the signal handler */
16 | FILE *fp;
17 | const char pidfile[] = "/var/run/my-daemon.pid";
18 |
19 | int main(void)
20 | {
21 | pid_t pid;
22 | time_t now; /* for the current time */
23 | struct sigaction action; /* for sigaction */
24 | const char daemonfile[] = "/tmp/my-daemon-is-alive.txt";
25 |
26 | if ( (pid = fork()) == -1 )
27 | {
28 | perror("Can't fork");
29 | return 1;
30 | }
31 | else if ( (pid != 0) )
32 | {
33 | exit(0);
34 | }
35 |
36 | /* the parent process has exited, which makes the rest of
37 | the code the child process */
38 | setsid(); /* create a new session to lose the controlling
39 | terminal */
40 |
41 | /* fork again, creating a grandchild, the actual daemon */
42 | if ( (pid = fork()) == -1 )
43 | {
44 | perror("Can't fork");
45 | return 1;
46 | }
47 | /* the child process which will exit */
48 | else if ( pid > 0 )
49 | {
50 | /* open pid-file for writing and error check it */
51 | if ( (fp = fopen(pidfile, "w")) == NULL )
52 | {
53 | perror("Can't open file for writing");
54 | return 1;
55 | }
56 | fprintf(fp, "%d\n", pid); /* write pid to file */
57 | fclose(fp); /* close the file pointer */
58 | exit(0);
59 | }
60 |
61 | umask(022); /* reset the umask to something sensible */
62 | chdir("/"); /* change working directory to / */
63 | /* open the "daemonfile" for writing */
64 | if ( (fp = fopen(daemonfile, "w")) == NULL )
65 | {
66 | perror("Can't open daemonfile");
67 | return 1;
68 | }
69 | /* from here, we don't need stdin, stdout or, stderr
70 | anymore, so let's close them all, then re-open them
71 | to /dev/null */
72 | close(STDIN_FILENO);
73 | close(STDOUT_FILENO);
74 | close(STDERR_FILENO);
75 | open("/dev/null", O_RDONLY); /* 0 = stdin */
76 | open("/dev/null", O_WRONLY); /* 1 = stdout */
77 | open("/dev/null", O_RDWR); /* 2 = stderr */
78 |
79 | /* prepare for sigaction */
80 | action.sa_handler = sigHandler;
81 | sigfillset(&action.sa_mask);
82 | action.sa_flags = SA_RESTART;
83 | /* register the signals we want to handle */
84 | sigaction(SIGTERM, &action, NULL);
85 | sigaction(SIGINT, &action, NULL);
86 | sigaction(SIGQUIT, &action, NULL);
87 | sigaction(SIGABRT, &action, NULL);
88 |
89 | /* here we start the daemons "work" */
90 | for (;;)
91 | {
92 | /* get the current time and write it to the
93 | "daemonfile" that we opened above */
94 | time(&now);
95 | fprintf(fp, "Daemon alive at %s", ctime(&now));
96 | fflush(fp); /* flush the stream */
97 | sleep(30);
98 | }
99 | return 0;
100 | }
101 |
102 | void sigHandler(int sig)
103 | {
104 | int status = 0;
105 | if ( sig == SIGTERM || sig == SIGINT
106 | || sig == SIGQUIT
107 | || sig == SIGABRT )
108 | {
109 | /* remove the pid-file */
110 | if ( (unlink(pidfile)) == -1 )
111 | status = 1;
112 | if ( (fclose(fp)) == EOF )
113 | status = 1;
114 | exit(status); /* exit with the status set */
115 | }
116 | else /* some other signal */
117 | {
118 | exit(1);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/ch10/pipe-example.c:
--------------------------------------------------------------------------------
1 | #define _POSIX_C_SOURCE 200809L
2 | #include
3 | #include
4 | #include
5 | #include
6 | #define MAX 128
7 |
8 | int main(void)
9 | {
10 | int pipefd[2] = { 0 };
11 | pid_t pid;
12 | char line[MAX];
13 |
14 | if ( (pipe(pipefd)) == -1 )
15 | {
16 | perror("Can't create pipe");
17 | return 1;
18 | }
19 |
20 | if ( (pid = fork()) == -1 )
21 | {
22 | perror("Can't fork");
23 | return 1;
24 | }
25 |
26 | if (pid > 0)
27 | {
28 | /* inside the parent */
29 | close(pipefd[0]); /* close the read end */
30 | dprintf(pipefd[1], "Hello from parent");
31 | }
32 | else
33 | {
34 | /* inside the child */
35 | close(pipefd[1]); /* close the write end */
36 | read(pipefd[0], line, MAX-1);
37 | printf("%s\n", line); /* print message from
38 | * the parent */
39 | }
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/ch10/read-memory.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #define DATASIZE 128
9 |
10 | int main(void)
11 | {
12 | int fd;
13 | float *addr;
14 | const char memid[] = "/my_memory";
15 | float numbers[3];
16 |
17 | /* open memory file descriptor */
18 | fd = shm_open(memid, O_RDONLY, 0600);
19 | if (fd == -1)
20 | {
21 | perror("Can't open file descriptor");
22 | return 1;
23 | }
24 |
25 | /* map shared memory */
26 | addr = mmap(NULL, DATASIZE, PROT_READ,
27 | MAP_SHARED, fd, 0);
28 | if (addr == MAP_FAILED)
29 | {
30 | perror("Memory mapping failed");
31 | return 1;
32 | }
33 |
34 | /* read the memory and print the numbers */
35 | memcpy(numbers, addr, sizeof(numbers));
36 | for (int i = 0; i<3; i++)
37 | {
38 | printf("Number %d: %.3f\n", i, numbers[i]);
39 | }
40 |
41 | return 0;
42 | }
43 |
--------------------------------------------------------------------------------
/ch10/shm-parent-child.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #define DATASIZE 128
10 |
11 | int main(void)
12 | {
13 | char *addr;
14 | int status;
15 | pid_t pid;
16 | const char startmsg[] = "Hello, we are running";
17 | const char childmsg[] = "Hello from child";
18 | const char parentmsg[] = "New msg from parent";
19 | addr = mmap(NULL, DATASIZE,
20 | PROT_WRITE | PROT_READ,
21 | MAP_SHARED | MAP_ANONYMOUS, -1, 0);
22 | if (addr == MAP_FAILED)
23 | {
24 | perror("mmap");
25 | return 1;
26 | }
27 |
28 | memcpy(addr, startmsg, strlen(startmsg) + 1);
29 | printf("Parent PID is %d\n", getpid());
30 | printf("Original message: %s\n", addr);
31 | if ( (pid = fork()) == -1 )
32 | {
33 | perror("Can't fork");
34 | return 1;
35 | }
36 | if (pid == 0)
37 | {
38 | /* child */
39 | memcpy(addr, childmsg, strlen(childmsg) + 1);
40 | }
41 | else if(pid > 0)
42 | {
43 | /* parent */
44 | waitpid(pid, &status, 0);
45 | printf("Child executed with PID %d\n", pid);
46 | printf("Message from child: %s\n", addr);
47 | memcpy(addr, parentmsg,
48 | strlen(parentmsg) + 1);
49 | printf("Parent message: %s\n", addr);
50 | }
51 | munmap(addr, DATASIZE);
52 | return 0;
53 | }
54 |
--------------------------------------------------------------------------------
/ch10/unix-client.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 700
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #define MAXLEN 128
12 |
13 | int main(void)
14 | {
15 | const char sockname[] = "/tmp/my_1st_socket";
16 | int fd;
17 | struct sockaddr_un addr;
18 | char sendbuffer[MAXLEN];
19 | char recvbuffer[MAXLEN];
20 |
21 | /* create socket file descriptor */
22 | fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
23 | if ( fd == -1 )
24 | {
25 | perror("Create socket failed");
26 | return 1;
27 | }
28 | /* set address family and socket path */
29 | addr.sun_family = AF_UNIX;
30 | strcpy(addr.sun_path, sockname);
31 |
32 | /* connect to the server */
33 | if ( (connect(fd, (const struct sockaddr*) &addr,
34 | sizeof(struct sockaddr_un))) == -1 )
35 | {
36 | perror("Can't connect");
37 | fprintf(stderr, "The server is down?\n");
38 | return 1;
39 | }
40 | while(1) /* main loop */
41 | {
42 | /* send message to server */
43 | printf("Message to send: ");
44 | fgets(sendbuffer, sizeof(sendbuffer), stdin);
45 | sendbuffer[strcspn(sendbuffer, "\n")] = '\0';
46 | if ( (write(fd, sendbuffer,
47 | strlen(sendbuffer) + 1)) == -1 )
48 | {
49 | perror("Couldn't write");
50 | break;
51 | }
52 |
53 | /* read response from server */
54 | if ( (read(fd, recvbuffer, MAXLEN)) == -1 )
55 | {
56 | perror("Can't read");
57 | return 1;
58 | }
59 | printf("Server said: %s\n", recvbuffer);
60 | }
61 | return 0;
62 | }
63 |
--------------------------------------------------------------------------------
/ch10/unix-server.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 700
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #define MAXLEN 128
12 |
13 | void cleanUp(int signum);
14 | const char sockname[] = "/tmp/my_1st_socket";
15 | int connfd;
16 | int datafd;
17 |
18 | int main(void)
19 | {
20 | int ret;
21 | struct sockaddr_un addr;
22 | char buffer[MAXLEN];
23 | struct sigaction action;
24 | /* prepare for sigaction */
25 | action.sa_handler = cleanUp;
26 | sigfillset(&action.sa_mask);
27 | action.sa_flags = SA_RESTART;
28 | /* register the signals we want to handle */
29 | sigaction(SIGTERM, &action, NULL);
30 | sigaction(SIGINT, &action, NULL);
31 | sigaction(SIGQUIT, &action, NULL);
32 | sigaction(SIGABRT, &action, NULL);
33 | sigaction(SIGPIPE, &action, NULL);
34 |
35 | /* create socket file descriptor */
36 | connfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
37 | if ( connfd == -1 )
38 | {
39 | perror("Create socket failed");
40 | return 1;
41 | }
42 | /* set address family and socket path */
43 | addr.sun_family = AF_UNIX;
44 | strcpy(addr.sun_path, sockname);
45 | /* bind the socket (we must cast our sockaddr_un
46 | * to sockaddr) */
47 | if ( (bind(connfd, (const struct sockaddr*)&addr,
48 | sizeof(struct sockaddr_un))) == -1 )
49 | {
50 | perror("Binding socket failed");
51 | return 1;
52 | }
53 | /* prepare for accepting connections */
54 | if ( (listen(connfd, 20)) == -1 )
55 | {
56 | perror("Listen error");
57 | return 1;
58 | }
59 | /* accept connection and create new file desc */
60 | datafd = accept(connfd, NULL, NULL);
61 | if (datafd == -1 )
62 | {
63 | perror("Accept error");
64 | return 1;
65 | }
66 | printf("Client connected\n");
67 | while(1) /* main loop */
68 | {
69 | while(1) /* receive message, line by line */
70 | {
71 | ret = read(datafd, buffer, MAXLEN);
72 | if ( ret == -1 )
73 | {
74 | perror("Error reading line");
75 | cleanUp(1);
76 | }
77 | else if ( ret == 0 )
78 | {
79 | printf("Client disconnected\n");
80 | cleanUp(1);
81 | }
82 | else
83 | {
84 | printf("Message: %s\n", buffer);
85 | break;
86 | }
87 | }
88 | /* write a confirmation message */
89 | write(datafd, "Message received\n", 18);
90 | }
91 | return 0;
92 | }
93 |
94 | void cleanUp(int signum)
95 | {
96 | printf("Quitting and cleaning up\n");
97 | close(connfd);
98 | close(datafd);
99 | unlink(sockname);
100 | exit(0);
101 | }
102 |
--------------------------------------------------------------------------------
/ch10/write-memory.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #define DATASIZE 128
9 |
10 | int main(void)
11 | {
12 | int fd;
13 | float *addr;
14 | const char memid[] = "/my_memory";
15 | const float numbers[3] = { 3.14, 2.718, 1.202};
16 | /* create shared memory file descriptor */
17 | if ( (fd = shm_open(memid,
18 | O_RDWR | O_CREAT, 0600)) == -1)
19 | {
20 | perror("Can't open memory fd");
21 | return 1;
22 | }
23 |
24 | /* truncate memory to DATASIZE */
25 | if ( (ftruncate(fd, DATASIZE)) == -1 )
26 | {
27 | perror("Can't truncate memory");
28 | return 1;
29 | }
30 |
31 | /* map memory using our file descriptor */
32 | addr = mmap(NULL, DATASIZE, PROT_WRITE,
33 | MAP_SHARED, fd, 0);
34 | if (addr == MAP_FAILED)
35 | {
36 | perror("Memory mapping failed");
37 | return 1;
38 | }
39 |
40 | /* copy data to memory */
41 | memcpy(addr, numbers, sizeof(numbers));
42 |
43 | /* wait for enter */
44 | printf("Hit enter when finished ");
45 | getchar();
46 | /* clean up */
47 | munmap(addr, DATASIZE);
48 | shm_unlink(memid);
49 | return 0;
50 | }
51 |
--------------------------------------------------------------------------------
/ch11/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=-Wall -Wextra -pedantic -std=c99
3 | LDFLAGS=-lpthread
4 | %: %.c
5 | $(CC) $< $(CFLAGS) -o $@ $(LDFLAGS)
6 |
--------------------------------------------------------------------------------
/ch11/cond-var.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | void *isprime(void *arg);
8 | void *progress(void *arg);
9 | pthread_mutex_t lock;
10 | pthread_cond_t ready;
11 | pthread_t primeid = 0;
12 |
13 | int main(int argc, char *argv[])
14 | {
15 | long long number1;
16 | long long number2;
17 | pthread_t tid_prime1;
18 | pthread_t tid_prime2;
19 | pthread_t tid_progress;
20 | pthread_attr_t threadattr;
21 | void *prime1Return;
22 | void *prime2Return;
23 |
24 | if ( (pthread_mutex_init(&lock, NULL)) != 0 )
25 | {
26 | fprintf(stderr,
27 | "Couldn't initialize mutex\n");
28 | return 1;
29 | }
30 |
31 | if ( (pthread_cond_init(&ready, NULL)) != 0 )
32 | {
33 | fprintf(stderr,
34 | "Couldn't initialize condition variable\n");
35 | return 1;
36 | }
37 |
38 | if ( argc != 3 )
39 | {
40 | fprintf(stderr, "Please supply two numbers.\n"
41 | "Example: %s 9 7\n", argv[0]);
42 | return 1;
43 | }
44 | number1 = atoll(argv[1]);
45 | number2 = atoll(argv[2]);
46 | pthread_attr_init(&threadattr);
47 | pthread_create(&tid_progress, &threadattr,
48 | progress, NULL);
49 | pthread_detach(tid_progress);
50 | pthread_create(&tid_prime1, &threadattr,
51 | isprime, &number1);
52 | pthread_create(&tid_prime2, &threadattr,
53 | isprime, &number2);
54 |
55 | pthread_mutex_lock(&lock);
56 | for (int i = 0; i < 2; i++)
57 | {
58 | while (primeid == 0)
59 | pthread_cond_wait(&ready, &lock);
60 | if (primeid == tid_prime1)
61 | {
62 | pthread_join(tid_prime1, &prime1Return);
63 | if ( (uintptr_t)prime1Return == 1 )
64 | printf("\n%lld is a prime number\n",
65 | number1);
66 | else
67 | printf("\n%lld is not a prime number\n",
68 | number1);
69 | primeid = 0;
70 | }
71 | else
72 | {
73 | pthread_join(tid_prime2, &prime2Return);
74 | if ( (uintptr_t)prime2Return == 1 )
75 | printf("\n%lld is a prime number\n",
76 | number2);
77 | else
78 | printf("\n%lld is not a prime number\n",
79 | number2);
80 | primeid = 0;
81 | }
82 | }
83 | pthread_mutex_unlock(&lock);
84 |
85 | pthread_attr_destroy(&threadattr);
86 | if ( pthread_cancel(tid_progress) != 0 )
87 | fprintf(stderr,
88 | "Couldn't cancel progress thread\n");
89 |
90 | return 0;
91 | }
92 |
93 | void *isprime(void *arg)
94 | {
95 | long long int number = *((long long*)arg);
96 | long long int j;
97 | int prime = 1;
98 |
99 | for(j=2; j
2 | #include
3 |
4 | void *add(void *arg);
5 | long long int i = 0;
6 | pthread_mutex_t i_mutex;
7 |
8 | int main(void)
9 | {
10 | pthread_attr_t threadattr;
11 | pthread_attr_init(&threadattr);
12 | pthread_t tid_add1, tid_add2, tid_add3,
13 | tid_add4, tid_add5;
14 |
15 | if ( (pthread_mutex_init(&i_mutex, NULL)) != 0 )
16 | {
17 | fprintf(stderr,
18 | "Couldn't initialize mutex\n");
19 | return 1;
20 | }
21 | pthread_create(&tid_add1, &threadattr,
22 | add, NULL);
23 | pthread_create(&tid_add2, &threadattr,
24 | add, NULL);
25 | pthread_create(&tid_add3, &threadattr,
26 | add, NULL);
27 | pthread_create(&tid_add4, &threadattr,
28 | add, NULL);
29 | pthread_create(&tid_add5, &threadattr,
30 | add, NULL);
31 |
32 | pthread_join(tid_add1, NULL);
33 | pthread_join(tid_add2, NULL);
34 | pthread_join(tid_add3, NULL);
35 | pthread_join(tid_add4, NULL);
36 | pthread_join(tid_add5, NULL);
37 |
38 | printf("Sum is %lld\n", i);
39 | if ( (pthread_mutex_destroy(&i_mutex)) != 0 )
40 | {
41 | fprintf(stderr, "Couldn't destroy mutex\n");
42 | return 1;
43 | }
44 | return 0;
45 | }
46 |
47 | void *add(void *arg)
48 | {
49 | long long int j = 1;
50 | while(j < 1000000000)
51 | {
52 | j = j + 1;
53 | }
54 |
55 | pthread_mutex_lock(&i_mutex);
56 | i = i + j;
57 | pthread_mutex_unlock(&i_mutex);
58 | return NULL;
59 | }
60 |
--------------------------------------------------------------------------------
/ch11/first-threaded.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | void *isprime(void *arg);
7 | void *progress(void *arg);
8 |
9 | int main(int argc, char *argv[])
10 | {
11 | long long number1;
12 | long long number2;
13 | pthread_t tid_prime1;
14 | pthread_t tid_prime2;
15 | pthread_t tid_progress;
16 | pthread_attr_t threadattr;
17 | if ( argc != 3 )
18 | {
19 | fprintf(stderr, "Please supply two numbers.\n"
20 | "Example: %s 9 7\n", argv[0]);
21 | return 1;
22 | }
23 | number1 = atoll(argv[1]);
24 | number2 = atoll(argv[2]);
25 | pthread_attr_init(&threadattr);
26 | pthread_create(&tid_progress, &threadattr,
27 | progress, NULL);
28 | pthread_detach(tid_progress);
29 | pthread_create(&tid_prime1, &threadattr,
30 | isprime, &number1);
31 | pthread_create(&tid_prime2, &threadattr,
32 | isprime, &number2);
33 | pthread_join(tid_prime1, NULL);
34 | pthread_join(tid_prime2, NULL);
35 | pthread_attr_destroy(&threadattr);
36 | if ( pthread_cancel(tid_progress) != 0 )
37 | fprintf(stderr,
38 | "Couldn't cancel progress thread\n");
39 | printf("Done!\n");
40 | return 0;
41 | }
42 |
43 | void *isprime(void *arg)
44 | {
45 | long long int number = *((long long*)arg);
46 | long long int j;
47 | int prime = 1;
48 |
49 | /* Test if the number is divisible, starting
50 | * from 2 */
51 | for(j=2; j
2 | #include
3 |
4 | void *add(void *arg);
5 | long long int i = 0;
6 | pthread_mutex_t i_mutex;
7 |
8 | int main(void)
9 | {
10 | pthread_attr_t threadattr;
11 | pthread_attr_init(&threadattr);
12 | pthread_t tid_add1, tid_add2, tid_add3,
13 | tid_add4, tid_add5;
14 |
15 | if ( (pthread_mutex_init(&i_mutex, NULL)) != 0 )
16 | {
17 | fprintf(stderr,
18 | "Couldn't initialize mutex\n");
19 | return 1;
20 | }
21 | pthread_create(&tid_add1, &threadattr,
22 | add, NULL);
23 | pthread_create(&tid_add2, &threadattr,
24 | add, NULL);
25 | pthread_create(&tid_add3, &threadattr,
26 | add, NULL);
27 | pthread_create(&tid_add4, &threadattr,
28 | add, NULL);
29 | pthread_create(&tid_add5, &threadattr,
30 | add, NULL);
31 |
32 | pthread_join(tid_add1, NULL);
33 | pthread_join(tid_add2, NULL);
34 | pthread_join(tid_add3, NULL);
35 | pthread_join(tid_add4, NULL);
36 | pthread_join(tid_add5, NULL);
37 |
38 | printf("Sum is %lld\n", i);
39 | if ( (pthread_mutex_destroy(&i_mutex)) != 0 )
40 | {
41 | fprintf(stderr, "Couldn't destroy mutex\n");
42 | return 1;
43 | }
44 | return 0;
45 | }
46 |
47 | void *add(void *arg)
48 | {
49 | for (long long int j = 1; j <= 1000000000; j++)
50 | {
51 | pthread_mutex_lock(&i_mutex);
52 | i = i + 1;
53 | pthread_mutex_unlock(&i_mutex);
54 | }
55 | return NULL;
56 | }
57 |
--------------------------------------------------------------------------------
/ch11/race.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | void *add(void *arg);
5 | long long int i = 0;
6 |
7 | int main(void)
8 | {
9 | pthread_attr_t threadattr;
10 | pthread_attr_init(&threadattr);
11 | pthread_t tid_add1, tid_add2, tid_add3,
12 | tid_add4, tid_add5;
13 |
14 | pthread_create(&tid_add1, &threadattr,
15 | add, NULL);
16 | pthread_create(&tid_add2, &threadattr,
17 | add, NULL);
18 | pthread_create(&tid_add3, &threadattr,
19 | add, NULL);
20 | pthread_create(&tid_add4, &threadattr,
21 | add, NULL);
22 | pthread_create(&tid_add5, &threadattr,
23 | add, NULL);
24 |
25 | pthread_join(tid_add1, NULL);
26 | pthread_join(tid_add2, NULL);
27 | pthread_join(tid_add3, NULL);
28 | pthread_join(tid_add4, NULL);
29 | pthread_join(tid_add5, NULL);
30 |
31 | printf("Sum is %lld\n", i);
32 | return 0;
33 | }
34 |
35 | void *add(void *arg)
36 | {
37 | for (long long int j = 1; j <= 1000000000; j++)
38 | {
39 | i = i + 1;
40 | }
41 | return NULL;
42 | }
43 |
--------------------------------------------------------------------------------
/ch11/second-threaded.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | void *isprime(void *arg);
8 | void *progress(void *arg);
9 |
10 | int main(int argc, char *argv[])
11 | {
12 | long long number1;
13 | long long number2;
14 | pthread_t tid_prime1;
15 | pthread_t tid_prime2;
16 | pthread_t tid_progress;
17 | pthread_attr_t threadattr;
18 | void *prime1Return;
19 | void *prime2Return;
20 | if ( argc != 3 )
21 | {
22 | fprintf(stderr, "Please supply two numbers.\n"
23 | "Example: %s 9 7\n", argv[0]);
24 | return 1;
25 | }
26 | number1 = atoll(argv[1]);
27 | number2 = atoll(argv[2]);
28 | pthread_attr_init(&threadattr);
29 | pthread_create(&tid_progress, &threadattr,
30 | progress, NULL);
31 | pthread_detach(tid_progress);
32 | pthread_create(&tid_prime1, &threadattr,
33 | isprime, &number1);
34 | pthread_create(&tid_prime2, &threadattr,
35 | isprime, &number2);
36 |
37 | pthread_join(tid_prime1, &prime1Return);
38 | if ( (uintptr_t)prime1Return == 1 )
39 | printf("\n%lld is a prime number\n",
40 | number1);
41 | else
42 | printf("\n%lld is not a prime number\n",
43 | number1);
44 |
45 | pthread_join(tid_prime2, &prime2Return);
46 | if ( (uintptr_t)prime2Return == 1 )
47 | printf("\n%lld is a prime number\n",
48 | number2);
49 | else
50 | printf("\n%lld is not a prime number\n",
51 | number2);
52 |
53 | pthread_attr_destroy(&threadattr);
54 | if ( pthread_cancel(tid_progress) != 0 )
55 | fprintf(stderr,
56 | "Couldn't cancel progress thread\n");
57 |
58 | return 0;
59 | }
60 |
61 | void *isprime(void *arg)
62 | {
63 | long long int number = *((long long*)arg);
64 | long long int j;
65 | int prime = 1;
66 |
67 | /* Test if the number is divisible, starting
68 | * from 2 */
69 | for(j=2; j
2 | #include
3 | float area(float radius);
4 |
5 | int main(int argc, char *argv[])
6 | {
7 | float number;
8 | float answer;
9 | if (argc != 2)
10 | {
11 | fprintf(stderr, "Type the radius of a "
12 | "circle\n");
13 | return 1;
14 | }
15 | number = atof(argv[1]);
16 | answer = area(number);
17 | printf("The area of a circle with a radius of "
18 | "%.2f is %.2f\n", number, answer);
19 | return 0;
20 | }
21 |
22 | float area(float radius)
23 | {
24 | static float pi = 3.14159;
25 | return pi*radius*radius;
26 | }
27 |
--------------------------------------------------------------------------------
/ch12/first-threaded.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | void *isprime(void *arg);
7 | void *progress(void *arg);
8 |
9 | int main(int argc, char *argv[])
10 | {
11 | long long number1;
12 | long long number2;
13 | pthread_t tid_prime1;
14 | pthread_t tid_prime2;
15 | pthread_t tid_progress;
16 | pthread_attr_t threadattr;
17 | if ( argc != 3 )
18 | {
19 | fprintf(stderr, "Please supply two numbers.\n"
20 | "Example: %s 9 7\n", argv[0]);
21 | return 1;
22 | }
23 | number1 = atoll(argv[1]);
24 | number2 = atoll(argv[2]);
25 | pthread_attr_init(&threadattr);
26 | pthread_create(&tid_progress, &threadattr,
27 | progress, NULL);
28 | pthread_create(&tid_prime1, &threadattr,
29 | isprime, &number1);
30 | pthread_create(&tid_prime2, &threadattr,
31 | isprime, &number2);
32 | pthread_join(tid_prime1, NULL);
33 | pthread_join(tid_prime2, NULL);
34 | pthread_attr_destroy(&threadattr);
35 | printf("Done!\n");
36 | return 0;
37 | }
38 |
39 | void *isprime(void *arg)
40 | {
41 | long long int number = *((long long*)arg);
42 | long long int j;
43 | int prime = 1;
44 |
45 | /* Test if the number is divisible, starting
46 | * from 2 */
47 | for(j=2; j
2 | #include
3 | #include
4 | #include
5 |
6 | int main(void)
7 | {
8 | pid_t pid;
9 | printf("My PID is %d\n", getpid());
10 | /* fork, save the PID, and check for errors */
11 | if ( (pid = fork()) == -1 )
12 | {
13 | perror("Can't fork");
14 | return 1;
15 | }
16 | if (pid == 0)
17 | {
18 | /* if pid is 0 we are in the child process */
19 | printf("Hello from the child process!\n");
20 | for(int i = 0; i<10; i++)
21 | {
22 | printf("Counter in child: %d\n", i);
23 | }
24 | }
25 | else if(pid > 0)
26 | {
27 | /* parent process */
28 | printf("My child has PID %d\n", pid);
29 | wait(&pid);
30 | }
31 | return 0;
32 | }
33 |
--------------------------------------------------------------------------------
/ch12/leak.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | int main(void)
6 | {
7 | char *c;
8 | c = calloc(sizeof(char), 20);
9 | strcpy(c, "Hello!");
10 | printf("%s\n", c);
11 | return 0;
12 | }
13 |
--------------------------------------------------------------------------------
/ch12/loop.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | int x;
6 | int y = 5;
7 | char text[20] = "Hello, world";
8 | for (x = 1; y < 100; x++)
9 | {
10 | y = (y*3)-x;
11 | }
12 | printf("%s\n", text);
13 | printf("y = %d\n", y);
14 | return 0;
15 | }
16 |
--------------------------------------------------------------------------------
/ch12/memtest.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | int main(void)
4 | {
5 | char text[20];
6 | memset(text, 'x', 20);
7 | strcpy(text, "Hello");
8 | printf("%s\n", text);
9 | return 0;
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/overflow.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | int main(void)
6 | {
7 | char *c;
8 | c = calloc(sizeof(char), 20);
9 | strcpy(c, "Hello, how are you doing?");
10 | printf("%s\n", c);
11 | free(c);
12 | return 0;
13 | }
14 |
--------------------------------------------------------------------------------
/ch2/ascii-table.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | char c;
6 | for (c = 65; c<=90; c++)
7 | {
8 | printf("%c = %d ", c, c); /* upper case */
9 | printf("%c = %d\n", c+32, c+32); /* lower case */
10 | }
11 | return 0;
12 | }
13 |
--------------------------------------------------------------------------------
/ch2/ascii-table.md:
--------------------------------------------------------------------------------
1 | # ASCII-table
2 |
3 | | DEC | OCT | HEX | BIN | Character |
4 | |------|------|------|----------|----------------------------|
5 | | 0 | 000 | 00 | 00000000 | NUL (null) |
6 | | 1 | 001 | 01 | 00000001 | SOH (start of heading) |
7 | | 2 | 002 | 02 | 00000010 | STX (start of text) |
8 | | 3 | 003 | 03 | 00000011 | ETX (end of text) |
9 | | 4 | 004 | 04 | 00000100 | EOT (end of transmission |
10 | | 5 | 005 | 05 | 00000101 | ENQ (enquiry) |
11 | | 6 | 006 | 06 | 00000110 | ACK (acknowledge |
12 | | 7 | 007 | 07 | 00000111 | BEL (bell) |
13 | | 8 | 010 | 08 | 00001000 | BS (backspace) |
14 | | 9 | 011 | 09 | 00001001 | HT (horzintal tab) |
15 | | 10 | 012 | 0A | 00001010 | LF (line feed / newline) |
16 | | 11 | 013 | 0B | 00001011 | VT (vertical tab) |
17 | | 12 | 014 | 0C | 00001100 | FF (form feed / new page) |
18 | | 13 | 015 | 0D | 00001101 | CR (carriage return) |
19 | | 14 | 016 | 0E | 00001110 | SO (shift out) |
20 | | 15 | 017 | 0F | 00001111 | SI (shift in) |
21 | | 16 | 020 | 10 | 00010000 | DLE (data link escape) |
22 | | 17 | 021 | 11 | 00010001 | DC1 (device control 1) |
23 | | 18 | 022 | 12 | 00010010 | DC2 (device control 2) |
24 | | 19 | 023 | 13 | 00010011 | DC3 (device control 3) |
25 | | 20 | 024 | 14 | 00010100 | DC4 (device control 4) |
26 | | 21 | 025 | 15 | 00010101 | NAK (negative acknowledge) |
27 | | 22 | 026 | 16 | 00010110 | SYN (synchrnous idle) |
28 | | 23 | 027 | 17 | 00010111 | ETB (end of trans. block) |
29 | | 24 | 030 | 18 | 00011000 | CAN (cancel) |
30 | | 25 | 031 | 19 | 00011001 | EM (end of medium) |
31 | | 26 | 032 | 1A | 00011010 | SUB (substitute) |
32 | | 27 | 033 | 1B | 00011011 | ESC (esacpe) |
33 | | 28 | 034 | 1C | 00011100 | FS (file separator) |
34 | | 29 | 035 | 1D | 00011101 | GS (group separator) |
35 | | 30 | 036 | 1E | 00011110 | RS (record separator) |
36 | | 31 | 037 | 1F | 00011111 | US (unit separator) |
37 | | 32 | 040 | 20 | 00100000 | (space) |
38 | | 33 | 041 | 21 | 00100001 | ! |
39 | | 34 | 042 | 22 | 00100010 | " |
40 | | 35 | 043 | 23 | 00100011 | # |
41 | | 36 | 044 | 24 | 00100100 | $ |
42 | | 37 | 045 | 25 | 00100101 | % |
43 | | 38 | 046 | 26 | 00100110 | & |
44 | | 39 | 047 | 27 | 00100111 | ' |
45 | | 40 | 050 | 28 | 00101000 | ( |
46 | | 41 | 051 | 29 | 00101001 | ) |
47 | | 42 | 052 | 2A | 00101010 | * |
48 | | 43 | 053 | 2B | 00101011 | + |
49 | | 44 | 054 | 2C | 00101100 | , |
50 | | 45 | 055 | 2D | 00101101 | - |
51 | | 46 | 056 | 2E | 00101110 | . |
52 | | 47 | 057 | 2F | 00101111 | / |
53 | | 48 | 060 | 30 | 00110000 | 0 |
54 | | 49 | 061 | 31 | 00110001 | 1 |
55 | | 50 | 062 | 32 | 00110010 | 2 |
56 | | 51 | 063 | 33 | 00110011 | 3 |
57 | | 52 | 064 | 34 | 00110100 | 4 |
58 | | 53 | 065 | 35 | 00110101 | 5 |
59 | | 54 | 066 | 36 | 00110110 | 6 |
60 | | 55 | 067 | 37 | 00110111 | 7 |
61 | | 56 | 070 | 38 | 00111000 | 8 |
62 | | 57 | 071 | 39 | 00111001 | 9 |
63 | | 58 | 072 | 3A | 00111010 | : |
64 | | 59 | 073 | 3B | 00111011 | ; |
65 | | 60 | 074 | 3C | 00111100 | < |
66 | | 61 | 075 | 3D | 00111101 | = |
67 | | 62 | 076 | 3E | 00111110 | > |
68 | | 63 | 077 | 3F | 00111111 | ? |
69 | | 64 | 100 | 40 | 01000000 | @ |
70 | | 65 | 101 | 41 | 01000001 | A |
71 | | 66 | 102 | 42 | 01000010 | B |
72 | | 67 | 103 | 43 | 01000011 | C |
73 | | 68 | 104 | 44 | 01000100 | D |
74 | | 69 | 105 | 45 | 01000101 | E |
75 | | 70 | 106 | 46 | 01000110 | F |
76 | | 71 | 107 | 47 | 01000111 | G |
77 | | 72 | 110 | 48 | 01001000 | H |
78 | | 73 | 111 | 49 | 01001001 | I |
79 | | 74 | 112 | 4A | 01001010 | J |
80 | | 75 | 113 | 4B | 01001011 | K |
81 | | 76 | 114 | 4C | 01001100 | L |
82 | | 77 | 115 | 4D | 01001101 | M |
83 | | 78 | 116 | 4E | 01001110 | N |
84 | | 79 | 117 | 4F | 01001111 | O |
85 | | 80 | 120 | 50 | 01010000 | P |
86 | | 81 | 121 | 51 | 01010001 | Q |
87 | | 82 | 122 | 52 | 01010010 | R |
88 | | 83 | 123 | 53 | 01010011 | S |
89 | | 84 | 124 | 54 | 01010100 | T |
90 | | 85 | 125 | 55 | 01010101 | U |
91 | | 86 | 126 | 56 | 01010110 | V |
92 | | 87 | 127 | 57 | 01010111 | W |
93 | | 88 | 130 | 58 | 01011000 | X |
94 | | 89 | 131 | 59 | 01011001 | Y |
95 | | 90 | 132 | 5A | 01011010 | Z |
96 | | 91 | 133 | 5B | 01011011 | \[ |
97 | | 92 | 134 | 5C | 01011100 | \\ |
98 | | 93 | 135 | 5D | 01011101 | \] |
99 | | 94 | 136 | 5E | 01011110 | ^ |
100 | | 95 | 137 | 5F | 01011111 | _ |
101 | | 96 | 140 | 60 | 01100000 | ` |
102 | | 97 | 141 | 61 | 01100001 | a |
103 | | 98 | 142 | 62 | 01100010 | b |
104 | | 99 | 143 | 63 | 01100011 | c |
105 | | 100 | 144 | 64 | 01100100 | d |
106 | | 101 | 145 | 65 | 01100101 | e |
107 | | 102 | 146 | 66 | 01100110 | f |
108 | | 103 | 147 | 67 | 01100111 | g |
109 | | 104 | 150 | 68 | 01101000 | h |
110 | | 105 | 151 | 69 | 01101001 | i |
111 | | 106 | 152 | 6A | 01101010 | j |
112 | | 107 | 153 | 6B | 01101011 | k |
113 | | 108 | 154 | 6C | 01101100 | l |
114 | | 109 | 155 | 6D | 01101101 | m |
115 | | 110 | 156 | 6E | 01101110 | n |
116 | | 111 | 157 | 6F | 01101111 | o |
117 | | 112 | 160 | 70 | 01110000 | p |
118 | | 113 | 161 | 71 | 01110001 | q |
119 | | 114 | 162 | 72 | 01110010 | r |
120 | | 115 | 163 | 73 | 01110011 | s |
121 | | 116 | 164 | 74 | 01110100 | t |
122 | | 117 | 165 | 75 | 01110101 | u |
123 | | 118 | 166 | 76 | 01110110 | v |
124 | | 119 | 167 | 77 | 01110111 | w |
125 | | 120 | 170 | 78 | 01111000 | x |
126 | | 121 | 171 | 79 | 01111001 | y |
127 | | 122 | 172 | 7A | 01111010 | z |
128 | | 123 | 173 | 7B | 01111011 | { |
129 | | 124 | 174 | 7C | 01111100 | \| |
130 | | 125 | 175 | 7D | 01111101 | } |
131 | | 126 | 176 | 7E | 01111110 | ~ |
132 | | 127 | 177 | 7F | 01111111 | DEL (delete) |
133 |
--------------------------------------------------------------------------------
/ch2/avg-with-garbage.txt:
--------------------------------------------------------------------------------
1 | 10-minute average: 61 mph
2 | 30-minute average: 55 mph
3 | 45-minute average: 54 mph
4 | 60-minute average: 52 mph
5 | 90-minute average: 52 mph
6 | 99-minute average: nn mph
7 | 120-minute average: 49 mph
8 | 160-minute average: 47 mph
9 | 180-minute average: nn mph
10 | error reading data from interface
11 | 200-minute average: 43 mph
12 |
--------------------------------------------------------------------------------
/ch2/avg.txt:
--------------------------------------------------------------------------------
1 | 10-minute average: 61 mph
2 | 30-minute average: 55 mph
3 | 45-minute average: 54 mph
4 | 60-minute average: 52 mph
5 | 90-minute average: 52 mph
6 | 99-minute average: nn mph
7 |
--------------------------------------------------------------------------------
/ch2/case-changer.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(void)
5 | {
6 | char c[20] = { 0 };
7 | char newcase[20] = { 0 };
8 | int i;
9 | while(fgets(c, sizeof(c), stdin) != NULL)
10 | {
11 | for(i=0; i<=sizeof(c); i++)
12 | {
13 | /* Upper case to lower case */
14 | if ( (c[i] >= 65) && (c[i] <= 90) )
15 | {
16 | newcase[i] = c[i] + 32;
17 | }
18 | /* Lower case to upper case */
19 | if ( (c[i] >= 97 && c[i] <= 122) )
20 | {
21 | newcase[i] = c[i] - 32;
22 | }
23 | }
24 | printf("%s\n", newcase);
25 | /* zero out the arrays so there are no
26 | left-overs in the next run */
27 | memset(c, 0, sizeof(c));
28 | memset(newcase, 0, sizeof(newcase));
29 | }
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/ch2/env-var-set.c:
--------------------------------------------------------------------------------
1 | #define _POSIX_C_SOURCE 200112L
2 | #include
3 | #include
4 |
5 | int main(void)
6 | {
7 | setenv("FULLNAME", "Jack-Benny", 1);
8 | printf("Your full name is %s\n", getenv("FULLNAME"));
9 | return 0;
10 | }
11 |
--------------------------------------------------------------------------------
/ch2/env-var.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | int main(void)
6 | {
7 | /* Using getenv() to fetch env. variables */
8 | printf("Your username is %s\n", getenv("USER"));
9 | printf("Your home directory is %s\n",
10 | getenv("HOME"));
11 | printf("Your preferred editor is %s\n",
12 | getenv("EDITOR"));
13 | printf("Your shell is %s\n", getenv("SHELL"));
14 |
15 | /* Check if the current terminal support colors*/
16 | if ( strstr(getenv("TERM"), "256color") )
17 | {
18 | /* Color the output with \033 + colorcode */
19 | printf("\033[0;31mYour \033[0;32mterminal "
20 | "\033[0;35msupport "
21 | "\033[0;33mcolors\033[0m\n");
22 | }
23 | else
24 | {
25 | printf("Your terminal doesn't support"
26 | " colors\n");
27 | }
28 | return 0;
29 | }
30 |
--------------------------------------------------------------------------------
/ch2/exist.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Check if the user supplied exactly one argument
4 | if [ "$#" -ne 1 ]; then
5 | echo "You must supply exactly one argument."
6 | echo "Example: $0 /etc"
7 | exit 1 # Return with value 1
8 | fi
9 |
10 | # Check if the file/directory exists
11 | test -e "$1" # Perform the actual test
12 | if [ "$?" -eq 0 ]; then
13 | echo "File or directory exists"
14 | elif [ "$?" -eq 1 ]; then
15 | echo "File or directory does not exist"
16 | exit 3 # Return with a special code so other
17 | # programs can use the value to see if a
18 | # file dosen't exist
19 | else
20 | echo "Unknown return value from test..."
21 | exit 1 # Unknown error occured, so exit with 1
22 | fi
23 | exit 0 # If the file or directory exists, we exit
24 | # with 0
25 |
26 |
--------------------------------------------------------------------------------
/ch2/functions_ver1.c:
--------------------------------------------------------------------------------
1 | #include
2 | int func1(void);
3 | int func2(void);
4 |
5 | int main(int argc, char *argv[])
6 | {
7 | printf("Inside main\n");
8 | printf("Calling function one\n");
9 | if (func1())
10 | {
11 | printf("Everything ok from function one\n");
12 | printf("Return with 0 from main - all ok\n");
13 | return 0;
14 | }
15 | else
16 | {
17 | printf("Caught an error from function one\n");
18 | printf("Return with 1 from main - error\n");
19 | return 1;
20 | }
21 | return 0; /* We shouldn't reach this, but
22 | just in case */
23 | }
24 |
25 | int func1(void)
26 | {
27 | printf("Inside function one\n");
28 | printf("Calling function two\n");
29 | if (func2())
30 | {
31 | printf("Everything ok from function two\n");
32 | return 1;
33 | }
34 | else
35 | {
36 | printf("Caught an error from function two\n");
37 | return 0;
38 | }
39 | }
40 |
41 | int func2(void)
42 | {
43 | printf("Inside function two\n");
44 | printf("Returning with 0 (error) from "
45 | "function two\n");
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/ch2/functions_ver2.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | int func1(void);
4 | int func2(void);
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | printf("Inside main\n");
9 | printf("Calling function one\n");
10 | if (func1())
11 | {
12 | printf("Everything ok from function one\n");
13 | printf("Return with 0 from main - all ok\n");
14 | return 0;
15 | }
16 | else
17 | {
18 | printf("Caught an error from funtcion one\n");
19 | printf("Return with 1 from main - error\n");
20 | return 1;
21 | }
22 | return 0; /* We shouldn't reach this, but just
23 | in case */
24 | }
25 |
26 | int func1(void)
27 | {
28 | printf("Inside function one\n");
29 | printf("Calling function two\n");
30 | if (func2())
31 | {
32 | printf("Everything ok from function two\n");
33 | exit(0);
34 | }
35 | else
36 | {
37 | printf("Caught an error from function two\n");
38 | exit(1);
39 | }
40 | }
41 |
42 | int func2(void)
43 | {
44 | printf("Inside function two\n");
45 | printf("Returning with (error) from "
46 | "function two\n");
47 | exit(1);
48 | }
49 |
--------------------------------------------------------------------------------
/ch2/mph-to-kph.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | int main(void)
6 | {
7 | char mph[10] = { 0 };
8 |
9 | while(fgets(mph, sizeof(mph), stdin) != NULL)
10 | {
11 | /* Check if mph is numeric
12 | * (and do conversion) */
13 | if( strspn(mph, "0123456789.-\n") ==
14 | strlen(mph) )
15 | {
16 | printf("%.1f\n", (atof(mph)*1.60934) );
17 | }
18 | /* If mph is NOT numeric, print error
19 | * and return */
20 | else
21 | {
22 | fprintf(stderr, "Found non-numeric"
23 | " value\n");
24 | return 1;
25 | }
26 | }
27 | return 0;
28 | }
29 |
--------------------------------------------------------------------------------
/ch2/mph-to-kph_v2.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 500
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | void printHelp(FILE *stream, char progname[]);
8 |
9 | int main(int argc, char *argv[])
10 | {
11 | char mph[10] = { 0 };
12 | int opt;
13 | int cont = 0;
14 |
15 | /* Parse command-line options */
16 | while ((opt = getopt(argc, argv, "ch")) != -1)
17 | {
18 | switch(opt)
19 | {
20 | case 'h':
21 | printHelp(stdout, argv[0]);
22 | return 0;
23 | case 'c':
24 | cont = 1;
25 | break;
26 | default:
27 | printHelp(stderr, argv[0]);
28 | return 1;
29 | }
30 | }
31 |
32 | while(fgets(mph, sizeof(mph), stdin) != NULL)
33 | {
34 | /* Check if mph is numeric
35 | * (and do conversion) */
36 | if( strspn(mph, "0123456789.-\n") ==
37 | strlen(mph) )
38 | {
39 | printf("%.1f\n", (atof(mph)*1.60934) );
40 | }
41 | /* If mph is NOT numeric, print error
42 | * and return */
43 | else
44 | {
45 | fprintf(stderr, "Found non-numeric "
46 | "value\n");
47 | if (cont == 1) /* Check if -c is set */
48 | {
49 | continue; /* Skip and continue if
50 | * -c is set */
51 | }
52 | else
53 | {
54 | return 1; /* Abort if -c is not set */
55 | }
56 | }
57 | }
58 | return 0;
59 | }
60 |
61 | void printHelp(FILE *stream, char progname[])
62 | {
63 | fprintf(stream, "%s [-c] [-h]\n", progname);
64 | fprintf(stream, " -c continues even though a non"
65 | "-numeric value was detected in the input\n"
66 | " -h print help\n");
67 | }
68 |
--------------------------------------------------------------------------------
/ch2/output.c:
--------------------------------------------------------------------------------
1 | #define _POSIX_C_SOURCE 200809L
2 | #include
3 |
4 | int main(void)
5 | {
6 | printf("A regular message on stdout\n");
7 |
8 | /* Using streams with fprintf() */
9 | fprintf(stdout, "Also a regular message on "
10 | "stdout\n");
11 | fprintf(stderr, "An error message on stderr\n");
12 |
13 | /* Using file descriptors with dprintf().
14 | * This requires _POSIX_C_SOURCE 200809L
15 | * (man 3 dprintf)*/
16 | dprintf(1, "A regular message, printed to "
17 | "fd 1\n");
18 | dprintf(2, "An error message, printed to "
19 | "fd 2\n");
20 | return 0;
21 | }
22 |
--------------------------------------------------------------------------------
/ch3/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=-Wall -Wextra -pedantic -std=c99
3 |
--------------------------------------------------------------------------------
/ch3/area/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=-std=c99 -Wall -Wextra -pedantic
3 | LIBS=-lm
4 | OBJS=area.o help.o rectangle.o triangle.o circle.o
5 | DEPS=area.h
6 | bindir=/usr/local/bin
7 |
8 | area: $(OBJS)
9 | $(CC) -o area $(OBJS) $(LIBS)
10 |
11 | area.o: $(DEPS)
12 |
13 | clean:
14 | rm area $(OBJS)
15 |
16 | install: area
17 | install -g root -o root area $(bindir)/area
18 |
19 | uninstall: $(bindir)/area
20 | rm $(bindir)/area
21 |
--------------------------------------------------------------------------------
/ch3/area/area.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 700
2 | #include
3 | #include
4 | #include "area.h"
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | int opt;
9 | /* Sanity check number of options */
10 | if (argc != 2)
11 | {
12 | printHelp(stderr, argv[0]);
13 | return 1;
14 | }
15 | /* Parse command-line options */
16 | while ((opt = getopt(argc, argv, "crth")) != -1)
17 | {
18 | switch(opt)
19 | {
20 | case 'c':
21 | if (circle() == -1)
22 | {
23 | printHelp(stderr, argv[0]);
24 | return 1;
25 | }
26 | break;
27 | case 'r':
28 | if (rectangle() == -1)
29 | {
30 | printHelp(stderr, argv[0]);
31 | return 1;
32 | }
33 | break;
34 | case 't':
35 | if (triangle() == -1)
36 | {
37 | printHelp(stderr, argv[0]);
38 | return 1;
39 | }
40 | break;
41 | case 'h':
42 | printHelp(stdout, argv[0]);
43 | return 0;
44 | default:
45 | printHelp(stderr, argv[0]);
46 | return 1;
47 | }
48 | }
49 | return 0;
50 | }
51 |
--------------------------------------------------------------------------------
/ch3/area/area.h:
--------------------------------------------------------------------------------
1 | void printHelp(FILE *stream, char progname[]);
2 | int circle(void);
3 | int rectangle(void);
4 | int triangle(void);
5 |
--------------------------------------------------------------------------------
/ch3/area/circle.c:
--------------------------------------------------------------------------------
1 | #define _XOPEN_SOURCE 700
2 | #include
3 | #include
4 |
5 | int circle(void)
6 | {
7 | float radius;
8 | printf("Enter the radius of the circle: ");
9 | if (scanf("%f", &radius))
10 | {
11 | printf("%.3f\n", M_PI*pow(radius, 2));
12 | return 1;
13 | }
14 | else
15 | {
16 | return -1;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ch3/area/help.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void printHelp(FILE *stream, char progname[])
4 | {
5 | fprintf(stream, "\nUsage: %s [-c] [-t] [-r] "
6 | "[-h]\n"
7 | "-c calculates the area of a circle\n"
8 | "-t calculates the area of a triangle\n"
9 | "-r calculates the area of a rectangle\n"
10 | "-h shows this help\n"
11 | "Example: %s -t\n"
12 | "Enter the height and width of the "
13 | "triangle: 5 9\n"
14 | "22.500\n", progname, progname);
15 | }
16 |
--------------------------------------------------------------------------------
/ch3/area/rectangle.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int rectangle(void)
4 | {
5 | float length, width;
6 | printf("Enter the length and width of "
7 | "the rectangle: ");
8 | if (scanf("%f %f", &length, &width))
9 | {
10 | printf("%.3f\n", length*width);
11 | return 1;
12 | }
13 | else
14 | {
15 | return -1;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ch3/area/triangle.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int triangle(void)
4 | {
5 | float height, width;
6 | printf("Enter the height and width of "
7 | "the triangle: ");
8 | if (scanf("%f %f", &height, &width))
9 | {
10 | printf("%.3f\n", height*width/2);
11 | return 1;
12 | }
13 | else
14 | {
15 | return -1;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ch3/circumference.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #define PI 3.14159
5 |
6 | int main(void)
7 | {
8 | char radius[20] = { 0 };
9 |
10 | while(fgets(radius, sizeof(radius), stdin)
11 | != NULL)
12 | {
13 | /* Check if radius is numeric
14 | * (and do conversion) */
15 | if( strspn(radius,"0123456789.\n") ==
16 | strlen(radius) )
17 | {
18 | printf("%.5f\n", PI*(atof(radius)*2) );
19 | }
20 | /* If radius is NOT numeric, print error
21 | * and return */
22 | else
23 | {
24 | fprintf(stderr, "Found non-numeric "
25 | "value\n");
26 | return 1;
27 | }
28 | }
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/ch3/comments.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | // A C99 comment
6 | printf("hello, world\n");
7 | return 0;
8 | }
--------------------------------------------------------------------------------
/ch3/cube/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=-Wall -Wextra -pedantic -std=c99
3 |
4 | cube: cube.h cube-prog.c cube-func.c
5 | $(CC) $(CFLAGS) -o cube cube-prog.c cube-func.c
6 |
--------------------------------------------------------------------------------
/ch3/cube/cube-func.c:
--------------------------------------------------------------------------------
1 | int cube(int n)
2 | {
3 | return n*n*n;
4 | }
5 |
--------------------------------------------------------------------------------
/ch3/cube/cube-prog.c:
--------------------------------------------------------------------------------
1 | #include "cube.h"
2 | #define NUMBER 4
3 |
4 | int main(void)
5 | {
6 | return cube(NUMBER);
7 | }
8 |
--------------------------------------------------------------------------------
/ch3/cube/cube.h:
--------------------------------------------------------------------------------
1 | int cube(int n);
2 |
--------------------------------------------------------------------------------
/ch3/for-test.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | for (int i = 10; i>0; i--)
6 | {
7 | printf("%d\n", i);
8 | }
9 | return 0;
10 | }
--------------------------------------------------------------------------------
/ch3/interest.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(void)
5 | {
6 | int years = 15; /* The number of years you will
7 | * keep the money in the bank
8 | * account */
9 | int savings = 99000; /* The inital amount */
10 | float interest = 1.5; /* The interest in % */
11 |
12 | printf("The total savings after %d years "
13 | "is %.2f\n", years,
14 | savings * pow(1+(interest/100), years));
15 | return 0;
16 | }
17 |
--------------------------------------------------------------------------------
/ch3/is-it-a-prime.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "prime.h"
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | long int num;
9 | /* Only one argument is accepted */
10 | if (argc != 2)
11 | {
12 | fprintf(stderr, "Usage: %s number\n",
13 | argv[0]);
14 | return 1;
15 | }
16 | /* Only numbers 0-9 are accepted */
17 | if ( strspn(argv[1], "0123456789") !=
18 | strlen(argv[1]) )
19 | {
20 | fprintf(stderr, "Only numeric values are "
21 | "accepted\n");
22 | return 1;
23 | }
24 | num = atol(argv[1]); /* String to long */
25 | if (isprime(num)) /* Check if num is a prime */
26 | {
27 | printf("%ld is a prime\n", num);
28 | }
29 | else
30 | {
31 | printf("%ld is not a prime\n", num);
32 | }
33 |
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/ch3/libprime.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Linux-System-Programming-Techniques/c1171207785323b14423961e935d95becab6486a/ch3/libprime.so
--------------------------------------------------------------------------------
/ch3/my-sys.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(void)
7 | {
8 | char cwd[100] = { 0 }; /* for current dir */
9 | struct sysinfo si; /* for system information */
10 |
11 | getcwd(cwd, 100); /* get current working dir */
12 | sysinfo(&si); /* get system information
13 | * (linux only) */
14 |
15 | printf("Your user ID is %d\n", getuid());
16 | printf("Your effective user ID is %d\n",
17 | geteuid());
18 | printf("Your current working directory is %s\n",
19 | cwd);
20 | printf("Your machine has %ld megabytes of "
21 | "total RAM\n", si.totalram / 1024 / 1024);
22 | printf("Your machine has %ld megabytes of "
23 | "free RAM\n", si.freeram / 1024 / 1024);
24 | printf("Currently, there are %d processes "
25 | "running\n", si.procs);
26 | printf("This process ID is %d\n", getpid());
27 | printf("The parent process ID is %d\n",
28 | getppid());
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/ch3/no-return.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | printf("Hello, world\n");
6 | }
7 |
--------------------------------------------------------------------------------
/ch3/prime.c:
--------------------------------------------------------------------------------
1 | int isprime(long int number)
2 | {
3 | long int j;
4 | int prime = 1;
5 |
6 | /* Test if the number is divisible, starting
7 | * from 2 */
8 | for(j=2; j
2 | #include
3 |
4 | int main(void)
5 | {
6 | char a[] = "Hello";
7 | char *b;
8 | b = strdup(a);
9 | printf("b = %s\n", b);
10 | return 0;
11 | }
12 |
--------------------------------------------------------------------------------
/ch3/sys-write.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | write(1, "hello, world\n", 13);
6 | return 0;
7 | }
--------------------------------------------------------------------------------
/ch3/which-c.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | #ifdef __STDC_VERSION__
6 | printf("Standard C version: %ld\n",
7 | __STDC_VERSION__);
8 | #endif
9 | #ifdef _XOPEN_SOURCE
10 | printf("XOPEN_SOURCE: %d\n",
11 | _XOPEN_SOURCE);
12 | #endif
13 | #ifdef _POSIX_C_SOURCE
14 | printf("POSIX_C_SOURCE: %ld\n",
15 | _POSIX_C_SOURCE);
16 | #endif
17 | #ifdef _GNU_SOURCE
18 | printf("GNU_SOURCE: %d\n",
19 | _GNU_SOURCE);
20 | #endif
21 | #ifdef _BSD_SOURCE
22 | printf("BSD_SOURCE: %d\n", _BSD_SOURCE);
23 | #endif
24 | #ifdef _DEFAULT_SOURCE
25 | printf("DEFAULT_SOURCE: %d\n",
26 | _DEFAULT_SOURCE);
27 | #endif
28 |
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/ch3/write-chars.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | fputs("hello, world\n", stdout);
6 | return 0;
7 | }
--------------------------------------------------------------------------------
/ch4/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=-Wall -Wextra -pedantic -std=c99
3 |
--------------------------------------------------------------------------------
/ch4/huge-test.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(void)
5 | {
6 | int number = 9999;
7 | double answer;
8 | if ( (answer = pow(number, number)) == HUGE_VAL )
9 | {
10 | fprintf(stderr, "A huge value\n");
11 | return 1;
12 | }
13 | else
14 | {
15 | printf("%lf\n", answer);
16 | }
17 | return 0;
18 | }
19 |
--------------------------------------------------------------------------------
/ch4/simple-touch-v1.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | char filename[PATH_MAX] = { 0 };
9 | if (argc != 2)
10 | {
11 | fprintf(stderr, "You must supply a filename "
12 | "as an argument\n");
13 | return 1;
14 | }
15 | strncpy(filename, argv[1], PATH_MAX-1);
16 | creat(filename, 00644);
17 | return 0;
18 | }
19 |
--------------------------------------------------------------------------------
/ch4/simple-touch-v2.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | char filename[PATH_MAX] = { 0 };
9 | if (argc != 2)
10 | {
11 | fprintf(stderr, "You must supply a filename "
12 | "as an argument\n");
13 | return 1;
14 | }
15 | strncpy(filename, argv[1], PATH_MAX-1);
16 | if ( creat(filename, 00644) == -1 )
17 | {
18 | fprintf(stderr, "Can't create file %s\n",
19 | filename);
20 | return 1;
21 | }
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/ch4/simple-touch-v3.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | char filename[PATH_MAX] = { 0 };
10 | if (argc != 2)
11 | {
12 | fprintf(stderr, "You must supply a filename "
13 | "as an argument\n");
14 | return 1;
15 | }
16 | strncpy(filename, argv[1], sizeof(filename)-1);
17 | if ( creat(filename, 00644) == -1 )
18 | {
19 | fprintf(stderr, "Can't create file %s\n",
20 | filename);
21 | if (errno == EACCES)
22 | {
23 | fprintf(stderr, "Permission denied\n");
24 | }
25 | else
26 | {
27 | fprintf(stderr, "Unknown error\n");
28 | }
29 | return 1;
30 | }
31 | return 0;
32 | }
33 |
--------------------------------------------------------------------------------
/ch4/simple-touch-v4.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | char filename[PATH_MAX] = { 0 };
10 | if (argc != 2)
11 | {
12 | fprintf(stderr, "You must supply a filename "
13 | "as an argument\n");
14 | return 1;
15 | }
16 | strncpy(filename, argv[1], sizeof(filename)-1);
17 | if ( creat(filename, 00644) == -1 )
18 | {
19 | fprintf(stderr, "Can't create file %s\n",
20 | filename);
21 | if (errno == EACCES)
22 | fprintf(stderr, "Permission denied\n");
23 | else if (errno == ENOENT)
24 | fprintf(stderr, "Parent directories does "
25 | "not exist\n");
26 | else
27 | fprintf(stderr, "Unknown error\n");
28 | return 1;
29 | }
30 | return 0;
31 | }
32 |
--------------------------------------------------------------------------------
/ch4/simple-touch-v5.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | int errornum;
10 | char filename[PATH_MAX] = { 0 };
11 | if (argc != 2)
12 | {
13 | fprintf(stderr, "You must supply a filename "
14 | "as an argument\n");
15 | return 1;
16 | }
17 | strncpy(filename, argv[1], sizeof(filename)-1);
18 | if ( creat(filename, 00644) == -1 )
19 | {
20 | errornum = errno;
21 | fprintf(stderr, "Can't create file %s\n",
22 | filename);
23 | fprintf(stderr, "%s\n", strerror(errornum));
24 | return 1;
25 | }
26 | return 0;
27 | }
28 |
--------------------------------------------------------------------------------
/ch4/simple-touch-v6.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | char filename[PATH_MAX] = { 0 };
10 | if (argc != 2)
11 | {
12 | fprintf(stderr, "You must supply a filename "
13 | "as an argument\n");
14 | return 1;
15 | }
16 | strncpy(filename, argv[1], sizeof(filename)-1);
17 | if ( creat(filename, 00644) == -1 )
18 | {
19 | perror("Can't create file");
20 | return 1;
21 | }
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/ch4/simple-touch-v7.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | char filename[PATH_MAX] = { 0 };
10 | if (argc != 2)
11 | {
12 | fprintf(stderr, "You must supply a filename "
13 | "as an argument\n");
14 | return 1;
15 | }
16 | strncpy(filename, argv[1], sizeof(filename)-1);
17 | if ( creat(filename, 00644) == -1 )
18 | {
19 | perror("Can't create file");
20 | return errno;
21 | }
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/ch4/str-safe.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | if (argc != 2)
7 | {
8 | fprintf(stderr, "Supply exactly one "
9 | "argument\n");
10 | return 1;
11 | }
12 | char buf[10] = { 0 };
13 | strncat(buf, argv[1], sizeof(buf)-1);
14 | printf("Test: %s\n", buf);
15 | return 0;
16 | }
17 |
--------------------------------------------------------------------------------
/ch4/str-unsafe.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | char buf[10] = { 0 };
7 | strcat(buf, argv[1]);
8 | printf("Test: %s\n", buf);
9 | return 0;
10 | }
11 |
--------------------------------------------------------------------------------
/ch5/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=-Wall -Wextra -pedantic -std=c99
3 |
--------------------------------------------------------------------------------
/ch5/binary-read.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | FILE *fp;
6 | float x[2];
7 | if ( (fp = fopen("my-binary-file", "rb")) == 0 )
8 | {
9 | fprintf(stderr, "Can't open file for "
10 | "reading\n");
11 | return 1;
12 | }
13 | fread(&x, sizeof(float),
14 | sizeof(x) / sizeof(float), fp);
15 | printf("The first number was: %f\n", x[0]);
16 | printf("The second number was: %f\n", x[1]);
17 | fclose(fp);
18 | return 0;
19 | }
20 |
--------------------------------------------------------------------------------
/ch5/binary-write.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | FILE *fp;
6 | float x[2];
7 | if ( (fp = fopen("my-binary-file", "wb")) == 0 )
8 | {
9 | fprintf(stderr, "Can't open file for "
10 | "writing\n");
11 | return 1;
12 | }
13 | printf("Type two floating point numbers, "
14 | "separated by a space: ");
15 | scanf("%f %f", &x[0], &x[1]);
16 | fwrite(&x, sizeof(float),
17 | sizeof(x) / sizeof(float), fp);
18 | fclose(fp);
19 | return 0;
20 | }
21 |
--------------------------------------------------------------------------------
/ch5/fd-read.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #define MAXSIZE 4096
7 |
8 | int main(int argc, char *argv[])
9 | {
10 | int fd; /* for the file descriptor */
11 | int maxread; /* the maximum we want to read*/
12 | off_t filesize; /* for the file size */
13 | struct stat fileinfo; /* struct for fstat */
14 | char rbuf[MAXSIZE] = { 0 }; /* the read buffer*/
15 |
16 | if (argc != 2)
17 | {
18 | fprintf(stderr, "Usage: %s [path]\n",
19 | argv[0]);
20 | return 1;
21 | }
22 |
23 | /* open the file in read-only mode and get
24 | the file size */
25 | if ( (fd = open(argv[1], O_RDONLY)) == -1 )
26 | {
27 | perror("Can't open file for reading");
28 | return 1;
29 | }
30 | fstat(fd, &fileinfo);
31 | filesize = fileinfo.st_size;
32 |
33 | /* determine the max size we want to read
34 | so we don't overflow the read buffer */
35 | if ( filesize >= MAXSIZE )
36 | maxread = MAXSIZE-1;
37 | else
38 | maxread = filesize;
39 |
40 | /* read the content and print it */
41 | if ( (read(fd, rbuf, maxread)) == -1 )
42 | {
43 | perror("Can't read file");
44 | return 1;
45 | }
46 | printf("%s", rbuf);
47 | return 0;
48 | }
49 |
--------------------------------------------------------------------------------
/ch5/fd-seek.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #define MAXSIZE 4096
8 |
9 | int main(int argc, char *argv[])
10 | {
11 | int fd; /* for the file descriptor */
12 | int maxread; /* the maximum we want to read*/
13 | off_t filesize; /* for the file size */
14 | struct stat fileinfo; /* struct for fstat */
15 | char rbuf[MAXSIZE] = { 0 }; /* the read buffer */
16 |
17 | if (argc < 3 || argc > 4)
18 | {
19 | fprintf(stderr, "Usage: %s [path] [from pos] "
20 | "[bytes to read]\n", argv[0]);
21 | return 1;
22 | }
23 |
24 | /* open the file in read-only mode and get
25 | the file size */
26 | if ( (fd = open(argv[1], O_RDONLY)) == -1 )
27 | {
28 | perror("Can't open file for reading");
29 | return 1;
30 | }
31 | fstat(fd, &fileinfo);
32 | filesize = fileinfo.st_size;
33 |
34 | /* determine the max size we want to read
35 | so we don't overflow the read buffer */
36 | if ( filesize >= MAXSIZE )
37 | {
38 | maxread = MAXSIZE-1;
39 | }
40 | else if ( argv[3] != NULL )
41 | {
42 | if ( atoi(argv[3]) >= MAXSIZE )
43 | {
44 | fprintf(stderr, "To big size specified\n");
45 | return 1;
46 | }
47 | maxread = atoi(argv[3]);
48 | }
49 | else
50 | {
51 | maxread = filesize;
52 | }
53 |
54 | /* move the read position */
55 | lseek(fd, atoi(argv[2]), SEEK_SET);
56 | /* read the content and print it */
57 | if ( (read(fd, rbuf, maxread)) == -1 )
58 | {
59 | perror("Can't read file");
60 | return 1;
61 | }
62 | printf("%s\n", rbuf);
63 | return 0;
64 | }
65 |
--------------------------------------------------------------------------------
/ch5/fd-write.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | int main(int argc, char *argv[])
9 | {
10 | int fd; /* for the file descriptor */
11 |
12 | if (argc != 3)
13 | {
14 | fprintf(stderr, "Usage: %s [path] [string]\n",
15 | argv[0]);
16 | return 1;
17 | }
18 |
19 | /* Open the file (argv[1]) and create it if it
20 | doesn't exist and set it in read-write mode.
21 | Set the access mode to 644 */
22 | if ( (fd = open(argv[1], O_CREAT|O_RDWR, 00644))
23 | == -1 )
24 | {
25 | perror("Can't open file for writing");
26 | return 1;
27 | }
28 | /* write content to file */
29 | if ( (write(fd, argv[2], strlen(argv[2])))
30 | == -1 )
31 | {
32 | perror("Can't write to file");
33 | return 1;
34 | }
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/ch5/my-chmod.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | void printUsage(FILE *stream, char progname[]);
7 |
8 | int main(int argc, char *argv[])
9 | {
10 | long int accessmode; /*To hold the access mode*/
11 | /* Check that the user supplied two arguments */
12 | if (argc != 3)
13 | {
14 | printUsage(stderr, argv[0]);
15 | return 1;
16 | }
17 | /* Simple check for octal numbers and
18 | correct length */
19 | if( strspn(argv[1], "01234567\n")
20 | != strlen(argv[1])
21 | || ( strlen(argv[1]) != 3 &&
22 | strlen(argv[1]) != 4 ) )
23 | {
24 | printUsage(stderr, argv[0]);
25 | return 1;
26 | }
27 | /* Convert to octal and set the permissions */
28 | accessmode = strtol(argv[1], NULL, 8);
29 | if (chmod(argv[2], accessmode) == -1)
30 | {
31 | perror("Can't change permissions");
32 | }
33 | return 0;
34 | }
35 |
36 | void printUsage(FILE *stream, char progname[])
37 | {
38 | fprintf(stream, "Usage: %s \n", progname);
40 | }
41 |
--------------------------------------------------------------------------------
/ch5/my-chown.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | int main(int argc, char *argv[])
11 | {
12 | struct passwd *user; /* struct for getpwnam */
13 | struct group *grp; /* struct for getgrnam */
14 | char *username = { 0 }; /* extracted username */
15 | char *groupname = { 0 }; /*extracted groupname*/
16 | unsigned int uid, gid; /* extracted UID/GID */
17 |
18 | /* Check that the user supplied two arguments
19 | (filename and user or user:group) */
20 | if (argc != 3)
21 | {
22 | fprintf(stderr, "Usage: %s [user][:group]"
23 | " [path]\n", argv[0]);
24 | return 1;
25 | }
26 |
27 | /* Extract username and groupname */
28 | username = strtok(argv[1], ":");
29 | groupname = strtok(NULL, ":");
30 |
31 | if ( (user = getpwnam(username)) == NULL )
32 | {
33 | fprintf(stderr, "Invalid username\n");
34 | return 1;
35 | }
36 | uid = user->pw_uid; /* get the UID */
37 |
38 | if (groupname != NULL) /* if we typed a group */
39 | {
40 | if ( (grp = getgrnam(groupname)) == NULL )
41 | {
42 | fprintf(stderr, "Invalid groupname\n");
43 | return 1;
44 | }
45 | gid = grp->gr_gid; /* get the GID */
46 | }
47 | else
48 | {
49 | /* if no group is specifed, -1 won't change
50 | it (man 2 chown) */
51 | gid = -1;
52 | }
53 |
54 | /* update user/group (argv[2] is the filename)*/
55 | if ( chown(argv[2], uid, gid) == -1 )
56 | {
57 | perror("Can't change owner/group");
58 | return 1;
59 | }
60 | return 0;
61 | }
62 |
--------------------------------------------------------------------------------
/ch5/my-stat-v1.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 filestat;
11 | if ( argc != 2 )
12 | {
13 | fprintf(stderr, "Usage: %s \n",
14 | argv[0]);
15 | return 1;
16 | }
17 | if ( stat(argv[1], &filestat) == -1 )
18 | {
19 | fprintf(stderr, "Can't read file %s: %s\n",
20 | argv[1], strerror(errno));
21 | return errno;
22 | }
23 | printf("Inode: %lu\n", filestat.st_ino);
24 | printf("Size: %zd\n", filestat.st_size);
25 | printf("Links: %lu\n", filestat.st_nlink);
26 | return 0;
27 | }
28 |
--------------------------------------------------------------------------------
/ch5/my-stat-v2.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include