1. 修改host name需要reboot吗?
2. host name与/etc/hosts有什么关系呢?
3. gethostname为什么不受/etc/nsswitch.conf的配置?
这三个问题在不了解host name是什么的时候, 比较纠结.
是否要reboot这个问题是最直接让我产生dig这个host name的动力, 还有就是工作中, 碰到一台机器无法使用sudo命令, 于是花时间学习学习.
平时看hostname(3)时, 发现hostname(3)与/etc/nsswitch.conf扯在一起, 这使host name与DNS中的记录纠结在一起. 更是希望了解之间的关系
在找资料的过程中, 本人发现了一个很有意思的方法:
* Linux kernel与GNU分开.
什么意思呢? 分界是为了把不同时期的产物, 概念之类的分开. 比如: 当你认host name是kernel的一个变量时, 那么它就与DNS中的记录有明显的不同.
gethostname是system call, 它不是glibc的东西, 所以它与glibc中的DNS查询机制(/etc/nsswitch.conf)是扯不上关系的. gethostbyname, gethostbyaddr都是glibc的东西
就算没有glibc的存在, kernel中的host name照样存在!
按上面的方法, 已经可以很清楚地知道host name与/etc/hosts, /etc/nsswitch.conf是没有关系的.
linux kernel提供了实时修改kernel参数的方法, 是无需要reboot内核就可以生效的. 如sysctl(2), 也有CLI的sysctl(3). 也可以修改/proc/sys/kernel下的文件.
在实际中, GNU软件又常常会使用到host name!
在工作中碰到一个这样的问题: 每当运行sudo时shell就hang住!
它被block了吗?
于是使用strace一查, sudo是在等socket的IO. 发现这台机器的DNS請求是发不出去的
为什么sudo需要使用网络呢?
这其实就是程序期望得到FQDN格式的host name的結果.
得到FQDN格式的host name就使得host name与DNS查询纠结在一起.
通过学习hostname命令的代码, 可以得到hostname -f其实是等同于下面的代码
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
int main(int argc, char *argv[]){
char hostname[64];
if ( gethostname( hostname, sizeof(hostname) ) != 0){
perror("1");
}
struct hostent * host_struct;
if ( (host_struct = gethostbyname( hostname )) == NULL ){
perror("2");
}
printf("%s\n", host_struct->h_name);
}
可以得到这样的信息: 得到FQDN格式的host name, 是需要使用到
1. host name
2. DNS
这就与linux下DNS查询顺序策略有关系(/etc/nsswitch.conf)
python里有一段很明了的代码(来自socket.py):
def getfqdn(name=''):
"""Get fully qualified domain name from name.
An empty argument is interpreted as meaning the local host.
First the hostname returned by gethostbyaddr() is checked, then
possibly existing aliases. In case no FQDN is available, hostname
from gethostname() is returned.
"""
name = name.strip()
if not name or name == '0.0.0.0':
name = gethostname()
try:
hostname, aliases, ipaddrs = gethostbyaddr(name)
except error:
pass
else:
aliases.insert(0, hostname)
for name in aliases:
if '.' in name:
break
else:
name = hostname
return name
这样还可以解开一个疑问: 为什么/etc/hosts里常常会出现hostname和它的FQDN记录
增加这样的信息在这里, 查hostname的FQDN时就无须通过网络得到, 当然, 的确有需求的话, 也是可以的, 如果牛B的话, 就每台机器有一个全球唯一的域名也没有人说
Wednesday, June 9, 2010
Sunday, May 30, 2010
帐号
1. 问题的来源
一直以来, 都有一种错误的认为: 使用useradd增加帐号和配置好ssh-key就可以使用此帐号登陆 .
实现上不如此. 这是需要usePAM的支持. PAM日后再细细学习, 现在先学习学习一般认证
于是, 把login和su命令的代码翻出来看看. 它们都使用如下的方式:
login(不扯PAM)的代码:
798 pp = getpass(_("Password: "));
799
800 # ifdef CRYPTOCARD
801 if (strncmp(pp, "CRYPTO", 6) == 0) {
802 if (pwd && cryptocard()) break;
803 }
804 # endif /* CRYPTOCARD */
805
806 p = crypt(pp, salt);
807 setpriority(PRIO_PROCESS, 0, 0);
.......
835 if (pwd && !strcmp(p, pwd->pw_passwd))
836 break;
837
838 printf(_("Login incorrect\n"));
su的代码:
265 unencrypted = getpass (_("Password:"));
266 if (!unencrypted)
267 {
268 error (0, 0, _("getpass: cannot open /dev/tty"));
269 return false;
270 }
271 encrypted = crypt (unencrypted, correct);
272 memset (unencrypted, 0, strlen (unencrypted));
273 return STREQ (encrypted, correct);
274 }
都是:
1. 使用了crypt函数
2. 最后都是字符串比较
3. 需要/etc/shadow里的加密后字符串
* 比红色部分可以看出getpass是在stdin被定重向后会报错(hard wire型的程序), 因为它使用了不回显功能(只有tty才有, pipe没有)
在python官网里看到可爱的python代码是这样的:
* 自来http://docs.python.org/library/crypt.html?highlight=crypt#crypt.crypt
2. Lock 与 Unlock 是怎么一个概念?
在man 5 shadow得到的信息:
从上面的C代码和crypt函数的特性可以猜测: Lock无疑就是让方程两边永远不相等, 代码没有其它测试的必要!
具体到ssh的实例, 当使用一指定用户登陆ssh server时, server并不去分别Lock与不Lock的帐号,
虽然没有看过sshd的代码, 但是从表现上: 不会马上打印: Lock user或者马上disconnect, 如使用全世界都公认的halt默认帐号也是提示输入密码:
$ ssh halt@localhost
halt@localhost's password:
3. 其它
su切换用户
FAIL : 以为切换什么用户都是输入root密码
大概看了一把su的代码, 才知道不是这样的~~~~
知道了下面的真相:
1. 需要输入切换到用户的密码
2. restricted shell : 凡不在/etc/shells里登陆的shell都是受限shell. 为了安全的
nologin
平时nologin默认打印信息是: This account is currently not available.
你也是可以修改的: /etc/nologin.txt, 例如下面的例子:
$ sudo su rpc
我顶~ 乱来~ 去问你妈要密码, 不然见一次骂一次
* 这个例子有点geek~
一直以来, 都有一种错误的认为: 使用useradd增加帐号和配置好ssh-key就可以使用此帐号登陆 .
实现上不如此. 这是需要usePAM的支持. PAM日后再细细学习, 现在先学习学习一般认证
于是, 把login和su命令的代码翻出来看看. 它们都使用如下的方式:
login(不扯PAM)的代码:
798 pp = getpass(_("Password: "));
799
800 # ifdef CRYPTOCARD
801 if (strncmp(pp, "CRYPTO", 6) == 0) {
802 if (pwd && cryptocard()) break;
803 }
804 # endif /* CRYPTOCARD */
805
806 p = crypt(pp, salt);
807 setpriority(PRIO_PROCESS, 0, 0);
.......
835 if (pwd && !strcmp(p, pwd->pw_passwd))
836 break;
837
838 printf(_("Login incorrect\n"));
su的代码:
265 unencrypted = getpass (_("Password:"));
266 if (!unencrypted)
267 {
268 error (0, 0, _("getpass: cannot open /dev/tty"));
269 return false;
270 }
271 encrypted = crypt (unencrypted, correct);
272 memset (unencrypted, 0, strlen (unencrypted));
273 return STREQ (encrypted, correct);
274 }
都是:
1. 使用了crypt函数
2. 最后都是字符串比较
3. 需要/etc/shadow里的加密后字符串
* 比红色部分可以看出getpass是在stdin被定重向后会报错(hard wire型的程序), 因为它使用了不回显功能(只有tty才有, pipe没有)
在python官网里看到可爱的python代码是这样的:
crypt.crypt(cleartext, cryptedpasswd) == cryptedpasswd
* 可以知道crypt函数的第二个参数可以是salt, 也可以不是salt, 而是加密后的字符串* 自来http://docs.python.org/library/crypt.html?highlight=crypt#crypt.crypt
2. Lock 与 Unlock 是怎么一个概念?
在man 5 shadow得到的信息:
If the password field contains some string that is not valid result of crypt(3), for instance ! or *, the user will not be able to use a unix password to log in, subject to pam(7).
从上面的C代码和crypt函数的特性可以猜测: Lock无疑就是让方程两边永远不相等, 代码没有其它测试的必要!
具体到ssh的实例, 当使用一指定用户登陆ssh server时, server并不去分别Lock与不Lock的帐号,
虽然没有看过sshd的代码, 但是从表现上: 不会马上打印: Lock user或者马上disconnect, 如使用全世界都公认的halt默认帐号也是提示输入密码:
$ ssh halt@localhost
halt@localhost's password:
3. 其它
su切换用户
FAIL : 以为切换什么用户都是输入root密码
大概看了一把su的代码, 才知道不是这样的~~~~
知道了下面的真相:
1. 需要输入切换到用户的密码
2. restricted shell : 凡不在/etc/shells里登陆的shell都是受限shell. 为了安全的
nologin
平时nologin默认打印信息是: This account is currently not available.
你也是可以修改的: /etc/nologin.txt, 例如下面的例子:
$ sudo su rpc
我顶~ 乱来~ 去问你妈要密码, 不然见一次骂一次
* 这个例子有点geek~
Friday, May 28, 2010
虚假终端: pseudo-terminal
之前只听前pseudo terminal, 但是没有理会. 前段时间在写脚本时受点一点限制
这里为什么需要self.stdin.close()呢? 这就是subprocess无法与子进程多次通信的地方.
在朋友(mrluanma (AT) gmail.com)的帮忙下, 找到pexpect程序(http://www.noah.org/wiki/Pexpect). 提供了一个很好的学习模板.

本人写了两个简单的例子:
1. 为什么使用subprocess无法与子进程多次通信?
2. 像su这种为什么使用subprocess无法调用? ( 这种软件有一个词来描述: hard wire , 表示需要terminal, 代码中使用了istty函数检测到 )
3. vim这种软件的交互是怎么实现的?
subprocess的communicate函数是代码是这样的:
if self.stdin:
if input:
self.stdin.write(input)
self.stdin.close()
这里为什么需要self.stdin.close()呢? 这就是subprocess无法与子进程多次通信的地方.
在不明白为什么需要close的情况下, 自己写的一段fork功能的代码, 結果: 当父进程在读子进程的stdout时被block了. 其实, 这时父进程和子进程都是block的, 这被称为"死锁". 这就是为什么subprocess里需要close
那么, 我的需求:
1. 在调用外部进程的情况下, 如何多次父-子进程通信?
2. 如何调用hard wire的程序?
种种问题的浮现让sysadmin岗位的本人不爽. 至少不方便工作....
例子:
1. passwd的调用
passwd是一典型的hard wire程序, 下面的方式调用是不行的:
$ echo "new password" | passwd
比较有意思的是passwd在不同的系统或者是distro下都是不同的.
* freeBSD下有参数控制(具体的忘了, 也没有环境回顾), 成为batch mode
* redhat系使用"--stdin"控制
* ubuntu下没有batch mode参数
2. su -c "my command"的调用
使用在系统上使用su ( 我不得不说, 没有sudo使用~~~), 这将是一个很大的麻烦~~后知后觉, 发现了pseudo terminal这一概念. 它的应用很广泛, 比如提供network login的sshd就使用到此概念
在朋友(mrluanma (AT) gmail.com)的帮忙下, 找到pexpect程序(http://www.noah.org/wiki/Pexpect). 提供了一个很好的学习模板.
刚接触pseudo terminal很头大的, 还好APUE一书中有这部分和关于terminal I/O的资料, 下面是一个很清晰的图:
本人写了两个简单的例子:
1. 使用pty.fork()函数产生子进程, 子进程与父进程的controlling terminal是不同的.
帐号与密码都是svn
2. 使用pty实现调用passwd这种hard wire外部程序
帐号与密码都是svn
Monday, May 24, 2010
记一次开源软件原理追查
有这种dig行为, 主要是本人想写完一篇笔记, 是关于xxx.pid文件与锁的文章。
在实际和自己了解的情况中, 掌握的东西不够多, 所以就dig下去了。
在shell中, 如果要得到文件锁,在debian系的distro下可以使用这个包: lockfile-progs
ubuntu下已经预装
http://packages.qa.debian.org/l/lockfile-progs.html
因为一直对lock file 和 file lock这两个名词纠结不清, 所以就下载源代码(还好, 很简短)来看
发现使用了liblockfile库, 视线被转到这一个library上, 首先想到的是找这个库的文档
dpkg -l|grep lockfile
得到:
liblockfile1
dpkg -L liblockfile1
只有一份man手册,是关于随liblockfile1包发布的dotlockfile程序的说明。
嗯, 至少比没有好吧.....man之
不过很有意思的是从这份手册里看到一点线索:
The above mentioned lockfile_create(3) manpage is present in the liblockfile-dev package.
呵呵, lockfile_create 这个API的手册在dev包里, 马上apt-get安装
lockfile_create API手册里有一节叫ALGORITHM的。 其实这一节已经说明了原理和流程了(从man手册里的文字转成流程还是需要很细心地阅读)
我对其它的 "A check is made to see if the existing lockfile is a valid one" 不是很明白, 所以找了lockfile_check函数的代码看, 这里就不贴代码了(还是wordpress写blog好呀~~)
代码可以出下面的地址得到:
* http://liblockfile.sourcearchive.com/documentation/1.06.1/lockfile_8c-source.html
lockfile_check函数的判断有两个:
1. lock file中保存PID号代表的进程是否还存在, 通过kill函数得到。 (用法与xxx.pid文件类似, 关于xxx.pid用法, 本人别起笔记)
2. 如果lock file 中保存的pid号为0, 则与5分钟为lock file生命期。
在实际和自己了解的情况中, 掌握的东西不够多, 所以就dig下去了。
在shell中, 如果要得到文件锁,在debian系的distro下可以使用这个包: lockfile-progs
ubuntu下已经预装
http://packages.qa.debian.org/l/lockfile-progs.html
因为一直对lock file 和 file lock这两个名词纠结不清, 所以就下载源代码(还好, 很简短)来看
发现使用了liblockfile库, 视线被转到这一个library上, 首先想到的是找这个库的文档
dpkg -l|grep lockfile
得到:
liblockfile1
dpkg -L liblockfile1
只有一份man手册,是关于随liblockfile1包发布的dotlockfile程序的说明。
嗯, 至少比没有好吧.....man之
不过很有意思的是从这份手册里看到一点线索:
The above mentioned lockfile_create(3) manpage is present in the liblockfile-dev package.
呵呵, lockfile_create 这个API的手册在dev包里, 马上apt-get安装
lockfile_create API手册里有一节叫ALGORITHM的。 其实这一节已经说明了原理和流程了(从man手册里的文字转成流程还是需要很细心地阅读)
我对其它的 "A check is made to see if the existing lockfile is a valid one" 不是很明白, 所以找了lockfile_check函数的代码看, 这里就不贴代码了(还是wordpress写blog好呀~~)
代码可以出下面的地址得到:
* http://liblockfile.sourcearchive.com/documentation/1.06.1/lockfile_8c-source.html
lockfile_check函数的判断有两个:
1. lock file中保存PID号代表的进程是否还存在, 通过kill函数得到。 (用法与xxx.pid文件类似, 关于xxx.pid用法, 本人别起笔记)
2. 如果lock file 中保存的pid号为0, 则与5分钟为lock file生命期。
xxx.pid文件与lock file
linux下, xxx.pid这类文件还是很常见的, 特别是在/var/run目录下, APUE一书都是推介在这里创建pid文件。
pid文件到底有什么作用呢? 用法是如何的呢?种种疑问让我产生了dig的冲动。
先看看实现生活中碰到的:
这类脚本的这些参数功能的实现是使用到了linux的signal机制, 无疑需要daemon进程的pidpid文件到底有什么作用呢? 用法是如何的呢?种种疑问让我产生了dig的冲动。
先看看实现生活中碰到的:
1. init.d脚本使用到pid文件
/etc/init.d目录下存放了众多daemon程序的控制脚本,这类脚本一般有几个参数:- start
- retstart
- stop
- 强大的专业服务端还有gracestop之类的参数
2. lock
lock主要是协调, 操作atomic时使用的一种方式。举个实际中的例子:
系统需要一个定时任务, 要求每分钟对系统N多状态收集(如硬盘,CPU, 网络等等), 收集过程中不断有日志产生。
这个例子会有两个问题:
- 运行间隔为每分钟, 可能会定时任务某次运行时长长于1分钟。
- 如果出现1的情况会对日志产生影响
linux系统本身有锁的机制, 如flock和fcntl函数。 这种锁称为file lock, 文件锁
linux下的文件锁可以对一个文件的一个区域进行锁定。
现在, 本笔记不想扯上这种强大功能, 只是谈论上面举的例子: 怎么让进程得到一个結果:能否处理
完成这需求, 只需要一个标志, 这个标志需要进程在得到时是atomic性的。
可以通过两种方法得这种标志:
使用linux的flock函数得到file lock, 这里有一个python的例子:
http://svn.lvscar.info/jessinio_repos/flock_example.py
* 帐号与密码都是svn
file lock是利用系统本身的fcntl或者flock函数对某一的文件进行锁定, 将能否成功锁定文件作为atomic的标志
无论是lock file 还是 file lock都是需要文件这一角色的. 但是这一文件起的作用不同.
1. NFS上可以使用(flock函数在旧版本的NFS上不起作用)
2. shell脚本可用. 因为是shell脚本是CLI, 时刻都是新的进程在处理, 不方便使用flock(这样需要一个daemon在保持file lock的存在
* 关于 lock file可以移步: http://en.wikipedia.org/wiki/File_locking#Lock_files
当一个进程成功创建了lock file后, 在不明异常的情况终止了, 后面的进程怎么判断刚才被创建的lock file是被进程使用的? ( 使用file lock就没有这种问题, 得到锁的进程终止后锁会被释放, 新的进程可以得到)- 指定文件已经存在, 表示有进程在处理. 这种方式称为lock file
- 使用系统本身的file lock机制, 如果open的file descriptor有锁, 表示有进程在处理
使用linux的flock函数得到file lock, 这里有一个python的例子:
http://svn.lvscar.info/jessinio_repos/flock_example.py
* 帐号与密码都是svn
lock file 和 file lock 的区别
lock file是利用系统本身的open, link, stat这样的函数, 实现文件创建的atomic性. 成功被创建的文件作为atomic的标志file lock是利用系统本身的fcntl或者flock函数对某一的文件进行锁定, 将能否成功锁定文件作为atomic的标志
无论是lock file 还是 file lock都是需要文件这一角色的. 但是这一文件起的作用不同.
本文主要是想扯lock file与xxx.pid文件的关系. 不想扯file lock和lock file
仅仅需要可以标志行为的atomic性的话, lock file是最好的方法:1. NFS上可以使用(flock函数在旧版本的NFS上不起作用)
2. shell脚本可用. 因为是shell脚本是CLI, 时刻都是新的进程在处理, 不方便使用flock(这样需要一个daemon在保持file lock的存在
* 关于 lock file可以移步: http://en.wikipedia.org/wiki/File_locking#Lock_files
使用lock file需要解决的问题
当使用lock file作为atomic的标志时, 有一种情况是需要解决的: 持锁者是否还存在, 例如:具体处理方式可以参考liblockfile的原代码:
* http://liblockfile.sourcearchive.com/documentation/1.06.1/lockfile_8c-source.html
在它的lockfile_check函数里, 使用到了kill函数. 这个kill函数需要的pid就是xxx.pid文件的pid
因此:
xxx.pid有两种作用:1. 方便daemon被控制(通过signal)
2. 可以用于实现lock file
利用了1不一定利用2, 但是作用了2一定需要利用1
另外
除了利用kill给指定的pid发signal的方式去判断某进程是否存在的方式后, 还可以使用如下URL提到的方法:http://stackoverflow.com/questions/2735926/how-to-capture-pid-of-a-linux-daemon-run-from-init-d
利用/proc/NamePID/exe得到的字符串是否为先前在进行的进程名. 这种方法需要知道进程的名称.
疑问
是否会出现pid号的进程存在, 但不是自己期望的进程呢?查阅了APUE也没有明确, 只知道是有一定的算法去reuse 进程号的.
在这方面, 还是flock方便, 不过此函数不是所有地方都可以使用的, 纠结`~~
Thursday, May 20, 2010
exec*族函数的好玩参数
一直以来, 感觉exec*族函数都是比较乱的。 查查手册就可以知道分来如下几类:
l: stands for list
v: stands for vector , 类似于main中的argv, 表示数组。
p: path
e: environment
本blog不是想写上面的内容的。
本人是对execl*都第二个参数, execv*第二个参数的第一个成员感兴趣。
很早之前就对这个参数不懂。 例如:
os.execlp("sleep", 'sleep', '10')
当同于:
os.execvp("sleep", ['sleep', '10])
看上去感觉不是很好, 第二个参数用来干嘛的? 为什么要重复写出来?
主要是在不知道那个参数是干什么的情况下, 写得和第一个参数相同, 所以就有这种重复的感觉.
起什么作用的呢? 看下面吧:
jessinio@jessinio-laptop:/proc/7345$ sleep 10 &
[1] 7594
jessinio@jessinio-laptop:/proc/7345$ ps x|grep sleep
7594 pts/10 S 0:00 sleep 10
jessinio@jessinio-laptop:/proc/7345$ /bin/sleep 10 &
[2] 7597
jessinio@jessinio-laptop:/proc/7345$ ps x|grep sleep
7597 pts/10 S 0:00 /bin/sleep 10
* 相同颜色部分的关系: 相同的
* 此字符串来自/proc/*/cmdline 文件内的信息
exec*族的第二个参数(对于v类是第二个参数的第一个成员)是起到显示的作用, 如:
import os
import sys
if __name__ == "__main__":
pid = os.fork()
if pid == 0:
child = ['i love linux', '10']
os.execv('/bin/sleep', child)
else:
print "%s" % pid
os._exit(0)
运行得到:
jessinio@jessinio-laptop:/tmp$ python exec_bin.py
7892
jessinio@jessinio-laptop:/tmp$ ps aux|grep 7892
jessinio 7892 0.0 0.0 2956 628 pts/9 S 21:55 0:00 i love linux 10
有点与众不同的玩法~~
l: stands for list
v: stands for vector , 类似于main中的argv, 表示数组。
p: path
e: environment
本blog不是想写上面的内容的。
本人是对execl*都第二个参数, execv*第二个参数的第一个成员感兴趣。
很早之前就对这个参数不懂。 例如:
os.execlp("sleep", 'sleep', '10')
当同于:
os.execvp("sleep", ['sleep', '10])
看上去感觉不是很好, 第二个参数用来干嘛的? 为什么要重复写出来?
主要是在不知道那个参数是干什么的情况下, 写得和第一个参数相同, 所以就有这种重复的感觉.
起什么作用的呢? 看下面吧:
jessinio@jessinio-laptop:/proc/7345$ sleep 10 &
[1] 7594
jessinio@jessinio-laptop:/proc/7345$ ps x|grep sleep
7594 pts/10 S 0:00 sleep 10
jessinio@jessinio-laptop:/proc/7345$ /bin/sleep 10 &
[2] 7597
jessinio@jessinio-laptop:/proc/7345$ ps x|grep sleep
7597 pts/10 S 0:00 /bin/sleep 10
* 相同颜色部分的关系: 相同的
* 此字符串来自/proc/*/cmdline 文件内的信息
exec*族的第二个参数(对于v类是第二个参数的第一个成员)是起到显示的作用, 如:
import os
import sys
if __name__ == "__main__":
pid = os.fork()
if pid == 0:
child = ['i love linux', '10']
os.execv('/bin/sleep', child)
else:
print "%s" % pid
os._exit(0)
运行得到:
jessinio@jessinio-laptop:/tmp$ python exec_bin.py
7892
jessinio@jessinio-laptop:/tmp$ ps aux|grep 7892
jessinio 7892 0.0 0.0 2956 628 pts/9 S 21:55 0:00 i love linux 10
有点与众不同的玩法~~
Monday, May 17, 2010
进程成为daemonize需要fork两次吗?
成为一个daemonize, 其实网上有很多例子, 也是可以使用的, 正如:
http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/
里给出的例子。
但是, 我无法明白为什么要fork两次!, 下面是我的测试:
jessinio@jessinio-laptop:/tmp$ ps axj|head -n 1
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
jessinio@jessinio-laptop:/tmp$ ps axj|grep apache
1 1820 1820 1820 ? -1 Ss 0 0:10
/usr/sbin/apache2 -k start
1820 16100 1820 1820 ? -1 S 1000 0:00
/usr/sbin/apache2 -k start
1820 16101 1820 1820 ? -1 Sl 1000 0:00
/usr/sbin/apache2 -k start
1820 16129 1820 1820 ? -1 Sl 1000 0:00
/usr/sbin/apache2 -k start
可以中从得到这样的信息:
daemonize进程的PPID==1, PID==PGID==SID, 没有tty(为?)
如果这就是daemonize进程的要求的话, 请看我自己写的python代码:
if __name__ == "__main__":
pid = os.fork()
# child process
if pid == 0:
os.setsid()
time.sleep(10)
else:
print 'parent %s, child %s' % (os.getpid(), pid)
os._exit(0)
其中只是调用了一次fork函数。下面是它的运行結果:
jessinio@jessinio-laptop:/tmp$ ps axj|head -n 1
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
jessinio@jessinio-laptop:/tmp$ python process.py
parent 26117, child 26118
jessinio@jessinio-laptop:/tmp$ ps axj|grep process
1 26118 26118 26118 ? -1 Ss 1000 0:00 python process.py
可以看到, PPID==1, PID==PGID==SID, 没有tty
这是否可以认为: 只fork一次, 然后调用setsid就可以成为daemonize进程了呢?
在众多不解的情况下, 决定好好看看圣经: APUE 一书.
也很高兴, 从中找到了一点信息:
under system v-based systems, some people recommend calling fork again at this point and having the parent terminate, the second child continues as the daemon, This guarantees that the daemon is not a session leader , which prevents it from acquiring a controlling terminal under the system v rules. alternatively, to avoid acquiring a controlling terminal, be sure to specify O_NOCTTY whenever opening a terminal device.
fork第二次是防止被在打开一个terminal device时被系统分配到controlling terminal
只要不乱open(或者使用O_NOCTTY是不需要fork第二次的.
话又说回来, linux是怎么分配controlling terminal的呢?
APUE在这里没有提到linux, 只是提到了BSD和system-V的不同. 搜了一下, linux和BSD是一样的, 使用ioctl得到controlling terminal, URL: http://linux.die.net/man/4/tty_ioctl
如下引用:
TIOCSCTTY int arg Make the given tty the controlling tty of the current process.
http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/
里给出的例子。
但是, 我无法明白为什么要fork两次!, 下面是我的测试:
jessinio@jessinio-laptop:/tmp$ ps axj|head -n 1
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
jessinio@jessinio-laptop:/tmp$ ps axj|grep apache
1 1820 1820 1820 ? -1 Ss 0 0:10
/usr/sbin/apache2 -k start
1820 16100 1820 1820 ? -1 S 1000 0:00
/usr/sbin/apache2 -k start
1820 16101 1820 1820 ? -1 Sl 1000 0:00
/usr/sbin/apache2 -k start
1820 16129 1820 1820 ? -1 Sl 1000 0:00
/usr/sbin/apache2 -k start
可以中从得到这样的信息:
daemonize进程的PPID==1, PID==PGID==SID, 没有tty(为?)
如果这就是daemonize进程的要求的话, 请看我自己写的python代码:
if __name__ == "__main__":
pid = os.fork()
# child process
if pid == 0:
os.setsid()
time.sleep(10)
else:
print 'parent %s, child %s' % (os.getpid(), pid)
os._exit(0)
其中只是调用了一次fork函数。下面是它的运行結果:
jessinio@jessinio-laptop:/tmp$ ps axj|head -n 1
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
jessinio@jessinio-laptop:/tmp$ python process.py
parent 26117, child 26118
jessinio@jessinio-laptop:/tmp$ ps axj|grep process
1 26118 26118 26118 ? -1 Ss 1000 0:00 python process.py
可以看到, PPID==1, PID==PGID==SID, 没有tty
这是否可以认为: 只fork一次, 然后调用setsid就可以成为daemonize进程了呢?
在众多不解的情况下, 决定好好看看圣经: APUE 一书.
也很高兴, 从中找到了一点信息:
under system v-based systems, some people recommend calling fork again at this point and having the parent terminate, the second child continues as the daemon, This guarantees that the daemon is not a session leader , which prevents it from acquiring a controlling terminal under the system v rules. alternatively, to avoid acquiring a controlling terminal, be sure to specify O_NOCTTY whenever opening a terminal device.
fork第二次是防止被在打开一个terminal device时被系统分配到controlling terminal
只要不乱open(或者使用O_NOCTTY是不需要fork第二次的.
话又说回来, linux是怎么分配controlling terminal的呢?
APUE在这里没有提到linux, 只是提到了BSD和system-V的不同. 搜了一下, linux和BSD是一样的, 使用ioctl得到controlling terminal, URL: http://linux.die.net/man/4/tty_ioctl
如下引用:
TIOCSCTTY int arg Make the given tty the controlling tty of the current process.
Subscribe to:
Posts (Atom)