开始学习Unix环境高级编程(第三版;中文版)
配置开发环境
本文所用操作系统:Win10 x64位下VMware15虚拟机Ubuntu 20.10镜像。通过apt命令来获取gcc编译器等等开发工具,使用vim时可以在~/.vimrc文件中自定义文本编辑器风格,建议直接抄网上作业。本文所使用风格:
1 set nu 2 syntax on 3 set guifont=DejaVu\ Sans\ Mono\ 12 4 set softtabstop=4 5 set shiftwidth=4 6 set expandtab 7 set guioptions-=T 8 set nobackup 9 set formatoptions=tcrqn 10 set cindent 11 set smartindent 12 set incsearch 13 set autoindent 14 set encoding=utf-8 15 set fileencodings=ucs-bom,utf-8,gb2312,gb18030,gbk,cp936,latin1,chinese,unicode 16 17 18 set modifiable 19 20 let mapleader='\' 21 nmap <leader>f :!youdao <C-R>=expand("<cword>")<CR><CR> 22 23 command -nargs=1 FY : !youdao <args> 24 25 26 "<CR>:copen<CR> 27 28 ":copen <CR> :copen :set modifiable 29 "Show matching bracets 30 set showmatch 31 " 32 ""Get out of VI's compatible mode 33 set nocompatible 34 35 if has("cscope") 36 set csprg=/usr/bin/cscope 37 set csto=0 38 set cst 39 set nocsverb 40 " add any database in current directory 41 if filereadable("cscope.out") 42 cs add cscope.out 43 " " else add database pointed to by 44 " environment 45 elseif $CSCOPE_DB != "" 46 cs add $CSCOPE_DB 47 endif 48 set csverb 49 set cscopetag 50 set cscopequickfix=s-,g-,c-,d-,t-,e-,f-,i- 51 nmap <C-c><C-s> :cs find s <C-R>=expand("<cword>")<CR><CR> 52 nmap <C-c><C-g> :cs find g <C-R>=expand("<cword>")<CR><CR> 53 nmap <C-c><C-c> :cs find c <C-R>=expand("<cword>")<CR><CR> 54 nmap <C-c><C-t> :cs find t <C-R>=expand("<cword>")<CR><CR> 55 nmap <C-c><C-e> :cs find e <C-R>=expand("<cword>")<CR><CR> 56 nmap <C-c><C-f> :cs find f <C-R>=expand("<cfile>")<CR><CR> 57 nmap <C-c><C-i> :cs find i <C-R>=expand("<cfile>")<CR><CR> 58 nmap <C-c><C-d> :cs find d <C-R>=expand("<cword>")<CR><CR> 59 endif 60 61 "Have the mouse enabled all the time 62 "set mouse=a 63 " 64 ""Set to auto read when a file is changed from the outside 65 set autoread 66 67 "Enable filetype plugin 68 filetype plugin indent on 69 colo desert 70 set hlsearch 71 72 "let Tlist_Ctags_Cmd = '/usr/bin/ctags-exuberant' 73 74 nnoremap <silent> <F9> :TlistToggle<CR> 75 "let Tlist_Use_Right_Window=1 76 colorscheme delek 77 "colorscheme evening 78 set ruler 79 hi Special ctermfg = red
最后建立共享文件夹,使用VMware tools。
创建工作目录
本书所有例程均使用了“apue.h”头文件,该文件及相关内容作者在附录B中已给出,建议自己打出来加深印象。apue 即是 Advanced Programming in the UNIX Environment。但是有些印刷错误,目前已发现:
1:722页 int send_err(int, int, const char *); 这里 const 印成了 onst;
2:724页 /* ISO C variable arguments */ 这里 arguments 印成了aruments;
3:725页 * Error code passed as explicit parameter. 这里 explicit 印成了explict,本页下方还有一处同样的错误;
4:727页 static void log_doit(int, int, int, const char * va_list); 这里 va_list 后面多了 ap 。
后面的两个是出错函数的实现 .c 文件,作者没有给出建议的文件名,我们既可以自己起名,也可以将它们直接与 apue.h 整合在一起。本文所用文件名:output_to_stderr.c 和 daemon_errfunc.c 。建议创建目录:mkdir apue_learning,将 apue.h 和 两个出错函数实现文件放入,学习到每一章的时候创建那一章的目录,例如:chapter_01。这样一来包含 apue.h 文件时需要 #include "../apue",编译时需要注意带上两个 .c 文件:gcc xxxx.c ../output_to_stderr.c ../daemon_errfunc.c -o xxxx,使用 tab 自动补全就好。
若编译后出现warning: relocate against ... 最后 error: ld returned 1 exit status,这就是需要在你的程序中加上 int log_to_stderr,其实用不到守护进程的话就不用带上 daemon_errfunc.c 进行编译了,这样也不用声明 log_to_stderr 了。
如此一来就可以顺利使用本书进行学习了。给白嫖党:
apue.h:
1 /* 2 * apue.h -- Header for Advanced Programming in the UNIX Environment, 3 * to be included before all standard system headers. 4 */ 5 #ifndef _APUE_H 6 #define _APUE_H 7 8 #define _POSIX_C_SOURCE 200809L 9 10 #if defined(SOLARIS) /* Solaris 10 */ 11 #define _XOPEN_SOURCE 600 12 #else 13 #define _XOPEN_SOURCE 700 14 #endif 15 16 #include <sys/types.h> /* some systems still require this */ 17 #include <sys/stat.h> 18 #include <sys/termios.h> /* for winsize */ 19 20 #if defined(MACOS) || !defined(TIOCGWINSZ) 21 #include <sys/ioctl.h> 22 #endif 23 24 #include <stdio.h> /* for convenience */ 25 #include <stdlib.h> /* for convenience */ 26 #include <stddef.h> /* for offsetof */ 27 #include <string.h> /* for convenience */ 28 #include <unistd.h> /* for convenience */ 29 #include <signal.h> /* for SIG_ERR */ 30 31 #define MAXLINE 4096 /* max line length */ 32 33 /* 34 * Default file access permissions for new files. 35 */ 36 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 37 38 /* 39 * Default permissions for new directories. 40 */ 41 42 #define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH) 43 44 typedef void Sigfunc(int);/* for signal handlers */ 45 46 #define min(a,b) ((a) < (b) ? (a) : (b)) 47 #define max(a,b) ((a) > (b) ? (a) : (b)) 48 49 /* 50 * Prototypes for our own functions 51 */ 52 53 char *path_alloc(size_t *); /* Figure 2.16 */ 54 long open_max(void); /* Figure 2.17 */ 55 56 int set_cloexec(int); /* Figure 13.9 */ 57 void clr_fl(int, int); 58 void set_fl(int, int); /* Figure 3.12 */ 59 60 void pr_exit(int); /* Figure 8.5 */ 61 62 void pr_mask(const char *); /* Figure 10.14 */ 63 Sigfunc *signal_intr(int, Sigfunc *); /* Figure 10.19 */ 64 65 void daemonize(const char *); /* Figure 13.1 */ 66 67 void sleep_us(unsigned int); /* Exercise 14.5 */ 68 ssize_t readn(int, void *, size_t); /* Figure 14.24 */ 69 ssize_t writen(int, const void *, size_t); /* Figure 14.24 */ 70 71 int fd_pipe(int *); /* Figure 17.2 */ 72 int recv_fd(int, ssize_t (*func)(int, 73 const void *, size_t)); /* Figure 17.14 */ 74 int send_fd(int, int); /* Figure 17.13 */ 75 int send_err(int, int, const char *); /* Figure 17.12 */ 76 int serv_listen(const char *); /* Figure 17.8 */ 77 int serv_accept(int, uid_t *); /* Figure 17.9 */ 78 int cli_conn(const char *); /* Figure 17.10 */ 79 int buf_args(char *, int (*func)(int, 80 char **)); /* Figure 17.23 */ 81 82 int tty_cbreak(int); /* Figure 18.20 */ 83 int tty_raw(int); /* Figure 18.20 */ 84 int tty_reset(int); /* Figure 18.20 */ 85 void tty_atexit(void); /* Figure 18.20 */ 86 struct termios *tty_termios(void); /* Figure 18.20 */ 87 88 int ptym_open(char *, int); /* Figure 19.9 */ 89 int ptys_open(char *); /* Figure 19.9 */ 90 91 #ifdef TIOCGWINSZ 92 pid_t pty_fork(int *, char *, int, const struct termios *, 93 const struct winsize *); /* Figure 19.10 */ 94 #endif 95 96 int lock_reg(int, int, int, off_t, 97 int, off_t); /* Figure 14.5 */ 98 99 #define read_lock(fd, offset, whence, len) \ 100 lock_reg((fd), F_SETLK, F_RDLCK, \ 101 (offset), (whence), (len)) 102 #define readw_lock(fd, offset, whence, len) \ 103 lock_reg((fd), F_SETLKW, F_RDLCK, \ 104 (offset), (whence), (len)) 105 #define write_lock(fd, offset, whence, len) \ 106 lock_reg((fd), F_SETLK, F_WRLCK, \ 107 (offset), (whence), (len)) 108 #define writew_lock(fd, offset, whence, len) \ 109 lock_reg((fd), F_SETLKW, F_WRLCK, \ 110 (offset), (whence), (len)) 111 #define un_lock(fd, offset, whence, len) \ 112 lock_reg((fd), F_SETLK, F_UNLCK, \ 113 (offset), (whence), (len)) 114 115 pid_t lock_test(int, int, off_t, int, off_t); /* Figure 14.6 */ 116 117 #define is_read_lockable(fd, offset, whence, len) \ 118 (lock_test((fd), F_RDLCK, (offset), \ 119 (whence), (len)) == 0) 120 #define is_write_lockable(fd, offset, whence, len) \ 121 (lock_test((fd), F_WRLCK, (offset), \ 122 (whence), (len)) == 0) 123 124 void err_msg(const char *, ...); /* Appendix B */ 125 void err_dump(const char *, ...) __attribute__((noreturn)); 126 void err_quit(const char *, ...) __attribute__((noreturn)); 127 void err_cont(int, const char *, ...); 128 void err_exit(int, const char *, ...) __attribute__((noreturn)); 129 void err_ret(const char *, ...); 130 void err_sys(const char *, ...) __attribute__((noreturn)); 131 132 void log_msg(const char *, ...); /* Appendix B */ 133 void log_open(const char *, int, int); 134 void log_quit(const char *, ...) __attribute__((noreturn)); 135 void log_ret(const char *, ...); 136 void log_sys(const char *, ...) __attribute__((noreturn)); 137 void log_exit(int, const char *, ...) __attribute__((noreturn)); 138 139 void TELL_WAIT(void); /* parent/child from Section 8.9 */ 140 void TELL_PARENT(pid_t); 141 void TELL_CHILD(pid_t); 142 void WAIT_PARENT(void); 143 void WAIT_CHILD(void); 144 145 #endif /* _APUE_H */
output_to_stderr.c:
1 #include "apue.h" 2 #include <errno.h> /* for definition of errno */ 3 #include <stdarg.h> /* ISO C variable arguments */ 4 5 static void err_doit(int, int, const char *, va_list); 6 7 /* 8 * Nonfatal error related to a system call. 9 * Peint a message and return. 10 */ 11 void 12 err_ret(const char *fmt, ...) 13 { 14 va_list ap; 15 16 va_start(ap, fmt); 17 err_doit(1, errno, fmt, ap); 18 va_end(ap); 19 } 20 21 /* 22 * Fatal error related to a system call. 23 * Print a message and terminate. 24 */ 25 void 26 err_sys(const char *fmt, ...) 27 { 28 va_list ap; 29 30 va_start(ap, fmt); 31 err_doit(1, errno, fmt, ap); 32 va_end(ap); 33 exit(1); 34 } 35 36 /* 37 * Nonfatal error unrelated to a system call. 38 * Errot code passed as explict parameter. 39 * Print a message and return. 40 */ 41 void 42 err_cont(int error, const char *fmt, ...) 43 { 44 va_list ap; 45 46 va_start(ap, fmt); 47 err_doit(1, error, fmt, ap); 48 va_end(ap); 49 } 50 51 /* 52 * Fatal error unrelated to a system call. 53 * Error code passed as explicit parameter. 54 * Print a message and terminate. 55 */ 56 void 57 err_exit(int error, const char *fmt, ...) 58 { 59 va_list ap; 60 61 va_start(ap, fmt); 62 err_doit(1, error, fmt, ap); 63 va_end(ap); 64 exit(1); 65 } 66 67 /* 68 * Fatal error related to a system call. 69 * Print a message, dump core, and terminate. 70 */ 71 void err_dump(const char *fmt, ...) 72 { 73 va_list ap; 74 75 va_start(ap, fmt); 76 err_doit(1, errno, fmt, ap); 77 va_end(ap); 78 abort(); /* dump core and terminate */ 79 exit(1); /* shouldn't get here */ 80 } 81 82 /* 83 * Nonfatal error unrelated to a system call. 84 * Print a message and return. 85 */ 86 void 87 err_msg(const char *fmt, ...) 88 { 89 va_list ap; 90 91 va_start(ap, fmt); 92 err_doit(0, 0, fmt, ap); 93 va_end(ap); 94 } 95 96 /* 97 * Fatal error unrelated to a system call. 98 * Print a message and terminate. 99 */ 100 void 101 err_quit(const char *fmt, ...) 102 { 103 va_list ap; 104 105 va_start(ap, fmt); 106 err_doit(0, 0, fmt, ap); 107 va_end(ap); 108 exit(1); 109 } 110 111 /* 112 * Print a message and return to caller 113 * Caller specifies "errnoflag". 114 */ 115 static void 116 err_doit(int errnoflag, int error, const char *fmt, va_list ap) 117 { 118 char buf[MAXLINE]; 119 120 vsnprintf(buf, MAXLINE-1, fmt, ap); 121 if (errnoflag) 122 snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, 123 ": %s", strerror(error)); 124 strcat(buf, "\n"); 125 fflush(stdout); /* in case stdout and stderr are the same */ 126 fputs(buf, stderr); 127 fflush(NULL); /* flushes all stdio output streams */ 128 }
daemon_errfunc.c:
1 /* 2 * Error routines for programs that can run as a daemon 3 */ 4 5 #include "apue.h" 6 #include <errno.h> /* for definition of errno */ 7 #include <stdarg.h> /* ISO C variable arguments */ 8 #include <syslog.h> 9 10 static void log_doit(int, int, int, const char *, va_list); 11 12 /* 13 * Caller must define and set this: nonzero if 14 * interactiv, zero if daemon 15 */ 16 extern int log_to_stderr; 17 18 /* 19 * Initialize syslog(), if running as daemon. 20 */ 21 void 22 log_open(const char *ident, int option, int facility) 23 { 24 if (log_to_stderr == 0) 25 openlog(ident, option, facility); 26 } 27 28 /* 29 * Nonfatal error related to a system call. 30 * Print a message with the system's errno value and return. 31 */ 32 void 33 log_ret(const char *fmt, ...) 34 { 35 va_list ap; 36 37 va_start(ap, fmt); 38 log_doit(1, errno, LOG_ERR, fmt, ap); 39 va_end(ap); 40 } 41 42 /* 43 * Fatal error related to a system call. 44 * Print a message and terminate. 45 */ 46 void 47 log_sys(const char *fmt, ...) 48 { 49 va_list ap; 50 51 va_start(ap, fmt); 52 log_doit(1, errno, LOG_ERR, fmt, ap); 53 va_end(ap); 54 exit(2); 55 } 56 57 /* 58 * Nonfatal error unrelated to a system call. 59 * Print a message and return. 60 */ 61 void 62 log_msg(const char *fmt, ...) 63 { 64 va_list ap; 65 66 va_start(ap, fmt); 67 log_doit(0, 0, LOG_ERR, fmt, ap); 68 va_end(ap); 69 } 70 71 /* 72 * Fatal error unrelated to a system call. 73 * Print a message and terminate. 74 */ 75 void 76 log_quit(const char *fmt, ...) 77 { 78 va_list ap; 79 va_start(ap, fmt); 80 log_doit(0, 0, LOG_ERR, fmt, ap); 81 va_end(ap); 82 exit(2); 83 } 84 85 /* 86 * Fatal error related to a system call. 87 * Error number passed as an explicit parameter. 88 * Print a message and terminate. 89 */ 90 void 91 log_exit(int error, const char *fmt, ...) 92 { 93 va_list ap; 94 95 va_start(ap, fmt); 96 log_doit(1, error, LOG_ERR, fmt, ap); 97 va_end(ap); 98 exit(2); 99 } 100 101 /* 102 * Print a message and return to caller. 103 * Caller specifies "errnoflag" and "priority". 104 */ 105 static void 106 log_doit(int errnoflag, int error, int priority, 107 const char *fmt, va_list ap) 108 { 109 char buf[MAXLINE]; 110 111 vsnprintf(buf, MAXLINE-1, fmt, ap); 112 if (errnoflag) 113 snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, 114 ": %s", strerror(error)); 115 strcat(buf, "\n"); 116 if (log_to_stderr) 117 { 118 fflush(stdout); 119 fputs(buf, stderr); 120 fflush(stderr); 121 } 122 else 123 { 124 syslog(priority, "%s", buf); 125 } 126 }