在init.d脚本中使用Python的特别注意事项?

10 投票
2 回答
2757 浏览
提问于 2025-04-15 14:12

在使用Python编写一个通过 init 运行的 'init.d' 脚本时,有什么特别需要注意的地方吗?(比如说,启动Ubuntu的时候)

根据我在网上查资料和在Ubuntu上测试的结果,给 'init.d' 脚本提供的环境变量很少,所以使用 "#!/usr/bin/env python" 可能不太管用。

还有其他需要注意的吗?

2 个回答

1

我假设你是在运行某种用Python写的后台程序,如果不是,那这个可能不适用。

你可能想要做标准的Unix双重分叉和重定向文件描述符的操作。这是我使用的代码(改编自一个ActiveState的代码示例,具体网址我现在记不起来了)。

def daemonize(stdin, stdout, stderr, pidfile):
    if os.path.isfile(pidfile):
        p = open(pidfile, "r")
        oldpid = p.read().strip()
        p.close()
        if os.path.isdir("/proc/%s"%oldpid):
            log.err("Server already running with pid %s"%oldpid)
            sys.exit(1)
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError, e:
        log.err("Fork #1 failed: (%d) %s"%(e.errno, e.strerror))
        sys.exit(1)
    os.chdir("/")
    os.umask(0)
    os.setsid()
    try:
        pid = os.fork()
        if pid > 0:
            if os.getuid() == 0:
                pidfile = open(pidfile, "w+")
                pidfile.write(str(pid))
                pidfile.close()
            sys.exit(0)
    except OSError, e:
        log.err("Fork #2 failed: (%d) %s"%(e.errno, e.strerror))
        sys.exit(1)
    try:
        os.setgid(grp.getgrnam("nogroup").gr_gid)
    except KeyError, e:
        log.err("Failed to get GID: %s"%e)
        sys.exit(1)
    except OSError, e:
        log.err("Failed to set GID: (%s) %s"%(e.errno, e.strerror))
        sys.exit(1)
    try:
        os.setuid(pwd.getpwnam("oracle").pw_uid)
    except KeyError, e:
        log.err("Failed to get UID: %s"%e)
        sys.exit(1)
    except OSError, e:
        log.err("Failed to set UID: (%s) %s"%(e.errno, e.strerror))
        sys.exit(1)
    for f in sys.stdout, sys.stderr:
        f.flush()
    si = open(stdin, "r")
    so = open(stdout, "a+")
    se = open(stderr, "a+", 0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

在你启动后台程序循环之前运行这个代码,它应该能正常工作。

顺便提一下,我在Ubuntu上使用#!/usr/bin/env python作为脚本的开头,这样运行得很好。

即使你不在运行后台程序,你可能还是想把标准输出和错误输出重定向到一个文件,这样可以提供调试信息。

4

这段话主要指出了在 init.d 脚本中使用 Python 的一个大问题——增加了复杂性。

Python 没有固定的标准,而且环境变量(env)不一定指向 cpython。如果你升级了 Python 结果出问题,那你就只能忍着。而且,Python 出问题的可能性比 sh(对于 init.d 脚本来说更安全的选择)要大得多。原因很简单:

ecarroll@x60s:/etc/init.d$ ldd /usr/bin/python
    linux-gate.so.1 =>  (0xb7ff7000)
    libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7fc9000)
    libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7fc5000)
    libutil.so.1 => /lib/tls/i686/cmov/libutil.so.1 (0xb7fc0000)
    libz.so.1 => /lib/libz.so.1 (0xb7faa000)
    libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0xb7f84000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e21000)
    /lib/ld-linux.so.2 (0xb7ff8000)
ecarroll@x60s:/etc/init.d$ ldd /bin/sh
    linux-gate.so.1 =>  (0xb803f000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7ec7000)
    /lib/ld-linux.so.2 (0xb8040000)

Python 需要链接到一些库,比如 libpthread、libdl、libutil、libz 和 libm 等等,这些都有可能导致问题。简单来说,Python 需要做的事情更多。

-rwxr-xr-x 1 root root  86K 2008-11-05 01:51 /bin/dash
-rwxr-xr-x 1 root root 2.2M 2009-04-18 21:53 /usr/bin/python2.6

如果你想了解更多关于环境变量的具体内容,可以在这里查看: http://www.debian.org/doc/debian-policy/ch-opersys.html#s9.9 主要的问题是,环境变量的默认设置可以在 /etc/profile 中进行配置,而这个配置只有在脚本在支持读取它的 shell 中运行时才会生效。

撰写回答