Linux系统编程之daemon进程创建

1 umask
1.1 对应系统调用sys_umask,源码实现在/kernel/sys.c中,SYSCALL_DEFINE1(umask, int, mask)
利用传进来的参数mask对当前进程的文件结构体掩码进行赋值:xchg(&current->fs->umask, mask & S_IRWXUGO);
task_struct结构体中fs的结构如下:
struct fs_struct {
int users;
spinlock_t lock;
seqcount_t seq;
int umask;
int in_exec;
struct path root, pwd;
};
1.2 作用描述
举一个使用位置来说,在文件系统的inode节点支持的操作函数atomic_open中被用于mode &= ~current_umask(),屏蔽掉某些权限位。
1.3 示例

#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
int main(int argc, char *argv[]){
    int fd = fd = open("./huha0", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    if(fd < 0){
        printf("open error!\n");
        exit(-1);
    }
    close(fd);

    umask(0);
    fd = open("./huha1", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    if(fd < 0){
        printf("open error!\n");
        exit(-1);
    }
    close(fd);

    umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    fd = open("./huha2",  O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    if(fd < 0){
        printf("open error!\n");
        exit(-1);
    }
    close(fd);
    return 0;
}

结果如下:
这里写图片描述
备注:系统默认的umask是S_IWGRP | S_IWOTH.
2 getrlimt
2.1 对应系统调用sys_getrlimt,为了获得进程可以使用的各类资源的上限值,原型如下:int getrlimit(int resource, struct rlimit *rlim),当resource是RLIMIT_NOFILE的时候,可以获得进程可以打开的文件的最大个数。函数成功返回0,失败返回-1.
rlimit的结构如下:
struct rlimit {
  rlim_t rlim_cur;
  rlim_t rlim_max;
};
rlimit_t是unsigned long类型的别名,rlim_cur代表的是内核对进程资源的限制,rlim_max是硬件对进程资源的最大支持。
2.2 示例

#include<stdio.h>
#include<sys/resource.h>
#include<stdlib.h>

int main(int argc, char *argv[]){
    int fd0, fd1, fd2;
    struct rlimit re;
    if(getrlimit(RLIMIT_NOFILE, &re) < 0){
        printf("getrlimit error!\n");
        exit(-1);
    }
    printf("max fd value which parent could open under the rule of kernel = %ld\n", re.rlim_cur);
    printf("max fd value which parent could open under the rule of hardware = %ld\n", re.rlim_max - 1);
    printf("1: parent can printf!\n");
    int fd;
    for(fd = 0; fd < re.rlim_cur; fd ++){
        close(fd);
    }
    printf("2: parent can printf!\n");
    return 0;
}

结果如图:
这里写图片描述
3 chdir getcwd
3.1 chdir可以改变进程当前的工作目录,getcwd可以获得进程当前的工作目录。
3.2 示例

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

#define MAX_PATH 100

int main(int argc, char *argv[]){
    char buf[MAX_PATH];
    getcwd(buf, sizeof(buf));
    printf("current dir = %s\n", buf);
    chdir("/tmp");
    getcwd(buf, sizeof(buf));
    printf("current dir = %s\n", buf);
    return 0;
}

结果如下图:
这里写图片描述

4 daemon进程创建
4.1 daemon进程是一类特殊的进程,特殊之处在于以下几点:(1)没有对应的终端可以输入输出,即文件句柄的0、1、2不对应于终端输入、终端输出、终端错误;(2)进程的生命周期与终端进程bash脱离关系,即一般使用bash启动的进程会随着bash进程的退出而终止,而daemon进程虽然也可能是通过终端启动,但其生命周期与终端进程bash脱离关系;(3)daemon进程的父进程一般是init进程,除了init进程启动的daemon进程外,其他通过使用终端bash进程启动的daemon会在终端bash进程退出后成为孤儿进程,之后内核将其挂在init进程的子进程链表中。
daemon进程的创建有很多方法,此处采用的方法如下:启动父进程 -> 父进程fork子进程A -> 进程A脱离旧的终端会话,产生新的终端会话,成为新终端会话的首进程 -> 进程A关闭继承自父进程的所有文件句柄,与终端脱离关系 -> 由于进程A是终端会话首进程,所以其可以再次打开一个新的终端,于是此处,进程A再次fork子进程B -> 此时,进程B不再是终端会话的首进程,不可以打开新的终端,将进程B的0、1、2分别设置为指向文件/dev/null、/tmp/out.log、/tmp/error.log的句柄,改变当前工作目录为/tmp -> 进程B便是我们的创建的daemon进程。
4.2 示例

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#include<sys/resource.h>

int main(int argc, char *arv[]){
    int fd;
    pid_t a, b;
    a = fork();
    if(a < 0){
        printf("fork error!\n");
        exit(-1);
    }else if(a > 0){
        printf("parent: succ to fork child!\n");
        printf("parent: exit!\n");
        exit(0);
    }
    printf("A: I'm here!\n");
    printf("A: I'm changing session ID!\n");
    if(setsid() < 0){
        printf("A: setsid error!\n");
        printf("A: bye!\n");
        exit(0);
    }
    printf("A: I'm going to close all the file handles!\n\
            So, You all won't see me again!\n\
            But maybe you can find my child B's words!\n");
    struct rlimit re;
    if(getrlimit(RLIMIT_NOFILE, &re) < 0){
        printf("A: I can not getrlimit()!\n");
        printf("A: bye!\n");
        exit(0);
    }
    for(fd = 0; fd < re.rlim_cur; fd ++){
        close(fd);
    }
    b = fork();
    if(b < 0){
        printf("A: anyway, you can not see error!\n");
        exit(0);
    }else if(b > 0){
         exit(0);
    }
    umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    int fd0, fd1, fd2;
    fd0 = open("/dev/null", O_RDWR);
    fd1 = open("/tmp/out.log", O_RDWR | O_CREAT, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);//for test
    fd2 = open("/tmp/error.log", O_RDWR | O_CREAT, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);//for test
    if(fd0 < 0 || fd1 < 0 || fd2 < 0){
        printf("B: sorry, you can not see error!\n");
        exit(0);
    }
    printf("B: CaN yOu Find mE?\n");
    printf("B: I am your daemon!\n");
    char buf[1000];
    getcwd(buf, sizeof(buf));
    printf("B: current pwd = %s\n", buf);
    chdir("/tmp");
    getcwd(buf, sizeof(buf));
    printf("B: current pwd = %s\n", buf);
    int i =0;
    while(++ i){
        printf("B: I am going to sleep %d sec.\n", i);
        sleep(i);
        sprintf(buf, "B: maybe I should output something like error!\tid = %d, con = 00000110010.\n", i);
        write(fd2, buf, strlen(buf));
    }
    return 0;
}

结果如图:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/u011414616/article/details/80865660