zoukankan      html  css  js  c++  java
  • 【Linux】【Basis】【Kernel】Linux常见系统调用

    一,进程控制
    1)getpid,getppid——获取进程识别号
    #include <sys/types.h>
    #include <unistd.h>
    pid_t getpid(void);
    获取进程标识号。这可以作为一个独一无二的临时文件名。
    pid_t getppid(void);
    获取父进程标示号。
     
    2)fork——创建一个子进程
    #include <sys/types.h>
    #include <unistd.h>
    pid_t fork(void);
    通过完全复制当前进程创建一个新进程。
    如果创建子进程成功,在父进程中返回子进程的进程标示符,在子进程中返回0。
    如果失败,在父进程中返回-1,子进程不会被创建,errno被设置。
    因为在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,
    变量值,程序调用栈,环境变量,缓冲区,等等。所以,子进程和父进程是不能通过
    程序内的变量(即使是全局变量)通信的,对于这两个进程来说,它们有各自的进程空间,
    互不影响。但父进程和子进程可以通过管道,共享内存,等方式实现通信。
     
    3)sleep——使进程睡眠指定的秒数
    #include <unistd.h>
    unsigned int sleep(unsigned int seconds);
    到达指定时间后返回0,若有信号中断,则返回剩余的秒数。
     
    4)wait,waitpid——等待子进程终止
    #include <sys/types.h>
    #include <sys/wait.h>
    pid_t wait(int *status);
    pid_t waitpid(pid_t pid, int *status, int options);
    等待子进程的状态发生变化,并且获得状态变化的信息。状态变化是指:子进程终止;子进程被信号停止;
    或者子进程被信号恢复。
    等待子进程终止可以让系统释放子进程的资源,如果不等待,那么就会产生僵尸进程。
    如果一个子进程状态发生变化,系统调用立即返回,否则就一直阻塞,直到子进程状态发生变化,或者一个
    信号中断系统调用。
    wait(&status);等价于waitpid(-1, &status, 0);
    wait等待一个子进程终止,waitpid等待pid指定的子进程状态改变。默认waitpid仅等待子进程终止,可以
    通过options来改变行为。
    wait执行成功返回终止子进程的进程号,否则返回-1.
    waitpid执行成功返回状态改变子进程的进程号;如果指定了WHOHANG并且pid指定的子进程存在,但是
    状态没有改变,立即返回0。错误返回-1.
    子进程的返回状态由status存储,可以通过宏来获得信息。如果不关心,可以将status设成NULL。
     
    5)execve——执行程序
    #include <unistd.h>
    int execve(const char *filename, char *const argv[],
                 char *const envp[]);
    execve执行一个名字为filename的程序,filename必须是一个二进制可执行文件或一个开始行为如下的脚本文件:
     
    1. #! interpreter [optional-arg]  
    argv是一个传给新程序的参数的字符串数组。为了方便起见,这个数组的第一个应该是filename,也就是执行文件本身。envp是一个字符串数组,每个字符串的形式为key=value,它是传给新程序的环境变量。argv和envp都必须以NULL结尾。这个参数和环境变量可以用被调用程序的main函数来访问,这时,main函数的定义如下:
     
    1. int main(int argc, char *argv[], char *envp[])  
    惊奇的发现,这么定义main函数,gcc带着-Wall选项竟然不警告。
    如果当前程序被跟踪了(ptraced),那么,当成功执行execve后,会产生一个SIGTRAP信号。
    在执行成功的情况下,execve函数不返回,执行失败返回-1,errno被设置。
    执行成功后,调用进程的text,data,bss和stack段被调用execve运行的程序覆盖。
     
    6)ptrace——进程跟踪
    #include <sys/ptrace.h>
    long ptrace(enum __ptrace_request request, pid_t pid,
                   void *addr, void *data);
    ptrace系统调用提供了一个进程(tracer)可以观察和控制另一个执行的进程(tracee),并且检查和改变tracee的内存和寄存器。
    一个tracee首先需要和一个tracer关联。关联和随后的命令是在一个线程中的,在多线程的进程中,每一个线程都可以单独的和一个tracer(可以不相同)关联或者不关联。因此,tracee总是意味着一个线程,而不是一个(多线程)进程。跟踪命令总是以如下的方式向tracee发送: 
    1. ptrace(PTRACE_foo, pid, ...)  
    这里,pid是一个相应的linux线程的id。
    当被跟踪时,tracee会在每次收到信号的时候停止,即使这个信号被忽略了,一种例外是SIGKILL信号,它和平常一样。tracer将会在下次调用waitpid(或者其他相关联的wait系统调用),这可以返回一个status值,表明tracee停止的原因。这时tracer可以使用ptarce请求来检查或修改tracee,然后tracer可以在忽略tracee收到的信号(或者传递另外一个信号)的情况下继续tracee的运行。
    当tracer跟踪完毕,可以让tracee继续以平常方式运行,这通过PTRACE_DETACH模式来完成。
    request的值决定要完成的动作,下面简单介绍几个:
    a)PTRACE_TRACEME
    表示该进程被父进程所跟踪,父进程应该希望跟踪该进程。
    b)PTRACE_PEEKTEXT, PTRACE_PEEKDATA
    从内存地址中读取一个字(word),内存地址由addr给出。在linux中没有区分test和data地址空间,所以它们是等价的。
    c)PTRACE_PEEKUSR
    从USER区域中读取一个字(word),偏移量为addr。
    d)PTRACE_POKETEXT, PTRACE_POKEDATA
    往内存地址中写入一个字(word)。内存地址由addr给出。
    e)PTRACE_POKEUSR
    往USER区域中写入一个字(word)。偏移量为addr。
    执行错误返回-1,errno被设置。
     
    7)setsid——创建一个会话
    #include <unistd.h>
    pid_t setsid(void);
    如果调用这个函数的进程不是进程组的leader,那么就创建一个新的会话,调用者进程是这个会话的leader,进程组的leader,并且没用控制终端与之相关联。进程组id和会话id设置为这个进程的pid。这个进程是这个进程组和会话的唯一一个进程。
    成功返回调用者进程的会话id,否则返回(pid_t)-1,errno被设置。
     
    8)getsid——获取会话id
    #include <unistd.h>
    pid_t getsid(pid_t pid);
    getsid(0)返回当前进程的会话id,getsid(p)返回进程id为p的会话id,会话id是会话leader的进程组id。
    成功返回会话id,否则返回(pid_t)-1,errno被设置。
     
    二,进程间通信
    1)kill——向进程发送一个信号
    #include <sys/types.h>
    #include <signal.h>
    int kill(pid_t pid, int sig);
    kill系统调用可以用来向任何进程组或进程发送信号。
    如果pid为正,则信号发给pid指定的进程。
    如果pid为0,则信号发送给调用进程所在进程组的所有进程。
    如果pid为-1,则信号发送给调用进程有权限发送信号的所有进程,除了进程1(init)。
    如果pid小于-1,则信号发送给进程组为-pid内的所有进程。
    如果sig为0,那么没有发送信号,但是错误检查会进行,这个可以用来检查进程号或进程组号存在与否。
    如果成功(至少一个发送了一个信号),返回0,否则,返回-1,errno被设置。
     
    2)pipe——创建管道
    #include <unistd.h>
    int pipe(int pipefd[2]);
    创建一个无向的管道用于进程间通信。数组pipefd返回两个文件描述符指向管道的两端。
    pipefd[0]指向读端,pipefd[1]指向写端。
    执行成功返回0,否则返回-1,errno被设置。
     
    3)mkfifo——创建一个FIFO的特殊文件(命名管道)
    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char *pathname, mode_t mode);
    mkfifo创建一个名称为pathname指向字符串的FIFO特殊文件,mode指定FIFO文件的访问权限。
    被umask修改,所以创建的文件权限是(mode & ~umask)。
    一旦创建了FIFO特殊文件,任何进程可以以读写的方式打开,就像使用一般文件一样。
    但它的写端和读端必须同时打开,以读的方式打开FIFO文件会阻塞直到另一个进程以写的方式
    打开同一个FIFO文件,反之亦然。
    执行成功返回0,错误情况下返回-1,errno被设置。
     
    4)semop——信号量操作
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    每一个信号量集有如下相关联的值:
    unsigned short semval; /* semaphore value */
    unsigned short semzcnt; /* # waiting for zero */
    unsigned short semncnt; /* # waiting for increase */
    pid_t sempid;/* ID of process that did last op */
    semop函数在semid指定的信号量上执行操作。有nsops个元素的的sops数组中的每个元素
    指定了单个信号量上的操作。sops数组的元素是一个结构体。包含如下成员:
    unsigned short sem_num; //semaphore number
    short  sem_op;//semaphore operations
    short  sem_flg;//operation flags
    sem_flg可以取两个值是IPC_NOWAIT和SEM_UNDO,如果指定了前者,当某个信号量的资源不足时
    进行P操作,此时不会阻塞等待,而是直接返回资源不可用的错误;不是如果指定了后者,那么在程
    序终止的时候会自动撤销对信号量的操作。IPC_UNDO标志保证进程终止(不论正常非正常)后,它对信号量的修改都撤销,
    好像它从来没有操作过信号量一样
    sops中的操作集合按照数组的顺序,原子的执行,也就是说,要么全部执行,要么全都不执行。
    每一个操作在信号量集的编号为sem_num的信号量上执行,第一个信号量的编号是0。根据sem_op
     的不同可以有三种操作:
    a,sem_op是一个正整数,这个操作将这个值加到信号量上(semval)。如果指定了SEM_UNDO,
    系统将从这个信号量的信号量调节值(semadj)减去sem_op。进程必须有信号量集上的写权限。
    b,sem_op是0,进程必须有信号量集上的读权限。这是一个“wait-for-zero”操作:如果semval是0,这个操作
    可以立即执行。否则,如果sem_flg指定了IPC_NOWAIT,semop执行失败,errno设置成EAGAIN(没有opos中的操作被执行)。
    如果没有指定IPC_NOWAIT,semzcnt(等待信号量值为0的线程数)加一,然后线程开始睡眠直到下面情况之一发生:
    第一,semval变成0,这时semzcnt减一;第二,移除了信号量集,semop执行失败,errno设置成EIDRM;第三,调用线程
    扑捉到了一个信号,semzcnt减一,semop执行失败,errno被设置成EINTR。
    semop函数成功执行完成后,数组sops中每一个信号量的sempid值被设置成调用进程的进程标识符,sem_otime被设置成当前时间。
    执行成功semop返回0,否则返回-1,errno被设置。
     
    5)semget——获取一个信号量集标识
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    int semget(key_t key, int nsems, int semflg);
    系统调用semget获取与参数key关联的信号量集标识。
    信号量集建立的方式有两种:
    a,一种是如果key的值是IPC_PRIVATE,那么新的有nsems个信号量的信号量集被建立。
    b,如果不存在信号量集与key关联,并且semflg指定IPC_CREAT。
    如果semflg同时指定了IPC_CREAT和IPC_EXCL并且key已经与信号量集关联,那么
    semget函数会执行失败,errno被设置成EEXIST。
    一旦创建信号量集成功,semflg的最低9个有效位,用来定义这个信号量集的权限(所有者,组和其他)。
    可执行权限对信号量没有意义,写权限意味着可以修改信号量的值。
    新创建的信号量集的值是不定的,尽管Linux像其他的实现那样,将信号量的值初始化为0,但是一个
    可移植的应用程序,不能依赖这一点,应该明确的将信号量的值初始化成希望的值。
    创建了信号量集后,它的相应semid_ds结构体被初始化为如下:
    sem_perm.cuid和sem_perm.uid被设置成该进程的有效用户ID(EUID)。
    sem_perm.cgid和sem_perm.gid被设置成该进程的有效组ID(EGID)。
    sem_perm.mode的最低9个有效位被设置成semflg的最低9个有效位。
    sem_nsems被设置成nsems。
    sem_otime被设置成0。
    sem_ctime被设置成当前时间。
    当信号量集没有被创建的时候,nsems可以为0(不关心),否则nsems必须大于0并且小于或等于每一个信号
    量集的最大信号量集(SEMMSL)。
    如果信号量集已经存在,则会验证权限。
    执行成功返回信号量集标识(一个非负整数),否则返回-1,errno被设置。
     
    6)ftok——转换IPC键值函数
    #include <sys/types.h>
    #include <sys/ipc.h>
    key_t ftok(const char *pathname, int proj_id);
    系统建立IPC通讯是必须指定一个IPC的键值,一般通过ftok函数来获得。
    该函数使用pathname指向的文件或目录(必须存在并且可访问)和proj_id的最低8个有效位(不能为0)
    来生成一个key_t的IPC键值,可以被msgget,semget,shmget使用。
    如果pathname指向同一个文件或目录,并且使用了相同的proj_id那么返回的键值是一样的。
    执行成功返回生成的键值,否则,返回-1,errno被设置。
     
    7)shmget——获取共享内存
    #include <sys/ipc.h>
    #include <sys/shm.h>
    int shmget(key_t key, size_t size, int shmflg);
    shmget函数得到一个与键值key关联的共享内存标识符。
    以下情况创建一个新的共享内存:
    a,key的值是IPC_PRIVATE,这时shmflg的值不起作用。
    b,key的值不是IPC_PRIVATE,且shmflg指定了IPC_CREAT,若key相应的共享内存不
    存在,就创建一个新的共享内存,如果存在则打开这个共享内存。
    以上两种情况创建一个大小为size(round到PAGE_SIZE的整数倍)的共享内存。
    如果shmflg同时制定了IPC_CREAT和IPC_EXCL,且key相应的共享内存存在,那么
    shmget执行失败,errno被设置。
    shmflg的最低9个有效位用来设置共享内存的访问权限,可执行没有意义。
    当一个新的共享内存创建的时候,它的内存被初始化成0,与它关联的结构体shmid_ds初始化为:
    shm_perm.cuid和shm_perm.uid被设置成进程的有效用户ID(EUID)。
    shm_perm.cgid和shm_perm.gid被设置成进程的有效组ID(GUID)。
    shm_perm.mode的最低9个有效位被设置成shmflg的最低9个有效位。
    shm_segsz被设置成size。
    shm_lpid,shm_nattch,shm_atime,shm_dtime被设置成0。
    shm_ctime被设置成当前时间。
    执行成功返回一个有效的共享内存标识符,否则返回-1,errno被设置。
     
    8)shmctl——共享内存控制
    #include <sys/ipc.h>
    #include <sys/shm.h>
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    shmctl执行一个cmd指定的操作在shmid指定的共享内存上。
    参数buf是一个shmid_ds结构体指针,定义在<sys/shm.h>文件中: 
    1. struct shmid_ds {  
    2.     struct ipc_perm shm_perm;    /* Ownership and permissions */  
    3.     size_t          shm_segsz;   /* Size of segment (bytes) */  
    4.     time_t          shm_atime;   /* Last attach time */  
    5.     time_t          shm_dtime;   /* Last detach time */  
    6.     time_t          shm_ctime;   /* Last change time */  
    7.     pid_t           shm_cpid;    /* PID of creator */  
    8.     pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */  
    9.     shmatt_t        shm_nattch;  /* No. of current attaches */  
    10.     ...  
    11. };  
    ipc_perm结构体定义如下: 
    1. struct ipc_perm {  
    2.     key_t          __key;    /* Key supplied to shmget(2) */  
    3.     uid_t          uid;      /* Effective UID of owner */  
    4.     gid_t          gid;      /* Effective GID of owner */  
    5.     uid_t          cuid;     /* Effective UID of creator */  
    6.     gid_t          cgid;     /* Effective GID of creator */  
    7.     unsigned short mode;     /* Permissions + SHM_DEST and 
    8.                            SHM_LOCKED flags */  
    9.     unsigned short __seq;    /* Sequence number */  
    10. };  
    cmd有三个可能的取值:
    a,IPC_STAT,复制shmid关联的shmid_ds结构内容到buf指向的空间,调用者必须有对共享内存的读权限。
    b,IPC_SET,将buf指向结构体中成员的值写入到与shmid关联的shmid_ds结构体,同事更新shm_ctime。
    下面的成员可以被改变:shm_perm.uid, shm_perm.gid和shm_perm.mode的最低9个有效位。必须有足够权限。
    b,IPC_RMID,删除共享内存段。必须有足够权限。只有没有进程与这个共享内存连接的时候才可以删除。
    执行错误返回-1,errno被设置。
     
    9)semctl——信号量控制
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    int semctl(int semid, int semnum, int cmd, ...);
    semctl执行一个由cmd指定的控制操作在semid指定的信号量集上或这个信号量集的编号为semnum的信号量上(编号从0开始)。
    这个函数根据cmd的取值可以有3个或4个参数。当参数为4个的时候,第四个参数是union semun类型。调用的程序必须定义这个
    联合类型为: 
    1. union semun {  
    2.     int              val;    /* Value for SETVAL */  
    3.     struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */  
    4.     unsigned short  *array;  /* Array for GETALL, SETALL */  
    5.     struct seminfo  *__buf;  /* Buffer for IPC_INFO 
    6.                            (Linux-specific) */  
    7. };  
    最后一个struct seminfo的结构体是linux特有的。
    cmd的合法取值有:
    a,IPC_STAT,复制shmid关联的shmid_ds结构内容到arg.buf指向的空间,这时,semnum会被忽略。
    调用者必须有对共享内存的读权限。
    b,IPC_SET,将arg.buf指向结构体中成员的值写入到与shmid关联的shmid_ds结构体,同事更新shm_ctime。
    下面的成员可以被改变:shm_perm.uid, shm_perm.gid和shm_perm.mode的最低9个有效位。必须有足够权限。
    参数semnum被忽略。
    c,IPC_RMID,立即移除信号量集,这会唤醒系统调用semop阻塞的所有进程。必须有足够权限。参数semnum被忽略。
    d,GETALL,返回信号量集中的所有信号量值(semval)到arg.array数组中,参数sennum被忽略,必须有读权限。
    e,GETNCNT,返回信号量集中编号为semnum的信号量的semncnt值(也就是等待编号为semnnum的信号量的值semval
    增加的进程数),必须具有读权限。
    f,GETPID,返回信号量集中编号为semnum的信号量的sempid值(也就是最后一个调用semop等待编号为semnnum的信号量
    的进程ID),必须具有读权限。
    g,GETVAL,返回信号量集中编号为semnum的信号量的semval值,必须具有读权限。
    h,GETZCNT,返回信号量集中编号为semnum的信号量的semzcnt值(也就是等待编号为semnnum的信号量的值semval
    变成0的进程数),必须具有读权限。
    i,SETALL,用arg.array数组中的值设置信号量集中的所有信号量值(semval),同事更新semid_ds的成员sem_ctime当前时间。
    所有进程调用semop设置的撤销操作将被清除。如果信号量集中信号量的修改可以使调用semop的进程执行,那么,那个进程将被唤醒。
    参数sennum被忽略,必须有写权限。
    j,SETVAl,将arg.val的值设置成编号为semnum的信号量的值(semval),并且更新与之关联的semid_ds结构体的sem_ctime值为
    当前时间。所有进程调用semop设置的撤销操作将被清除。如果信号量集中信号量的修改可以使调用semop的进程执行,
    那么,那个进程将被唤醒。必须有写权限。
    执行失败返回-1,errno被设置。
     
    10)shmat,shmdt——共享内存操作
    #include <sys/types.h>
    #include <sys/shm.h>
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    int shmdt(const void *shmaddr);
    shmat将shmid指向的共享内存段连接到进程地址空间。这个地址可由如下方式获得:
    a,shmaddr是NULL,系统选择一个合适的没有使用的地址连接到共享内存段。
    b,shmadrr不是NULL,并且SHM_RND被shmflg指定, 那么连接的地址会向下自动的调整为SHMLBA的整数倍。
    否则,这个连接的地址必须是shmaddr必须是page-aligned的。
    如果shmflg指定了SHM_RDONLY,那么进程必须对共享内存段有读权限,且只能以读的方式操作这个返回的共享内存地址。
    否则,进程必须对共享内存段有读写权限,能以读写的方式操作这个返回的共享内存地址。没有符号来指定只写的操作。
    shmat执行成功后会更新共享内存关联的shmid_ds结构体中的成员:
    shm_atime被设置成当前时间,shm_lpid被设置成调用进程的进程id,shm_nattch加1。
    shmdt将用户空间的shmaddr地址与共享内存段脱离,这个shmaddr必须与shmat返回的一样。
    shmdt执行成功后会更新共享内存关联的shmid_ds结构体中的成员:
    shm_dtime被设置成当前时间,shm_lpid被设置成调用进程的进程id,shm_nattch减1,当它变成0时,意味着将共享内存段删除。
    fork执行后,子进程继承连接的共享内存段。execve执行过后,全部连接的共享内存段将从进程脱离,一旦执行了_exit函数,全部连接
    的共享内存段将从进程脱离。
    shmat执行成功返回连接的用户空间地址,否则返回(void *)-1,errno被设置。
    shmdt执行成功后返回0,否则返回-1,errno被设置。
     
    11)msgget——获取消息队列
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    int msgget(key_t key, int msgflg);
    msgget函数返回一个与键值key关联的消息队列标识符。
    以下情况创建一个新的消息队列:
    a)key的值为IPC_PRIVATE。
    b)key的值不是IPC_PRIVATE,与键值key关联的消息队列不存在,并且msgflg指定了IPC_CREAT。
    如果msgflg同时指定了IPC_CREAT和IPC_EXCL并且与键值key关联的消息队列已经存在,那么msgget执行失败,
    errno被设置成EEXIST。
    一旦消息队列被创建,msgflg的最低9个有效位被用来设置消息队列的权限(可执行权限没有意义)。
    如果一个新的消息队列被创建,那么与它关联的数据结构msgid_ds被初始化为:
    msg_perm.cuid和msg_perm.uid被设置成进程的有效用户ID。
    msg_perm.cgid和msg_perm.gid被设置成进程的有效组ID。
    msg_perm.mode的最低9个有效位被设置成msgflg的最低9个有效位。
    msg_qnum,msg_lsqid,msg_lrpid,msg_stime,msg_rtime被设置成0。
    msg_ctime被设置成当前时间。
    msg_qbytes被设置成MSGMNB。
    执行成功返回一个消息队列标识符(非负整数),否则返回-1,errno被设置。
     
    12)msgctl——消息队列控制操作
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
    msgctl函数在msqid指定的消息队列上执行一个cmd指定的操作。
    msqid_ds结构体定在在文件<sys/msg.h>中: 
    1. struct msqid_ds {  
    2.     struct ipc_perm msg_perm;     /* Ownership and permissions */  
    3.     time_t          msg_stime;    /* Time of last msgsnd(2) */  
    4.     time_t          msg_rtime;    /* Time of last msgrcv(2) */  
    5.     time_t          msg_ctime;    /* Time of last change */  
    6.     unsigned long   __msg_cbytes; /* Current number of bytes in 
    7.                                 queue (nonstandard) */  
    8.     msgqnum_t       msg_qnum;     /* Current number of messages 
    9.                                 in queue */  
    10.     msglen_t        msg_qbytes;   /* Maximum number of bytes 
    11.                                 allowed in queue */  
    12.     pid_t           msg_lspid;    /* PID of last msgsnd(2) */  
    13.     pid_t           msg_lrpid;    /* PID of last msgrcv(2) */  
    14. };  
    ipc_perm结构体定义如下: 
    1. struct ipc_perm {  
    2.     key_t          __key;       /* Key supplied to msgget(2) */  
    3.     uid_t          uid;         /* Effective UID of owner */  
    4.     gid_t          gid;         /* Effective GID of owner */  
    5.     uid_t          cuid;        /* Effective UID of creator */  
    6.     gid_t          cgid;        /* Effective GID of creator */  
    7.     unsigned short mode;        /* Permissions */  
    8.     unsigned short __seq;       /* Sequence number */  
    9. };  

    有效的cmd值是:
    a)IPC_STAT,将msqid关联的msqid_ds结构体中的内容复制到buf指向的空间。进程调用者必须对消息
    队列有读权限。
    b)IPC_SET,将buf指向的结构体中的内容写入到msqid关联的msqid_ds结构体中,同时更新msg_ctime。
    下面的成员可以被更新:msg_qbytes,msg_perm.uid,msg_perm.gid,msg_perm.mode的最低9个有效位。
    调用者必须有足够的权限。
    c)IPC_RMID,立即删除消息队列,唤醒所有等待读和写这个消息队列的进程,这些进程中,产生一个失败的错误,errno被设置成EIDRM。
    调用者必须有足够的权限。
    执行成功返回0,否则返回-1,errno被设置。
     
    13)msgsnd,msgrcv——发送,接收消息
    #include <sys/types.h>
    #inlcude <sys/ipc.h>
    #include <sys/msg.h>
    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
    msgsnd,msgrcv系统调用分别用来向消息队列发送消息和从消息队列中接收消息。调用的进程对消息队列必须
    有写(msgsnd)和读(msgrcv)的权限。
    参数msgp是一个调用者定义的结构体指针,这个结构体一般有如下形式: 
    1. struct msgbuf {  
    2.     long mtype;       /* message type, must be > 0 */  
    3.     char mtext[1];    /* message data */  
    4. };  
    结构体中的mtest成员是一个数组(或者其他的结构体),它的大小由参数msgsz(非负整数)指定。
    长度为0的消息是允许的(也就是说没有mtext成员)。mtype成员必须是一个正整数,这个值可以用来作为
    接收进程的消息选择。
    msgsnd系统调用将msgp指向的结构体的拷贝添加到msqid指向的消息队列。
    如果队列中的可用空间足够,msgsnd立即执行成功。(队列的容量被消息队列关联的msqid_ds结构体中的
    msg_qbytes成员定义。这个限制可以使用msgctl修改)如果没有足够的可用空间,那么msgsnd的默认行为是
    阻塞直到空间足够。如果msgflg指定了IPC_NOWAIT,那么msgsnd执行失败,errno被设置成EAGAIN。
    msgsnd阻塞时也可能发生错误:
    a)消息队列被移除,msgsnd执行失败,errno被设置成EIDRM。
    b)捕捉到一个信号,在这种情况下,msgsnd执行失败,errno被设置成EINTR。msgsnd不会在信号处理函数
    执行过后自动重新发送,除非信号处理函数设置了SA_RESTART标志。
    一旦执行成功,消息队列关联的数据结构更新如下内容:
    msg_lspid被设置成进程的ID。msg_qnum加1。msg_stime被设置成当前时间。
    msgrcv系统调用从msqid指向的消息队列中移除一个消息,将其存放在msgp指向的空间中。
    参数msgsz指定了msgp的mtext成员的最大字节数。如果消息的长度大于msgsz,那么msgrcv函数的行为取决于
    在msgflg参数中有没有指定MSG_NOERROR。如果没有MSG_NOERROR,那么消息不会从消息队列中移除,
    msgrcv返回-1,errno被设置成E2BIG。
    参数msgtyp有以下类型:
    a)如果msgtyp是0,那么读入队列中的第一个消息。
    b)如果msgtyp大于0,那么读入队列中第一个类型为msgtyp的消息。如果msgflg指定了MSG_EXCEPT,那么,
    读入队列中第一个不是msgtyp类型的消息。
    c)如果msgtyp小于0,那么读入消息队列中消息类型小于或等于-msgtyp的最小的类型的消息。
    参数msgflg可以由或运算获得,取值有:
    a)IPC_NOWAIT,如果没有请求的消息,就立即返回。errno被设置成ENOMSG。
    b)MSG_EXCEPT,当msgtyp大于0的时候,读入队列中第一个不是msgtyp类型的消息。
    c)MSG_NOERROR,当消息长度大于msgsz时,截取消息。
    如果没有请求的消息,并且msgflg没有指定IPC_NOWAIT,那么msgrcv一直阻塞,直到下面情况之一满足:
    a)请求的消息被放入了消息队列。
    b)消息队列被移除。这种情况下,执行失败,errno被设置成EIDRM。
    c)进程捕捉到一个信号。在这种情况下,执行失败,errno被设置成EINTR。msgrcv不会在信号处理函数
    执行过后自动重新接收,除非信号处理函数设置了SA_RESTART标志。
    一旦执行成功,与消息队列关联的数据结构跟新如下内容:
    msg_lrpid被设置成进程ID,msg_qnum减1,msg_rtime被设置成当前时间。
    执行失败返回-1,errno被设置。否则,msgsnd返回0,msgrcv返回实际复制到mtext数组中的字节数。
     
    三,文件系统控制
    1)open,creat——打开或创建文件
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int open(const char *pathname, int flags);
    int open(const char *pathname, int flags, mode_t mode);
    int creat(const char *pathname, mode_t mode);
    给定一个pathname,返回一个文件描述符,它是一个小的,非负整数,可以被
    其他系统调用使用(read,write,lseek,fcntl,等等)。
    参数flags必须包含下面三个中的一个:O_RDONLY, O_WRONLY, ORDWR,分别
    表示只读,只写,读写。
    此外,另外的选项是可选的,通过按位或操作添加,它们是:O_CLOEXEC, O_CREAT,
    O_DIRECTORY,O_EXCL,O_NOCTTY,O_NOFOLLOW,O_TRUNC和O_TTY_INIT.
    creat与open的flags参数为O_CREAT|O_WRONLY|O_TRUNC等价。
    文件打开后,这些可选参数可以通过fcntl来改变。
    新文件被创建时mode参数具体指明了使用权限。这个参数必须在flags设置O_CREAT是才起作用,否则,会被忽略。它通常会被umask修改,所以一般创建的文件的权限是(mode & ~umask)。
    mode参数的具体值如下:
    S_IRWXU:所有者拥有读写执行权限。
    S_IRUSR(S_IREAD):允许所有者读
    S_IWUSR(S_IWRITE):允许所有者写
    S_IXUSR(S_IEXEC):允许所有者执行
    S_IRWXG:允许所在组读写执行
    S_IRGRP:允许所在组读
    S_IWGRP:允许所在组写
    S_IXGRP:允许所在组执行
    S_IRWXO:允许其他用户读写执行
    S_IROTH:允许其他用户读
    S_IWOTH:允许其他用户写
    S_IXOTH:允许其他用户执行
    执行成功返回一个新的文件描述符,否则返回-1,errno被设置。
     
    2)read——从一个文件描述符中读取内容
    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);
    read从文件描述符fd指向的文件读取count个字节存放在buf缓冲区中。read从当前
    文件指针指向的位置读取,如果在文件末尾,返回0,表示没有读取字节。
    执行成功返回读取的字节个数,错误情况下返回-1,errno被设置。
     
    3)write——向一个文件描述符中写入内容
    #include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count);
    write向文件描述符fd指向的文件写入buf缓冲区指向的count个字节。
    写入的字节数可能会少于count,如存储空间不足或系统调用setrlimit设置了RLIMIT_FSIZE资源限制,或者
    write被信号中断。
    执行成功返回写入的字节个数,0表示没有写入,否则返回-1,errno被设置。
     
    4)close——关闭文件描述符
    关闭一个文件描述符,它不再引用一个文件和重新使用。
    执行成功返回0,否则返回-1,errno被设置。
     
    5)access——确定文件的可存取性
    #include <unistd.h>
    int access(const char *pathname, int mode);
    access检查进程对pathname指向文件的可存取性,如果它是一个符号链接,就指向原来的文件。
    mode指定检查的权限,如下:
    F_OK:检测文件的存在性。
    R_OK,W_OK,X_OK分别检测文件的读,写,执行权限。
    mode可以是F_OK或者另外三个的按位或。
    拥有权限或文件存在返回0,出错或文件不存在或没有权限返回-1。
     
    6)fcntl——对文件描述符操作
    #include <unistd.h>
    #include <fcntl.h>
    int fcntl(int fd, int cmd, ... /* arg */ );
    对文件描述符fd执行一个由cmd指定的操作。
    fcntl由cmd确定是不是可以有第三个可选的参数。
    具体参数见:
    执行错误返回-1,成功,返回值由cmd确定。
     
    7)truncate,ftruncate——改变文件大小
    #include <unistd.h>
    #include <sys/types.h>
    int truncate(const char *path, off_t length);
    int ftruncate(int fd, off_t length);
    将一个path或fd指向的普通文件大小改变为length,如果原来文件大小大于length,那么额外的数据会丢失,如果原来文件小于length,那么原来文件会被扩展,扩展部分为''。文件偏移指针不会被改变。文件必须是可写的。
    执行成功返回0,否则返回-1,errno被设置。
     
    8)fallocate(),在创建文件时预留空间大小,xfs和ext4文件系统创建文件的时候要使用
     
    四,系统控制
    1)getrlimit, setrlimit——获取/设置系统资源限制
    #include <sys/time.h>
    #include <sys/resource.h>
    int getrlimit(int resource, struct rlimit *rlim);
    int setrlimit(int resource, const struct rlimit *rlim);
    这两个函数分别获取和设置系统资源限制。每一种资源有软限制和硬限制,被定义在rlimit结构体中,其定义如下: 
    1. struct rlimit {  
    2.         rlim_t rlim_cur;  /* Soft limit */  
    3.         rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */  
    4. };  
    软限制是内核强制相应资源的限制值,硬限制是软限制的向上取整。一个没有授权的进程可以设置软限制的值为从0到硬限制的值和设置(不可逆)硬限制的值为一个更低的值,而一个授权的进程可以任意的改变这两个值,在linux中,这个权限是CAP_SYS_RESOURCE。
    两个函数中,值RLIM_INFINITY表示对资源没有限制。
    resource参数的值必须是如下的值(部分,详细见手册):
    a)RLIMIT_AS,进程最大的虚拟内存空间,单位为字节。
    b)RLIMIT_CORE,内核转存文件的最大长度。
    c)RLIMIT_CPU,最大允许的CPU使用时间,秒为单位。当进程达到软限制,内核将给其发送SIGXCPU信号,这一信号的默认行为是终止进程的执行。然而,可以捕捉信号,处理句柄可将控制返回给主程序。如果进程继续耗费CPU时间,核心会以每秒一次的频率给其发送SIGXCPU信号,直到达到硬限制,那时将给进程发送 SIGKILL信号终止其执行。
    d)RLIMIT_DATA,进程数据段的最大值。
    e)RLIMIT_FSIZE,进程可建立的文件的最大长度。如果进程试图超出这一限制时,核心会给其发送SIGXFSZ信号,默认情况下将终止进程的执行。
    f)RLIMIT_LOCKS,进程可建立的锁和租赁的最大值。
    g)RLIMIT_MEMLOCK,进程可锁定在内存中的最大数据量,字节为单位。
    h)RLIMIT_MSGQUEUE,进程可为POSIX消息队列分配的最大字节数。
    i)RLIMIT_NICE,进程可通过setpriority() 或 nice()调用设置的最大完美值。
    j)RLIMIT_NOFILE,指定比进程可打开的最大文件描述词大一的值,超出此值,将会产生EMFILE错误。
    k)RLIMIT_NPROC,用户可拥有的最大进程数。
    l)RLIMIT_RTPRIO,进程可通过sched_setscheduler 和 sched_setparam设置的最大实时优先级。
    m)RLIMIT_SIGPENDING,用户可拥有的最大挂起信号数。
    n)RLIMIT_STACK,最大的进程堆栈,以字节为单位
    执行成功,返回0,否则,返回-1,errno被设置。
     
    最后介绍一下其他非系统调用函数:
    一,多线程
    因为pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,
    因此加上-lpthread(或-pthread)以显式链接该库。函数在执行错误时的错误信息将作为返
    回值返回,并不修改系统全局变量errno,当然也无法使用perror()打印错误信息。
    1)pthread_create——创建一个新的线程
    #include <pthread.h>
    int pthread_create(pthread_t *thread, const pthread_addr_t *addr, void *(*start_routine)(void *), void *arg);
    编译和链接的时候要使用-pthread或-lpthread。
    pthread_create函数在进程中开启一个新的线程。这个线程调用start_routine()函数开始执行,arg是传给start_routine函数的参数。
    这个线程可以通过如下的方式之一终止:
    a,调用pthread_exit函数,这个函数指定的参数由该进程另外一个调用pthread_join的线程获得。
    b,函数start_routine返回。
    c,取消线程(调用pthread_cancel)。
    d,进程中的任意一个线程调用exit,或者主线程中main函数中返回。这将导致进程中的所有线程终止。
    参数attr用来确定创建的线程的各种属性,这个结构体可以用pthread_attr_init来初始化,如果attr为NULL,
    那么用默认的属性来创建一个线程。
    pthread_create函数返回之前,如果执行成功,将新创建的线程的ID号存放在thread指向的内存中。
    函数执行成功返回0,错误情况下,返回错误号,这时*thread的内容是未定义的。
     
    2)pthread_self——获取线程的ID号
    #include <pthread.h>
    pthread_t pthread_self(void);
    返回调用线程的线程ID,这与创建线程时分配的ID号一致。
    这个函数总是成功的,返回线程ID。
     
    3)pthread_exit——终止线程
    #include <pthread.h>
    void pthread_exit(void *retval);
    终止调用线程,通过retval返回一个值,前提是这个线程是joinable的,这个值可以通过本进程的
    其他线程调用pthread_join获得。
     
    4)pthread_join——等待一个指定的线程终止
    #include <pthread.h>
    int pthread_join(pthread_t thread, void **retval);
    pthread_join阻塞到thread指定的线程终止时返回,如果该线程已经终止,则它立即返回。
    thread指向的线程必须是joinable的。ruguo如果retval不是NULL,那么pthread_join将复制
    thread线程的退出状态(这个值由pthread_exit提供)到*retval指定的内存。如果thread线程已经
    取消,那么将PTHREAD_CANCELED存放在*retval中。
    执行成功返回0,否则返回错误编号。
     
    二,其他
    1)system——执行一个shell命令。
    #include <stdlib.h>
    int system(const char *command);
    通过/bin/sh -c执行命令。执行错误返回-1,否则返回命令的执行状态。
     
    2)perror——打印一个系统错误信息
    #include <stdio.h>
    void perror(const char *s);
    #include <error.h>
    int errno;
    perror函数在标准错误输出上产生一个信息,描述最后依次调用系统或库函数出现的错误。
    如果s不是NULL并且*s不是'',那么首先输出s,然后一个冒号和一个空格,然后是错误信息
    和换行符。
     
    3)printf,fprintf,sprintf,snprintf——格式化输出函数
    #include <stdio.h>
    int printf(const char *format, ...);
    int fprintf(FILE *stream, const char *format, ...);
    int sprintf(char *str, const char *format, ...);
    int snprintf(char *str, size_t size, const char *format, ...);
    printf输出到标准输出(stdout),fprintf输出到stream指定的文件,sprintf输出的str指向的
    缓冲区,snprintf指定了最大输出的字符数(包括'')。
    执行成功返回输出的字符数(不包括''),否则返回一个负数。errno被设置。
     
    4)fflush——刷新缓冲区
    #include <stdio.h>
    int fflush(FILE *stream);
    对于输出流,强制刷新缓冲区中的内容到文件流;对于输入流,丢弃缓冲区中的数据。
    如果stream参数是NULL,刷新所有打开的输出流。
    执行成功返回0,否则返回EOF并且errno被设置。
     
    5)fgetc,fgets,getc,getchar,gets,ungetc——输入字符或字符串
    #include <stdio.h>
    int fgetc(FILE *stream);
    char *fgets(char *s, int size, FIZE *stream);
    int getc(FILE *stream);
    int getchar(void);
    char *gets(char *s);
    int ungetc(int c, FILE *stream);
    fgetc从流stream中读取下一个字符,将unsigned char强制转换成int,文件结尾或错误返回EOF。
    getc等价于fgetc,不过getc可能是通过宏来实现的,stream能会被多次求值。
    getchar等价于getc(stdin);
    gets从stdin读取一行,存放在s指向的缓冲区中,直到遇到换行符或EOF,将换行符替换为''。
    fgets最多从stream读size个字符(包括''),存放在s指向的缓冲区中,直到遇到换行符或EOF,
    换行符读进来后将其存放在缓冲区中,''存放在最后一个字符后边。
    ungetc将c强制转换成unsigned char放回stream,它可以被后来的读取操作读取到。
    fgetc,getc,getchar返回一个强制转换成int的字符或者在文件结尾或出错时返回EOF。
    gets,fgets执行成功返回s,在错误或文件结尾返回NULL。
    ungetc执行成功返回c,错误返回EOF。
    ISO C11将gets从c语言规范中移除,所以不建议使用gets。
     
    6)fputc,fputs,putc,putchar,puts——输出字符或字符串
    #include <stdio.h>
    int fputc(int c, FILE *stream);
    int fputs(const char *s, FILE *stream);
    int putc(int c, FILE *stream);
    int putchar(int c);
    int puts(const char *s);
    fputc向stream写入一个字符c,强制转换成unsigned char。
    fputs向stream写入一个字符串s,不包括''。
    putc与fputc等价,不过putc可能使用宏来实现,stream可能被求值多次。
    putchar与putc(c,stdout)等价。
    fputc,putc,putchar执行成功返回写入的字符(unsigned char强制转换成int),执行失败返回EOF。
    puts和fputs执行成功返回一个非负数,否则返回EOF。
     
    7)fopen,fdopen,freopn——打开文件流
    #include <stdio.h>
    FILE *fopen(const char *path, const char *mode);
    FILE *fdopen(int fd, const char *mode);
    FILE *freopen(const char *path, const char *mode, FILE *stream);
    fopen打开一个path指向的文件,并用一个流来关联它。
    mode指定打开文件的方式。描述如下:
    r —— 以读的方式打开文件,文件指针指向文件开头。
    r+ —— 以读写的方式打开文件,文件指针指向文件开头。
    w —— 以写的方式打开文件,如果文件不存在则创建,如果文件存在则覆盖。文件指针指向文件开头。
    w+ —— 以读写的方式打开文件。其他同w。
    a —— 以添加的方式打开文件(在文件末尾写入)。文件不存在则创建,文件指针指向文件结尾。
    a+ —— 以读和添加的方式打开文件(在文件末尾写入)。其他同a。
    mode字符串还可以包含b字符,其作为最后一个字符或者在+前边,如rb或rb+。表示打开一个二进制文件。
    这完全兼容C89.但字符b在全部遵循POSIX的系统中被忽略,包括linux。其他系统可能将文本文件和二进制
    文件以不同的方式对待。在读写二进制文件时,最好加上字符b,便于向non-UNIX系统移植。
    fdopen将一个存在的文件描述符fd与一个流关联。打开流的mode("r","r+","w","w+","a","a+"中的一个)必须
    与文件描述符的模式兼容。新流的文件指针与fd一致,错误和文件末尾指针被清除。模式w和w+不会覆盖文件。
    文件描述符没有被复制,当使用fd创建的流关闭时,文件描述符也会被关闭。将fdopen用于共享内存对象的结果是未定义的。
    freopen打开一个path指向的文件,并与stream流关联。freopen的主要用途是对stderr,stdin,stdout进行重定向。
    fopen,fdopen,freopen执行成功返回一个文件指针,否则返回NULL,errno被设置。
     
    8)popen,pclose——进程输入输出的管道流
    #include <stdio.h>
    FILE *popen(const char *command, const char *type);
    int pclose(FILE *stream);
    popen函数通过创建一个管道,调用fork产生一个子进程,执行一个shell以运行命令来开启一个进程。因为管道是双向的,所以type参数只能是读或者写,而不能两者都是。
    参数command是一个以''结尾的字符串,表示一个shell命令,这个命令使用/bin/sh并带-c标志来运行。type必须是包含'r'或'w'的以''结尾的字符串。函数的返回值是一个标准IO流,它必须使用pclose来关闭,而不是fclose。向这个流写入相当于对这个命令的标准输入进行写入,命令的标准输出与调用popen进程的相同,从这个流读相当于从这个命令的标准输出读,命令的标准输入与调用popen进程的标准输入相同。
    pclose通过调用wait4等待命令相关的进程结束,返回命令的执行状态。
    popen调用fork或pipe失败,或不能分配内存,返回NULL。
    pclose执行错误返回-1,errno被设置。
     
    9)execl, execlp, execle, execv, execvp——运行一个文件
    #include <unistd.h>
    extern char **environ;
    int execl(const char *path, const char *arg, ...);
    int execlp(const char *file, const char *arg, ...);
    int execle(const char *path, const char *arg,
               ..., char * const envp[]);
    int execv(const char *path, char *const argv[]);
    int execvp(const char *file, char *const argv[]);
    int execvpe(const char *file, char *const argv[],
                   char *const envp[]);
    exec函数家族用新运行程序的镜像代替当前进程的镜像,具体见execve的手册。
    第一个参数是将要执行的可执行程序名字。
    在函数execl,execlp,execle中,const char *arg和后边的省略号可以传进来形如arg0,arg1,...,argn的参数。这个列表表示传递给运行程序的参数列表,每个参数指向一个以''结尾的字符串。这个参数列表必须以NULL指针结尾,因为是可变参数,所以,必须强转成char *,也就是(char *)NULL。
    函数execv,execvp提供了一个字符串数组,每个字符串以''结尾,表示传递给新程序的参数列表,为了方便,第一个参数为新程序的名字,也就是这两个函数的第一个参数值,这个字符串数据必须以NULL结尾。
    execle函数允许通过envp参数来向新程序传递一些环境变量。evnp是一个以''结尾的字符串数组,这个数组必须以NULL结尾,调用execle进程的其他函数可以通过外部变量environ来获取这写环境变量。
    这些函数只有在错误的时候返回-1,errno被设置。
     
    10)fexecve——通过一个文件描述符来执行程序
    #include <unistd.h>
    int fexecve(int fd, char *const argv[], char *const envp[]);
    fexecve函数与execve做相同的事情,不过,它通过文件描述符来执行一个程序,而不是通过文件名。这个文件描述符必须以只读的方式打开,并且调用者必须有权限执行它只想的文件。
    这个函数只在失败的时候返回-1,errno被设置。
     
    11)closelog,openlog,syslog,vsyslog——向系统日志发送一个消息
     #include <syslog.h>
    void openlog(const char *ident, int option, int facility);
    void syslog(int priority, const char *format, ...);
    void closelog(void);

    #include <stdarg.h>
    void vsyslog(int priority, const char *format, va_list ap);
    closelog关闭一个系统日志写入描述符,这个函数的使用是可选的。
    openlog打开一个系统日志的连接。ident指向的字符串会在每个消息前加上,典型的设置的程序名。如果ident是NULL,程序名就会被使用。
    option参数指定控制openlog和后来的syslog的标记。facility参数指定一个缺省值,它会在随后的syslog没有指定priority时起作用。option和facility的值会在下面描述。
    openlog的使用是可选的,调用syslog的时候会自动调用openlog,这种情况下,ident是NULL。
    syslog生成一个系统日志消息,这个消息被syslogd发布。priority参数的形式是facility和level(下面会描述)的或运算。format参数与printf类似,除了两个字符序列%m会被代替为字符串strerror(errno),换行符会在需要的时候打印出来。
    vsyslog与syslog类似,不过它没有使用可变参数,而是使用了一个va_list类型的变量作为参数。
    下面介绍参数的取值:
    A)option
    a)LOG_CONS,如果将信息发送给syslogd守护进程时发生错误,直接将相关信息输出到终端
    b)LOG_NDELAY,立即打开与系统日志的连接(通常情况下,只有在产生第一条日志信息的情况下才会打开与日志系统的连接)
    c)LOG_NOWAIT,在记录日志信息时,不等待可能的子进程的创建
    d)LOG_ODELAY,类似于LOG_NDELAY参数,与系统日志的连接只有在syslog函数调用时才会创建
    e)LOG_PERROR,在将信息写入日志的同时,将信息发送到标准错误输出(POSIX.1-2001和POSIX.1-2008不支持该参数)
    f)LOG_PID,每条日志信息中都包括进程号
     
    B)facility
    这个参数通常用来表示写入日志的程序的类型,这会让配置文件以不同的方式处理这些日志消息。
    a)LOG_AUTH,安全/授权信息
    b)LOG_AUTHPRIV,安全/授权信息(私有)
    c)LOG_CRON,时钟守护进程(cron和at)
    d)LOG_DAEMON,没有单独facility值的系统守护进程
    e)LOG_FTP,ftp守护进程
    f)LOG_KERN,内核消息(不能由用户进程产生)
    g)LOG_LOCAL0到LOG_LOCAL7,为本地用户预留
    h)LOG_LPR,line printer subsystem
    i)LOG_MAIL,mail subsystem
    j)LOG_NEWS,USENET news subsystem
    k)LOG_SYSLOG,messages generated internally by syslogd(8)
    l)LOG_USER,通常的用户级消息
    m)LOG_UUCP,UUCP subsystem
     
    C)level
    这用来确定消息的重要程度,重要程度依次递减:
    LOG_EMERG      system is unusable
    LOG_ALERT      action must be taken immediately
    LOG_CRIT       critical conditions
    LOG_ERR        error conditions
    LOG_WARNING    warning conditions
    LOG_NOTICE     normal, but significant, condition
    LOG_INFO       informational message
    LOG_DEBUG      debug-level message
    Never pass a string with user-supplied data as a format, use the following instead:
    syslog(priority, "%s", string);
     
    参考:
    1)http://blog.sina.com.cn/s/blog_4ac74e9a0100n7w1.html
    2)http://www.cnblogs.com/resound/archive/2010/06/17/1759290.html
    3)http://blog.csdn.net/bingqingsuimeng/article/details/8741389
     
     
  • 相关阅读:
    0-J2EE
    3-Spring
    linux部分常用命令
    linux配置bond
    免密登录和配置网卡
    配置网卡的子接口
    mysqldump备份
    python的数据结构
    mysql一主一从复制
    Python3 基本数据类型和类型转换
  • 原文地址:https://www.cnblogs.com/demonzk/p/9052840.html
Copyright © 2011-2022 走看看