守护进程的特点:
UID = 0 以超级用户启动
TTY = ? 没有控制终端
TPGID=-1 没有任何相关的前台进程组
PPID = 1 父进程都为Init
创建守护进程的方法:
1、让Init成为它的父进程
用fork产生新进程后,杀死父进程,使Init收养它。
2、使用setsid创建新会话
使其失去原父进程的控制终端和前台进程组
3、用chdir修改当前工作目录
4、关闭文件描述符,重定向输入输出,避免出现打印
5、为守护进程的文件权限创建掩码
可以使用umask,避免其他用户查看。
代码举例:
createdaemon.c:
- #include <stdio.h>
-
#include <unistd.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
int main(int argc, char *argv[])
-
{
-
pid_t pid;
-
int nochdir;
-
int noclosefp;
-
int fd;
-
int mode;
-
-
/* 入参检查:命令行参数不得少于三个(进程名、模式、守护进程路径) */
-
if(argc < 3)
-
{
-
printf("not enough argument!\n");
-
printf("arg[1]=1|2|3. 1-->nochdir;2-->noclosefp;3-->1+2.\n");
-
printf("arg[2..]=daemon program file and command line args...\n");
-
return -1;
-
}
-
-
/* 模式判断:mode+1:重置当前工作目录. mode+2:关闭输入输出 */
-
mode = atoi(argv[1]);
-
switch (mode)
-
{
-
case 1:
-
{
-
nochdir = 1;
-
noclosefp = 0;
-
break;
-
}
-
case 2:
-
{
-
noclosefp = 1;
-
nochdir = 0;
-
break;
-
}
-
case 3:
-
{
-
nochdir = 1;
-
noclosefp = 1;
-
break;
-
}
-
default:
-
{
-
printf("invalid args! exit.\n");
-
return -1;
-
}
-
}
-
-
/* 判断守护进程程序是否存在 */
-
if (access(argv[2], 0) < 0)
-
{
-
perror("access");
-
return -1;
-
}
-
/* 创建守护进程 */
-
pid = fork();
-
if(pid < 0)
-
{
-
perror("fork");
-
return -1;
-
}
-
else if(pid != 0)
-
{
-
_exit(0); /* 父进程直接退出,由init收养子进程 */
-
}
-
-
/* 成为会话头进程 */
-
pid = setsid();
-
if(pid < 0)
-
{
-
perror("setsid");
-
return -1;
-
}
-
-
printf("starting daemon process:%s, mode %d....\n", argv[2], mode);
-
-
/* 重置工作目录 */
-
if(!nochdir)
-
{
-
chdir("/");
-
}
-
-
/* 关闭输入输出 */
-
if(!noclosefp)
-
{
-
fd = open("/dev/null", O_RDWR, 0);
-
if(fd != -1)
-
{
-
dup2(fd, STDIN_FILENO);
-
dup2(fd, STDOUT_FILENO);
-
dup2(fd, STDERR_FILENO);
-
if(fd > 2)
-
{
-
close(fd);
-
}
-
}
-
}
-
-
umask(0027);
-
-
if(execvp(argv[2], &(argv[2])) < 0)
-
{
-
perror("execvp");
-
return -1;
-
}
-
-
return 0;
-
}
testdaemon.c:
- #include <stdio.h>
-
#include <unistd.h>
-
-
int main(int argc, char *argv[])
-
{
-
while(1)
-
{
-
sleep(5);
-
printf("\ndaemon test is running.\n");
-
}
-
return 0;
-
}
运行测试,不改变工作目录,不关闭输入输出:
lisong@lisong:~/code/experiment/proc/daemon$ ./createdaemon 3 ./testdaemon
starting daemon process:./testdaemon, mode 3....
lisong@lisong:~/code/experiment/proc/daemon$
daemon test is running.
daemon test is running.
改变工作目录,不关闭输入输出:
lisong@lisong:~/code/experiment/proc/daemon$ ./createdaemon 2 ./testdaemon
starting daemon process:./testdaemon, mode 2....
execvp: No such file or directory
改变目录之后,找不到testdaemon,因此无法执行。但“execvp: No such file or directory”可以打印。
不改变工作目录,关闭输入输出:
lisong@lisong:~/code/experiment/proc/daemon$ ./createdaemon 1 ./testdaemon
starting daemon process:./testdaemon, mode 1....
lisong@lisong:~/code/experiment/proc/daemon$ ps -axj|grep testdaemon
Warning: bad ps syntax, perhaps a bogus '-'? See
1 3980 3980 3980 ? -1 Ss 1000 0:00 ./testdaemon
2392 3982 3981 2392 pts/1 3981 S+ 1000 0:00 grep --color=auto testdaemon
lisong@lisong:~/code/experiment/proc/daemon$
关闭输入输出后,“daemon test is running.”无法打印,但可以看到守护进程已经开启了。
遗留问题:
1、找不到 程序时,access() 似乎没有返回异常状态。
2、待测umask
阅读(1439) | 评论(0) | 转发(1) |