├── .gitignore ├── tlpi-dist ├── lib │ ├── semun.h │ ├── pty_fork.c │ ├── pty_fork.h │ ├── rdwrn.c │ ├── rdwrn.h │ ├── signal.c │ ├── curr_time.c │ ├── curr_time.h │ ├── file_perms.c │ ├── file_perms.h │ ├── read_line.c │ ├── read_line.h │ ├── binary_sems.c │ ├── binary_sems.h │ ├── event_flags.c │ ├── event_flags.h │ ├── inet_sockets.c │ ├── inet_sockets.h │ ├── print_rlimit.c │ ├── print_rlimit.h │ ├── print_rusage.c │ ├── print_rusage.h │ ├── tty_functions.c │ ├── tty_functions.h │ ├── unix_sockets.c │ ├── unix_sockets.h │ ├── become_daemon.c │ ├── become_daemon.h │ ├── pty_master_open.c │ ├── pty_master_open.h │ ├── read_line_buf.c │ ├── read_line_buf.h │ ├── region_locking.c │ ├── region_locking.h │ ├── create_pid_file.c │ ├── create_pid_file.h │ ├── signal_functions.c │ ├── signal_functions.h │ ├── ugid_functions.c │ ├── ugid_functions.h │ ├── itimerspec_from_str.c │ ├── itimerspec_from_str.h │ ├── print_wait_status.c │ ├── print_wait_status.h │ ├── libtlpi.a │ ├── README │ └── Makefile ├── shlibs │ ├── g │ │ ├── sv_v1.map │ │ ├── vis.map │ │ ├── sv_v2.map │ │ ├── vis_build.sh │ │ ├── sv_build.sh │ │ ├── sv_lib_v1.c │ │ ├── vis_f1.c │ │ ├── vis_f2.c │ │ ├── vis_comm.c │ │ ├── sv_prog.c │ │ ├── sv_libabc.c │ │ ├── sv_prog_abc.c │ │ └── sv_lib_v2.c │ ├── version_scripts │ │ ├── sv_v1.map │ │ ├── vis.map │ │ ├── sv_v2.map │ │ ├── sv_build.sh │ │ ├── vis_build.sh │ │ ├── sv_lib_v1.c │ │ ├── vis_f1.c │ │ ├── vis_f2.c │ │ ├── vis_comm.c │ │ ├── sv_prog.c │ │ ├── sv_libabc.c │ │ ├── sv_prog_abc.c │ │ └── sv_lib_v2.c │ ├── Demo_no_lib.sh │ ├── Demo_static_lib.sh │ ├── demo_Bsymbolic │ │ ├── build.sh │ │ ├── foo3.c │ │ ├── prog.c │ │ ├── foo1.c │ │ └── foo2.c │ ├── Makefile │ ├── Demo_shared_lib.sh │ ├── rpath_demo │ │ ├── d1 │ │ │ └── modx1.c │ │ └── d2 │ │ │ └── modx2.c │ ├── prog.c │ ├── mod1.c │ ├── mod2.c │ └── mod3.c ├── procexec │ ├── longest_line.awk │ ├── Makefile │ ├── fork_whos_on_first.count.awk │ ├── print_wait_status.h │ ├── necho.c │ ├── fork_stdio_buf.c │ └── t_execlp.c ├── filelock │ ├── Makefile │ ├── create_pid_file.h │ └── region_locking.h ├── proccred │ └── Makefile ├── getopt │ └── Makefile ├── pty │ ├── Makefile │ ├── pty_master_open.h │ └── pty_fork.h ├── memalloc │ └── Makefile ├── progconc │ └── Makefile ├── daemons │ ├── Makefile │ └── test_become_daemon.c ├── syslim │ └── Makefile ├── xattr │ └── Makefile ├── svipc │ └── Makefile ├── tty │ ├── Makefile │ └── tty_functions.h ├── procres │ ├── Makefile │ ├── print_rlimit.h │ └── print_rusage.h ├── filesys │ └── Makefile ├── sysinfo │ └── Makefile ├── vmem │ └── Makefile ├── loginacct │ └── Makefile ├── files │ ├── Makefile │ └── file_perms.h ├── mmap │ └── Makefile ├── altio │ └── Makefile ├── pgsjc │ └── Makefile ├── Makefile.inc.MacOSX ├── inotify │ └── Makefile ├── svsem │ └── Makefile ├── Makefile.inc.FreeBSD ├── proc │ ├── Makefile │ ├── necho.c │ ├── display_env.c │ └── t_getenv.c ├── fileio │ └── Makefile ├── dirs_links │ └── Makefile ├── Makefile.inc.Tru64 ├── pipes │ └── Makefile ├── acl │ └── Makefile ├── procpri │ └── Makefile ├── cap │ └── Makefile ├── users_groups │ ├── Makefile │ ├── ugid_functions.h │ └── t_getpwent.c ├── Makefile.inc.Solaris ├── seccomp │ └── Makefile ├── svshm │ └── Makefile ├── pshm │ ├── Makefile │ └── pshm_unlink.c ├── svmsg │ └── Makefile ├── time │ ├── Makefile │ └── curr_time.h ├── Makefile.inc.HP-UX ├── pmsg │ ├── Makefile │ └── pmsg_unlink.c ├── timers │ ├── Makefile │ └── itimerspec_from_str.h ├── sockets │ ├── README │ ├── read_line.h │ ├── us_xfr_v2.h │ ├── rdwrn.h │ ├── scm_rights.h │ ├── id_echo.h │ ├── scm_cred.h │ ├── i6d_ucase.h │ ├── Makefile │ ├── is_seqnum.h │ └── unix_sockets.h ├── psem │ └── Makefile ├── filebuff │ └── Makefile ├── threads │ └── Makefile ├── signals │ └── signal_functions.h ├── namespaces │ └── Makefile └── Makefile.inc ├── chapter-27 ├── example │ ├── t_execlp.c │ ├── t_execl.c │ ├── envargs.c │ ├── t_execle.c │ ├── closeonexec.c │ ├── simple_system.c │ └── t_system.c └── exercise │ ├── 27-3.md │ ├── 27-5.md │ ├── 27-1.md │ ├── test.c │ └── 27-6.c ├── chapter-34 ├── exercise │ ├── 34-1.md │ ├── 34-2.c │ └── 34-3.c └── example │ ├── setsid.c │ └── catch_SIGHUP.c ├── chapter-6 ├── example │ ├── display_env.c │ ├── modify_env.c │ ├── longjmp.c │ └── setjmp_vars.c └── exercise │ └── mem_segments.c ├── chapter-25 ├── example │ ├── fork_stdio_buf.c │ └── exit_handlers.c └── exercise │ └── 25-1.c ├── chapter-18 ├── exercise │ ├── 18-1.md │ ├── 18-7.c │ └── 18-2.md └── example │ ├── t_dirbasename.c │ ├── view_symlink.c │ └── t_unlink.c ├── chapter-28 ├── example │ └── acct_on.c └── exercise │ └── 28-1.c ├── .vscode ├── settings.json ├── tasks.json └── launch.json ├── chapter-41 └── exercise │ └── 41-1.md ├── chapter-20 ├── exercise │ ├── 20-4.c │ ├── 20-3.c │ └── 20-2.c └── example │ ├── ouch.c │ ├── intquit.c │ ├── sig_sender.c │ ├── t_kill.c │ └── signal_functions.h ├── chapter-5 ├── example │ ├── fcntl_F_GETFLL.c │ ├── large_file.c │ ├── t_readv.c │ └── bad_exclusive_open.c ├── relationshipBetweenFdAndOpenFile.md └── exercise │ ├── 5-6.c │ ├── 5-2.c │ └── 5-4.c ├── chapter-46 └── example │ ├── svmsg_rm.c │ ├── svmsg_chqbytes.c │ └── svmsg_send.c ├── chapter-38 └── exercise │ └── 38-1.md ├── chapter-10 ├── exercise │ └── 10-1.md └── example │ ├── curr_time.h │ ├── show_time.c │ └── strtime.c ├── chapter-23 ├── exercise │ └── 23-1.c └── example │ └── timed_read.c ├── chapter-36 ├── exercise │ ├── 36-3.c │ └── 36-1.c └── example │ ├── print_rlimit.h │ └── rlimit_nproc.c ├── chapter-44 └── example │ ├── fifo_seqnum.h │ └── pipe_sync.c ├── chapter-40 ├── exercise │ ├── 40-4.c │ └── 40-1.c └── example │ └── view_lastlog.c ├── chapter-8 └── exercise │ └── 8-1.md ├── chapter-24 ├── example │ ├── t_vfork.c │ ├── t_fork.c │ └── fork_whos_on_first.c └── exercise │ └── 24-2.c ├── chapter-31 └── example │ ├── strerror.c │ ├── strerror_tls.c │ └── strerror_test.c ├── chapter-15 ├── exercise │ ├── 15-5.c │ ├── 15-6.c │ └── 15-4.c └── example │ └── file_perms.c ├── chapter-22 ├── example │ ├── signal.c │ ├── t_sigqueue.c │ └── signalfd_sigval.c └── exercise │ └── 22-1.c ├── chapter-12 └── example │ ├── t_uname.c │ └── procfs_pidmax.c ├── chapter-29 ├── exercise │ ├── 29-2.md │ └── 29-1.c └── example │ └── simple_thread.c ├── chapter-35 ├── exercise │ ├── 35-2.c │ └── 35-1.c └── example │ ├── sched_set.c │ ├── t_setpriority.c │ └── sched_view.c ├── chapter-4 ├── example │ ├── strange_str.c │ └── copy.c └── exercise │ └── mycp.c ├── chapter-11 └── example │ ├── t_fpathconf.c │ └── t_sysconf.c ├── chapter-42 ├── example │ └── dynload.c └── exercise │ ├── 42-1.c │ └── 42-2.c ├── chapter-16 └── exercise │ └── 16-1.c ├── chapter-21 └── example │ ├── abort_test.c │ └── nonreentrant.c ├── chapter-45 ├── exercise │ ├── 45-1.c │ └── 45-2.c └── example │ └── svmsg_demo_server.c ├── chapter-32 └── example │ └── thread_cancel.c ├── chapter-26 └── example │ ├── make_zombie.c │ ├── print_wait_status.h │ └── child_status.c ├── chapter-30 └── example │ └── thread_incr.c ├── chapter-13 └── example │ └── direct_read.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | a.out -------------------------------------------------------------------------------- /tlpi-dist/lib/semun.h: -------------------------------------------------------------------------------- 1 | ../svsem/semun.h -------------------------------------------------------------------------------- /tlpi-dist/lib/pty_fork.c: -------------------------------------------------------------------------------- 1 | ../pty/pty_fork.c -------------------------------------------------------------------------------- /tlpi-dist/lib/pty_fork.h: -------------------------------------------------------------------------------- 1 | ../pty/pty_fork.h -------------------------------------------------------------------------------- /tlpi-dist/lib/rdwrn.c: -------------------------------------------------------------------------------- 1 | ../sockets/rdwrn.c -------------------------------------------------------------------------------- /tlpi-dist/lib/rdwrn.h: -------------------------------------------------------------------------------- 1 | ../sockets/rdwrn.h -------------------------------------------------------------------------------- /tlpi-dist/lib/signal.c: -------------------------------------------------------------------------------- 1 | ../signals/signal.c -------------------------------------------------------------------------------- /tlpi-dist/lib/curr_time.c: -------------------------------------------------------------------------------- 1 | ../time/curr_time.c -------------------------------------------------------------------------------- /tlpi-dist/lib/curr_time.h: -------------------------------------------------------------------------------- 1 | ../time/curr_time.h -------------------------------------------------------------------------------- /tlpi-dist/lib/file_perms.c: -------------------------------------------------------------------------------- 1 | ../files/file_perms.c -------------------------------------------------------------------------------- /tlpi-dist/lib/file_perms.h: -------------------------------------------------------------------------------- 1 | ../files/file_perms.h -------------------------------------------------------------------------------- /tlpi-dist/lib/read_line.c: -------------------------------------------------------------------------------- 1 | ../sockets/read_line.c -------------------------------------------------------------------------------- /tlpi-dist/lib/read_line.h: -------------------------------------------------------------------------------- 1 | ../sockets/read_line.h -------------------------------------------------------------------------------- /tlpi-dist/lib/binary_sems.c: -------------------------------------------------------------------------------- 1 | ../svsem/binary_sems.c -------------------------------------------------------------------------------- /tlpi-dist/lib/binary_sems.h: -------------------------------------------------------------------------------- 1 | ../svsem/binary_sems.h -------------------------------------------------------------------------------- /tlpi-dist/lib/event_flags.c: -------------------------------------------------------------------------------- 1 | ../svsem/event_flags.c -------------------------------------------------------------------------------- /tlpi-dist/lib/event_flags.h: -------------------------------------------------------------------------------- 1 | ../svsem/event_flags.h -------------------------------------------------------------------------------- /tlpi-dist/lib/inet_sockets.c: -------------------------------------------------------------------------------- 1 | ../sockets/inet_sockets.c -------------------------------------------------------------------------------- /tlpi-dist/lib/inet_sockets.h: -------------------------------------------------------------------------------- 1 | ../sockets/inet_sockets.h -------------------------------------------------------------------------------- /tlpi-dist/lib/print_rlimit.c: -------------------------------------------------------------------------------- 1 | ../procres/print_rlimit.c -------------------------------------------------------------------------------- /tlpi-dist/lib/print_rlimit.h: -------------------------------------------------------------------------------- 1 | ../procres/print_rlimit.h -------------------------------------------------------------------------------- /tlpi-dist/lib/print_rusage.c: -------------------------------------------------------------------------------- 1 | ../procres/print_rusage.c -------------------------------------------------------------------------------- /tlpi-dist/lib/print_rusage.h: -------------------------------------------------------------------------------- 1 | ../procres/print_rusage.h -------------------------------------------------------------------------------- /tlpi-dist/lib/tty_functions.c: -------------------------------------------------------------------------------- 1 | ../tty/tty_functions.c -------------------------------------------------------------------------------- /tlpi-dist/lib/tty_functions.h: -------------------------------------------------------------------------------- 1 | ../tty/tty_functions.h -------------------------------------------------------------------------------- /tlpi-dist/lib/unix_sockets.c: -------------------------------------------------------------------------------- 1 | ../sockets/unix_sockets.c -------------------------------------------------------------------------------- /tlpi-dist/lib/unix_sockets.h: -------------------------------------------------------------------------------- 1 | ../sockets/unix_sockets.h -------------------------------------------------------------------------------- /tlpi-dist/lib/become_daemon.c: -------------------------------------------------------------------------------- 1 | ../daemons/become_daemon.c -------------------------------------------------------------------------------- /tlpi-dist/lib/become_daemon.h: -------------------------------------------------------------------------------- 1 | ../daemons/become_daemon.h -------------------------------------------------------------------------------- /tlpi-dist/lib/pty_master_open.c: -------------------------------------------------------------------------------- 1 | ../pty/pty_master_open.c -------------------------------------------------------------------------------- /tlpi-dist/lib/pty_master_open.h: -------------------------------------------------------------------------------- 1 | ../pty/pty_master_open.h -------------------------------------------------------------------------------- /tlpi-dist/lib/read_line_buf.c: -------------------------------------------------------------------------------- 1 | ../sockets/read_line_buf.c -------------------------------------------------------------------------------- /tlpi-dist/lib/read_line_buf.h: -------------------------------------------------------------------------------- 1 | ../sockets/read_line_buf.h -------------------------------------------------------------------------------- /tlpi-dist/lib/region_locking.c: -------------------------------------------------------------------------------- 1 | ../filelock/region_locking.c -------------------------------------------------------------------------------- /tlpi-dist/lib/region_locking.h: -------------------------------------------------------------------------------- 1 | ../filelock/region_locking.h -------------------------------------------------------------------------------- /tlpi-dist/lib/create_pid_file.c: -------------------------------------------------------------------------------- 1 | ../filelock/create_pid_file.c -------------------------------------------------------------------------------- /tlpi-dist/lib/create_pid_file.h: -------------------------------------------------------------------------------- 1 | ../filelock/create_pid_file.h -------------------------------------------------------------------------------- /tlpi-dist/lib/signal_functions.c: -------------------------------------------------------------------------------- 1 | ../signals/signal_functions.c -------------------------------------------------------------------------------- /tlpi-dist/lib/signal_functions.h: -------------------------------------------------------------------------------- 1 | ../signals/signal_functions.h -------------------------------------------------------------------------------- /tlpi-dist/lib/ugid_functions.c: -------------------------------------------------------------------------------- 1 | ../users_groups/ugid_functions.c -------------------------------------------------------------------------------- /tlpi-dist/lib/ugid_functions.h: -------------------------------------------------------------------------------- 1 | ../users_groups/ugid_functions.h -------------------------------------------------------------------------------- /tlpi-dist/lib/itimerspec_from_str.c: -------------------------------------------------------------------------------- 1 | ../timers/itimerspec_from_str.c -------------------------------------------------------------------------------- /tlpi-dist/lib/itimerspec_from_str.h: -------------------------------------------------------------------------------- 1 | ../timers/itimerspec_from_str.h -------------------------------------------------------------------------------- /tlpi-dist/lib/print_wait_status.c: -------------------------------------------------------------------------------- 1 | ../procexec/print_wait_status.c -------------------------------------------------------------------------------- /tlpi-dist/lib/print_wait_status.h: -------------------------------------------------------------------------------- 1 | ../procexec/print_wait_status.h -------------------------------------------------------------------------------- /tlpi-dist/lib/libtlpi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyyzero/tlpi/HEAD/tlpi-dist/lib/libtlpi.a -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_v1.map: -------------------------------------------------------------------------------- 1 | VER_1 { 2 | global: xyz; 3 | local: *; # Hide all other symbols 4 | }; 5 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/vis.map: -------------------------------------------------------------------------------- 1 | VER_1 { 2 | global: 3 | vis_f1; 4 | vis_f2; 5 | local: 6 | *; 7 | }; 8 | -------------------------------------------------------------------------------- /tlpi-dist/procexec/longest_line.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | length > max { max = length; } 3 | END { print max; } 4 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_v1.map: -------------------------------------------------------------------------------- 1 | VER_1 { 2 | global: xyz; 3 | local: *; # Hide all other symbols 4 | }; 5 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/vis.map: -------------------------------------------------------------------------------- 1 | VER_1 { 2 | global: 3 | vis_f1; 4 | vis_f2; 5 | local: 6 | *; 7 | }; 8 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_v2.map: -------------------------------------------------------------------------------- 1 | VER_1 { 2 | global: xyz; 3 | local: *; # Hide all other symbols 4 | }; 5 | 6 | VER_2 { 7 | global: pqr; 8 | } VER_1; 9 | 10 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_v2.map: -------------------------------------------------------------------------------- 1 | VER_1 { 2 | global: xyz; 3 | local: *; # Hide all other symbols 4 | }; 5 | 6 | VER_2 { 7 | global: pqr; 8 | } VER_1; 9 | -------------------------------------------------------------------------------- /chapter-27/example/t_execlp.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | execlp(argv[1], argv[1], "Hello world", NULL); 6 | errExit("execlp"); 7 | } -------------------------------------------------------------------------------- /chapter-34/exercise/34-1.md: -------------------------------------------------------------------------------- 1 | 如果使用了 `shell` 管道,那么创建的进程会放在一个进程组,进程组的其他进程可能会收到发送 `SIGUSR1` 信号,然后调用处理函数。 2 | 3 | 解决方案是先使用 `setpgid()` 确保子进程会被放置在自己的新组中(第一个子进程的进程 `ID` 可以用作组的进程 `ID`),然后向改进程组发送信号。 -------------------------------------------------------------------------------- /tlpi-dist/shlibs/Demo_no_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Build a program without using libraries 4 | 5 | cc -c -g prog.c mod1.c mod2.c mod3.c 6 | cc -g -o prog_nolib prog.o mod1.o mod2.o mod3.o 7 | -------------------------------------------------------------------------------- /chapter-6/example/display_env.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | extern char **environ; 4 | 5 | int main(int argc, char **argv) 6 | { 7 | char **ep; 8 | 9 | for (ep = environ; *ep != NULL; ++ep) 10 | puts(*ep); 11 | 12 | exit(EXIT_SUCCESS); 13 | } -------------------------------------------------------------------------------- /chapter-27/exercise/27-3.md: -------------------------------------------------------------------------------- 1 | > 27-3 What output would we see if we make the following script executable and exec() it? 2 | 3 | ``` 4 | #!/bin/cat -n 5 | Hello world 6 | ``` 7 | 8 | --- 9 | 10 | 将会输出: 11 | 12 | ``` 13 | 1 #!/bin/cat -n 14 | 2 Hello world 15 | ``` -------------------------------------------------------------------------------- /chapter-25/example/fork_stdio_buf.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | printf("Hello world\n"); 6 | write(STDOUT_FILENO, "Giao\n", 5); 7 | 8 | if (fork() == -1) 9 | errExit("fork"); 10 | exit(EXIT_SUCCESS); 11 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/Demo_static_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Build a program using a static library 3 | # 4 | 5 | cc -g -c mod1.c mod2.c mod3.c 6 | ar r libdemo.a mod1.o mod2.o mod3.o 7 | 8 | cc -g -o prog_static prog.c libdemo.a 9 | # Or: cc -g -o prog_static prog.c -L. -ldemo 10 | -------------------------------------------------------------------------------- /chapter-18/exercise/18-1.md: -------------------------------------------------------------------------------- 1 | 正常来说按写模式打开一个正在执行的可执行文件是会失败的(`open()`调用返回-1,且将`errno`置为`ETXTBSY`)。但是是可以"覆盖"。比如说以下的执行就会成功: 2 | 3 | ```shell 4 | $ cc -o longrunner longrnnner.c 5 | $ ./longrnner & 6 | $ vi longrunner.c 7 | $ cc -o longrunner longrunner.c 8 | ``` 9 | 10 | 每次用 `ls -il` 命令查看后就会发现,编译出来的新的可执行文件文件有了的新的i节点,而不会直接覆盖原文件的i-node编号。 11 | -------------------------------------------------------------------------------- /chapter-28/example/acct_on.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | if (acct(argv[1]) == -1) 8 | errExit("acct"); 9 | 10 | printf("Process accounting %s\n", (argv[1] == NULL) ? "disabled" : "enabled"); 11 | exit(EXIT_SUCCESS); 12 | } -------------------------------------------------------------------------------- /tlpi-dist/filelock/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = i_fcntl_locking t_flock 4 | 5 | EXE = ${GEN_EXE} ${LINUX_EXE} 6 | 7 | all : ${EXE} 8 | 9 | allgen : ${GEN_EXE} 10 | 11 | clean : 12 | ${RM} ${EXE} *.o 13 | 14 | showall : 15 | @ echo ${EXE} 16 | 17 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 18 | -------------------------------------------------------------------------------- /tlpi-dist/proccred/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = 4 | 5 | LINUX_EXE = idshow 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/getopt/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = t_getopt 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/pty/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = script unbuffer 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/memalloc/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = free_and_sbrk 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/progconc/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = syscall_speed 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "tlpi_hdr.h": "c", 4 | "unistd.h": "c", 5 | "dirent.h": "c", 6 | "stdbool.h": "c", 7 | "cstdbool": "c", 8 | "stdio.h": "c", 9 | "signal.h": "c", 10 | "types.h": "c", 11 | "print_wait_status.h": "c", 12 | "stdarg.h": "c", 13 | "cstdarg": "c", 14 | "pthread.h": "c" 15 | } 16 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "command": "gcc", 6 | "args": [ 7 | "-g","-std=c11", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}", "-ltlpi" 8 | ], 9 | "problemMatchers": [ 10 | "$gcc" 11 | ] 12 | } -------------------------------------------------------------------------------- /tlpi-dist/daemons/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = daemon_SIGHUP t_syslog test_become_daemon 4 | 5 | EXE = ${GEN_EXE} ${LINUX_EXE} 6 | 7 | all : ${EXE} 8 | 9 | allgen : ${GEN_EXE} 10 | 11 | clean : 12 | ${RM} ${EXE} *.o 13 | 14 | showall : 15 | @ echo ${EXE} 16 | 17 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 18 | -------------------------------------------------------------------------------- /tlpi-dist/syslim/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = t_fpathconf t_sysconf 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/xattr/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = 4 | 5 | LINUX_EXE = t_setxattr xattr_view 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/svipc/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = svmsg_demo_server t_ftok 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/tty/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = demo_SIGWINCH new_intr no_echo test_tty_functions 4 | 5 | EXE = ${GEN_EXE} ${LINUX_EXE} 6 | 7 | all : ${EXE} 8 | 9 | allgen : ${GEN_EXE} 10 | 11 | clean : 12 | ${RM} ${EXE} *.o 13 | 14 | showall : 15 | @ echo ${EXE} 16 | 17 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 18 | -------------------------------------------------------------------------------- /chapter-27/example/t_execl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | printf("Initial value of USER: %s\n", getenv("USER")); 7 | if (putenv("USER=britta") != 0) 8 | errExit("putenv"); 9 | 10 | execl("/usr/bin/printenv", "printenv", "USER", "SHELL", NULL); 11 | errExit("execl"); 12 | } -------------------------------------------------------------------------------- /tlpi-dist/procres/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = rusage rusage_wait 4 | 5 | LINUX_EXE = rlimit_nproc 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/filesys/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = t_statvfs 4 | 5 | LINUX_EXE = t_statfs t_mount t_umount 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/sysinfo/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = t_uname 4 | 5 | LINUX_EXE = procfs_pidmax procfs_user_exe 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/vmem/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = memlock madvise_dontneed 4 | 5 | LINUX_EXE = t_mprotect 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/loginacct/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = 4 | 5 | LINUX_EXE = dump_utmpx utmpx_login view_lastlog 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/files/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = t_chown t_stat t_umask t_utime t_utimes 4 | 5 | LINUX_EXE = chiflag 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/mmap/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = anon_mmap mmcat mmcopy t_mmap 4 | 5 | LINUX_EXE = t_remap_file_pages 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /chapter-41/exercise/41-1.md: -------------------------------------------------------------------------------- 1 | > Try compiling a program with and without the –static option, to see the difference in size between an executable dynamically linked with the C library and one that is linked against the static version of the C library. 2 | 3 | --- 4 | 5 | 用一个很简单的调用`printf()`做了下测试,静态链接的大小为892K,动态链接的大小为8.2K。有丶真实。后来又让`main()`函数体为空做了下测试,发现静态链接仍然有890K。看来可执行文件中`main()`调用的的入口和出口还是很复杂的。 -------------------------------------------------------------------------------- /chapter-27/example/envargs.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | extern char **environ; 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int j; 8 | char **ep; 9 | 10 | for (j = 0; j < argc; ++j) 11 | printf("argv[%d] = %s\n", j, argv[j]); 12 | 13 | for (ep = environ; *ep != NULL; ++ep) 14 | printf("envirn: %s\n", *ep); 15 | 16 | exit(EXIT_SUCCESS); 17 | } -------------------------------------------------------------------------------- /chapter-20/exercise/20-4.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | 4 | int my_siginterrupt(int sig, int flag) 5 | { 6 | int ret; 7 | struct sigaction act; 8 | sigaction(sig, NULL, &act); 9 | 10 | if (flag) 11 | act.sa_flags &= SA_RESTART; 12 | else 13 | act.sa_flags |= SA_RESTART; 14 | ret = sigaction(sig, &act, NULL); 15 | return ret; 16 | } -------------------------------------------------------------------------------- /chapter-5/example/fcntl_F_GETFLL.c: -------------------------------------------------------------------------------- 1 | /************************** 2 | 省略了前面的代码,已知一个变量fd, 3 | 保存了文件描述符,要判断访问模式 4 | ***************************/ 5 | int flags, accessMode; 6 | flags = fcntl(fd, F_GETFL); 7 | if (flsgs == -1) 8 | exit(EXIT_FAILURE); 9 | accessMode = flags & O_ACCMODE; 10 | if (accessMode == O_WRONLY || accessMode == O_RDWR) 11 | printf("file is writable\n"); 12 | 13 | 14 | -------------------------------------------------------------------------------- /tlpi-dist/altio/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = demo_sigio poll_pipes select_mq self_pipe t_select 4 | 5 | LINUX_EXE = epoll_input 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /tlpi-dist/pgsjc/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = catch_SIGHUP disc_SIGHUP job_mon \ 4 | orphaned_pgrp_SIGHUP handling_SIGTSTP t_setsid 5 | 6 | EXE = ${GEN_EXE} ${LINUX_EXE} 7 | 8 | all : ${EXE} 9 | 10 | allgen : ${GEN_EXE} 11 | 12 | clean : 13 | ${RM} ${EXE} *.o 14 | 15 | showall : 16 | @ echo ${EXE} 17 | 18 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 19 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/demo_Bsymbolic/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -v 4 | 5 | gcc -g -shared -fPIC -o libfoo1.so foo1.c 6 | gcc -g -Wl,-Bsymbolic -Wl,-dynamic-list=d --shared -fPIC -o libfoo2.so foo2.c 7 | gcc -g -Wl,-Bsymbolic -Wl,-allow-shlib-undefined \ 8 | -shared -fPIC -o libfoo3.so foo3.c 9 | 10 | gcc -g -o prog prog.c -L. -lfoo1 -lfoo2 -lfoo3 11 | 12 | LD_LIBRARY_PATH=. ./prog 13 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = dynload 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | dynload : dynload.o 14 | ${CC} -o $@ dynload.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBDL} 15 | 16 | clean : 17 | ${RM} ${EXE} *.o *.so.* 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /chapter-46/example/svmsg_rm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int j; 8 | 9 | for (j = 1; j < argc; ++j) 10 | if (msgctl(getInt(argv[j], 0, "msqid"), IPC_RMID, NULL) == -1) 11 | { 12 | errExit("msgctl %s", argv[j]); 13 | } 14 | 15 | exit(EXIT_SUCCESS); 16 | } -------------------------------------------------------------------------------- /tlpi-dist/Makefile.inc.MacOSX: -------------------------------------------------------------------------------- 1 | # Makefile.inc - common definitions used by all makefiles 2 | # Mac OS (Lion) version 3 | 4 | TLPI_DIR = .. 5 | TLPI_LIB = ${TLPI_DIR}/libtlpi.a 6 | TLPI_INCL_DIR = ${TLPI_DIR}/lib 7 | 8 | IMPL_CFLAGS += -g -I${TLPI_INCL_DIR} 9 | CFLAGS = ${IMPL_CFLAGS} 10 | IMPL_THREAD_FLAGS = 11 | 12 | IMPL_LDLIBS = ${TLPI_LIB} -lm 13 | LDLIBS = ${IMPL_LDLIBS} 14 | 15 | RM = rm -f 16 | -------------------------------------------------------------------------------- /tlpi-dist/inotify/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = 4 | 5 | LINUX_EXE = demo_inotify dnotify inotify_dtree rand_dtree 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allftw : ${FTW_EXE} 12 | 13 | allgen : ${GEN_EXE} 14 | 15 | clean : 16 | ${RM} ${EXE} *.o 17 | 18 | showall : 19 | @ echo ${EXE} 20 | 21 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 22 | -------------------------------------------------------------------------------- /tlpi-dist/svsem/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = svsem_create svsem_demo svsem_mon svsem_op svsem_rm svsem_setall 4 | 5 | LINUX_EXE = svsem_info 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 20 | -------------------------------------------------------------------------------- /chapter-27/exercise/27-5.md: -------------------------------------------------------------------------------- 1 | > 27-5 When we run the following program, we find it produces no output. Why is this? 2 | 3 | 4 | ```C 5 | #include "tlpi_hdr.h" 6 | 7 | int 8 | main(int argc, char *argv[]) 9 | { 10 | printf("Hello world"); 11 | execlp("sleep", "sleep", "0", (char *) NULL); 12 | } 13 | ``` 14 | 15 | --- 16 | 17 | 因为`printf()`默认用的行缓冲,还没把字符串从用户空间的缓冲复制到内核空间,就`execev`了`sleep`,进程的数据段,堆,栈都被替换了。 -------------------------------------------------------------------------------- /chapter-38/exercise/38-1.md: -------------------------------------------------------------------------------- 1 | > Log in as a normal, unprivileged user, create an executable file (or copy an existing file such as /bin/sleep), and enable the set-user-ID permission bit on that file (chmod u+s). Try modifying the file (e.g., cat >> file). What happens to the file permissions as a result (ls –l)? Why does this happen? 2 | 3 | --- 4 | 5 | 当文件被非特权用户修改后,内核会清除文件上的 `set-user-ID` 权限位。这么做是为了防止修改这些程序的同时还保留一些特权。 6 | 7 | -------------------------------------------------------------------------------- /tlpi-dist/Makefile.inc.FreeBSD: -------------------------------------------------------------------------------- 1 | # Makefile.inc - common definitions used by all makefiles 2 | # FreeBSD version 3 | 4 | TLPI_DIR = .. 5 | TLPI_LIB = ${TLPI_DIR}/libtlpi.a 6 | TLPI_INCL_DIR = ${TLPI_DIR}/lib 7 | 8 | IMPL_CFLAGS += -g -I${TLPI_INCL_DIR} 9 | CFLAGS = ${IMPL_CFLAGS} 10 | IMPL_THREAD_FLAGS = -pthread 11 | 12 | IMPL_LDLIBS = ${TLPI_LIB} -lcrypt -lm 13 | LDLIBS = ${IMPL_LDLIBS} 14 | 15 | RM = rm -f 16 | -------------------------------------------------------------------------------- /chapter-20/example/ouch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | static void sig_handler(int sig) 5 | { 6 | printf("Ouch!\n"); 7 | } 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | int j; 12 | 13 | if (signal(SIGINT, sig_handler) == SIG_ERR) 14 | errExit("signal"); 15 | 16 | for (j = 0; ; ++j) 17 | { 18 | printf("%d\n", j); 19 | sleep(3); 20 | } 21 | } -------------------------------------------------------------------------------- /tlpi-dist/proc/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = bad_longjmp display_env longjmp \ 4 | necho setjmp_vars setjmp_vars_opt t_getenv 5 | 6 | LINUX_EXE = modify_env 7 | 8 | EXE = ${GEN_EXE} ${LINUX_EXE} 9 | 10 | all : ${EXE} 11 | 12 | allgen : ${GEN_EXE} 13 | 14 | clean : 15 | ${RM} ${EXE} *.o 16 | 17 | showall : 18 | @ echo ${EXE} 19 | 20 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 21 | -------------------------------------------------------------------------------- /chapter-27/example/t_execle.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | char *env_vec[] = {"GREET=salut", "BYE=adieu", NULL}; 6 | char *filename; 7 | 8 | filename = strchr(argv[1], '/'); 9 | if (filename != NULL) 10 | filename++; 11 | else 12 | filename = argv[1]; 13 | 14 | execle(argv[1], filename, "hello world", NULL, env_vec); 15 | errExit("execle"); 16 | } -------------------------------------------------------------------------------- /tlpi-dist/fileio/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = atomic_append bad_exclusive_open copy \ 4 | multi_descriptors seek_io t_readv t_truncate 5 | 6 | LINUX_EXE = large_file 7 | 8 | EXE = ${GEN_EXE} ${LINUX_EXE} 9 | 10 | all : ${EXE} 11 | 12 | allgen : ${GEN_EXE} 13 | 14 | clean : 15 | ${RM} ${EXE} *.o 16 | 17 | showall : 18 | @ echo ${EXE} 19 | 20 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 21 | -------------------------------------------------------------------------------- /chapter-10/exercise/10-1.md: -------------------------------------------------------------------------------- 1 | > Assume a system where the value returned by the call sysconf(_SC_CLK_TCK) is 100. Assuming that the clock_t value returned by times() is an unsigned 32-bit integer, how long will it take before this value cycles so that it restarts at 0? Perform the same calculation for the CLOCKS_PER_SEC value returned by clock(). 2 | 3 | ## 答案: 4 | 5 | 32位无符号整数最大为 `2^32`。所以需要 `2^32/100` s。 6 | 7 | 同理, `2^32 / CLOCKS_PER_SEC` 。 8 | 9 | -------------------------------------------------------------------------------- /tlpi-dist/dirs_links/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = bad_symlink file_type_stats list_files list_files_readdir_r \ 4 | nftw_dir_tree t_dirbasename t_unlink view_symlink 5 | 6 | LINUX_EXE = 7 | 8 | EXE = ${GEN_EXE} ${LINUX_EXE} 9 | 10 | all : ${EXE} 11 | 12 | allgen : ${GEN_EXE} 13 | 14 | clean : 15 | ${RM} ${EXE} *.o 16 | 17 | showall : 18 | @ echo ${EXE} 19 | 20 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 21 | -------------------------------------------------------------------------------- /chapter-23/exercise/23-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned int alarm(unsigned int seconds) 4 | { 5 | struct itimerval new_value; 6 | struct itimerval old_value; 7 | 8 | new_value.it_value.tv_sec = seconds; 9 | new_value.it_value.tv_usec = 0; 10 | new_value.it_interval.tv_sec = 0; 11 | new_value.it_interval.tv_sec = 0; 12 | setitimer(ITIMER_REAL, &new_value, &old_value); 13 | 14 | return old_value.it_value.tv_sec; 15 | } -------------------------------------------------------------------------------- /tlpi-dist/Makefile.inc.Tru64: -------------------------------------------------------------------------------- 1 | # Makefile.inc - common definitions used by all makefiles 2 | # Tru64 version 3 | 4 | TLPI_DIR = .. 5 | TLPI_LIB = ${TLPI_DIR}/libtlpi.a 6 | TLPI_INCL_DIR = ${TLPI_DIR}/lib 7 | 8 | IMPL_CFLAGS = -g -I${TLPI_INCL_DIR} -D_POSIX_PII_SOCKET -D_OSF_SOURCE 9 | CFLAGS = ${IMPL_CFLAGS} 10 | IMPL_THREAD_FLAGS = -pthread 11 | 12 | IMPL_LDLIBS = ${TLPI_LIB} -lrt -lm 13 | LOADLIBES = ${IMPL_LDLIBS} 14 | LDLIBS = ${IMPL_LDLIBS} 15 | 16 | RM = rm -f 17 | -------------------------------------------------------------------------------- /tlpi-dist/pipes/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = change_case fifo_seqnum_client fifo_seqnum_server \ 4 | pipe_ls_wc pipe_sync popen_glob simple_pipe 5 | 6 | EXE = ${GEN_EXE} ${LINUX_EXE} 7 | 8 | all : ${EXE} 9 | 10 | allgen : ${GEN_EXE} 11 | 12 | fifo_seqnum_client.o fifo_seqnum_server.o : fifo_seqnum.h 13 | 14 | clean : 15 | ${RM} ${EXE} *.o 16 | 17 | showall : 18 | @ echo ${EXE} 19 | 20 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 21 | -------------------------------------------------------------------------------- /chapter-10/example/curr_time.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define BUF_SIZE 1000 3 | 4 | static inline char* curr_time(const char *format) 5 | { 6 | static char buf[BUF_SIZE]; 7 | time_t t; 8 | size_t s; 9 | struct tm *tm; 10 | 11 | t = time(NULL); 12 | tm = localtime(&t); 13 | 14 | if (tm == NULL) 15 | return NULL; 16 | 17 | s = strftime(buf, BUF_SIZE, (format != NULL) ? format : "%c", tm); 18 | 19 | return (s == 0) ? NULL : buf; 20 | } -------------------------------------------------------------------------------- /chapter-27/exercise/27-1.md: -------------------------------------------------------------------------------- 1 | > 27-1 The final command in the following shell session uses the program in Listing 27-3 to exec the program xyz. What happens? 2 | 3 | ```shell 4 | $ echo $PATH 5 | /usr/local/bin:/usr/bin:/bin:./dir1:./dir2 6 | $ ls -l dir1 7 | total 8 8 | -rw-r--r-- 1 mtk users 7860 Jun 13 11:55 xyz 9 | $ ls -l dir2 10 | total 28 11 | -rwxr-xr-x 1 mtk users 27452 Jun 13 11:55 xyz 12 | $ ./t_execlp xyz 13 | ``` 14 | 15 | --- 16 | 17 | 将会从环境变量`./dir2`下找到`xyz`可执行文件并执行。 -------------------------------------------------------------------------------- /tlpi-dist/acl/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = 4 | 5 | LINUX_EXE = acl_update acl_view 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | LDLIBS = ${IMPL_LDLIBS} ${LINUX_LIBACL} 14 | # All of the programs in this directory need the 15 | # ACL library, libacl. 16 | 17 | clean : 18 | ${RM} ${EXE} *.o 19 | 20 | showall : 21 | @ echo ${EXE} 22 | 23 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 24 | -------------------------------------------------------------------------------- /tlpi-dist/procpri/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = sched_set sched_view t_setpriority 4 | 5 | LINUX_EXE = demo_sched_fifo t_sched_setaffinity t_sched_getaffinity 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | LDLIBS = ${IMPL_LDLIBS} #CF[ ${LINUX_LIBRT} ] 10 | 11 | all : ${EXE} 12 | 13 | allgen : ${GEN_EXE} 14 | 15 | clean : 16 | ${RM} ${EXE} *.o 17 | 18 | showall : 19 | @ echo ${EXE} 20 | 21 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 22 | -------------------------------------------------------------------------------- /tlpi-dist/cap/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = 4 | 5 | LINUX_EXE = check_password_caps 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | LDLIBS = ${IMPL_LDLIBS} ${LINUX_LIBCAP} ${LINUX_LIBCRYPT} 14 | # The only program we build here needs libcap and libcrypt 15 | 16 | clean : 17 | ${RM} ${EXE} *.o 18 | 19 | showall : 20 | @ echo ${EXE} 21 | 22 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 23 | -------------------------------------------------------------------------------- /chapter-36/exercise/36-3.c: -------------------------------------------------------------------------------- 1 | // 感觉根据资源类型而改变? 进程 RLIMIT_NPROC 超出范围会导致fork()失败,并设置errno为 EAGAIN 2 | #include 3 | #include 4 | 5 | #include "tlpi_hdr.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | struct rlimit sr = {1, 1}; 10 | 11 | if (setrlimit(RLIMIT_NPROC, &sr) == -1) 12 | errExit("setrlimit"); 13 | 14 | while (1) 15 | { 16 | if (fork() == -1) 17 | errExit("fork"); 18 | 19 | printf("Fuck\n"); 20 | } 21 | } -------------------------------------------------------------------------------- /tlpi-dist/users_groups/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = t_getpwent t_getpwnam_r 4 | 5 | LINUX_EXE = check_password idshow 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | check_password : check_password.o 17 | ${CC} -o $@ check_password.o ${LDFLAGS} ${LDLIBS} ${LINUX_LIBCRYPT} 18 | 19 | showall : 20 | @ echo ${EXE} 21 | 22 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 23 | -------------------------------------------------------------------------------- /tlpi-dist/Makefile.inc.Solaris: -------------------------------------------------------------------------------- 1 | # Makefile.inc - common definitions used by all makefiles 2 | # Solaris version 3 | 4 | TLPI_DIR = .. 5 | TLPI_LIB = ${TLPI_DIR}/libtlpi.a 6 | TLPI_INCL_DIR = ${TLPI_DIR}/lib 7 | 8 | IMPL_CFLAGS += -g -I${TLPI_INCL_DIR} -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 -D_XPG4_2 -D_POSIX_C_SOURCE=199506 9 | CFLAGS = ${IMPL_CFLAGS} 10 | IMPL_THREAD_FLAGS = -mt 11 | 12 | IMPL_LDLIBS = ${TLPI_LIB} -lsocket -lnsl -lrt -ldl -lm -lresolv 13 | LDLIBS = ${IMPL_LDLIBS} 14 | 15 | RM = rm -f 16 | -------------------------------------------------------------------------------- /tlpi-dist/lib/README: -------------------------------------------------------------------------------- 1 | A small design note... Many of the library functions defined in the 2 | source code modules in this directory handle errors from system calls 3 | and C library functions by simply terminating the process. This 4 | isn't acceptable design for a "real world" suite of library functions; 5 | I did things this way to keep the source code simpler and shorter. 6 | A properly designed function should indicate an error to its caller 7 | using a status argument or some special function return value. 8 | -------------------------------------------------------------------------------- /tlpi-dist/seccomp/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = 4 | 5 | LINUX_EXE = libseccomp_demo seccomp_control_open seccomp_deny_open seccomp_perf 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | clean : 14 | ${RM} ${EXE} *.o 15 | 16 | showall : 17 | @ echo ${EXE} 18 | 19 | libseccomp_demo : libseccomp_demo.c 20 | ${CC} -o $@ libseccomp_demo.c ${CFLAGS} ${LDLIBS} -lseccomp 21 | 22 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 23 | -------------------------------------------------------------------------------- /tlpi-dist/svshm/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = svshm_attach svshm_create svshm_mon svshm_rm \ 4 | svshm_xfr_reader svshm_xfr_writer 5 | 6 | LINUX_EXE = svshm_info svshm_lock svshm_unlock 7 | 8 | EXE = ${GEN_EXE} ${LINUX_EXE} 9 | 10 | all : ${EXE} 11 | 12 | allgen : ${GEN_EXE} 13 | 14 | clean : 15 | ${RM} ${EXE} *.o 16 | 17 | svshm_xfr_reader.o svshm_xfr_writer.o: svshm_xfr.h 18 | 19 | showall : 20 | @ echo ${EXE} 21 | 22 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 23 | -------------------------------------------------------------------------------- /chapter-44/example/fifo_seqnum.h: -------------------------------------------------------------------------------- 1 | #ifndef FIFO_SEQNUM_H 2 | #define FIFO_SEQNUM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tlpi_hdr.h" 8 | 9 | #define SERVER_FIFO "/tmp/seqnum_sv" 10 | #define CLIENT_FIFO_TEMPLATE "/tmp/seqnum_cl.%ld" 11 | #define CLIENT_FIFO_NAME_LEN (sizeof(CLIENT_FIFO_TEMPLATE) + 20) 12 | 13 | struct request 14 | { 15 | pid_t pid; 16 | int seq_len; 17 | }; 18 | 19 | struct response 20 | { 21 | int seq_num; 22 | }; 23 | 24 | #endif -------------------------------------------------------------------------------- /tlpi-dist/pshm/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = pshm_create pshm_read pshm_write pshm_unlink 4 | 5 | LINUX_EXE = 6 | 7 | EXE = ${GEN_EXE} ${LINUX_EXE} 8 | 9 | all : ${EXE} 10 | 11 | allgen : ${GEN_EXE} 12 | 13 | LDLIBS = ${IMPL_LDLIBS} ${LINUX_LIBRT} 14 | # All of the programs in this directory need the 15 | # realtime library, librt. 16 | 17 | 18 | clean : 19 | ${RM} ${EXE} *.o 20 | 21 | showall : 22 | @ echo ${EXE} 23 | 24 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 25 | -------------------------------------------------------------------------------- /chapter-34/example/setsid.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 500 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | if (fork() != 0) 9 | _exit(EXIT_SUCCESS); 10 | 11 | if (setsid() == -1) 12 | errExit("setsid"); 13 | 14 | printf("PID=%ld, PGID=%ld, SID=%ld\n", (long)getpid(), (long)getpgrp(), (long)getsid); 15 | 16 | if (open("/dev/tty", O_RDWR) == -1) 17 | errExit("open /dev/tty"); 18 | exit(EXIT_SUCCESS); 19 | } -------------------------------------------------------------------------------- /tlpi-dist/svmsg/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = svmsg_chqbytes svmsg_file_client svmsg_file_server \ 4 | svmsg_create svmsg_receive svmsg_rm svmsg_send 5 | 6 | LINUX_EXE = svmsg_info svmsg_ls 7 | 8 | EXE = ${GEN_EXE} ${LINUX_EXE} 9 | 10 | all : ${EXE} 11 | 12 | allgen : ${GEN_EXE} 13 | 14 | clean : 15 | ${RM} ${EXE} *.o 16 | 17 | svmsg_file_client.o svmsg_file_server.o : svmsg_file.h 18 | 19 | showall : 20 | @ echo ${EXE} 21 | 22 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 23 | -------------------------------------------------------------------------------- /chapter-46/example/svmsg_chqbytes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | struct msqid_ds ds; 8 | int msqid; 9 | 10 | msqid = getInt(argv[1], 0, "msqid"); 11 | if (msgctl(msqid, IPC_STAT, &ds) == -1) 12 | errExit("msgctl"); 13 | 14 | ds.msg_qbytes = getInt(argv[2], 0, "max-bytes"); 15 | 16 | if (msgctl(msqid, IPC_SET, &ds) == -1) 17 | errExit("msgctl"); 18 | 19 | exit(EXIT_SUCCESS); 20 | } -------------------------------------------------------------------------------- /chapter-40/exercise/40-4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | struct utmpx *ut; 8 | setutxent(); 9 | 10 | while ((ut = getutxent()) != NULL) 11 | { 12 | if (ut->ut_type == USER_PROCESS || ut->ut_type == LOGIN_PROCESS) 13 | { 14 | printf("%-8s ", ut->ut_user); 15 | printf("%-5s ", ut->ut_line); 16 | 17 | printf("%s", ctime((time_t*) &(ut->ut_tv.tv_sec))); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /chapter-8/exercise/8-1.md: -------------------------------------------------------------------------------- 1 | > 8-1:执行下列代码时,将会发现,尽管这两个用户在密码文件中对应不同的ID,但该程序的输出还是会将同一个数字显示两次。请问为什么? 2 | 3 | ```C 4 | printf("%ld %ld\n", (long) (getpwnam("avr")->pw_uid), 5 | (long) (getpwnam("tsr")->pw_uid)); 6 | ``` 7 | 8 | 这里作者是想强调`getpwnam()`是不可重入的,但例子有问题的,参数被复制过去,所以会打印出不同的值。作者也给出了勘误:(http://www.man7.org/tlpi/errata/index.html)[http://www.man7.org/tlpi/errata/index.html]。在第166条。 9 | 10 | 现在例子改成了: 11 | 12 | ```C 13 | printf("%s %s\n", getpwuid(uid1)->pw_name, 14 | getpwuid(uid2)->pw_name); 15 | ``` -------------------------------------------------------------------------------- /chapter-24/example/t_vfork.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int istack = 222; 6 | 7 | switch (vfork()) 8 | { 9 | case -1: 10 | errExit("vfork"); 11 | case 0: 12 | sleep(3); 13 | write(STDOUT_FILENO, "Child executing\n", 16); 14 | istack *= 3; 15 | _exit(EXIT_SUCCESS); 16 | default: 17 | write (STDOUT_FILENO, "Parent executing\n", 17); 18 | printf("istack=%d\n", istack); 19 | exit(EXIT_SUCCESS); 20 | } 21 | } -------------------------------------------------------------------------------- /chapter-31/example/strerror.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | 6 | #define MAX_ERROR_LEN 256 7 | 8 | static char buf[MAX_ERROR_LEN]; 9 | 10 | char *strerror(int err) 11 | { 12 | if (err < 0 || err > _sys_nerr || _sys_errlist[err] == NULL) 13 | { 14 | snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", err); 15 | } 16 | else 17 | { 18 | strncpy(buf, _sys_errlist[err], MAX_ERROR_LEN-1); 19 | buf[MAX_ERROR_LEN-1] = '\0'; 20 | } 21 | 22 | return buf; 23 | } -------------------------------------------------------------------------------- /chapter-27/example/closeonexec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int flags; 7 | 8 | if (argc > 1) 9 | { 10 | flags = fcntl(STDOUT_FILENO, F_GETFD); 11 | if (flags == -1) 12 | errExit("fcntl - F_GETFD"); 13 | 14 | flags |= FD_CLOEXEC; 15 | 16 | if (fcntl(STDOUT_FILENO, F_SETFD, flags) == -1) 17 | errExit("fcntl - F_SETFD"); 18 | } 19 | execlp("ls", "ls", "-l", argv[0], NULL); 20 | errExit("execlp"); 21 | } -------------------------------------------------------------------------------- /chapter-27/example/simple_system.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int system(char *command) 6 | { 7 | int status; 8 | pid_t child_pid; 9 | 10 | switch (child_pid = fork()) 11 | { 12 | case -1: 13 | return -1; 14 | 15 | case 0: 16 | execl("/bin/sh", "sh", "-c", command, NULL); 17 | _exit(127); 18 | 19 | default: 20 | if (waitpid(child_pid, &status, 0) == -1) 21 | return -1; 22 | else 23 | return status; 24 | } 25 | } -------------------------------------------------------------------------------- /chapter-6/example/modify_env.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | extern char **environ; 6 | 7 | int main(int argc, char **argv) 8 | { 9 | int j; 10 | char **ep; 11 | 12 | clearenv(); 13 | 14 | for (j = 0; j < argc; ++j) 15 | if (putenv(argv[j] != 0)) 16 | errExit("putenv:%s", argv[j]); 17 | 18 | if (setenv("GREET", "Hello world", 0) == -1) 19 | errExit("setenv"); 20 | 21 | unsetenv("setenv"); 22 | 23 | for (ep = environ; *ep != NULL; ep++) 24 | puts(*ep); 25 | 26 | exit(EXIT_SUCCESS); 27 | } -------------------------------------------------------------------------------- /chapter-15/exercise/15-5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | struct stat sb; 10 | int fd, umask_bits; 11 | 12 | fd = open("test", O_CREAT | O_EXCL, 0777); 13 | 14 | if (fd == -1) 15 | errExit("open"); 16 | 17 | if (stat("test", &sb) == -1) 18 | errExit("stat"); 19 | 20 | umask_bits = ~(sb.st_mode & 0777) & 0777; 21 | 22 | printf("%04o\n", umask_bits); 23 | 24 | return 0; 25 | } -------------------------------------------------------------------------------- /tlpi-dist/time/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = calendar_time show_time process_time strtime t_stime 4 | 5 | EXE = ${GEN_EXE} ${LINUX_EXE} 6 | 7 | all : ${EXE} 8 | 9 | allgen : ${GEN_EXE} 10 | 11 | clean : 12 | ${RM} ${EXE} *.o 13 | 14 | showall : 15 | @ echo ${EXE} 16 | 17 | cal_time: cal_time.o 18 | ${CC} -o $@ cal_time.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBRT} 19 | 20 | process_time_test: process_time_test.o 21 | ${CC} -o $@ process_time_test.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBRT} 22 | 23 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 24 | -------------------------------------------------------------------------------- /chapter-31/example/strerror_tls.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX_ERROR_LEN 256 8 | 9 | static __thread char buf[MAX_ERROR_LEN]; 10 | 11 | char *strerror(int err) 12 | { 13 | if (err < 0 || err >= _sys_nerr || _sys_errlist[err] == NULL) 14 | { 15 | snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", err); 16 | } 17 | else 18 | { 19 | strncpy(buf, _sys_errlist[err], MAX_ERROR_LEN-1); 20 | buf[MAX_ERROR_LEN-1] = '\0'; 21 | } 22 | 23 | return buf; 24 | } -------------------------------------------------------------------------------- /tlpi-dist/Makefile.inc.HP-UX: -------------------------------------------------------------------------------- 1 | # Makefile.inc - common definitions used by all makefiles 2 | # HP-UX Version 3 | 4 | TLPI_DIR = .. 5 | TLPI_LIB = ${TLPI_DIR}/libtlpi.a 6 | TLPI_INCL_DIR = ${TLPI_DIR}/lib 7 | 8 | LINUX_LIBRT = -lrt 9 | LINUX_LIBDL = -ldl 10 | LINUX_LIBACL = -lacl 11 | LINUX_LIBCRYPT = -lcrypt 12 | LINUX_LIBCAP = -lcap 13 | 14 | IMPL_CFLAGS = -g -I${TLPI_INCL_DIR} -D_XOPEN_SOURCE_EXTENDED 15 | CFLAGS = ${IMPL_CFLAGS} 16 | IMPL_THREAD_FLAGS = -mt 17 | 18 | IMPL_LDLIBS = ${TLPI_LIB} -lm 19 | LDFLAGS = ${IMPL_LDLIBS} 20 | LDLIBS = ${IMPL_LDLIBS} 21 | 22 | RM = rm -f 23 | -------------------------------------------------------------------------------- /chapter-22/example/signal.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 2 | #include 3 | 4 | typedef void (*sighandler_t)(int); 5 | 6 | sighandler_t signal(int sig, sighandler_t handler) 7 | { 8 | struct sigaction new_disp, prev_disp; 9 | 10 | new_disp.sa_handler = handler; 11 | sigemptyset(&new_disp.sa_mask); 12 | #ifdef OLD_SIGNAL 13 | new_disp.sa_flags = SA_RESETHAND | SA_NODEFER; 14 | #else 15 | new_disp.sa_flags = SA_RESTART; 16 | #endif 17 | 18 | if (sigaction(sig, &new_disp, &prev_disp) == -1) 19 | return SIG_ERR; 20 | else 21 | return prev_disp.sa_handler; 22 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # sv_build.sh 4 | # 5 | set -v 6 | 7 | # Build version 1 of shared library 8 | 9 | gcc -g -c -fPIC -Wall sv_lib_v1.c 10 | gcc -g -shared -o libsv.so sv_lib_v1.o -Wl,--version-script,sv_v1.map 11 | 12 | gcc -g -o p1 sv_prog.c libsv.so 13 | 14 | LD_LIBRARY_PATH=. ./p1 15 | 16 | # Build version 2 of shared library 17 | 18 | gcc -g -c -fPIC -Wall sv_lib_v2.c 19 | gcc -g -shared -o libsv.so sv_lib_v2.o -Wl,--version-script,sv_v2.map 20 | 21 | gcc -g -o p2 sv_prog.c libsv.so 22 | 23 | LD_LIBRARY_PATH=. ./p2 24 | LD_LIBRARY_PATH=. ./p1 25 | -------------------------------------------------------------------------------- /chapter-18/example/t_dirbasename.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | char *t1, *t2; 7 | int j; 8 | 9 | for (j = 1; j < argc; ++j) 10 | { 11 | t1 = strdup(argv[j]); 12 | if (t1 == NULL) 13 | errExit("strdup"); 14 | t2 = strdup(argv[j]); 15 | if (t2 == NULL) 16 | errExit("strdup"); 17 | 18 | printf("%s ==> %s + %s\n", argv[j], dirname(t1), basename(t2)); 19 | 20 | free(t1); 21 | free(t2); 22 | } 23 | 24 | exit(EXIT_SUCCESS); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /chapter-20/exercise/20-3.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | static void handler(int sig) 6 | { 7 | printf("SIGINT is caught.\n"); 8 | } 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | struct sigaction sb; 13 | 14 | sigemptyset(&sb.sa_mask); 15 | sb.sa_handler = handler; 16 | 17 | // sb.sa_flags = SA_RESETHAND; 18 | // sigaction(SIGINT, &sb, NULL); 19 | 20 | // sleep(10); 21 | // printf("----------\n"); 22 | sb.sa_flags = SA_RESETHAND; 23 | sigaction(SIGINT, &sb, NULL); 24 | while (1) 25 | sleep(1); 26 | } -------------------------------------------------------------------------------- /chapter-6/example/longjmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | static jmp_buf env; 5 | 6 | static void f2(void) 7 | { 8 | longjmp(env, 2); 9 | } 10 | 11 | static void f1(int argc) 12 | { 13 | if (argc == 1) 14 | longjmp(env, 1); 15 | f2(); 16 | } 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | switch(setjmp(env)) 21 | { 22 | case 0: 23 | printf("Calling f1() after the initial setjmp()\n"); 24 | f1(argc); 25 | break; 26 | case 1: 27 | printf("We jumped back from f1()\n"); 28 | case 2: 29 | printf("We jumped back from f2()\n"); 30 | } 31 | exit(EXIT_SUCCESS); -------------------------------------------------------------------------------- /chapter-24/example/t_fork.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | static int idata = 111; 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int istack = 222; 8 | pid_t child_pid; 9 | 10 | switch (child_pid = fork()) 11 | { 12 | case -1: 13 | errExit("fork"); 14 | case 0: 15 | idata *= 3; 16 | istack *= 3; 17 | break; 18 | default: 19 | sleep(3); 20 | break; 21 | } 22 | 23 | printf("PID=%ld %s idata=%d istack=%d\n", (long)getpid(), 24 | (child_pid == 0) ? "(child)" : "(parent)", idata, istack); 25 | 26 | exit(EXIT_SUCCESS); 27 | } -------------------------------------------------------------------------------- /chapter-24/exercise/24-2.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | int main(int argc, char *argv[]) 7 | { 8 | pid_t pid; 9 | 10 | switch (pid = vfork()) 11 | { 12 | case -1: 13 | errExit("vfork"); 14 | case 0: 15 | if (close(STDOUT_FILENO) == -1) 16 | errExit("close"); 17 | assert(write(STDOUT_FILENO, "child-fuck\n", 12) == -1); 18 | _exit(EXIT_SUCCESS); 19 | default: 20 | write(STDOUT_FILENO, "parent-fuck\n", 13); 21 | exit(EXIT_SUCCESS); 22 | } 23 | } -------------------------------------------------------------------------------- /chapter-12/example/t_uname.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | struct utsname uts; 8 | 9 | if (uname(&uts) == -1) 10 | errExit("uname"); 11 | 12 | printf("Node name: %s\n", uts.nodename); 13 | printf("System name: %s\n", uts.sysname); 14 | printf("Release: %s\n", uts.release); 15 | printf("Version: %s\n", uts.version); 16 | printf("Machine: %s\n", uts.machine); 17 | #ifdef _GNU_SOURCE 18 | printf("Domain name: %s", uts.domainname); 19 | #endif 20 | exit(EXIT_SUCCESS); 21 | } -------------------------------------------------------------------------------- /chapter-34/exercise/34-2.c: -------------------------------------------------------------------------------- 1 | // 父进程能够在子进程执行 exec() 之前修改子进程的进程 ID, 但是无法在执行 exec() 之后修改 2 | // 子进程的进程组 ID 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | int main(void) 8 | { 9 | pid_t child_pid; 10 | 11 | switch (child_pid = fork()) 12 | { 13 | case -1: 14 | errExit("fork"); 15 | 16 | case 0: 17 | sleep(3); 18 | if (execl("./a.out", "./a.out", NULL) == -1) 19 | errExit("execl"); 20 | 21 | default: 22 | //sleep(3); 23 | if (setpgid(child_pid, child_pid) == -1) 24 | errExit("setpgid"); 25 | } 26 | } -------------------------------------------------------------------------------- /tlpi-dist/pmsg/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = mq_notify_sig mq_notify_sigwaitinfo mq_notify_thread \ 4 | mq_notify_via_signal mq_notify_via_thread \ 5 | pmsg_create pmsg_getattr pmsg_receive pmsg_send pmsg_unlink 6 | 7 | LINUX_EXE = 8 | 9 | EXE = ${GEN_EXE} ${LINUX_EXE} 10 | 11 | all : ${EXE} 12 | 13 | allgen : ${GEN_EXE} 14 | 15 | LDLIBS = ${IMPL_LDLIBS} ${LINUX_LIBRT} 16 | # All of the programs in this directory need the 17 | # realtime library, librt. 18 | 19 | clean : 20 | ${RM} ${EXE} *.o 21 | 22 | showall : 23 | @ echo ${EXE} 24 | 25 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 26 | -------------------------------------------------------------------------------- /chapter-29/exercise/29-2.md: -------------------------------------------------------------------------------- 1 | > 29-2. Aside from the absence of error checking and various variable and structure declarations, what is the problem with the following program? 2 | 3 | ```C 4 | static void * 5 | threadFunc(void *arg) 6 | { 7 | struct someStruct *pbuf = (struct someStruct *) arg; 8 | 9 | /* Do some work with structure pointed to by 'pbuf' */ 10 | } 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | struct someStruct buf; 16 | 17 | pthread_create(&thr, NULL, threadFunc, (void *) &buf); 18 | pthread_exit(NULL); 19 | } 20 | ``` 21 | 22 | --- 23 | 24 | 感觉问题是在于传给新线程的指针指向别的线程栈上的数据,必须保证它们之间同步才能正常工作,否则容易出现 `dangling pointer`。 -------------------------------------------------------------------------------- /tlpi-dist/procexec/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = acct_on acct_view child_status closeonexec envargs exit_handlers \ 4 | footprint fork_file_sharing fork_sig_sync \ 5 | fork_stdio_buf fork_whos_on_first \ 6 | make_zombie multi_SIGCHLD multi_wait necho orphan \ 7 | t_execl t_execle t_execve t_execlp t_fork t_system \ 8 | t_vfork vfork_fd_test 9 | 10 | LINUX_EXE = demo_clone t_clone acct_v3_view 11 | 12 | EXE = ${GEN_EXE} ${LINUX_EXE} 13 | 14 | all : ${EXE} 15 | 16 | allgen : ${GEN_EXE} 17 | 18 | clean : 19 | ${RM} ${EXE} *.o 20 | 21 | showall : 22 | @ echo ${EXE} 23 | 24 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 25 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | 5 | { 6 | "name": "(gdb) Launch", 7 | "type": "cppdbg", 8 | "request": "launch", 9 | "program": "${fileDirname}/${fileBasenameNoExtension}", 10 | "args": [], 11 | "stopAtEntry": false, 12 | "cwd": "${workspaceRoot}", 13 | "environment": [], 14 | "externalConsole": false, 15 | "MIMode": "gdb", 16 | "preLaunchTask": "gcc", 17 | "setupCommands": [ 18 | { 19 | "description": "Enable pretty-printing for gdb", 20 | "text": "-enable-pretty-printing", 21 | "ignoreFailures": true 22 | } 23 | ] 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /tlpi-dist/timers/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = ptmr_null_evp ptmr_sigev_signal ptmr_sigev_thread \ 4 | real_timer t_nanosleep timed_read 5 | 6 | LINUX_EXE = demo_timerfd t_clock_nanosleep 7 | 8 | EXE = ${GEN_EXE} ${LINUX_EXE} 9 | 10 | all : ${EXE} 11 | 12 | allgen : ${GEN_EXE} 13 | 14 | LDLIBS = ${IMPL_LDLIBS} ${LINUX_LIBRT} 15 | # Many of the programs in this directory need the 16 | # realtime library, librt; to keep this Makefile simple, 17 | # we link *all* of the programs against that library. 18 | 19 | clean : 20 | ${RM} ${EXE} *.o 21 | 22 | showall : 23 | @ echo ${EXE} 24 | 25 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 26 | -------------------------------------------------------------------------------- /chapter-35/exercise/35-2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | int sched_kind; 10 | struct sched_param sp; 11 | 12 | if (strncmp(argv[1], "r", 1)) 13 | { 14 | sched_kind = SCHED_RR; 15 | } 16 | else if (strncmp(argv[1], "f", 1)) 17 | { 18 | sched_kind = SCHED_FIFO; 19 | } 20 | 21 | sp.sched_priority = getInt(argv[2], 0, "sched_priority"); 22 | if (sched_setscheduler(0, sched_kind, &sp) == -1) 23 | errExit("sched_setscheduler"); 24 | if (execvp(argv[3], argv+3) == -1) 25 | errExit("execvp"); 26 | } -------------------------------------------------------------------------------- /chapter-20/example/intquit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | static void sig_handler(int sig) 5 | { 6 | static int count = 0; 7 | 8 | if (sig == SIGINT) 9 | { 10 | ++count; 11 | printf("Caught SIGINT (%d)\n", count); 12 | return; 13 | } 14 | 15 | printf("Caught SIGQUIT - that's all folks!\n"); 16 | exit(EXIT_SUCCESS); 17 | } 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | if (signal(SIGINT, sig_handler) == SIG_ERR) 22 | errExit("signal"); 23 | if (signal(SIGQUIT, sig_handler) == SIG_ERR) 24 | errExit("signal"); 25 | 26 | for (;;) 27 | { 28 | pause(); 29 | } 30 | } -------------------------------------------------------------------------------- /chapter-35/example/sched_set.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int j, pol; 7 | struct sched_param sp; 8 | 9 | pol = (argv[1][0] == 'r') ? SCHED_RR : 10 | (argv[1][0] == 'f') ? SCHED_FIFO : 11 | #ifdef SCHED_BATCH 12 | (argv[1][0] == 'b') ? SHCED_BATCH; 13 | #endif 14 | #ifdef SHCED_IDLE 15 | (argv[1][0] == 'i') ? SCHED_IDLE: 16 | #endif 17 | SCHED_OTHER; 18 | 19 | for (j = 3; j < argc; ++j) 20 | { 21 | if (sched_setscheduler(getLong(argv[j], 0, "pid"), pol, &sp) == -1) 22 | errExit("sched_setscheduler"); 23 | } 24 | exit(EXIT_FAILURE); 25 | } -------------------------------------------------------------------------------- /tlpi-dist/sockets/README: -------------------------------------------------------------------------------- 1 | Many of the programs in this directory are named according to the 2 | conventions described below. 3 | 4 | A prefix identifies the socket domain in which the program operates, 5 | and the socket type employed. The socket domain is indicated by one 6 | or two letters: 7 | 8 | u UNIX 9 | i Internet (both v4 and v6) 10 | i6 Internet v6 only 11 | 12 | The socket type is one of the following: 13 | 14 | d datagram 15 | s stream 16 | 17 | A suffix indicates whether the program is a client or server: 18 | 19 | cl client 20 | sv server 21 | 22 | Thus, id_echo_sv.c is a server program that uses datagram sockets in 23 | the Internet domain. 24 | -------------------------------------------------------------------------------- /chapter-15/exercise/15-6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | int main(int argc, char *argv[]) 6 | { 7 | struct stat sb; 8 | 9 | for (int i = 1; i < argc; ++i) 10 | { 11 | if (stat(argv[i], &sb) == -1) 12 | { 13 | perror("Fuck U"); 14 | continue; 15 | } 16 | 17 | sb.st_mode |= (S_IRUSR | S_IRGRP | S_IROTH); 18 | 19 | if (S_ISDIR(sb.st_mode) || 20 | (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) 21 | { 22 | sb.st_mode |= (S_IXUSR | S_IXGRP | S_IXOTH); 23 | } 24 | chmod(argv[i], sb.st_mode); 25 | } 26 | return 0; 27 | } -------------------------------------------------------------------------------- /chapter-29/example/simple_thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | static void *thread_func(void *arg) 5 | { 6 | char *s = (char *)arg; 7 | 8 | printf("%s", s); 9 | 10 | return (void *)strlen(s); 11 | } 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | pthread_t t1; 16 | void *res; 17 | int s; 18 | 19 | s= pthread_create(&t1, NULL, thread_func, "Hello world\n"); 20 | if (s != 0) 21 | errExitEN(s, "pthread_create"); 22 | 23 | printf("Message from main()\n"); 24 | s = pthread_join(t1, &res); 25 | if (s != 0) 26 | errExitEN(s, "pthread_join"); 27 | 28 | printf("Thread returned %ld\n", (long)res); 29 | 30 | exit(EXIT_SUCCESS); 31 | } -------------------------------------------------------------------------------- /chapter-4/example/strange_str.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define MAX_READ 20 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | char buffer[MAX_READ]; 9 | /* if(read(STDIN_FILENO, buffer, MAX_READ) == -1) 10 | { 11 | fputs("read", stderr); 12 | _exit(-1); 13 | } 14 | */ 15 | //输出的结果可能会有点带有其他字符,因为read函数不会给buffer末尾添加/0 16 | //因为输入信息可能是其他二进制形式的数据结构,read()无法区分这些数据 17 | //所以无法遵从C语言对字符串处理的约定,正确方法如下 18 | 19 | ssize_t numRead; 20 | numRead = read(STDIN_FILENO, buffer, MAX_READ); 21 | if (numRead == -1) { 22 | fputs("read", stderr); 23 | _exit(EXIT_FAILURE); 24 | } 25 | buffer[numRead] = '\0'; 26 | printf("The input data was: %s\n", buffer); 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /chapter-35/example/t_setpriority.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int which, prio; 8 | id_t who; 9 | 10 | which = (argv[1][0] == 'p') ? PRIO_PROCESS : 11 | (argv[1][0] == 'g') ? PRIO_PGRP : PRIO_USER; 12 | 13 | who = getLong(argv[2], O, "who"); 14 | prio = getInt(argv[3], O, "prio"); 15 | 16 | if (setpriority(which, who, prio) == -1) 17 | errExit("getpriority"); 18 | 19 | errno = 0; 20 | prio = getpriority(which, who); 21 | if (prio == -1 && errno != 0) 22 | errExit("getpriority"); 23 | 24 | printf("Nice value = %d\n", prio); 25 | 26 | exit(EXIT_SUCCESS); 27 | } -------------------------------------------------------------------------------- /tlpi-dist/lib/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile to build library used by all programs 2 | # 3 | # This make file relies on the assumption that each C file in this 4 | # directory belongs in the library 5 | # 6 | # This makefile is very simple so that every version of make 7 | # should be able to handle it 8 | # 9 | include ../Makefile.inc 10 | 11 | # The library build is "brute force" -- we don't bother with 12 | # dependency checking. 13 | 14 | allgen : ${TLPI_LIB} 15 | 16 | ${TLPI_LIB} : *.c ename.c.inc 17 | ${CC} -c -g ${CFLAGS} *.c 18 | ${RM} ${TLPI_LIB} 19 | ${AR} rs ${TLPI_LIB} *.o 20 | 21 | ename.c.inc : 22 | sh Build_ename.sh > ename.c.inc 23 | echo 1>&2 "ename.c.inc built" 24 | 25 | clean : 26 | ${RM} *.o ename.c.inc ${TLPI_LIB} 27 | 28 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/vis_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # vis_build.sh 4 | # 5 | # Show how versions scripts can be used to control symbol visibility. 6 | # 7 | set -v 8 | 9 | # In the following, vis_comm() is accidentally exported by the 10 | # shared library 11 | 12 | gcc -g -c -fPIC -Wall vis_comm.c vis_f1.c vis_f2.c 13 | gcc -g -shared -o vis.so vis_comm.o vis_f1.o vis_f2.o 14 | readelf --syms --use-dynamic vis.so | grep vis_ 15 | 16 | # Now we use a version script to control exactly which symbols 17 | # are exported by the library 18 | 19 | gcc -g -c -fPIC -Wall vis_comm.c vis_f1.c vis_f2.c 20 | gcc -g -shared -o vis.so vis_comm.o vis_f1.o vis_f2.o \ 21 | -Wl,--version-script,vis.map 22 | readelf --syms --use-dynamic vis.so | grep vis_ 23 | -------------------------------------------------------------------------------- /chapter-11/example/t_fpathconf.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | static void fpathconf_print(const char *msg, int fd, int name) 4 | { 5 | long lim; 6 | 7 | errno = 0; 8 | lim = fpathconf(fd, name); 9 | if (lim != -1) 10 | { 11 | printf("%s, %ld\n", msg, lim); 12 | } 13 | else 14 | { 15 | if (errno == 0) 16 | printf("%s (indeterminate)\n", msg); 17 | else 18 | errExit("fpathconf %s", msg); 19 | } 20 | } 21 | 22 | int main(void) 23 | { 24 | fpathconf_print("_PC_NAME_MAX", STDIN_FILENO, _PC_NAME_MAX); 25 | fpathconf_print("_PC_PATH_MAX", STDIN_FILENO, _PC_PATH_MAX); 26 | fpathconf_print("_PC_PIPE_BUF", STDIN_FILENO, _PC_PIPE_BUF); 27 | exit(EXIT_SUCCESS); 28 | } -------------------------------------------------------------------------------- /chapter-24/example/fork_whos_on_first.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int num_children, j; 7 | pid_t child_pid; 8 | 9 | num_children = (argc > 1) ? getInt(argv[1], GN_GT_0, "num-children") : 1; 10 | 11 | setbuf(stdout, NULL); 12 | 13 | for (j = 0; j < num_children; ++j) 14 | { 15 | switch (child_pid = fork()) 16 | { 17 | case -1: 18 | errExit("fork"); 19 | case 0: 20 | printf("%d child\n", j); 21 | _exit(EXIT_SUCCESS); 22 | default: 23 | printf("%d parent\n", j); 24 | wait(NULL); 25 | break; 26 | } 27 | } 28 | exit(EXIT_SUCCESS); 29 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # sv_build.sh 4 | # 5 | set -ve 6 | 7 | # Build version 1 of shared library 8 | 9 | gcc -g -c -fPIC -Wall sv_lib_v1.c 10 | gcc -g -shared -o libsv.so sv_lib_v1.o -Wl,--version-script,sv_v1.map 11 | 12 | gcc -g -o p1 sv_prog.c libsv.so 13 | 14 | LD_LIBRARY_PATH=. ./p1 15 | 16 | # Build version 2 of shared library 17 | 18 | gcc -g -c -fPIC -Wall sv_lib_v2.c 19 | gcc -g -shared -o libsv.so sv_lib_v2.o -Wl,--version-script,sv_v2.map 20 | 21 | gcc -g -o p2 sv_prog.c libsv.so 22 | 23 | LD_LIBRARY_PATH=. ./p2 24 | LD_LIBRARY_PATH=. ./p1 25 | 26 | gcc -g -c -fPIC -Wall sv_lib_v3.c 27 | gcc -g -shared -o libsv.so sv_lib_v3.o -Wl,--version-script,sv_v3.map 28 | 29 | gcc -g -o p3 sv_prog.c libsv.so 30 | 31 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/vis_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # vis_build.sh 4 | # 5 | # Show how versions scripts can be used to control symbol visibility. 6 | # 7 | set -v 8 | 9 | # In the following, vis_comm() is accidentally exported by the 10 | # shared library 11 | 12 | gcc -g -c -fPIC -Wall vis_comm.c vis_f1.c vis_f2.c 13 | gcc -g -shared -o vis.so vis_comm.o vis_f1.o vis_f2.o 14 | readelf --syms --use-dynamic vis.so | grep vis_ 15 | 16 | # Now we use a version script to control exactly which symbols 17 | # are exported by the library 18 | 19 | gcc -g -c -fPIC -Wall vis_comm.c vis_f1.c vis_f2.c 20 | gcc -g -shared -o vis.so vis_comm.o vis_f1.o vis_f2.o \ 21 | -Wl,--version-script,vis.map 22 | readelf --syms --use-dynamic vis.so | grep vis_ 23 | -------------------------------------------------------------------------------- /tlpi-dist/psem/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = psem_getvalue psem_create psem_post psem_unlink \ 4 | psem_timedwait psem_trywait psem_wait thread_incr_psem 5 | 6 | LINUX_EXE = 7 | 8 | EXE = ${GEN_EXE} ${LINUX_EXE} 9 | 10 | all : ${EXE} 11 | 12 | allgen : ${GEN_EXE} 13 | 14 | CFLAGS = ${IMPL_CFLAGS} ${IMPL_THREAD_FLAGS} 15 | LDLIBS = ${IMPL_LDLIBS} ${IMPL_THREAD_FLAGS} 16 | # POSIX semaphores need the NPTL thread library on Linux 17 | 18 | # psem_timedwait uses clock_gettime() which is in librt 19 | psem_timedwait: psem_timedwait.o 20 | ${CC} -o $@ psem_timedwait.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBRT} 21 | 22 | clean : 23 | ${RM} ${EXE} *.o 24 | 25 | showall : 26 | @ echo ${EXE} 27 | 28 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 29 | -------------------------------------------------------------------------------- /chapter-22/exercise/22-1.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | void handler(int sig) 7 | { 8 | printf("SIGCONT is caught"); 9 | exit(EXIT_SUCCESS); 10 | } 11 | 12 | int main(void) 13 | { 14 | int flag; 15 | struct sigaction sa; 16 | sigset_t mask; 17 | 18 | sigemptyset(&sa.sa_mask); 19 | sa.sa_handler = handler; 20 | sa.sa_flags = 0; 21 | 22 | sigaction(SIGCONT, &sa, NULL); 23 | 24 | sigemptyset(&mask); 25 | sigaddset(&mask, SIGCONT); 26 | sigprocmask(SIG_BLOCK, &mask, NULL); 27 | 28 | for (;;) 29 | { 30 | scanf("%d", &flag); 31 | if (flag == 1) 32 | { 33 | sigprocmask(SIG_UNBLOCK, &mask, NULL); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /chapter-27/exercise/test.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | static volatile sig_atomic_t has_sig = 0; 8 | 9 | void handler(int sig) 10 | { 11 | has_sig = 1; 12 | } 13 | 14 | 15 | int main(void) 16 | { 17 | struct sigaction sa; 18 | sigset_t mask; 19 | 20 | sigemptyset(&mask); 21 | sigaddset(&mask, SIGCHLD); 22 | sigprocmask(SIG_UNBLOCK, &mask, NULL); 23 | 24 | sa.sa_flags = 0; 25 | sigemptyset(&sa.sa_mask); 26 | sa.sa_handler = handler; 27 | if (sigaction(SIGCHLD, &sa, NULL) == -1) 28 | errExit("sigaction"); 29 | 30 | system("ls -ahl"); 31 | 32 | if (has_sig == 1) 33 | { 34 | printf("SIGCHLD has been caught.\n"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /chapter-10/example/show_time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | #define BUF_SIZE 200 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | time_t t; 10 | struct tm *loc; 11 | char buf[BUF_SIZE]; 12 | 13 | if (setlocale(LC_ALL, "") == NULL) 14 | errExit("setlocale"); 15 | 16 | t = time(NULL); 17 | printf("ctime() of time() values is: %s", ctime(&t)); 18 | 19 | loc = localtime(&t); 20 | if (loc == NULL) 21 | errExit("localtime"); 22 | 23 | printf("asctime() of local time is: %s", asctime(loc)); 24 | 25 | if (strftime(buf, BUF_SIZE, "%A, %d, %B %Y, %H:%M:%S %Y", loc) == 0) 26 | fatal("strftime returned 0"); 27 | printf("strftime() of local time is: %s\n", buf); 28 | 29 | exit(EXIT_SUCCESS); 30 | } -------------------------------------------------------------------------------- /chapter-15/exercise/15-4.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | //#include 6 | #include 7 | #include 8 | 9 | int effective_access(const char *name, int mode) 10 | { 11 | int ret; 12 | uid_t euid, ruid; 13 | gid_t egid, rgid; 14 | 15 | euid = geteuid(); 16 | ruid = getuid(); 17 | setresuid(euid, ruid, -1); 18 | rgid = getgid(); 19 | egid = getegid(); 20 | setresgid(egid, rgid, -1); 21 | 22 | ret = access(name, mode); 23 | 24 | setresuid(ruid, euid, -1); 25 | setresgid(rgid, egid, -1); 26 | 27 | return ret; 28 | } 29 | 30 | int main(int argc, char argv[]) 31 | { 32 | printf("%d\n", effective_access("15-4.c", F_OK | R_OK | W_OK | X_OK)); 33 | return 0; 34 | } -------------------------------------------------------------------------------- /chapter-18/example/view_symlink.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | #define BUF_SIZE PATH_MAX 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | struct stat statbuf; 10 | char buf[BUF_SIZE]; 11 | ssize_t num_bytes; 12 | 13 | if (argc != 2 || strcmp(argv[1], "--help") == 0) 14 | usageErr("%s pathname\n", argv[0]); 15 | if (lstat(argv[1], &statbuf) == -1) 16 | errExit("lstat"); 17 | 18 | if (!S_ISLNK(statbuf.st_mode)) 19 | fatal("%s is not a symbolic link", argv[1]); 20 | 21 | num_bytes = readlink(argv[1], buf, BUF_SIZE-1); 22 | if (num_bytes == -1) 23 | errExit("readlink"); 24 | 25 | buf[num_bytes] = '\0'; 26 | printf("readlink: %s --> %s\n", argv[1], buf); 27 | 28 | exit(EXIT_SUCCESS); 29 | } -------------------------------------------------------------------------------- /tlpi-dist/filebuff/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = copy mix23_linebuff mix23io \ 4 | write_bytes \ 5 | write_bytes_fdatasync \ 6 | write_bytes_fsync \ 7 | write_bytes_o_sync 8 | 9 | LINUX_EXE = direct_read 10 | 11 | EXE = ${GEN_EXE} ${LINUX_EXE} 12 | 13 | all : ${EXE} 14 | 15 | allgen : ${GEN_EXE} 16 | 17 | clean : 18 | ${RM} ${EXE} *.o 19 | 20 | write_bytes_fdatasync : write_bytes.c 21 | ${CC} -DUSE_FDATASYNC -o $@ write_bytes.c ${CFLAGS} ${LDLIBS} 22 | 23 | write_bytes_fsync : write_bytes.c 24 | ${CC} -DUSE_FSYNC -o $@ write_bytes.c ${CFLAGS} ${LDLIBS} 25 | 26 | write_bytes_o_sync : write_bytes.c 27 | ${CC} -DUSE_O_SYNC -o $@ write_bytes.c ${CFLAGS} ${LDLIBS} 28 | 29 | showall : 30 | @ echo ${EXE} 31 | 32 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 33 | -------------------------------------------------------------------------------- /chapter-42/example/dynload.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | void *lib_handler; 8 | int (*funcp)(const char *, ...); 9 | const char *err; 10 | 11 | lib_handler = dlopen(argv[1], RTLD_LAZY); 12 | if (lib_handler == NULL) 13 | fatal("dlopen: %s", dlerror()); 14 | 15 | (void) dlerror(); 16 | *(void **)(&funcp) = dlsym(lib_handler, argv[2]); 17 | // printf("DD\n"); 18 | err = dlerror(); 19 | if (err != NULL) 20 | fatal("dlsym: %s", err); 21 | 22 | if (funcp == NULL) 23 | printf("%s is NULL\n", argv[2]); 24 | else 25 | { 26 | (*funcp)("fuck\n"); 27 | // printf("fuck\n"); 28 | } 29 | dlclose(lib_handler); 30 | exit(EXIT_SUCCESS); 31 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/Demo_shared_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Build a program using a shared library 4 | # 5 | # Objects for library must be compiled with PIC (position 6 | # independent code) generation 7 | 8 | gcc -g -c -fPIC -Wall mod1.c mod2.c mod3.c 9 | 10 | # Create library with "real name" (libXYZ.so.maj#.min#.rel#) 11 | # and embed the "soname" (libXYZ.so.maj#) 12 | 13 | gcc -g -shared -Wl,-soname,libdemo.so.1 -o libdemo.so.1.0.1 \ 14 | mod1.o mod2.o mod3.o 15 | 16 | # Create "soname" (libXYZ.so.maj# - a symbolic link to real name) 17 | 18 | ln -sf libdemo.so.1.0.1 libdemo.so.1 19 | 20 | # Create "linker name" (libXYZ.so - a symbolic link to "soname") 21 | 22 | ln -sf libdemo.so.1 libdemo.so 23 | 24 | # Build program by linking against "linker name" 25 | 26 | cc -g -Wall -c prog.c 27 | cc -g -o prog_so prog.o -L. -ldemo 28 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_lib_v1.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_lib_v1.c 12 | 13 | */ 14 | #include 15 | 16 | void xyz(void) { printf("v1 xyz()\n"); } 17 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/rpath_demo/d1/modx1.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* modx1.c */ 12 | 13 | void 14 | x1(void) { 15 | extern void x2(void); 16 | 17 | x2(); 18 | } 19 | -------------------------------------------------------------------------------- /chapter-16/exercise/16-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | int opt; 10 | const char *name, *value; 11 | 12 | name = value = NULL; 13 | 14 | while ((opt = getopt(argc, argv, "n:v:")) != -1) 15 | { 16 | switch (opt) 17 | { 18 | case 'n': 19 | name = optarg; 20 | break; 21 | case 'v': 22 | value = optarg; 23 | break; 24 | default: 25 | printf("Error arg -%c\n", (char)opt); 26 | exit(EXIT_FAILURE); 27 | } 28 | //printf("-%c: %s\n", (char)opt, optarg); 29 | } 30 | if (name != NULL) 31 | setxattr(argv[optind], name, value, strlen(value), 0); 32 | return 0; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_lib_v1.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_lib_v1.c 12 | 13 | */ 14 | #include 15 | 16 | void xyz(void) { printf("v1 xyz()\n"); } 17 | -------------------------------------------------------------------------------- /chapter-21/example/abort_test.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | sigjmp_buf env; 8 | 9 | void handler(int sig) 10 | { 11 | printf("SIGABORT is caugnt!\n"); 12 | 13 | siglongjmp(env, 1); 14 | } 15 | 16 | void handler_return(int sig) 17 | { 18 | printf("SIGABORT is caught! It will return.\n"); 19 | } 20 | 21 | int main(void) 22 | { 23 | if (sigsetjmp(env, 1) == 0) 24 | { 25 | printf("sigsetjmp called\n"); 26 | if (signal(SIGABRT, handler) == SIG_ERR) 27 | errExit("signal"); 28 | } 29 | else 30 | { 31 | printf("Return from abort\n"); 32 | if (signal(SIGABRT, handler_return) == SIG_ERR) 33 | errExit("signal"); 34 | } 35 | 36 | 37 | 38 | abort(); 39 | printf("Call abort!\n"); 40 | } -------------------------------------------------------------------------------- /chapter-29/exercise/29-1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 线程 join 自身会导致运行时错误 ERROR [EDEADLK/EDEADLOCK Resource deadlock avoided] pthread_join 3 | * 在实际编程中应该避免这种情况。比如说在发起 join 操作的时候应该保证第一个参数与 pthread_self() 返回值不同 4 | */ 5 | 6 | #include 7 | #include "tlpi_hdr.h" 8 | 9 | void *pthread_func(void *arg) 10 | { 11 | printf("Pthread t1 is running.\n"); 12 | } 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | pthread_t t1; 17 | int s; 18 | 19 | s = pthread_create(&t1, NULL, pthread_func, NULL); 20 | if (s != 0) 21 | errExitEN(s, "pthread_create"); 22 | 23 | // It occurs a runtime error: ERROR [EDEADLK/EDEADLOCK Resource deadlock avoided] pthread_join 24 | // s = pthread_join(pthread_self(), NULL); 25 | // if (s != 0) 26 | // errExitEN(s, "pthread_join"); 27 | 28 | printf("Pthread t1 is over.\n"); 29 | 30 | return 0; 31 | 32 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/rpath_demo/d2/modx2.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* modx2.c */ 12 | 13 | #include 14 | 15 | void 16 | x2(void) { 17 | printf("Called modx2\n"); 18 | } 19 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/vis_f1.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* vis_f1.c 12 | 13 | */ 14 | int 15 | vis_f1(int k) 16 | { 17 | int vis_comm(int j); 18 | 19 | return vis_comm(k) / 2; 20 | } 21 | -------------------------------------------------------------------------------- /chapter-22/example/t_sigqueue.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_C_SOURCE 199309 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int sig, num_sigs, j, sig_data; 8 | union sigval sv; 9 | 10 | if (argc < 4 || strcmp(argv[1], "--help") == 0) 11 | usageErr("%s pid sig-num data [num-sigs]\n", argv[0]); 12 | 13 | printf("%s: PID is %ld, UID is %ld\n", argv[0], (long)getpid(), (long)getuid()); 14 | 15 | sig = getInt(argv[2], 0, "sig-num"); 16 | sig_data = getInt(argv[3], GN_ANY_BASE, "data"); 17 | num_sigs = (argc > 4) ? getInt(argv[4], GN_GT_0, "num-sigs") : 1; 18 | 19 | for (j = 0; j < num_sigs; ++j) 20 | { 21 | sv.sival_int = sig_data + j; 22 | if (sigqueue(getLong(argv[1], 0, "pid"), sig, sv) == -1) 23 | errExit("sigqueue %d", j); 24 | } 25 | 26 | exit(EXIT_SUCCESS); 27 | } -------------------------------------------------------------------------------- /chapter-12/example/procfs_pidmax.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | #define MAX_LINE 100 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | int fd; 9 | char line[MAX_LINE]; 10 | ssize_t n; 11 | 12 | fd = open("/proc/sys/kernel/pid_max", (argc > 1) ? O_RDWR : O_RDONLY); 13 | if (fd == -1) 14 | errExit("open"); 15 | 16 | n = read(fd, line, MAX_LINE); 17 | if (n == -1) 18 | errExit("read"); 19 | 20 | if (argc > 1) 21 | printf("Old value: "); 22 | printf("%.*s", (int)n, line); 23 | 24 | if (argc > 1) 25 | { 26 | size_t len = strlen(argv[1]); 27 | if (write(fd, argv[1], len) != len) 28 | fatal("write() failed"); 29 | 30 | system("echo /proc/sys/kernel/pid_max now contains " 31 | "`cat /proc/sys/kernel/pid_max`"); 32 | } 33 | exit(EXIT_SUCCESS); 34 | } -------------------------------------------------------------------------------- /chapter-40/exercise/40-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | char *my_getlogin(void) 8 | { 9 | static char buf[UT_NAMESIZE]; 10 | char *tty_name; 11 | struct utmp *line; 12 | 13 | if ((tty_name = ttyname(STDIN_FILENO)) == NULL) 14 | { 15 | return NULL; 16 | } 17 | 18 | tty_name = basename(tty_name); 19 | 20 | setutent(); 21 | 22 | //puts(tty_name); 23 | while ((line = getutent()) != NULL) 24 | { 25 | //puts(line->ut_line); 26 | if (strcmp(line->ut_line, tty_name) == 0) 27 | { 28 | strcpy(buf, line->ut_user); 29 | return buf; 30 | } 31 | } 32 | return NULL; 33 | } 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | char *p = my_getlogin(); 38 | puts(p ? p : "fuck"); 39 | } 40 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/vis_f2.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* vis_f2.c 12 | 13 | */ 14 | int 15 | vis_f2(int k) 16 | { 17 | int vis_comm(int j); 18 | 19 | return vis_comm(k) * vis_comm(k); 20 | } 21 | -------------------------------------------------------------------------------- /chapter-45/exercise/45-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | const char* FILE_PATH = "45-1.c"; 8 | 9 | int main(void) 10 | { 11 | struct stat st; 12 | key_t key; 13 | int proj_id; 14 | 15 | if (stat(FILE_PATH, &st) == -1) 16 | errExit("stat"); 17 | 18 | proj_id = 0x1234; 19 | key = ftok(FILE_PATH, proj_id); 20 | 21 | printf("key: %x\n", key); 22 | printf("inode: %lx\n", st.st_ino); 23 | printf("device: %lx\n", st.st_dev); 24 | printf("proj_id:%x\n", proj_id); 25 | 26 | /* 27 | key 比特示意 |31|30|...|1|0| 28 | key 31-24位是prod_id的低8位,23-16位是次设备号,即st_dev的低8位,15-0是i节点的低16位。 29 | key |= (proj_id & 0xff); 30 | key <<= 8; 31 | key |= (st.st_dev & 0xff); 32 | key <<= 16; 33 | key |= (st.st_ino & 0xffff); 34 | */ 35 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/vis_f1.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* vis_f1.c 12 | 13 | */ 14 | int 15 | vis_f1(int k) 16 | { 17 | int vis_comm(int j); 18 | 19 | return vis_comm(k) / 2; 20 | } 21 | -------------------------------------------------------------------------------- /chapter-5/relationshipBetweenFdAndOpenFile.md: -------------------------------------------------------------------------------- 1 | # 文件描述符表和打开文件之间的关系 2 | 3 | 内核维护了三个数据结构: 4 | 5 | - 进程级的文件描述符( open file descriptor )表。该表的每一条目都记录了单个文件描述系统的相关信息。如下所示 6 | 7 | - 控制文件描述符操作的一组表示。根据书中所描述,目前为止(此处存疑,我没探究具体是哪个内核版本)就定义了一个,即 `close-on-exec` 标志。 8 | - 对打开文件句柄的引用。 9 | 10 | - 系统级的打开文件表(open file description table)。表中各个条目成为打开文件句柄( open file handle ),存储了打开文件的全部信息: 11 | 12 | - 当前文件的偏移量 13 | - 打开文件时所使用的状态标志位 (open() 的flag参数) 14 | - 文件访问模式 (open() 时设置的只读,只写或者读写) 15 | - 与信号驱动 I/O 相关的设置 16 | - 对文件 i-node 对象的引用 17 | 18 | - 文件系统的i-node表。慈湖忽略 i-node 在磁盘和内存中的表示差异。大概有如下信息: 19 | 20 | - 文件类型 21 | - 一个指针,指向该文件所持有的锁的列表 22 | - 文件的各种属性,包括文件大小以及与不同类型操作相关的时间戳 23 | 24 | 所以,有可能会出现如下情况: 25 | 26 | - 相同进程内的不同文件描述符指向同一个打开文件句柄。 (可能通过 dup()等操作) 27 | - 不同进程内的文件描述符指向同一个打开文件句柄。 (可能在 fork() 后出现这种情况) 28 | - 不同进程内的文件描述符指向不同的打开文件句柄,但是这些句柄都指向 i-node 表中相同的条目。 (可能在不同进程内 open 了同一个文件) 29 | 30 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/vis_comm.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* vis_comm.c 12 | 13 | */ 14 | int /* Function used by vis_f1() and vis_f2() */ 15 | vis_comm(int j) 16 | { 17 | return j * j; 18 | } 19 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/vis_f2.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* vis_f2.c 12 | 13 | */ 14 | int 15 | vis_f2(int k) 16 | { 17 | int vis_comm(int j); 18 | 19 | return vis_comm(k) * vis_comm(k); 20 | } 21 | -------------------------------------------------------------------------------- /chapter-11/example/t_sysconf.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void sysconf_print(const char* msg, int name) 4 | { 5 | long lim; 6 | 7 | errno = 0; 8 | lim = sysconf(name); 9 | if (lim != -1) 10 | { 11 | printf("%s %ld\n", msg, lim); 12 | } 13 | else 14 | { 15 | if (errno == 0) 16 | printf("%s (indeterminate)\n", msg); 17 | else 18 | errExit("sysconf %s", msg); 19 | } 20 | } 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | sysconf_print("_SC_ARG_MAX: ", _SC_ARG_MAX); 25 | sysconf_print("_SC_LOGIN_NAME_MAX: ", _SC_LOGIN_NAME_MAX); 26 | sysconf_print("_SC_OPEN_MAX ", _SC_OPEN_MAX); 27 | sysconf_print("_SC_NGROUPS_MAX ", _SC_NGROUPS_MAX); 28 | sysconf_print("_SC_PAGESIZE ", _SC_PAGESIZE); 29 | sysconf_print("_SC_RTSIG_MAX ", _SC_RTSIG_MAX); 30 | exit(EXIT_SUCCESS); 31 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/vis_comm.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* vis_comm.c 12 | 13 | */ 14 | int /* Function used by vis_f1() and vis_f2() */ 15 | vis_comm(int j) 16 | { 17 | return j * j; 18 | } 19 | -------------------------------------------------------------------------------- /chapter-20/example/sig_sender.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int num_sigs, sig, j; 7 | pid_t pid; 8 | 9 | if (argc < 4 || strcmp(argv[1], "--help") == 0) 10 | usageErr("%s pid num-sigs sig-num [sig-num-2]\n", argv[0]); 11 | pid = getLong(argv[1], 0, "PID"); 12 | num_sigs = getInt(argv[2], GN_GT_0, "num-sigs"); 13 | sig = getInt(argv[3], 0, "sig-num"); 14 | 15 | printf("%s: sending signal %d to process %ld %d times\n", argv[0], sig, (long)pid, num_sigs); 16 | 17 | for (j = 0; j < num_sigs; ++j) 18 | { 19 | if (kill(pid, sig) == -1) 20 | errExit("kill"); 21 | } 22 | 23 | if (argc > 4) 24 | { 25 | if (kill(pid, getInt(argv[4], 0, "sig-num-2")) == -1) 26 | errExit("kill"); 27 | } 28 | 29 | printf("%s: exiting\n", argv[0]); 30 | exit(EXIT_SUCCESS); 31 | } -------------------------------------------------------------------------------- /chapter-18/exercise/18-7.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 500 2 | #include 3 | #include 4 | #include 5 | 6 | size_t sock, lnk, reg, blk, dir, chr, fifo; 7 | 8 | int fn(const char *fpath, const struct stat *sb, 9 | int typeflag, struct FTW *ftwbuf) 10 | { 11 | for (int i = 0; i < ftwbuf->level; ++i) 12 | printf("\t"); 13 | 14 | printf("%s\n", &fpath[ftwbuf->base]); 15 | switch (sb->st_mode & S_IFMT) 16 | { 17 | case S_IFSOCK: ++sock; break; 18 | case S_IFLNK: ++lnk; break; 19 | case S_IFREG: ++reg; break; 20 | case S_IFBLK: ++blk; break; 21 | case S_IFDIR: ++dir; break; 22 | case S_IFCHR: ++chr; break; 23 | case S_IFIFO: ++fifo; break; 24 | } 25 | return 0; 26 | } 27 | 28 | int main(void) 29 | { 30 | nftw("../../", fn, 10, 0); 31 | printf("%ld %ld %ld %ld %ld %ld %ld\n", sock, lnk, reg, blk, dir, chr, fifo); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /chapter-42/exercise/42-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "tlpi_hdr.h" 8 | 9 | int main(void) 10 | { 11 | int status; 12 | void *parent_ret; 13 | pid_t child_pid; 14 | 15 | switch(child_pid = fork()) 16 | { 17 | case -1: 18 | errExit("fork()"); 19 | case 0: 20 | pause(); 21 | default: 22 | parent_ret = dlopen("libc.so.6", RTLD_NOW); 23 | if (parent_ret == NULL) 24 | fatal("dlopen: %s", dlerror()); 25 | assert(dlclose(parent_ret) == 0); 26 | assert(dlopen("libc.so.6", RTLD_LAZY | RTLD_NOLOAD) != NULL); 27 | //if (parent_ret == NULL) 28 | // fatal("dlopen: %s", dlerror()); 29 | printf("libc.so.6 is still in memory\n"); 30 | kill(child_pid, SIGINT); 31 | wait(&status); 32 | } 33 | } -------------------------------------------------------------------------------- /chapter-31/example/strerror_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | static void *thread_func(void *arg) 7 | { 8 | char *str; 9 | 10 | printf("Other thread about to call strerror()\n"); 11 | str = strerror(EPERM); 12 | printf("Other thread: str (%p) = %s\n", str, str); 13 | 14 | return NULL; 15 | } 16 | 17 | int main(int argc, char *argv[]) 18 | { 19 | pthread_t t; 20 | int s; 21 | char *str; 22 | 23 | str = strerror(EINVAL); 24 | printf("Main thread has called strerror()\n"); 25 | 26 | s = pthread_create(&t, NULL, thread_func, NULL); 27 | if (s != 0) 28 | { 29 | errExitEN(s, "pthread_create"); 30 | } 31 | 32 | s = pthread_join(t, NULL); 33 | if (s != 0) 34 | errExitEN(s, "pthread_join"); 35 | 36 | printf("Main thread: str (%p) = %s\n", str, str); 37 | 38 | exit(EXIT_SUCCESS); 39 | } -------------------------------------------------------------------------------- /chapter-35/example/sched_view.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int j, pol; 7 | struct sched_param sp; 8 | 9 | for (j = 1; j < argc; ++j) 10 | { 11 | pol = sched_getscheduler(getLong(argv[j], 0, "pid")); 12 | if (pol == -1) 13 | errExit("sched_getscheduler"); 14 | 15 | if (sched_getparam(getLong(argv[j], 0, "pid"), &sp) == -1) 16 | errExit("sched_getparam"); 17 | 18 | printf("%s: %-5s %2d\n", argv[j], (pol == SCHED_OTHER) ? "OTHER" : 19 | (pol == SCHED_RR) ? "RR" : 20 | (pol == SCHED_FIFO) ? "FIFO": 21 | #ifdef SCHED_BATCH 22 | (pol == SCHED_BATCH) ? "BATCH": 23 | #endif 24 | #ifdef SCHED_IDLE 25 | (pol == SCHED_IDLE) ? "IDLE" : 26 | #endif 27 | "???", sp.sched_priority); 28 | } 29 | 30 | errExit(EXIT_SUCCESS); 31 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_prog.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_prog.c 12 | 13 | */ 14 | #include 15 | 16 | int 17 | main(int argc, char *argv[]) 18 | { 19 | void xyz(void); 20 | 21 | xyz(); 22 | 23 | exit(EXIT_SUCCESS); 24 | } 25 | -------------------------------------------------------------------------------- /chapter-34/exercise/34-3.c: -------------------------------------------------------------------------------- 1 | // 进程组首进程调用 setsid() 会失败 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | int main(void) 8 | { 9 | pid_t child_pid; 10 | // if (setpgid(0, 0) == -1) 11 | // errExit("setpgid"); 12 | 13 | // if (setsid() == -1) 14 | // errExit("setsid"); 15 | switch (child_pid = fork()) 16 | { 17 | case -1: 18 | errExit("fork"); 19 | case 0: 20 | printf("PID: %ld PGID: %ld\n", (long)getpid(), (long)getpgrp()); 21 | if (setpgid(0, 0) == -1) 22 | errExit("setpgid"); 23 | signal(SIGTTOU, SIG_IGN); 24 | if (tcsetpgrp(STDOUT_FILENO, getpgrp()) == -1) 25 | errExit("tcsetpgrp"); 26 | printf("fuck\n"); 27 | if (setsid() == -1) 28 | errExit("setsid"); 29 | printf("fuck\n"); 30 | break; 31 | default: 32 | sleep(3); 33 | } 34 | } -------------------------------------------------------------------------------- /chapter-25/example/exit_handlers.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | static void atexit_func1(void) 6 | { 7 | printf("atexit function 1 called\n"); 8 | } 9 | 10 | static void atexit_func2(void) 11 | { 12 | printf("atexit function 2 called\n"); 13 | } 14 | 15 | static void onexit_func(int exit_status, void *arg) 16 | { 17 | printf("on_exit function called: status=%d, arg = %ld\n", 18 | exit_status, (long)arg); 19 | } 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | if (on_exit(onexit_func, (void *)10) != 0) 24 | { 25 | fatal("on_exit 1"); 26 | } 27 | if (atexit(atexit_func1) != 0) 28 | { 29 | fatal("atexit 1"); 30 | } 31 | if (atexit(atexit_func2) != 0) 32 | { 33 | fatal("atexit 2"); 34 | } 35 | if (on_exit(onexit_func, (void *)20) != 0) 36 | { 37 | fatal("on_exit 2"); 38 | } 39 | exit(2); 40 | } -------------------------------------------------------------------------------- /chapter-36/example/print_rlimit.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINT_RLIMIT_H 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | static inline int print_rlimit(const char *msg, int resource) 6 | { 7 | struct rlimit rlim; 8 | 9 | if (getrlimit(resource, &rlim) == -1) 10 | return -1; 11 | 12 | printf("%s soft=", msg); 13 | if (rlim.rlim_cur == RLIM_INFINITY) 14 | printf("infinite"); 15 | #ifdef RLIM_SAVED_CUR 16 | else if (rlim.rlim_cur == RLIM_SAVED_CUR) 17 | printf("unrepresentable"); 18 | #endif 19 | else 20 | printf("%lld", (long long)rlim.rlim_cur); 21 | 22 | printf("; hard="); 23 | if (rlim.rlim_max == RLIM_INFINITY) 24 | printf("ininite\n"); 25 | #ifdef RLIM_SAVED_CUR 26 | else if (rlim.rlim_max == RLIM_SAVED_CUR) 27 | printf("unpresentable"); 28 | #endif 29 | else 30 | printf("%lld\n", (long long)rlim.rlim_max); 31 | 32 | return 0; 33 | } 34 | 35 | #endif -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_prog.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_prog.c 12 | 13 | */ 14 | #include 15 | 16 | int 17 | main(int argc, char *argv[]) 18 | { 19 | void xyz(void); 20 | 21 | xyz(); 22 | 23 | exit(EXIT_SUCCESS); 24 | } 25 | -------------------------------------------------------------------------------- /chapter-36/exercise/36-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "tlpi_hdr.h" 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | int status; 11 | struct rusage sr; 12 | 13 | switch (fork()) 14 | { 15 | case -1: 16 | errExit("fork"); 17 | case 0: 18 | for (int i = 0; i < 1000000000; ++i) 19 | continue; 20 | _exit(EXIT_SUCCESS); 21 | default: 22 | if (getrusage(RUSAGE_CHILDREN, &sr) == -1) 23 | errExit("getrusage"); 24 | 25 | printf("%ld\t%ld\n", sr.ru_utime.tv_sec, sr.ru_utime.tv_usec); 26 | if (wait(&status) == -1) 27 | errExit("wait"); 28 | //printf("%d\n", status); 29 | if (getrusage(RUSAGE_CHILDREN, &sr) == -1) 30 | errExit("getrusage"); 31 | printf("%ld\t%ld\n", sr.ru_utime.tv_sec, sr.ru_utime.tv_usec); 32 | } 33 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_libabc.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_libabc.c 12 | 13 | */ 14 | #include 15 | 16 | void 17 | abc(void) 18 | { 19 | void xyz(void); 20 | 21 | printf("abc() calling xyz()\n"); 22 | xyz(); 23 | } 24 | 25 | __asm__(".symver xyz,xyz@VER_1"); 26 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/prog.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* prog.c */ 12 | 13 | #include 14 | #include 15 | 16 | void x1(void); 17 | void x2(void); 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | x1(); 23 | x2(); 24 | exit(EXIT_SUCCESS); 25 | } 26 | -------------------------------------------------------------------------------- /chapter-5/example/large_file.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | 编译程序时候定义_LARGEFILE64_SOURCE功能测试宏,以使用过度型的LFS API。 3 | 该API所属函数具有处理64位文件大小和文件偏移量的能力。通常在32位版本尾部缀以64以示区别。 4 | 不过这是过渡型API,不推荐使用 5 | 推荐使用#define _FILE_OFF_SETBITS 64,就无需显式使用64位函数版本 6 | ***************************************************************************/ 7 | #define _LARGEFILE64_SOURCE 8 | #include 9 | #include 10 | #include "tlpi_hdr.h" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | int fd; 15 | off64_t off; 16 | if (argc != 3 || strcmp(argv[1]. "--help") == 0) 17 | { 18 | usageErr("%s pathname offset\n", argv[0]); 19 | } 20 | 21 | fd = open64(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 22 | (fd == -1) 23 | errExit("open64"); 24 | 25 | off = atoll(argv[2]); 26 | if (lseek64(fd, off, SEEK_SET) == -1) 27 | errExit("lseek64"); 28 | 29 | if (write(fd, "test", 4) == -1) 30 | errExit("write"); 31 | exit(EXIT_SUCCESS); 32 | } -------------------------------------------------------------------------------- /tlpi-dist/procexec/fork_whos_on_first.count.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | # 3 | # fork_whos_on_first.count.awk 4 | # 5 | # Copyright, Michael Kerrisk, 2002 6 | # 7 | # Read (on stdin) the results of running the fork_whos_on_first.c 8 | # program to assess the percentage iof cases in which parent or child 9 | # was first to print a post-fork() message 10 | # 11 | BEGIN { 12 | last = -1; 13 | } 14 | 15 | { 16 | # match pairs of lines by field 1 (loop counter) 17 | 18 | if ($1 != last) { 19 | cat[$2]++; 20 | tot++; 21 | } 22 | last = $1; 23 | } 24 | 25 | # Our input file may be long - periodically print a progress 26 | # message with statistics so far 27 | NR % 200000 == 0 { 28 | print "Num children = ", NR / 2; 29 | for (k in cat) 30 | printf "%-6s %6d %6.2f%%\n", k, cat[k], cat[k] / tot * 100; 31 | } 32 | 33 | END { 34 | print "All done"; 35 | for (k in cat) 36 | printf "%-6s %6d %6.2f%%\n", k, cat[k], cat[k] / tot * 100; 37 | } 38 | -------------------------------------------------------------------------------- /chapter-22/example/signalfd_sigval.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | sigset_t mask; 9 | int sfd, j; 10 | struct signalfd_siginfo fdsi; 11 | ssize_t s; 12 | 13 | printf("PID = %ld\n", (long)getpid()); 14 | 15 | sigemptyset(&mask); 16 | for (j = 1; j < argc; ++j) 17 | sigaddset(&mask, atoi(argv[j])); 18 | 19 | sfd = signalfd(-1, &mask, 0); 20 | if (sfd == -1) 21 | errExit("signalfd"); 22 | 23 | for (;;) 24 | { 25 | s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo)); 26 | if (s != sizeof(struct signalfd_siginfo)) 27 | errExit("read"); 28 | 29 | printf("got signal %d", fdsi.ssi_signo); 30 | if (fdsi.ssi_code == SI_QUEUE) 31 | { 32 | printf("; ssi_pid=%d;ssiint=%d", fdsi.ssi_pid, fdsi.ssi_int); 33 | } 34 | printf("\n"); 35 | } 36 | } -------------------------------------------------------------------------------- /chapter-32/example/thread_cancel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | static void *thread_func(void *arg) 5 | { 6 | int j; 7 | printf("New thread started\n"); 8 | for (j = 0; ; ++j) 9 | { 10 | printf("Loop %d\n", j); 11 | } 12 | 13 | return NULL; 14 | } 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | pthread_t thr; 19 | int s; 20 | void *res; 21 | 22 | s = pthread_create(&thr, NULL, thread_func, NULL); 23 | if (s != 0) 24 | errExitEN(s, "pthread_create"); 25 | 26 | sleep(3); 27 | 28 | s = pthread_cancel(thr); 29 | if (s != 0) 30 | errExitEN(s, "pthread_cancel"); 31 | 32 | s = pthread_join(thr, &res); 33 | if (s != 0) 34 | errExitEN(s, "pthread_join"); 35 | 36 | if (res == PTHREAD_CANCELED) 37 | printf("Thread was canceled\n"); 38 | else 39 | printf("Thread was not canceled (should not happen!)\n"); 40 | 41 | exit(EXIT_SUCCESS); 42 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_libabc.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_libabc.c 12 | 13 | */ 14 | #include 15 | 16 | void 17 | abc(void) 18 | { 19 | void xyz(void); 20 | 21 | printf("abc() calling xyz()\n"); 22 | xyz(); 23 | } 24 | 25 | __asm__(".symver xyz,xyz@VER_1"); 26 | -------------------------------------------------------------------------------- /chapter-18/exercise/18-2.md: -------------------------------------------------------------------------------- 1 | 以下程序运行到`chmod()`函数会出错。这是为什么呢? 2 | 3 | ```C 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "tlpi_hdr.h" 9 | 10 | int main(void) 11 | { 12 | int fd; 13 | 14 | mkdir("test", S_IRUSR | S_IWUSR | S_IXUSR); 15 | chdir("test"); 16 | fd = open("myfile", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 17 | symlink("myfile", "../mylink"); 18 | if (chmod("../mylink", S_IRUSR) == -1) 19 | errExit("chmod"); 20 | return 0; 21 | } 22 | ``` 23 | 24 | 首先了解一下,符号链接本质就是存一串代表路径的字符串作为`handle`,然后就能根据这个路径找到链接的文件。 25 | 26 | 从linux自带的manual上可以查到,symlink函数原型是: 27 | 28 | ```C 29 | int symlink(const char *target, const char *linkpath); 30 | ``` 31 | 32 | 作用之一是: 33 | 34 | > symlink() creates a symbolic link named linkpath which contains the string target. 35 | 36 | 划重点:*contains the string target*。也就是说符号链接 `mylink` 中存字符串的是`myfile`,对 `myfile` 解引用自然找不到这个文件(因为在test目录下)。 37 | 38 | 所以符号链接最好直接存绝对路径...防止被坑。 -------------------------------------------------------------------------------- /tlpi-dist/shlibs/mod1.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* mod1.c */ 12 | 13 | #include 14 | #include 15 | int test1[250000] = { 1, 2, 3 }; 16 | 17 | #ifndef VERSION 18 | #define VERSION "" 19 | #endif 20 | 21 | void 22 | x1(void) { 23 | printf("Called mod1-x1 " VERSION "\n"); 24 | } 25 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/mod2.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* mod2.c */ 12 | 13 | #include 14 | #include 15 | int test2[100000] = { 1, 2, 3 }; 16 | 17 | #ifndef VERSION 18 | #define VERSION "" 19 | #endif 20 | 21 | void 22 | x2(void) { 23 | printf("Called mod2-x2 " VERSION "\n"); 24 | } 25 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/mod3.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* mod3.c */ 12 | 13 | #include 14 | #include 15 | int test3[10000] = { 1, 2, 3 }; 16 | 17 | #ifndef VERSION 18 | #define VERSION "" 19 | #endif 20 | 21 | void 22 | x3(void) { 23 | printf("Called mod3-x3 " VERSION "\n"); 24 | } 25 | -------------------------------------------------------------------------------- /chapter-26/example/make_zombie.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | #define CMD_SIZE 200 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | char cmd[CMD_SIZE]; 10 | pid_t child_pid; 11 | 12 | setbuf(stdout, NULL); 13 | 14 | printf("Parent PID=%ld\n", (long)getpid()); 15 | 16 | switch (child_pid = fork()) 17 | { 18 | case -1: 19 | errExit("fork"); 20 | 21 | case 0: 22 | printf("Child (PID=%ld) exiting\n", (long)getpid()); 23 | _exit(EXIT_SUCCESS); 24 | 25 | default: 26 | sleep(3); 27 | snprintf(cmd, CMD_SIZE, "ps | grep %s", basename(argv[0])); 28 | cmd[CMD_SIZE-1] = '\0'; 29 | system(cmd); 30 | 31 | if (kill(child_pid, SIGKILL) == -1) 32 | errMsg("kill"); 33 | sleep(3); 34 | printf("After sending SIGKILL to zombie (PID=%ld):\n", (long)child_pid); 35 | system(cmd); 36 | 37 | exit(EXIT_SUCCESS); 38 | } 39 | } -------------------------------------------------------------------------------- /chapter-25/exercise/25-1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * WEXITSTATUS(status) 3 | * returns the exit status of the child. This consists of the 4 | * least significant 8 bits of the status argument that the child 5 | * specified in a call to exit(3) or _exit(2) or as the argument 6 | * for a return statement in main(). This macro should be employed 7 | * only if WIFEXITED returned true. 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "tlpi_hdr.h" 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | pid_t pid; 17 | int status; 18 | 19 | switch (pid = fork()) 20 | { 21 | case -1: 22 | errExit("fork"); 23 | case 0: 24 | exit(-1); 25 | default: 26 | if (wait(&status) == -1) 27 | errExit("wait"); 28 | if (WIFEXITED(status)) 29 | printf("0x%x\n", WEXITSTATUS(status)); // Output 0xff 30 | else 31 | errExit("WIFEXITED"); 32 | exit(EXIT_SUCCESS); 33 | } 34 | } -------------------------------------------------------------------------------- /chapter-28/exercise/28-1.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | void run(pid_t (*fun)(void), size_t cnt) 11 | { 12 | int status; 13 | clock_t begin, end; 14 | 15 | begin = clock(); 16 | for (int i = 0; i < cnt; ++i) 17 | { 18 | 19 | switch (fun()) 20 | { 21 | case -1: 22 | exit(EXIT_FAILURE); 23 | case 0: 24 | _exit(EXIT_SUCCESS); 25 | default: 26 | wait(&status); 27 | break; 28 | } 29 | } 30 | end = clock(); 31 | printf("%lf\n", (double)(end-begin)/CLOCKS_PER_SEC); 32 | } 33 | 34 | int main(void) 35 | { 36 | const size_t times = 10000; 37 | printf("fork() %llu :", (unsigned long long)times); 38 | run(fork, times); 39 | 40 | printf("vfork() %llu :", (unsigned long long)times); 41 | run(vfork, times); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /tlpi-dist/sockets/read_line.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 59-1 */ 12 | 13 | /* read_line.h 14 | 15 | Header file for read_line.c. 16 | */ 17 | #ifndef READ_LINE_H 18 | #define READ_LINE_H 19 | 20 | #include 21 | 22 | ssize_t readLine(int fd, void *buffer, size_t n); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tlpi-dist/time/curr_time.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 10-2 */ 12 | 13 | /* curr_time.h 14 | 15 | Header file for curr_time.c. 16 | */ 17 | #ifndef CURR_TIME_H 18 | #define CURR_TIME_H /* Prevent accidental double inclusion */ 19 | 20 | char *currTime(const char *fmt); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /chapter-10/example/strtime.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | #define SBUF_SIZE 1000 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | struct tm tm; 11 | char sbuf[SBUF_SIZE]; 12 | char *ofmt; 13 | 14 | if (argc < 3 || strcmp(argv[1], "--help") == 0) 15 | usageErr("%s input-date-time in-format [out-format]\n", argv[0]); 16 | 17 | if (setlocale(LC_ALL, "") == NULL) 18 | errExit("setlocale"); 19 | 20 | memset(&tm, 0, sizeof(struct tm)); 21 | if (strptime(argv[1], argv[2], &tm) == NULL) 22 | fatal("strptime"); 23 | 24 | tm.tm_isdst = -1; 25 | 26 | printf("calender time (seconds since Epoch): %ld\n", (long)mktime(&tm)); 27 | 28 | ofmt = (argc > 3) ? argv[3] : "%H:%M:%S %A, %d %B %Y %Z"; 29 | if (strftime(sbuf, SBUF_SIZE, ofmt, &tm) == 0) 30 | fatal("strftime returned 0"); 31 | 32 | printf("strftime() yields: %s\n", sbuf); 33 | 34 | exit(EXIT_SUCCESS); 35 | 36 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/demo_Bsymbolic/foo3.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* foo3.c 12 | 13 | */ 14 | #include 15 | #include 16 | 17 | void 18 | xyz(void) 19 | { 20 | printf(" func3-xyz\n"); 21 | } 22 | 23 | void 24 | func3(int x) 25 | { 26 | printf("Called func3\n"); 27 | xyz(); 28 | abc(); 29 | } 30 | -------------------------------------------------------------------------------- /chapter-5/exercise/5-6.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 内核维护了三个数据结构: 3 | * 1.进程级的文件描述符表 4 | * 2.系统级的打开文件表 5 | * 3.文件系统的i-node表 6 | * 成功调用dup的话(man上的资料):They (指的是newfd和oldfd) refer to the same open file description and 7 | * thus share file offset and file status flags. 8 | * 也就是说公用打开文件表中的一项,从而偏移量相同。 9 | * 而对同一个文件调用两次open的话,打开文件表中会出现两项 10 | * 从而最后结果是写入了 Giddayworld 11 | ********************************************************************************/ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int main() 19 | { 20 | int fd1, fd2, fd3; 21 | const char *file = "test.txt"; 22 | fd1 = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 23 | fd2 = dup(fd1); 24 | fd3 = open(file, O_RDWR); 25 | write(fd1, "Hello,", 6); 26 | write(fd2, "world", 6); 27 | lseek(fd2, 0, SEEK_SET); 28 | write(fd1, "HELLO,", 6); 29 | write(fd3, "Gidday", 6); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /chapter-34/example/catch_SIGHUP.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 500 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | static void handler(int sig) 7 | { 8 | } 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | pid_t child_pid; 13 | struct sigaction sa; 14 | 15 | setbuf(stdout, NULL); 16 | 17 | sigemptyset(&sa.sa_mask); 18 | sa.sa_flags = 0; 19 | sa.sa_handler = handler; 20 | if (sigaction(SIGHUP, &sa, NULL) == -1) 21 | errExit("sigaction"); 22 | 23 | child_pid = fork(); 24 | if (child_pid == -1) 25 | errExit("fork"); 26 | 27 | if (child_pid == 0 && argc > 1) 28 | { 29 | if (setpgid(0, 0) == -1) 30 | errExit("setpgid"); 31 | } 32 | 33 | printf("PID=%ld; PPID=%ld; PGID=%ld; SID=%ld\n", (long)getpid(), 34 | (long)getppid(), (long)getpgrp(), (long)getsid(0)); 35 | 36 | alarm(30); 37 | 38 | for (;;) 39 | { 40 | pause(); 41 | printf("%ld: caught SIGHUP\n", (long)getpid()); 42 | } 43 | } -------------------------------------------------------------------------------- /chapter-27/example/t_system.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "print_wait_status.h" 3 | #include "tlpi_hdr.h" 4 | 5 | #define MAX_CMD_LEN 200 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | char str[MAX_CMD_LEN]; 10 | int status; 11 | 12 | for (;;) 13 | { 14 | printf("Command: "); 15 | fflush(stdout); 16 | if (fgets(str, MAX_CMD_LEN, stdin) == NULL) 17 | break; 18 | 19 | status = system(str); 20 | printf("system() returned: status=%04x (%d,%d)\n", 21 | (unsigned int)status, status >> 8, status & 0xff); 22 | 23 | if (status== -1) 24 | { 25 | errExit("system"); 26 | } 27 | else 28 | { 29 | if (WIFEXITED(status) && WEXITSTATUS(status) == 127) 30 | { 31 | printf("(Probably) could not ivoke shell\n"); 32 | } 33 | else 34 | { 35 | print_wait_status(NULL, status); 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /tlpi-dist/procres/print_rlimit.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 36-2 */ 12 | 13 | /* print_rlimit.h 14 | 15 | Header file for print_rlimit.c. 16 | */ 17 | #ifndef PRINT_RLIMIT_H /* Prevent accidental double inclusion */ 18 | #define PRINT_RLIMIT_H 19 | 20 | int printRlimit(const char *msg, int resource); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_prog_abc.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_prog_abc.c 12 | 13 | */ 14 | #include 15 | #include 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | void xyz(void), abc(void); 21 | 22 | printf("main() calling xyz()\n"); 23 | xyz(); 24 | 25 | abc(); 26 | 27 | exit(EXIT_SUCCESS); 28 | } 29 | -------------------------------------------------------------------------------- /tlpi-dist/sockets/us_xfr_v2.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Solution for Exercise 59-3:c */ 12 | 13 | /* us_xfr_v2.h 14 | 15 | Header file for us_xfr_sv.c and us_xfr_cl.c. 16 | */ 17 | #include "unix_sockets.h" /* Declares our socket functions */ 18 | #include "tlpi_hdr.h" 19 | 20 | #define SV_SOCK_PATH "us_xfr_v2" 21 | 22 | #define BUF_SIZE 100 23 | -------------------------------------------------------------------------------- /chapter-45/exercise/45-2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "tlpi_hdr.h" 7 | 8 | key_t my_ftok(const char *pathname, int proj_id) 9 | { 10 | key_t key; 11 | struct stat st; 12 | 13 | if (stat(pathname, &st) == -1) 14 | { 15 | key = -1; 16 | } 17 | else 18 | { 19 | key = 0; 20 | // printf("%x\n", proj_id&0xff); 21 | key |= (proj_id & 0xff); 22 | // printf("%x\n", key); 23 | key <<= 8; 24 | // printf("%x\n", st.st_dev&0xff); 25 | key |= (st.st_dev & 0xff); 26 | // printf("%x\n", key); 27 | key <<= 16; 28 | // printf("%x\n", st.st_ino&0xffff); 29 | key |= (st.st_ino & 0xffff); 30 | // printf("%x\n", key); 31 | } 32 | return key; 33 | } 34 | 35 | int main(void) 36 | { 37 | // printf("%x\n%x\n", my_ftok("./45-2.c", 666), ftok("./45-2.c", 666)); 38 | assert(my_ftok("./45-2.c", 666) == ftok("./45-2.c", 666)); 39 | } -------------------------------------------------------------------------------- /chapter-5/exercise/5-2.c: -------------------------------------------------------------------------------- 1 | /********************************* 2 | 使用O_APPEND标志打开一个已存在的文件, 3 | 且将文件偏移量置于文件起始处。再写入数据, 4 | 数据会接在原文件后。这是因为 对于lseek来 5 | 说,它直接修改文件描述符表项中的当前文件偏 6 | 移量,并返回当前的文件偏移量,而对于O_APPEND 7 | 标志,则只是将其设置到了文件表项的文件状态 8 | 标志中,此时当前文件偏移量并未修改,仍然为 9 | 0,只有当用户企图写入文件时,才将文件当前 10 | 偏移量置为文件长度。 11 | *********************************/ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int main(int argc, char **argv) 21 | { 22 | int fd; 23 | off_t off; 24 | ssize_t numWritten; 25 | 26 | if (argc != 2 || strcmp(argv[1], "--help") == 0) 27 | { 28 | exit(EXIT_FAILURE); 29 | } 30 | 31 | fd = open(argv[1], O_WRONLY | O_APPEND); 32 | if (fd == -1) 33 | { 34 | exit(EXIT_FAILURE); 35 | } 36 | 37 | off = lseek(fd, 0, SEEK_SET); 38 | if (off == -1) 39 | exit(EXIT_FAILURE); 40 | 41 | numWritten = write(fd, "f**k\n", 5); 42 | if (numWritten == -1) 43 | exit(EXIT_FAILURE); 44 | close(fd); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /tlpi-dist/pty/pty_master_open.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 64-1 */ 12 | 13 | /* pty_open.h 14 | 15 | Header file for pty_open.c (and pty_master_open_bsd.c). 16 | */ 17 | #ifndef PTY_MASTER_OPEN_H 18 | #define PTY_MASTER_OPEN_H 19 | 20 | #include 21 | 22 | int ptyMasterOpen(char *slaveName, size_t snLen); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_prog_abc.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_prog_abc.c 12 | 13 | */ 14 | #include 15 | #include 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | void xyz(void), abc(void); 21 | 22 | printf("main() calling xyz()\n"); 23 | xyz(); 24 | 25 | abc(); 26 | 27 | exit(EXIT_SUCCESS); 28 | } 29 | -------------------------------------------------------------------------------- /tlpi-dist/sockets/rdwrn.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 61-1 */ 12 | 13 | /* rdwrn.h 14 | 15 | Header file for rdwrn.c. 16 | */ 17 | #ifndef RDWRN_H 18 | #define RDWRN_H 19 | 20 | #include 21 | 22 | ssize_t readn(int fd, void *buf, size_t len); 23 | 24 | ssize_t writen(int fd, const void *buf, size_t len); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /chapter-5/exercise/5-4.c: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | * 用fcntl实现dup和dup2 3 | * 用fcntl(oldfd, F_GETFL) 可以检查oldfd是否打开, 4 | * 未打开返回-1 5 | *******************************************/ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int mydup(int oldfd); 13 | int mydup2(int oldfd, int newfd); 14 | int main(int argc, char **argv) 15 | { 16 | int fd, newfd; 17 | 18 | newfd = mydup(0); 19 | 20 | printf("old fd is 0, new fd is %d\n", newfd); 21 | 22 | newfd = mydup2(0, 4); 23 | 24 | printf("old fd is 0, new fd is %d\n", newfd); 25 | 26 | return 0; 27 | } 28 | 29 | int mydup(int oldfd) 30 | { 31 | return fcntl(oldfd, F_DUPFD, 0); 32 | } 33 | 34 | int mydup2(int oldfd, int newfd) 35 | { 36 | if (newfd < 0) 37 | { 38 | errno = EBADF; 39 | return -1; 40 | } 41 | 42 | if (fcntl(oldfd, F_GETFL) == -1) 43 | return -1; 44 | 45 | if (oldfd == newfd) 46 | return old; 47 | 48 | close(newfd); 49 | 50 | return fcntl(oldfd, F_DUPFD, newfd); 51 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/version_scripts/sv_lib_v2.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_lib_v2.c 12 | 13 | */ 14 | 15 | #include 16 | 17 | __asm__(".symver xyz_old,xyz@VER_1"); 18 | __asm__(".symver xyz_new,xyz@@VER_2"); 19 | 20 | void xyz_old(void) { printf("v1 xyz\n"); } 21 | 22 | void xyz_new(void) { printf("v2 xyz\n"); } 23 | 24 | void pqr(void) { printf("v2 pqr\n"); } 25 | -------------------------------------------------------------------------------- /tlpi-dist/timers/itimerspec_from_str.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 23-6 */ 12 | 13 | /* itimerspec_from_str.h 14 | 15 | Header file for itimerspec_from_str.c. 16 | */ 17 | #ifndef ITIMERSPEC_FROM_STR_H 18 | #define ITIMERSPEC_FROM_STR_H 19 | 20 | #include 21 | 22 | void itimerspecFromStr(char *str, struct itimerspec *tsp); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tlpi-dist/procexec/print_wait_status.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 26-2 */ 12 | 13 | /* print_wait_status.h 14 | 15 | Header file for print_wait_status.c. 16 | */ 17 | #ifndef PRINT_WAIT_STATUS_H /* Prevent accidental double inclusion */ 18 | #define PRINT_WAIT_STATUS_H 19 | 20 | void printWaitStatus(const char *msg, int status); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /chapter-20/example/t_kill.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | int s, sig; 7 | 8 | if (argc != 3 || strcmp(argv[1], "--help") == 0) 9 | usageErr("%s sig-num pid\n", argv[0]); 10 | 11 | sig = getInt(argv[2], 0, "sig-num"); 12 | 13 | s = kill(getLong(argv[1], 0, "pid"), sig); 14 | 15 | if (sig != 0) 16 | { 17 | if (s == -1) 18 | errExit("kill"); 19 | } 20 | else 21 | { 22 | if (s == 0) 23 | printf("Process exists and we can send it a signal\n"); 24 | else 25 | { 26 | if (errno == EPERM) 27 | { 28 | printf("Process exits, but we don't have " 29 | "permission to send it a signal\n"); 30 | } 31 | else if (errno == ESRCH) 32 | { 33 | printf("Process does not exits\n"); 34 | } 35 | else 36 | errExit("kill"); 37 | } 38 | } 39 | exit(EXIT_SUCCESS); 40 | } -------------------------------------------------------------------------------- /chapter-6/example/setjmp_vars.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************************* 2 | * 编译器优化会重组程序的指令执行顺序,并在寄存器中存储变量。longjmp()操作会导致经过优化的变量被赋以错误值。 3 | * 将变量声明为volatile告诉优化器不要对其进行优化,从而避免了代码重组。 4 | **********************************************************************************************************************/ 5 | #include 6 | #include 7 | #include 8 | 9 | static jmp_buf env; 10 | 11 | static void doJump(int nvar, int rvar, int vvar) 12 | { 13 | printf("Inside doJump(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar); 14 | longjmp(env, 1); 15 | } 16 | 17 | int main(int argc, char **argv) 18 | { 19 | int nvar; 20 | register int rvar; 21 | volatile int vvar; 22 | 23 | nvar = 111; 24 | rvar = 222; 25 | vvar = 333; 26 | 27 | if (setjmp(env) == 0) { 28 | nvar = 777; 29 | rvar = 888; 30 | vvar = 999; 31 | doJump(nvar, rvar, vvar); 32 | } else { 33 | printf("After longjmp(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar); 34 | } 35 | exit(EXIT_SUCCESS); 36 | } -------------------------------------------------------------------------------- /chapter-6/exercise/mem_segments.c: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | * Q:为什么程序包含了一个约10mb的数组,但可执行文件的大小远小于此? 3 | * A:因为可执行文件加载后才会占据内存。进程与可执行文件不同。 4 | * 详细点来说,对于ELF格式的文件来说,初始化的全局变量和局部静态变量都保存在 .data 段; 5 | * 未初始化的全局变量和局部静态变量都放在 .bss 段。但是只是预留位置,并没有内容(在文件中不占空间)。 6 | *************************************************************************************/ 7 | #include 8 | #include 9 | 10 | char globBuf[65536]; 11 | int primes[] = {2,3,5,7}; 12 | 13 | static int sequare(int x) 14 | { 15 | int result; 16 | 17 | result = x*x; 18 | return result; 19 | } 20 | 21 | static void doCalc(int val) 22 | { 23 | printf("The square of %d is %d\n", val, square(val)); 24 | 25 | if (val < 1000) 26 | { 27 | int t; 28 | t = val * val * val; 29 | printf("The cube of %d is %d\n", val, t); 30 | } 31 | } 32 | 33 | int main(int argc, char **argv) 34 | { 35 | static int key = 9973; 36 | static char mbuf[10240000]; 37 | char *p; 38 | 39 | p = malloc(1024); 40 | 41 | doCalc(key); 42 | 43 | exit(EXIT_SUCCESS); 44 | 45 | } -------------------------------------------------------------------------------- /tlpi-dist/proc/necho.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 6-2 */ 12 | 13 | /* necho.c 14 | 15 | A simple version of echo(1): echo our command-line arguments. 16 | */ 17 | #include "tlpi_hdr.h" 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | int j; 23 | 24 | for (j = 0; j < argc; j++) 25 | printf("argv[%d] = %s\n", j, argv[j]); 26 | 27 | exit(EXIT_SUCCESS); 28 | } 29 | -------------------------------------------------------------------------------- /tlpi-dist/procres/print_rusage.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Solution for Exercise 36-2:c */ 12 | 13 | /* print_rusage.h 14 | 15 | Header file for print_rusage.c. 16 | */ 17 | #ifndef PRINT_RUSAGE_H /* Prevent accidental double inclusion */ 18 | #define PRINT_RUSAGE_H 19 | 20 | #include 21 | 22 | void printRusage(const char *leader, const struct rusage *ru); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tlpi-dist/procexec/necho.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 6-2 */ 12 | 13 | /* necho.c 14 | 15 | A simple version of echo(1): echo our command-line arguments. 16 | */ 17 | #include "tlpi_hdr.h" 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | int j; 23 | 24 | for (j = 0; j < argc; j++) 25 | printf("argv[%d] = %s\n", j, argv[j]); 26 | 27 | exit(EXIT_SUCCESS); 28 | } 29 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/demo_Bsymbolic/prog.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* prog.c 12 | 13 | */ 14 | #include 15 | #include 16 | 17 | void 18 | xyz(void) 19 | { 20 | printf(" main-xyz\n"); 21 | } 22 | 23 | int 24 | main(int argc, char*argv[]) 25 | { 26 | void func1(void), func2(void), func3(void); 27 | 28 | func1(); 29 | func2(); 30 | 31 | exit(EXIT_SUCCESS); 32 | } 33 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/g/sv_lib_v2.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* sv_lib_v2.c 12 | 13 | */ 14 | 15 | #include 16 | 17 | __asm__(".symver xyz_old,xyz@VER_1"); 18 | __asm__(".symver xyz_new,xyz@@VER_2"); 19 | __asm__(".symver pqr_old,pqr@VER_2"); 20 | 21 | void xyz_old(void) { printf("v1 xyz\n"); } 22 | 23 | void xyz_new(void) { printf("v2 xyz\n"); } 24 | 25 | void pqr_old(void) { printf("v2 pqr\n"); } 26 | -------------------------------------------------------------------------------- /tlpi-dist/tty/tty_functions.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 62-3 */ 12 | 13 | /* tty_functions.h 14 | 15 | Header file for tty_functions.c. 16 | */ 17 | #ifndef TTY_FUNCTIONS_H 18 | #define TTY_FUNCTIONS_H 19 | 20 | #include 21 | 22 | int ttySetCbreak(int fd, struct termios *prevTermios); 23 | 24 | int ttySetRaw(int fd, struct termios *prevTermios); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /chapter-30/example/thread_incr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tlpi_hdr.h" 3 | 4 | static int glob = 0; 5 | 6 | static void *thread_func(void *arg) 7 | { 8 | int loops = *((int *)arg); 9 | int loc, j; 10 | 11 | for (j = 0; j < loops; ++j) 12 | { 13 | loc = glob; 14 | loc++; 15 | glob = loc; 16 | } 17 | return NULL; 18 | } 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | pthread_t t1, t2; 23 | int loops, s; 24 | 25 | loops = (argc > 1) ? getInt(argv[1], GN_GT_0, "num-loops") : 10000000; 26 | 27 | s = pthread_create(&t1, NULL, thread_func, &loops); 28 | if (s != 0) 29 | errExitEN(s, "pthread_create"); 30 | 31 | s = pthread_create(&t2, NULL, thread_func, &loops); 32 | if (s != 0) 33 | errExitEN(s, "pthread_create"); 34 | 35 | s = pthread_join(t1, NULL); 36 | if (s != 0) 37 | errExitEN(s, "pthread_join"); 38 | 39 | s = pthread_join(t2, NULL); 40 | if (s != 0) 41 | errExitEN(s, "pthread_join"); 42 | 43 | printf("glob=%d\n", glob); 44 | exit(EXIT_SUCCESS); 45 | } -------------------------------------------------------------------------------- /tlpi-dist/shlibs/demo_Bsymbolic/foo1.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* foo1.c 12 | 13 | */ 14 | #include 15 | #include 16 | 17 | void 18 | xyz(void) 19 | { 20 | printf(" func1-xyz\n"); 21 | } 22 | 23 | void 24 | abc(void) 25 | { 26 | printf(" func1-abc\n"); 27 | } 28 | 29 | void 30 | func1(int x) 31 | { 32 | printf("Called func1\n"); 33 | xyz(); 34 | abc(); 35 | } 36 | -------------------------------------------------------------------------------- /tlpi-dist/shlibs/demo_Bsymbolic/foo2.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* foo2.c 12 | 13 | */ 14 | #include 15 | #include 16 | 17 | void 18 | xyz(void) 19 | { 20 | printf(" func2-xyz\n"); 21 | } 22 | 23 | void 24 | abc(void) 25 | { 26 | printf(" func1-abc\n"); 27 | } 28 | 29 | void 30 | func2(int x) 31 | { 32 | printf("Called func2\n"); 33 | xyz(); 34 | abc(); 35 | } 36 | -------------------------------------------------------------------------------- /chapter-27/exercise/27-6.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 父进程阻塞 SIGCHLD 信号,并wait子进程。子进程退出仍会发送 SIGCHLD 信号。 3 | * 这意味着当前进程调用 system() 后,会收到一个 SIGCHLD 信号,需要程序猿对这个信号正确地处理。 4 | * 可以试着编译 test.c 查看运行结果。 5 | */ 6 | #define _XOPEN_SOURCE 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "tlpi_hdr.h" 12 | 13 | void handler(int sig) 14 | { 15 | printf("SIGCHLD is caught!\n"); 16 | } 17 | int main(void) 18 | { 19 | int status; 20 | sigset_t mask; 21 | struct sigaction sa; 22 | 23 | sigemptyset(&mask); 24 | sigaddset(&mask, SIGCHLD); 25 | sigprocmask(SIG_BLOCK, &mask, NULL); 26 | 27 | sigemptyset(&sa.sa_mask); 28 | sa.sa_flags = 0; 29 | sa.sa_handler = handler; 30 | sigaction(SIGCHLD, &sa, NULL); 31 | 32 | switch (fork()) 33 | { 34 | case -1: 35 | errExit("fork"); 36 | 37 | case 0: 38 | _exit(EXIT_SUCCESS); 39 | 40 | default: 41 | if (wait(&status) == -1) 42 | errExit("wait"); 43 | 44 | sigprocmask(SIG_UNBLOCK, &mask, NULL); 45 | exit(EXIT_SUCCESS); 46 | } 47 | } -------------------------------------------------------------------------------- /tlpi-dist/filelock/create_pid_file.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 55-4 */ 12 | 13 | /* create_pid_file.h 14 | 15 | Header file for create_pid_file.c. 16 | */ 17 | #ifndef CREATE_PID_FILE_H /* Prevent accidental double inclusion */ 18 | #define CREATE_PID_FILE_H 19 | 20 | #define CPF_CLOEXEC 1 21 | 22 | int createPidFile(const char *progName, const char *pidFile, int flags); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tlpi-dist/sockets/scm_rights.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Supplementary program for Chapter 61 */ 12 | 13 | /* scm_rights.h 14 | 15 | Header file used by scm_rights_send.c and scm_rights_recv.c. 16 | */ 17 | #include 18 | #include 19 | #include 20 | #include "unix_sockets.h" /* Declares our unix*() socket functions */ 21 | #include "tlpi_hdr.h" 22 | 23 | #define SOCK_PATH "scm_rights" 24 | -------------------------------------------------------------------------------- /chapter-44/example/pipe_sync.c: -------------------------------------------------------------------------------- 1 | #include "tlpi_hdr.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int pfd[2]; 6 | int j, dummy; 7 | 8 | setbuf(stdout, NULL); 9 | 10 | printf("Parent started\n"); 11 | 12 | if (pipe(pfd) == -1) 13 | errExit("pipe"); 14 | 15 | for (j = 1; j < argc; ++j) 16 | { 17 | switch (fork()) 18 | { 19 | case -1: 20 | errExit("fork"); 21 | 22 | case 0: 23 | if (close(pfd[0]) == -1) 24 | errExit("close"); 25 | 26 | sleep(getInt(argv[j], GN_NONNEG, "sleep-time")); 27 | 28 | printf("Chid %d (PID=%ld) closing pipe\n", j, (long)getpid()); 29 | if (close(pfd[1]) == -1) 30 | errExit("close"); 31 | _exit(EXIT_SUCCESS); 32 | default: 33 | break; 34 | } 35 | } 36 | 37 | if (close(pfd[1]) == -1) 38 | errExit("close"); 39 | 40 | if (read(pfd[0], &dummy, 1) != 0) 41 | fatal("parent didn't get EOF"); 42 | 43 | printf("Parent ready to go\n"); 44 | 45 | exit(EXIT_SUCCESS); 46 | } -------------------------------------------------------------------------------- /chapter-23/example/timed_read.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | #define BUF_SIZE 200 6 | 7 | static void handler(int sig) 8 | { 9 | printf("Caught signal\n"); 10 | } 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | struct sigaction sa; 15 | char buf[BUF_SIZE]; 16 | ssize_t num_read; 17 | int saved_errno; 18 | 19 | sa.sa_flags = (argc > 2) ? SA_RESTART : 0; 20 | sigemptyset(&sa.sa_mask); 21 | sa.sa_handler = handler; 22 | if (sigaction(SIGALRM, &sa, NULL) == -1) 23 | errExit("sigaction"); 24 | 25 | alarm((argc > 1) ? getInt(argv[1], GN_NONNEG, "num-secs") : 10); 26 | 27 | num_read = read(STDIN_FILENO, buf, BUF_SIZE - 1); 28 | 29 | saved_errno = errno; 30 | alarm(0); 31 | 32 | if (num_read == -1) 33 | { 34 | if (saved_errno == EINTR) 35 | printf("Read timed out\n"); 36 | else 37 | errMsg("read"); 38 | } 39 | else 40 | { 41 | printf("Successful read (%ld bytes): %.*s", (long)num_read, (int)num_read, buf); 42 | } 43 | exit(EXIT_SUCCESS); 44 | } -------------------------------------------------------------------------------- /chapter-40/example/view_lastlog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ugid_functions.h" 6 | #include "tlpi_hdr.h" 7 | 8 | int main(int argc, char*argv[]) 9 | { 10 | struct lastlog llog; 11 | int fd, j; 12 | uid_t uid; 13 | 14 | fd = open(_PATH_LASTLOG, O_RDONLY); 15 | if (fd == -1) 16 | errexit("open"); 17 | 18 | for (j = 1; j < argc; j++) 19 | { 20 | uid = user_id_from_name(argv[j]); 21 | if (uid == -1) 22 | { 23 | printf("No such user:%s\n", argv[j]); 24 | continue; 25 | } 26 | 27 | if (lseek(fd, uid * sizeof(struct lastlog), SEEK_SET) == -1) 28 | errExit("lseek"); 29 | 30 | if (read(fd, &llog, sizeof(struct lastlog) <= 0)) 31 | { 32 | printf("read failed for %s\n", argv[j]); 33 | continue; 34 | } 35 | 36 | printf("%-8.8s %6.6s %-20.20s %s", argv[j], llog.ll_line, 37 | llog.ll_host, ctime((time_t *)(&llog.ll_time))); 38 | } 39 | 40 | close(fd); 41 | exit(EXIT_SUCCESS); 42 | } -------------------------------------------------------------------------------- /chapter-21/example/nonreentrant.c: -------------------------------------------------------------------------------- 1 | #define _XOPEN_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | static char *str2; 8 | static int handled = 0; 9 | 10 | static void handler(int sig) 11 | { 12 | crypt(str2, "xx"); 13 | handled++; 14 | } 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | char *cr1; 19 | int call_num, mismatch; 20 | struct sigaction sa; 21 | 22 | if (argc != 3) 23 | usageErr("%s str1 str2\n", argv[0]); 24 | 25 | str2 = argv[2]; 26 | cr1 = strdup(crypt(argv[1], "xx")); 27 | 28 | if (cr1 == NULL) 29 | errExit("strdup"); 30 | 31 | sigemptyset(&sa.sa_mask); 32 | sa.sa_flags = 0; 33 | sa.sa_handler = handler; 34 | if (sigaction(SIGINT, &sa, NULL) == -1) 35 | errExit("sigaction"); 36 | 37 | for (call_num = 1, mismatch = 0; ; call_num++) 38 | { 39 | if (strcmp(crypt(argv[1], "xx"), cr1) != 0) 40 | { 41 | mismatch++; 42 | printf("Mismatch on call %d (mismatch=%d handled=%d)\n", call_num, mismatch, handled); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /chapter-36/example/rlimit_nproc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "print_rlimit.h" 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | struct rlimit rl; 8 | int j; 9 | pid_t child_pid; 10 | 11 | print_rlimit("Initial maximun process limits: ", RLIMIT_NPROC); 12 | 13 | rl.rlim_cur = (argv[1][0] == 'i') ? RLIM_INFINITY : 14 | getInt(argv[1], 0, "soft-limit"); 15 | 16 | rl.rlim_max = (argc > 2) ? rl.rlim_cur : 17 | (argv[2][0] == 'i') ? RLIM_INFINITY: 18 | getInt(argv[2], 0, "hard-limit"); 19 | 20 | if (setrlimit(RLIMIT_NPROC, &rl) == -1) 21 | errExit("setrlimit"); 22 | 23 | print_rlimit("New maximun process liits: ", RLIMIT_NPROC); 24 | 25 | for (j = 1; ; ++j) 26 | { 27 | switch (child_pid = fork()) 28 | { 29 | case -1: 30 | errExit("fork"); 31 | case 0: 32 | _exit(EXIT_SUCCESS); 33 | default: 34 | printf("Child %d (PID=%ld) started\n", j, (long)child_pid); 35 | break; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /chapter-45/example/svmsg_demo_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | #define KEY_FILE "/some-path/some-file" 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | int msqid; 12 | key_t key; 13 | const int MQ_PERMS = S_IRUSR | S_IWUSR | S_IWGRP; /*rw--w----*/ 14 | 15 | 16 | key = ftok(KEY_FILE, 1); 17 | if (key == -1) 18 | { 19 | errExit("ftok"); 20 | } 21 | 22 | while ((msqid = msgget(key, IPC_CREAT | IPC_EXCL | MQ_PERMS)) == -1) 23 | { 24 | if (errno == EEXIST) 25 | { 26 | msqid = msgget(key, 0); 27 | if (msqid == -1) 28 | errExit("msgget() failed to retrive old queue ID"); 29 | if (msgctl(msqid, IPC_RMID, NULL) == -1) 30 | { 31 | errExit("msgget() failed to delete old queue"); 32 | } 33 | printf("Removed old message queue (id=%d)\n", msqid); 34 | } 35 | else 36 | errExit("msgget() failed"); 37 | } 38 | 39 | exit(EXIT_SUCCESS); 40 | 41 | } -------------------------------------------------------------------------------- /tlpi-dist/pty/pty_fork.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 64-2 */ 12 | 13 | /* pty_fork.h 14 | 15 | Header file for pty_fork.c. 16 | */ 17 | #ifndef FORK_PTY_H 18 | #define FORK_PTY_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | pid_t ptyFork(int *masterFd, char *slaveName, size_t snLen, 25 | const struct termios *slaveTermios, const struct winsize *slaveWS); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /chapter-42/exercise/42-2.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | Dl_info info; 9 | void *lib_handler; 10 | int (*funcp)(const char *, ...); 11 | const char *err; 12 | 13 | lib_handler = dlopen(argv[1], RTLD_LAZY); 14 | if (lib_handler == NULL) 15 | fatal("dlopen: %s", dlerror()); 16 | 17 | (void) dlerror(); 18 | *(void **)(&funcp) = dlsym(lib_handler, argv[2]); 19 | // printf("DD\n"); 20 | err = dlerror(); 21 | if (err != NULL) 22 | fatal("dlsym: %s", err); 23 | 24 | if (funcp == NULL) 25 | printf("%s is NULL\n", argv[2]); 26 | else 27 | { 28 | (*funcp)("fuck\n"); 29 | // printf("fuck\n"); 30 | dladdr(*(void **)(&funcp), &info); 31 | printf("pathname:%s\n" 32 | "baseaddr:%p\n" 33 | "symname :%s\n" 34 | "symaddr :%p\n", 35 | info.dli_fname, info.dli_fbase, 36 | info.dli_sname, info.dli_saddr); 37 | } 38 | dlclose(lib_handler); 39 | exit(EXIT_SUCCESS); 40 | } -------------------------------------------------------------------------------- /tlpi-dist/threads/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = detached_attrib one_time_init prod_condvar prod_no_condvar \ 4 | pthread_barrier_demo \ 5 | simple_thread strerror_test strerror_test_tsd \ 6 | thread_cancel thread_cleanup thread_incr thread_incr_mutex \ 7 | thread_incr_rwlock thread_incr_spinlock \ 8 | thread_lock_speed \ 9 | thread_multijoin 10 | 11 | LINUX_EXE = strerror_test_tls 12 | 13 | EXE = ${GEN_EXE} ${LINUX_EXE} 14 | 15 | all : ${EXE} 16 | 17 | allgen : ${GEN_EXE} 18 | 19 | CFLAGS = ${IMPL_CFLAGS} ${IMPL_THREAD_FLAGS} 20 | LDLIBS = ${IMPL_LDLIBS} ${IMPL_THREAD_FLAGS} 21 | 22 | strerror_test: strerror_test.o strerror.o 23 | ${CC} -o $@ strerror_test.o strerror.o \ 24 | ${CFLAGS} ${LDLIBS} 25 | 26 | strerror_test_tsd: strerror_test.o strerror_tsd.o 27 | ${CC} -o $@ strerror_test.o strerror_tsd.o \ 28 | ${CFLAGS} ${LDLIBS} 29 | 30 | strerror_test_tls: strerror_test.o strerror_tls.o 31 | ${CC} -o $@ strerror_test.o strerror_tls.o \ 32 | ${CFLAGS} ${LDLIBS} 33 | 34 | clean : 35 | ${RM} ${EXE} *.o 36 | 37 | showall : 38 | @ echo ${EXE} 39 | 40 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 41 | -------------------------------------------------------------------------------- /chapter-4/example/copy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | #ifndef BUF_SIZE 6 | #define BUF_SIZE 1024 7 | #endif 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | int inputFd, outputFd, openFlags; 12 | mode_t filePerms; 13 | ssize_t numRead; 14 | char buf[BUF_SIZE]; 15 | 16 | if(argc != 3 || strcmp(argv[1], "--help") == 0) 17 | usageErr("%s old-file new-file\n", argv[0]); 18 | inputFd = open(argv[1], O_RDONLY); 19 | if (inputFd == -1) 20 | errExit("opening file %s", argv[1]); 21 | 22 | openFlags = O_CREAT | O_WRONLY | O_TRUNC; 23 | filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 24 | outputFd = open (argv[2], openFlags, filePerms); 25 | if(outputFd == -1) 26 | errExit("Open file %s", argv[2]); 27 | while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0) 28 | if (write(outputFd, buf, numRead) != numRead) 29 | fatal("Couldn't write whole buffer"); 30 | if (numRead == -1) 31 | errExit("read"); 32 | 33 | if (close(inputFd) == -1) 34 | errExit("close input"); 35 | if(close(outputFd) == -1) 36 | errExit("close output"); 37 | exit(EXIT_SUCCESS); 38 | } 39 | -------------------------------------------------------------------------------- /tlpi-dist/files/file_perms.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 15-3 */ 12 | 13 | /* file_perms.h 14 | 15 | Header file for file_perms.c. 16 | */ 17 | #ifndef FILE_PERMS_H 18 | #define FILE_PERMS_H 19 | 20 | #include 21 | 22 | #define FP_SPECIAL 1 /* Include set-user-ID, set-group-ID, and sticky 23 | bit information in returned string */ 24 | 25 | char *filePermStr(mode_t perm, int flags); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /tlpi-dist/sockets/id_echo.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 60-1 */ 12 | 13 | /* id_echo.h 14 | 15 | Header file for id_echo_sv.c and id_echo_cl.c. 16 | */ 17 | #include "inet_sockets.h" /* Declares our socket functions */ 18 | #include "tlpi_hdr.h" 19 | 20 | #define SERVICE "echo" /* Name of UDP service */ 21 | 22 | #define BUF_SIZE 500 /* Maximum size of datagrams that can 23 | be read by client and server */ 24 | -------------------------------------------------------------------------------- /tlpi-dist/proc/display_env.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 6-3 */ 12 | 13 | /* display_env.c 14 | 15 | Display the process environment list. 16 | */ 17 | #include "tlpi_hdr.h" 18 | 19 | extern char **environ; 20 | /* Or define _GNU_SOURCE to get it from */ 21 | 22 | int 23 | main(int argc, char *argv[]) 24 | { 25 | char **ep; 26 | 27 | for (ep = environ; *ep != NULL; ep++) 28 | puts(*ep); 29 | 30 | exit(EXIT_SUCCESS); 31 | } 32 | -------------------------------------------------------------------------------- /tlpi-dist/users_groups/ugid_functions.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 8-1 */ 12 | 13 | /* ugid_functions.h 14 | 15 | Header file for ugid_functions.c. 16 | */ 17 | #ifndef UGID_FUNCTIONS_H 18 | #define UGID_FUNCTIONS_H 19 | 20 | #include "tlpi_hdr.h" 21 | 22 | char *userNameFromId(uid_t uid); 23 | 24 | uid_t userIdFromName(const char *name); 25 | 26 | char *groupNameFromId(gid_t gid); 27 | 28 | gid_t groupIdFromName(const char *name); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /chapter-13/example/direct_read.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | int fd; 9 | ssize_t num_read; 10 | size_t length, alignment; 11 | off_t offset; 12 | void *buf; 13 | 14 | if (argc < 3 || strcmp(argv[1], "--help") == 0) 15 | usageErr("%s file length [offset [alignment]]\n", argv[0]); 16 | length = getLong(argv[2], GN_ANY_BASE, "length"); 17 | offset = (argc > 3) ? getLong(argv[2], GN_ANY_BASE, "offset") : 0; 18 | alignment = (argc > 4) ? getLong(argv[4], GN_ANY_BASE, "alignment") : 4096; 19 | 20 | fd = open(argv[1], O_RDONLY | O_DIRECT); 21 | if (fd == -1) 22 | errExit("open"); 23 | 24 | buf = (char*) memalign(alignment * 2, length + alignment) + alignment; 25 | if (buf == NULL) 26 | errExit("memalign"); 27 | 28 | if (lseek(fd, offset, SEEK_SET) == -1) 29 | errExit("lseek"); 30 | 31 | num_read = read(fd, buf, length); 32 | if (num_read == -1) 33 | errExit("read"); 34 | printf("Read %ld bytes\n", (long)num_read); 35 | 36 | exit(EXIT_SUCCESS); 37 | 38 | } -------------------------------------------------------------------------------- /chapter-5/example/t_readv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | #define STR_SIZE 100 6 | int main(int argc, char *argv[]) 7 | { 8 | int fd; 9 | struct iovec iov[3]; 10 | struct stat myStruct; 11 | int x; 12 | char str[STR_SIZE]; 13 | ssize_t numRead, totRequired; 14 | 15 | if (argc != 2 || strcmp(argv[1], "--help") == 0) 16 | usageErr("%s file\n", argv[0]); 17 | 18 | fd = open(argv[1], O_RDONLY); 19 | if (fd == -1) 20 | errExit("open"); 21 | 22 | totRequired = 0; 23 | 24 | iov[0].iov_base = &myStruct; 25 | iov[0].iov_len = sizeof(struct stat); 26 | totRequired += iov[0].iov_len; 27 | 28 | iov[1].iov_base = &x; 29 | iov[1].iov_len = sizeof(x); 30 | totRequired += iov[1].iov_len; 31 | 32 | iov[2].iov_base = str; 33 | iov[2].iov_len = STR_SIZE; 34 | totRequired += iov[2].iov_len; 35 | 36 | numRead = readv(fd, iov, 3); 37 | if (numRead == -1) 38 | errExit("readv"); 39 | 40 | if (numRead < totRequired) 41 | printf("Read fewer bytes than requested\n"); 42 | 43 | printf("total bytes requested: %ld; bytes read:%ld\n", 44 | (long) totRequired, (long) numRead); 45 | exit(EXIT_SUCCESS); 46 | } -------------------------------------------------------------------------------- /chapter-35/exercise/35-1.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include "tlpi_hdr.h" 6 | 7 | extern char **environ; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | 12 | int prio; 13 | 14 | prio = getpriority(PRIO_PROCESS, 0); 15 | 16 | if (prio == -1) 17 | errExit("getpriority"); 18 | 19 | if (argc == 1) 20 | { 21 | printf("%d\n", prio); 22 | } 23 | else 24 | { 25 | int opt, flag, add_nice; 26 | while ((opt = getopt(argc, argv, "n:")) != -1) 27 | { 28 | switch (opt) 29 | { 30 | case 'n': 31 | flag = 1; 32 | add_nice = getInt(optarg, 0, "add_nice"); 33 | break; 34 | default: 35 | fatal("Unknown args"); 36 | } 37 | } 38 | 39 | if (optind < argc-1) 40 | fatal("Error\n"); 41 | 42 | if (setpriority(PRIO_PROCESS, 0, prio + add_nice) == -1) 43 | errExit("setpriority"); 44 | 45 | if (execvp(argv[optind], argv+optind) == -1) 46 | errExit("execve"); 47 | } 48 | } -------------------------------------------------------------------------------- /chapter-15/example/file_perms.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define FP_SPECIAL 1 6 | #define STR_SIZE sizeof("rwxrwxrwx") 7 | 8 | char *file_perm_str(mode_t perm, int flags) 9 | { 10 | static char str[STR_SIZE]; 11 | snprintf(str, STR_SIZE, "%c%c%c%c%c%c%c%c%c", 12 | (perm & S_IRUSR) ? 'r' : '-', 13 | (perm & S_IWUSR) ? 'w' : '-', 14 | (perm & S_IXUSR) ? (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 's' : 'x') : 15 | (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 'S' : '-'), 16 | (perm & S_IRGRP) ? 'r' : '-', 17 | (perm & S_IWGRP) ? 'w' : '-', 18 | (perm & S_IXGRP) ? (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 's' : 'x') : 19 | (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 'S' : '-'), 20 | (perm & S_IROTH) ? 'r' : '-', 21 | (perm & S_IWOTH) ? 'w' : '-', 22 | (perm & S_IXOTH) ? (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 't' : 'x') : 23 | (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 'T' : '-')); 24 | 25 | return str; 26 | } -------------------------------------------------------------------------------- /tlpi-dist/procexec/fork_stdio_buf.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 25-2 */ 12 | 13 | /* fork_stdio_buf.c 14 | 15 | Experiment with fork() and stdio buffering. 16 | */ 17 | #include "tlpi_hdr.h" 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | printf("Hello world\n"); 23 | write(STDOUT_FILENO, "Ciao\n", 5); 24 | 25 | if (fork() == -1) 26 | errExit("fork"); 27 | 28 | /* Both child and parent continue execution here */ 29 | 30 | exit(EXIT_SUCCESS); 31 | } 32 | -------------------------------------------------------------------------------- /tlpi-dist/signals/signal_functions.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 20-4 */ 12 | 13 | /* signal_functions.h 14 | 15 | Header file for signal_functions.c. 16 | */ 17 | #ifndef SIGNAL_FUNCTIONS_H 18 | #define SIGNAL_FUNCTIONS_H 19 | 20 | #include 21 | #include "tlpi_hdr.h" 22 | 23 | int printSigMask(FILE *of, const char *msg); 24 | 25 | int printPendingSigs(FILE *of, const char *msg); 26 | 27 | void printSigset(FILE *of, const char *ldr, const sigset_t *mask); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /chapter-26/example/print_wait_status.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINT_WAIT_STATUS_H 2 | #define PRINT_WAIT_STATUS_H 3 | #define _GNU_SOURCE 4 | #include 5 | #include 6 | #include "tlpi_hdr.h" 7 | 8 | static inline void print_wait_status(const char *msg, int status) 9 | { 10 | if (msg != NULL) 11 | printf("%s", msg); 12 | 13 | if (WIFEXITED(status)) 14 | printf("child exited, status=%d\n", WEXITSTATUS(status)); 15 | else if (WIFSIGNALED(status)) 16 | { 17 | printf("child killed by signal %d (%s)", 18 | WTERMSIG(status), strsignal(WTERMSIG(status))); 19 | #ifdef WCOREDUMP 20 | if (WCOREDUMP(status)) 21 | printf("(core dumped)"); 22 | #endif 23 | printf("\n"); 24 | } 25 | else if (WIFSTOPPED(status)) 26 | { 27 | printf("child stopped by signal %d (%s)\n", 28 | WSTOPSIG(status), strsignal(WSTOPSIG(status))); 29 | #ifdef WIFCONTINUED 30 | } 31 | else if (WIFCONTINUED(status)) 32 | { 33 | printf("child continued\n"); 34 | #endif 35 | } 36 | else 37 | { 38 | printf("what happened to this child? (status=%x)\n", (unsigned int)status); 39 | } 40 | } 41 | #endif -------------------------------------------------------------------------------- /tlpi-dist/namespaces/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = orphan 4 | 5 | LINUX_EXE = \ 6 | demo_userns \ 7 | demo_uts_namespaces \ 8 | hostname \ 9 | multi_pidns \ 10 | ns_child_exec \ 11 | ns_exec \ 12 | ns_run \ 13 | pidns_init_sleep \ 14 | simple_init \ 15 | t_setns_userns \ 16 | unshare \ 17 | userns_child_exec \ 18 | userns_setns_test 19 | 20 | EXE = ${GEN_EXE} ${LINUX_EXE} 21 | 22 | all : ${EXE} 23 | 24 | allgen : ${GEN_EXE} 25 | 26 | clean : 27 | ${RM} ${EXE} *.o 28 | 29 | showall : 30 | @ echo ${EXE} 31 | 32 | demo_userns: demo_userns.o 33 | ${CC} -o $@ demo_userns.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBCAP} 34 | 35 | t_setns_userns: t_setns_userns.o 36 | ${CC} -o $@ t_setns_userns.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBCAP} 37 | 38 | unshare: unshare.o 39 | ${CC} -o $@ unshare.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBCAP} 40 | 41 | userns_child_exec: userns_child_exec.o 42 | ${CC} -o $@ userns_child_exec.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBCAP} 43 | 44 | userns_setns_test: userns_setns_test.o 45 | ${CC} -o $@ userns_setns_test.o ${CFLAGS} ${LDLIBS} ${LINUX_LIBCAP} 46 | 47 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 48 | -------------------------------------------------------------------------------- /tlpi-dist/sockets/scm_cred.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Supplementary program for Chapter 61 */ 12 | 13 | /* scm_cred.h 14 | 15 | Header file used by scm_cred_send.c and scm_cred_recv.c. 16 | */ 17 | #define _GNU_SOURCE /* To get SCM_CREDENTIALS definition from 18 | */ 19 | #include 20 | #include 21 | #include "unix_sockets.h" /* Declares our socket functions */ 22 | #include "tlpi_hdr.h" 23 | 24 | #define SOCK_PATH "scm_cred" 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 《linux/unix系统编程手册》学习记录 2 | 3 | ## 文件夹组织结构 4 | 5 | * tlpi-dist:从[这本书的官网](http://www.man7.org/tlpi/)下载的源码 6 | * chapter-x:第x章节 7 | * example:书中例子 8 | * exercise:书后习题 9 | 10 | 第三章介绍了后面章节要用到的头文件以及实现,如下 11 | * ename.c.inc 定义了一个字符串数组,用于对应错误码的名称 12 | * error_functions.h 声明了本书自定义的错误处理函数 13 | * get_num.h 声明了本书自定义的数值提取函数 14 | * tlpi_hdr.h 包含了后续需用到的系统调用头文件 15 | 16 | 由于存在3个头文件以及2个实现,每次编译时必须对实现也进行编译,为方便后续学习,将头文件和静态库复制到默认的编译器寻找目录下。 17 | 18 | - 第一步:下载本书所给的源码文件 19 | 20 | ``` 21 | $ wget "http://man7.org/tlpi/code/download/tlpi-161214-dist.tar.gz" 22 | ``` 23 | 24 | - 第二步:解压后,make编译(可以跳过下载和解压的过程,repo已经包含tlpi-dist目录) 25 | 26 | ``` 27 | $ tar -zxvf tlpi-161214-dist.tar.gz 28 | $ cd tlpi-dist/ 29 | $ make -j8 30 | ``` 31 | 32 | - 第三步:拷贝头文件和静态库至系统目录 33 | 34 | ``` 35 | $ cd lib/ 36 | $ sudo cp tlpi_hdr.h /usr/local/include/ 37 | $ sudo cp get_num.h /usr/local/include/ 38 | $ sudo cp error_functions.h /usr/local/include/ 39 | $ sudo cp ename.c.inc /usr/local/include/ 40 | $ sudo cp ../libtlpi.a /usr/local/lib 41 | ``` 42 | 43 | 以后每次编译包含上述四个头文件的代码时,需要链接静态库。 44 | 以编译 example.c 为例: 45 | 46 | ``` 47 | $ gcc example.c -o example -ltlpi 48 | ``` 49 | 50 | 希望以后能坚持学习吧。 51 | 52 | -------------------------------------------------------------------------------- /tlpi-dist/filelock/region_locking.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Header file for Listing 55-3 */ 12 | 13 | /* region_locking.h 14 | 15 | Header file for region_locking.c. 16 | */ 17 | #ifndef REGION_LOCKING_H 18 | #define REGION_LOCKING_H 19 | 20 | #include 21 | 22 | int lockRegion(int fd, int type, int whence, int start, int len); 23 | 24 | int lockRegionWait(int fd, int type, int whence, int start, int len); 25 | 26 | pid_t regionIsLocked(int fd, int type, int whence, int start, int len); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /chapter-20/exercise/20-2.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | static int flag = 0; 7 | 8 | void handler(int sig) 9 | { 10 | printf("SIG %d is caught.\n", sig); 11 | if (sig == SIGINT) 12 | flag = 1; 13 | } 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | sigset_t set; 18 | 19 | for (int i = 1; i < NSIG; ++i) 20 | signal(i, handler); 21 | 22 | while (flag == 0) 23 | pause(); 24 | 25 | printf("----------\n"); 26 | 27 | flag = 0; 28 | // if (sigfillset(&set) == -1) 29 | // errExit("sigfillset"); 30 | // if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) 31 | // errExit("sigprocmask"); 32 | 33 | // sleep(10); 34 | 35 | // sigpending(&set); 36 | 37 | // for (int i = 1; i < NSIG; ++i) 38 | // { 39 | // if (sigismember(&set, i)) 40 | // printf("%d is blocked.\n"); 41 | // } 42 | 43 | // if (sigemptyset(&set) == -1) 44 | // errExit("signempty"); 45 | 46 | // sigprocmask(SIG_SETMASK, &set, NULL); 47 | for (int i = 1; i < NSIG; ++i) 48 | signal(i, SIG_IGN); 49 | pause(); 50 | // sleep(10); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /tlpi-dist/daemons/test_become_daemon.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Supplementary program for Chapter 37 */ 12 | 13 | /* test_become_daemon.c 14 | 15 | Test our becomeDaemon() function. 16 | */ 17 | #include "become_daemon.h" 18 | #include "tlpi_hdr.h" 19 | 20 | int 21 | main(int argc, char *argv[]) 22 | { 23 | becomeDaemon(0); 24 | 25 | /* Normally a daemon would live forever; we just sleep for a while */ 26 | 27 | sleep((argc > 1) ? getInt(argv[1], GN_GT_0, "sleep-time") : 20); 28 | 29 | exit(EXIT_SUCCESS); 30 | } 31 | -------------------------------------------------------------------------------- /tlpi-dist/sockets/i6d_ucase.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 59-2 */ 12 | 13 | /* i6d_ucase.h 14 | 15 | Header file for i6d_ucase_sv.c and i6d_ucase_cl.c. 16 | */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "tlpi_hdr.h" 22 | 23 | #define BUF_SIZE 10 /* Maximum size of messages exchanged 24 | between client and server */ 25 | 26 | #define PORT_NUM 50002 /* Server port number */ 27 | -------------------------------------------------------------------------------- /chapter-26/example/child_status.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "print_wait_status.h" 3 | #include "tlpi_hdr.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | int status; 8 | pid_t child_pid; 9 | 10 | switch (fork()) 11 | { 12 | case -1: 13 | errExit("fork"); 14 | 15 | case 0: 16 | printf("Child started with PID = %ld\n", (long)getpid()); 17 | if (argc > 1) 18 | exit(getInt(argv[1], 0, "exit-status")); 19 | else 20 | for(;;) 21 | pause(); 22 | exit(EXIT_SUCCESS); 23 | 24 | default: 25 | for (;;) 26 | { 27 | child_pid = waitpid(-1, &status, WUNTRACED 28 | #ifdef WCONTINUED 29 | | WCONTINUED 30 | #endif 31 | ); 32 | if (child_pid == -1) 33 | errExit("waitpid"); 34 | printf("waitpid() returned: PID=%ld;status=0x%04d (%d,%d)\n", 35 | (long)child_pid, (unsigned int)status, status >> 8, status & 0xff); 36 | print_wait_status(NULL, status); 37 | 38 | if (WIFEXITED(status) || WIFSIGNALED(status)) 39 | exit(EXIT_SUCCESS); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /chapter-46/example/svmsg_send.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | #define MAX_MTEXT 1024 6 | 7 | struct mbuf { 8 | long mtype; 9 | char mtext[MAX_MTEXT]; 10 | }; 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | int msqid, flags, msg_len; 15 | struct mbuf msg; 16 | int opt; 17 | 18 | flags = 0; 19 | while ((opt = getop(argc, argv, "n")) != -1) 20 | { 21 | if (opt == 'n') 22 | flags |= IPC_NOWAIT; 23 | else 24 | exit(-1); 25 | } 26 | 27 | if (argc < optind + 2 || argc > optind + 3) 28 | exit(-1); 29 | 30 | msqid = getInt(argv[optind], 0, "msqid"); 31 | msg.mtype = getInt(argv[optind + 1], 0, "msg-type"); 32 | 33 | if (argc > optind + 2) 34 | { 35 | msg_len = strlen(argv[optind + 2]) + 1; 36 | if (msg_len > MAX_MTEXT) 37 | cmdLineErr("msg-text too long (max: %d characters)\n", MAX_MTEXT); 38 | 39 | memcpy(msg.mtext, argv[optind + 2], msg_len); 40 | } 41 | else 42 | { 43 | msg_len = 0; 44 | } 45 | 46 | if (msgsnd(msqid, &msg, msg_len, flags) == -1) 47 | errExit("msgsnd"); 48 | exit(EXIT_SUCCESS); 49 | 50 | } -------------------------------------------------------------------------------- /tlpi-dist/users_groups/t_getpwent.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Supplementary program for Chapter 8 */ 12 | 13 | /* t_getpwent.c 14 | 15 | Demonstrate the use of getpwent() to retrieve records from the system 16 | password file. 17 | */ 18 | #include 19 | #include "tlpi_hdr.h" 20 | 21 | int 22 | main(int argc, char *argv[]) 23 | { 24 | struct passwd *pwd; 25 | 26 | while ((pwd = getpwent()) != NULL) 27 | printf("%-8s %5ld\n", pwd->pw_name, (long) pwd->pw_uid); 28 | endpwent(); 29 | exit(EXIT_SUCCESS); 30 | } 31 | -------------------------------------------------------------------------------- /tlpi-dist/Makefile.inc: -------------------------------------------------------------------------------- 1 | # Makefile.inc - common definitions used by all makefiles 2 | 3 | TLPI_DIR = .. 4 | TLPI_LIB = ${TLPI_DIR}/libtlpi.a 5 | TLPI_INCL_DIR = ${TLPI_DIR}/lib 6 | 7 | LINUX_LIBRT = -lrt 8 | LINUX_LIBDL = -ldl 9 | LINUX_LIBACL = -lacl 10 | LINUX_LIBCRYPT = -lcrypt 11 | LINUX_LIBCAP = -lcap 12 | 13 | # "-Wextra" is a more descriptive synonym for "-W", but only 14 | # available in more recent gcc versions 15 | 16 | # Defining _DEFAULT_SOURCE is a workaround to avoid the warnings that 17 | # would otherwise be produced when compiling code that defines _BSD_SOURCE 18 | # or _SVID_SOURCE against glibc headers in version 2.20 and later. 19 | # (The alternative would be to replace each instance of "#define _SVID_SOURCE" 20 | # or "#define _BSD_SOURCE" in the example programs with 21 | # "#define _DEFAULT_SOURCE".) 22 | 23 | IMPL_CFLAGS = -std=c99 -D_XOPEN_SOURCE=600 \ 24 | -D_DEFAULT_SOURCE \ 25 | -g -I${TLPI_INCL_DIR} \ 26 | -pedantic \ 27 | -Wall \ 28 | -W \ 29 | -Wmissing-prototypes \ 30 | -Wno-sign-compare \ 31 | -Wno-unused-parameter 32 | 33 | CFLAGS = ${IMPL_CFLAGS} 34 | 35 | IMPL_THREAD_FLAGS = -pthread 36 | 37 | IMPL_LDLIBS = ${TLPI_LIB} -lm 38 | 39 | LDLIBS = ${IMPL_LDLIBS} 40 | 41 | RM = rm -f 42 | -------------------------------------------------------------------------------- /tlpi-dist/sockets/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | GEN_EXE = i6d_ucase_sv i6d_ucase_cl \ 4 | id_echo_cl id_echo_sv \ 5 | is_echo_cl is_echo_sv is_echo_inetd_sv is_echo_v2_sv \ 6 | is_seqnum_sv is_seqnum_cl is_seqnum_v2_sv is_seqnum_v2_cl \ 7 | socknames t_gethostbyname t_getservbyname \ 8 | ud_ucase_sv ud_ucase_cl \ 9 | us_xfr_cl us_xfr_sv us_xfr_v2_cl us_xfr_v2_sv 10 | 11 | LINUX_EXE = list_host_addresses \ 12 | scm_cred_recv scm_cred_send scm_rights_recv scm_rights_send \ 13 | us_abstract_bind 14 | 15 | EXE = ${GEN_EXE} ${LINUX_EXE} 16 | 17 | all : ${EXE} 18 | 19 | allgen : ${GEN_EXE} 20 | 21 | i6d_ucase_sv.o i6d_ucase_cl.o : i6d_ucase.h 22 | 23 | id_echo_cl.o id_echo_sv.o : id_echo.h 24 | 25 | is_seqnum_sv.o is_seqnum_cl.o : is_seqnum.h 26 | 27 | is_seqnum_v2_sv.o is_seqnum_v2_cl.o : is_seqnum_v2.h 28 | 29 | scm_cred_recv.o scm_cred_send.o : scm_cred.h 30 | 31 | scm_rights_recv.o scm_rights_send.o : scm_rights.h 32 | 33 | us_xfr_sv.o us_xfr_cl.o : us_xfr.h 34 | 35 | us_xfr_v2_sv.o us_xfr_v2_cl.o : us_xfr_v2.h 36 | 37 | ud_ucase_sv.o ud_ucase_cl.o : ud_ucase.h 38 | 39 | clean : 40 | ${RM} ${EXE} *.o 41 | 42 | showall : 43 | @ echo ${EXE} 44 | 45 | ${EXE} : ${TLPI_LIB} # True as a rough approximation 46 | -------------------------------------------------------------------------------- /chapter-18/example/t_unlink.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tlpi_hdr.h" 4 | 5 | #define CMD_SIZE 200 6 | #define BUF_SIZE 1024 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | int fd, j, num_blocks; 11 | char shell_cmd[CMD_SIZE]; 12 | char buf[BUF_SIZE]; 13 | 14 | if (argc < 2 || strcmp(argv[1], "--help") == 0) 15 | usageErr("%s temp-file [number-1kB-blocks] \n", argv[0]); 16 | 17 | num_blocks = (argc > 2) ? getInt(argv[2], GN_GT_0, "num-1kB-blocks") 18 | : 100000; 19 | 20 | fd = open(argv[1], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 21 | if (fd == -1) 22 | errExit("open"); 23 | 24 | system("ls -ahl"); 25 | if (unlink(argv[1]) == -1) 26 | errExit("unlink"); 27 | system("ls -ahl"); 28 | for (j = 0; j < num_blocks; ++j) 29 | { 30 | if (write(fd, buf, BUF_SIZE) != BUF_SIZE) 31 | fatal("partial/failed write"); 32 | } 33 | 34 | snprintf(shell_cmd, CMD_SIZE, "df -k `dirname %s`", argv[1]); 35 | system(shell_cmd); 36 | 37 | if (close(fd) == -1) 38 | errExit("close"); 39 | 40 | printf("******** Close file descriptor\n"); 41 | system(shell_cmd); 42 | exit(EXIT_SUCCESS); 43 | } -------------------------------------------------------------------------------- /chapter-5/example/bad_exclusive_open.c: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | $ ./bad_exclusive_open tfile sleep & 3 | $ ./bad_exclusive_open tfile 4 | 会发现两个进程都认为是自己打开了tfile文件 5 | (这里是使用了sleep,实际进程调度时间很短,不过仍有可能发生竞争状态) 6 | *******************************************************************/ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "tlpi_hdr.h" 14 | #include "error_functions.h" 15 | int main(int argc, char *argv[]) 16 | { 17 | pid_t fd = open(argv[1], O_WRONLY); 18 | if( fd != -1) { 19 | printf("[PID %ld] File \"%s\" already exists\n", 20 | (long)getpid(), argv[1]); 21 | close(fd); 22 | } else { 23 | if (errno != ENOENT) { 24 | errExit("open"); 25 | } else { 26 | printf("[PID %ld] File \"%s\" doesn't exist yet\n", (long)getpid(), argv[1]); 27 | if (argc > 2) { 28 | sleep(5); 29 | printf("[PID %ld] Done sleeping\n", (long)getpid()); 30 | } 31 | fd = open(argv[1], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); 32 | if (fd == -1) 33 | errExit("open"); 34 | printf("[PID %ld] Creat file \"%s\" exclusively\n", 35 | (long)getpid(), argv[1]); 36 | } 37 | } 38 | return 0; 39 | } -------------------------------------------------------------------------------- /tlpi-dist/procexec/t_execlp.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 27-3 */ 12 | 13 | /* t_execlp.c 14 | 15 | Demonstrate the use of execlp() to execute a program. 16 | */ 17 | #include "tlpi_hdr.h" 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | if (argc != 2 || strcmp(argv[1], "--help") == 0) 23 | usageErr("%s pathname\n", argv[0]); 24 | 25 | /* Execute the program specified in argv[1] */ 26 | 27 | execlp(argv[1], argv[1], "hello world", (char *) NULL); 28 | errExit("execlp"); /* If we get here, something went wrong */ 29 | } 30 | -------------------------------------------------------------------------------- /tlpi-dist/pshm/pshm_unlink.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 54-4 */ 12 | 13 | /* pshm_unlink.c 14 | 15 | Usage: pshm_unlink shm-name 16 | 17 | Remove the POSIX shared memory object identified by 'name' 18 | */ 19 | #include 20 | #include 21 | #include "tlpi_hdr.h" 22 | 23 | int 24 | main(int argc, char *argv[]) 25 | { 26 | if (argc != 2 || strcmp(argv[1], "--help") == 0) 27 | usageErr("%s shm-name\n", argv[0]); 28 | 29 | if (shm_unlink(argv[1]) == -1) 30 | errExit("shm_unlink"); 31 | exit(EXIT_SUCCESS); 32 | } 33 | -------------------------------------------------------------------------------- /chapter-4/exercise/mycp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 练习 4-2 3 | * 简单实现cp,命令格式 cp [src-file] [dest-file] 4 | * cp - copy files and directories 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef BUF_SIZE 12 | #define BUF_SIZE 1024 13 | #endif 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | if (argc != 3) 18 | { 19 | fputs("argements error\n", stderr); 20 | exit(EXIT_FAILURE); 21 | } 22 | int fdRead, fdWrite; 23 | ssize_t numRead; 24 | if ((fdRead = open(argv[1], O_RDONLY)) == -1) 25 | { 26 | fprintf(stderr, "Open \"%s\" error.\n", argv[1]); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | if ((fdWrite = open(argv[2], O_WRONLY | O_CREAT)) == -1) 31 | { 32 | fprintf(stderr, "Open \"%s\" error.\n", argv[2]); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | char buf[BUF_SIZE]; 37 | while ((numRead = read(fdRead, buf, BUF_SIZE)) > 0) 38 | { 39 | write(fdWrite, buf, numRead); 40 | } 41 | 42 | if (close(fdRead) == -1) 43 | { 44 | fprintf(stderr, "Close file \"%s\" error.\n", argv[1]); 45 | exit(EXIT_FAILURE); 46 | } 47 | 48 | if (close(fdWrite) == -1) 49 | { 50 | fprintf(stderr, "Close file \"%s\" error.\n", argv[2]); 51 | exit(EXIT_FAILURE); 52 | } 53 | 54 | exit(EXIT_SUCCESS); 55 | } -------------------------------------------------------------------------------- /tlpi-dist/sockets/is_seqnum.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 59-5 */ 12 | 13 | /* is_seqnum.h 14 | 15 | Header file for is_seqnum_sv.c and is_seqnum_cl.c. 16 | */ 17 | #include 18 | #include 19 | #include 20 | #include "read_line.h" /* Declaration of readLine() */ 21 | #include "tlpi_hdr.h" 22 | 23 | #define PORT_NUM "50000" /* Port number for server */ 24 | 25 | #define INT_LEN 30 /* Size of string able to hold largest 26 | integer (including terminating '\n') */ 27 | -------------------------------------------------------------------------------- /tlpi-dist/pmsg/pmsg_unlink.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Listing 52-1 */ 12 | 13 | /* pmsg_unlink.c 14 | 15 | Usage: pmsg_unlink mq-name 16 | 17 | Unlink a POSIX message queue. 18 | 19 | Linux supports POSIX message queues since kernel 2.6.6. 20 | */ 21 | #include 22 | #include "tlpi_hdr.h" 23 | 24 | int 25 | main(int argc, char *argv[]) 26 | { 27 | if (argc != 2 || strcmp(argv[1], "--help") == 0) 28 | usageErr("%s mq-name\n", argv[0]); 29 | 30 | if (mq_unlink(argv[1]) == -1) 31 | errExit("mq_unlink"); 32 | exit(EXIT_SUCCESS); 33 | } 34 | -------------------------------------------------------------------------------- /tlpi-dist/proc/t_getenv.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU General Public License as published by the * 6 | * Free Software Foundation, either version 3 or (at your option) any * 7 | * later version. This program is distributed without any warranty. See * 8 | * the file COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Supplementary program for Chapter 6 */ 12 | 13 | /* t_getenv.c 14 | 15 | Demonstrate the use of getenv() to retrieve the value of an 16 | environment variable. 17 | */ 18 | #include "tlpi_hdr.h" 19 | 20 | int 21 | main(int argc, char *argv[]) 22 | { 23 | char *val; 24 | 25 | if (argc != 2 || strcmp(argv[1], "--help") == 0) 26 | usageErr("%s environ-var\n", argv[0]); 27 | 28 | val = getenv(argv[1]); 29 | printf("%s\n", (val != NULL) ? val : "No such variable"); 30 | 31 | exit(EXIT_SUCCESS); 32 | } 33 | -------------------------------------------------------------------------------- /chapter-20/example/signal_functions.h: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include "tlpi_hdr.h" 5 | 6 | static inline void print_sigset(FILE *of, const char *prefix, const sigset_t *sigset) 7 | { 8 | int sig, cnt; 9 | 10 | cnt = 0; 11 | for (sig = 1; sig < NSIG; ++sig) 12 | { 13 | if (sigismember(sigset, sig)) 14 | { 15 | cnt++; 16 | fprintf(of, "%s%d (%s) \n", prefix, sig, strsignal(sig)); 17 | } 18 | } 19 | 20 | if (cnt == 0) 21 | fprintf(of, "%s\n", prefix); 22 | } 23 | 24 | static inline int print_sig_mask(FILE *of, const char *msg) 25 | { 26 | sigset_t curr_mask; 27 | 28 | if (msg != NULL) 29 | fprintf(of, "%s", msg); 30 | 31 | if (sigprocmask(SIG_BLOCK, NULL, &curr_mask) == -1) 32 | return -1; 33 | 34 | print_sigset(of, "\t\t", &curr_mask); 35 | 36 | return 0; 37 | } 38 | 39 | static inline int print_pending_sigs(FILE *of, const char *msg) 40 | { 41 | sigset_t pending_sigs; 42 | 43 | if (msg != NULL) 44 | fprintf(of, "%s", msg); 45 | 46 | if (sigpending(&pending_sigs) == -1) 47 | return -1; 48 | 49 | print_sigset(of, "\t\t", &pending_sigs); 50 | 51 | return 0; 52 | } -------------------------------------------------------------------------------- /tlpi-dist/sockets/unix_sockets.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************\ 2 | * Copyright (C) Michael Kerrisk, 2016. * 3 | * * 4 | * This program is free software. You may use, modify, and redistribute it * 5 | * under the terms of the GNU Lesser General Public License as published * 6 | * by the Free Software Foundation, either version 3 or (at your option) * 7 | * any later version. This program is distributed without any warranty. * 8 | * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * 9 | \*************************************************************************/ 10 | 11 | /* Solution for Exercise 59-3:a */ 12 | 13 | /* unix_sockets.h 14 | 15 | Header file for unix_sockets.c. 16 | */ 17 | #ifndef UNIX_SOCKETS_H 18 | #define UNIX_SOCKETS_H /* Prevent accidental double inclusion */ 19 | 20 | #include 21 | #include 22 | 23 | int unixBuildAddress(const char *path, struct sockaddr_un *addr); 24 | 25 | int unixConnect(const char *path, int type); 26 | 27 | int unixListen(const char *path, int backlog); 28 | 29 | int unixBind(const char *path, int type); 30 | 31 | #endif 32 | --------------------------------------------------------------------------------