《UNIX 环境高级编程》第一个例子
UNIX
环境高级编程第一个例子
我的博客
本文是对《UNIX 环境高级编程》这本书的第一章第一个例子进行的实现,本文给出了 myls.c
源码,Makefile
源码,以及后续所有章节都会用到的附录中的头文件以及头文件函数实现源码。
我的目录结构是这样的:
# myls.c 源码放在如下目录下
arv@arv-OptiPlex-7090:~/advanced_UNIX_PRO/src/1_test$ ls
Makefile myls.c
# 头文件与错误、日志记录源码放在如下目录下
arv@arv-OptiPlex-7090:~/advanced_UNIX_PRO/inc$ ls
apue.h error_a.c error_b.c
对本文例子,在 Makefile
同级目录下执行:
arv@arv-OptiPlex-7090:~/advanced_UNIX_PRO/src/1_test$ make
gcc -Wall -c -o error_a.o /home/arv/advanced_UNIX_PRO/inc/error_a.c
gcc -Wall -c -o error_b.o /home/arv/advanced_UNIX_PRO/inc/error_b.c
gcc -Wall -c -o myls.o myls.c
gcc -o myls *.o -lm
运行结果:
arv@arv-OptiPlex-7090:~/advanced_UNIX_PRO/src/1_test$ ./myls ./
error_b.o
myls
Makefile
myls.c
.
..
myls.o
error_a.o
myls.c
源码
#include "../../inc/apue.h"
#include <dirent.h>
int main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if(argc != 2)
err_quit("usage: lsdirectory_name");
if((dp = opendir(argv[1])) == NULL)
{
err_sys("can't open %s", argv[1]);
}
while((dirp = readdir(dp)) != NULL)
printf("%s\r\n", dirp->d_name);
closedir(dp);
exit(0);
}
Makefile
CC = gcc
CFLAGS = -Wall
LDFLAGS = -lm
VPATH = /home/arv/advanced_UNIX_PRO/inc (PWD)#/home/arv/advanced_UNIX_PRO/src/1_test
EXENAME = myls
OBJECTS = error_a.o error_b.o myls.o
# make target
all:${OBJECTS}
${CC} -o ${EXENAME} *.o ${LDFLAGS}
# make clean
clean:
rm -rf ${EXENAME} ${OBJECTS}
# dependence
头文件 apue.h
/*
* @Author: Arvin
* @Date: 2022-03-23 21:04:49
* @LastEditTime: 2022-03-23 21:45:12
* @LastEditors: Please set LastEditors
* @Description: This is for Advanced Unix Program
* @FilePath: \undefinedc:\Users\XDD\Desktop\apue.h
*/
#ifndef _APUE_H
#define _APUE_H
#define _POSIX_C_SOURCE 200809L
#if defined(SOLARIS) /* Solaris 10 */
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 700
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/termios.h>
#if defined(MACOS) || !defined(TIOCGWINSZ)
#include <sys/ioctl.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define MAXLINE 4096 /* max line length */
/* Default file access permissions for new files */
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/* Default permissions for new directories */
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
typedef void Sigfunc(int); /* for signal handlers */
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
/* Prototypes for our own functions */
char *path_alloc(size_t *); /* Figure 2.16 */
long open_max(void); /* Figure 2.17 */
int set_cloexec(int); /* Figure 13.9 */
void clr_fl(int, int);
void set_fl(int, int); /* Figure 3.12 */
void pr_exit(int); /* Figure 8.5 */
void pr_mask(const char *); /* Figure 10.14 */
Sigfunc *signal_intr(int, Sigfunc *); /* Figure 10.19 */
void daemonize(const char *); /* Figure 13.1 */
void sleep_us(unsigned int); /* Exercise 14.5 */
ssize_t readn(int, void *, size_t); /* Figure 14.24 */
ssize_t writen(int, const void *, size_t); /* Figure 14.24 */
int fd_pipe(int *); /* Figure 17.2 */
int recv_fd(int, ssize_t (*func)(int, const void *, size_t)); /* Figure 17.14 */
int send_fd(int, int); /* Figure 17.13 */
int send_err(int, int, const char *); /* Figure 17.12 */
int serv_listen(const char *); /* Figure 17.8 */
int serc_accept(int, uid_t *); /* Figure 17.9 */
int cli_conn(const char *); /* Figure 17.10 */
int buf_args(char *, int (*func)(int, char **)); /* Figure 17.23 */
int tty_cbreak(int); /* Figure 18.20 */
int tty_raw(int); /* Figure 18.20 */
int tty_reset(int); /* Figure 18.20 */
int tty_atexit(void); /* Figure 18.20 */
struct termios *tty_termios(void); /* Figure 18.20 */
int ptym_open(char *, int); /* Figure 19.9 */
int ptys_open(char *); /* Figure 19.9 */
#ifdef TIOCGWINSZ
pid_t pty_fork(int *, char *, int, const struct termios *, const struct winsize *); /* Figure 19.10 */
#endif
int lock_reg(int, int, int, off_t, int, off_t); /* Figure 14.5 */
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
pid_t lock_test(int, int, off_t, int, off_t); /* Figure 14.6 */
#define is_read_lockable(fd, offset, whence, len) \
(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd, offset, whence, len) \
(lock_test((fd), FWRLCK, (offset), (whence), (len)) == 0)
void err_msg(const char *, ...); /* Appendix B */
void err_dump(const char *, ...) __attribute__((noreturn));
void err_quit(const char *, ...) __attribute__((noreturn));
void err_cont(int, const char *, ...);
void err_exit(int, const char *, ...) __attribute__((noreturn));
void err_ret(const char *, ...);
void err_sys(const char *, ...) __attribute__((noreturn));
void log_msg(const char *, ...); /* Appendix B */
void log_open(const char *, int, int);
void log_quit(const char *, ...) __attribute__((noreturn));
void log_ret(const char *, ...);
void log_sys(const char *, ...) __attribute__((noreturn));
void log_exit(int, const char *, ...) __attribute__((noreturn));
void TELL_WAIT(void); /* parent/child/from Section 8.9 */
void TELL_PARENT(pid_t);
void TELL_CHILD(pid_t);
void WAIT_PARENT(void);
void WAIT_CHILD(void);
#endif /* _APUE_H */
错误处理函数
/*
* @Author: Arvin
* @Date: 2022-03-23 21:46:36
* @LastEditTime: 2022-03-23 22:03:59
* @LastEditors: Please set LastEditors
* @Description:
* @FilePath: \undefinedc:\Users\XDD\Desktop\error_a.c
*/
#include "apue.h"
#include <errno.h>
#include <stdarg.h>
static void err_doit(int, int, const char *, va_list);
/**
* @brief Prit a message and return
* @note Nonfatal error related to a system call
* @param *fmt:
* @retval None
*/
void err_ret(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
}
/**
* @brief Print a message and terminate
* @note Fatal error related to a system call
* @param *fmt:
* @retval None
*/
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
exit(1);
}
/**
* @brief Prit a message and return
* @note Nonfatal error unrelated to a system call
* @param error: Error code passed as explict parameter
* @param *fmt:
* @retval None
*/
void err_cont(int error, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
}
/**
* @brief Print a message and terminate
* @note Fatal error unrelated to a system call
* @param error: Error code passed as explict parameter
* @param *fmt:
* @retval None
*/
void err_exit(int error, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
exit(1);
}
/**
* @brief Print a message, dump core, and terminate
* @note Fatal error related to a system call
* @param *fmt:
* @retval None
*/
void err_dump(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(1); /* shouldn;t get here */
}
/**
* @brief Print a message and return
* @note Nonfatal error unrelated to a system call
* @param *fmt:
* @retval None
*/
void err_msg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
}
/**
* @brief Print a message and terminate
* @note Fatal error unrelated to a system call
* @param *fmt:
* @retval None
*/
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
exit(1);
}
/**
* @brief Caller specifies "errnoflag"
* @note Print a message and return to caller
* @param errnoflag:
* @param error:
* @param fmt:
* @param ap:
* @retval None
*/
static void err_doit(int errnoflag, int error, const char * fmt, va_list ap)
{
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if(errnoflag)
{
snprintf(buf+strlen(buf), MAXLINE-strlen(buf) - 1, ": %s", strerror(error));
}
strcat(buf, "\n");
fflush(stdout); /* In case stdout and stderr are the same */
fputs(buf, stderr);
fflush(NULL); /* Flushes all stdio output streams */
}
错误记录函数
/*
* @Author: Arvin
* @Date: 2022-03-23 22:04:31
* @LastEditTime: 2022-03-24 21:35:17
* @LastEditors: Please set LastEditors
* @Description:
* @FilePath: \undefinedc:\Users\XDD\Desktop\error_b.c
*/
#include "apue.h"
#include <errno.h>
#include <stdarg.h>
#include <syslog.h>
static void log_doit(int, int, int, const char *, va_list ap);
/**
* @brief Caller must define and set this: nonzero if interactive, zero if daemon
* @note
* @retval None
*/
//extern int log_to_stderr;
/**
* @brief Initialize syslog(), if runing as daemon
* @note
* @param *ident:
* @param option:
* @param facility:
* @retval None
*/
void log_open(const char *ident, int option, int facility)
{
if(1)//(log_to_stderr == 0)
{
openlog(ident, option, facility);
}
}
/**
* @brief Print a message with the system's errno value and return
* @note Nonfatal error related to a system call
* @param *fmt:
* @retval None
*/
void log_ret(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
}
/**
* @brief Print a message and terminate
* @note Fatal error related to a system call
* @param *fmt:
* @retval None
*/
void log_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/**
* @brief Print a message and return
* @note Nonfatal error unrelated to a system call
* @param *fmt:
* @retval None
*/
void log_msg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
}
/**
* @brief Print a message and terminate
* @note Fatal error unrelated to a system call
* @param *fmt:
* @retval None
*/
void log_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/**
* @brief Print a message and terminate
* @note Fatal error related to a system call
* @param error: Error number passed as an explicit parameter
* @param fmt:
* @retval None
*/
void log_exit(int error, const char * fmt, ...)
{
va_list ap;
va_start(ap, fmt);
log_doit(1, error, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/**
* @brief Print a message and return to caller
* @note Caller specifies "errnoflag" and "priority"
* @param errnoflag:
* @param error:
* @param priority:
* @param *fmt:
* @param ap:
* @retval None
*/
static void log_doit(int errnoflag, int error, int priority, const char *fmt, va_list ap)
{
char buf[MAXLINE];
vsnprintf(buf, MAXLINE - 1, fmt, ap);
if(errnoflag)
{
snprintf(buf + strlen(buf), MAXLINE - strlen(buf) - 1, ": %s", strerror(error));
}
strcat(buf, "\n");
if(1)//(log_to_stderr)
{
fflush(stdout);
fputs(buf, stderr);
fflush(stderr);
}
else
{
syslog(priority, "%s", buf);
}
}