在Python中覆盖基本信号(SIGINT,SIGQUIT,SIGKILL ??)

时间:2011-04-19 04:53:25

标签: python linux signals

我正在编写一个程序,根据我们公司的政策添加正常的UNIX帐户(即修改/ etc / passwd,/ etc / group和/ etc / shadow)。它还会做一些有点花哨的事情,例如向用户发送电子邮件。

我已经完成了所有代码,但有三段非常关键的代码,它们会更新上面的三个文件。代码已经相当健壮,因为它锁定了这些文件(例如/etc/passwd.lock),写入临时文件(例如/etc/passwd.tmp),然后用临时文件覆盖原始文件。我很高兴它不会干扰我的程序的其他运行版本或系统useradd,usermod,passwd等程序。

我最担心的是在这些部分的中间有一个迷路ctrl + c,ctrl + d或kill命令。这让我进入了信号模块,它似乎正是我想要的:在“关键”区域内忽略某些信号。 我正在使用旧版本的Python,它没有signal.SIG_IGN,所以我有一个很棒的“传递”功能:

def passer(*a):
    pass

我看到的问题是信号处理程序无法按照我的预期运行。 给出以下测试代码:

def passer(a=None, b=None):
pass

def signalhander(enable):
    signallist = (signal.SIGINT, signal.SIGQUIT, signal.SIGABRT, signal.SIGPIPE,       signal.SIGALRM, signal.SIGTERM, signal.SIGKILL)
    if enable:
        for i in signallist:
            signal.signal(i, passer)
    else:
        for i in signallist:
            signal.signal(i, abort)
    return


def abort(a=None, b=None):
    sys.exit('\nAccount was not created.\n')
    return
signalhander(True)                                                                                                                                                                                                                 
print('Enabled')
time.sleep(10)   # ^C during this sleep

此代码的问题是在time.sleep(10)调用期间^ C(SIGINT)导致该函数停止,然后,我的信号处理程序将根据需要接管。但是,这并没有解决我上面的“关键”区域问题,因为我不能容忍遇到信号失败的任何语句。

我需要某种信号处理程序,它将完全忽略SIGINT和SIGQUIT。 Fedora / RH命令“yum”是用Python编写的,基本上完全符合我的要求。如果你在安装任何东西的时候做了^ C,它会打印一条消息,比如“在两秒钟内按下^ C强行杀死”。否则,忽略^ C.因为我的程序在几分之一秒内完成,所以我并不关心第二次警告。

有人可以帮我实现CPython 2.3的信号处理程序,在信号被忽略之前不会导致当前语句/函数被取消吗?

一如既往,提前谢谢。


编辑:在S.Lott回答之后,我决定放弃信号模块。

我要回到try: except:块。查看我的代码,每个关键区域都会发生两件无法中止的事情:使用file.tmp覆盖文件并在完成后删除锁定(或者其他工具将无法修改文件,直到手动删除)。我将其中的每一个放在try:块中的自己的函数中,而except:只是再次调用该函数。这样,该函数将在KeyBoardInterruptEOFError的情况下重新调用自身,直到关键代码完成。 我不认为我会遇到太多麻烦,因为我只捕获用户提供的退出命令,即便如此,只有两到三行代码。从理论上讲,如果能够足够快地提高这些例外情况,我想我可以得到“最大复发深度超出”错误,但这似乎很遥远。

还有其他问题吗?

04-0030-03代码:

def criticalRemoveLock(file):
    try:
        if os.path.isFile(file):
            os.remove(file)
        else:
            return True
    except (KeyboardInterrupt, EOFError):
        return criticalRemoveLock(file)
def criticalOverwrite(tmp, file):
    try:
        if os.path.isFile(tmp):
            shutil.copy2(tmp, file)
            os.remove(tmp)
        else:
            return True
     except (KeyboardInterrupt, EOFError):
        return criticalOverwrite(tmp, file)

1 个答案:

答案 0 :(得分:3)

没有真正的方法可以让您的脚本真正保存。当然,您可以使用try: except:忽略信号并捕获键盘中断,但是您的应用程序可以对这些中断进行幂等,并且必须能够在某种保存点处理中断后恢复操作。

你唯一能做的就是处理临时文件(而不是原始文件)并在完成最终目的地之后移动它们。我认为这样的文件操作应该是" atomic"从文件系统的角度来看。否则,如果发生中断:从干净的数据开始重新开始处理。