1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
"""File utilities"""
import os
__all__ = ['write_atomic', 'signal_pidfile']
def write_atomic(fn, data, bakext=None, mode='b'):
"""Write file with rename."""
if mode not in ['', 'b', 't']:
raise ValueError("unsupported fopen mode")
# write new data to tmp file
fn2 = fn + '.new'
f = open(fn2, 'w' + mode)
f.write(data)
f.close()
# link old data to bak file
if bakext:
if bakext.find('/') >= 0:
raise ValueError("invalid bakext")
fnb = fn + bakext
try:
os.unlink(fnb)
except OSError, e:
if e.errno != errno.ENOENT:
raise
try:
os.link(fn, fnb)
except OSError, e:
if e.errno != errno.ENOENT:
raise
# atomically replace file
os.rename(fn2, fn)
def signal_pidfile(pidfile, sig):
"""Send a signal to process whose ID is located in pidfile.
Read only first line of pidfile to support multiline
pidfiles like postmaster.pid.
Returns True is successful, False if pidfile does not exist
or process itself is dead. Any other errors will passed
as exceptions."""
ln = ''
try:
f = open(pidfile, 'r')
ln = f.readline().strip()
f.close()
pid = int(ln)
if sig == 0 and sys.platform == 'win32':
return win32_detect_pid(pid)
os.kill(pid, sig)
return True
except IOError, ex:
if ex.errno != errno.ENOENT:
raise
except OSError, ex:
if ex.errno != errno.ESRCH:
raise
except ValueError, ex:
# this leaves slight race when someone is just creating the file,
# but more common case is old empty file.
if not ln:
return False
raise ValueError('Corrupt pidfile: %s' % pidfile)
return False
def win32_detect_pid(pid):
"""Process detection for win32."""
# avoid pywin32 dependecy, use ctypes instead
import ctypes
# win32 constants
PROCESS_QUERY_INFORMATION = 1024
STILL_ACTIVE = 259
ERROR_INVALID_PARAMETER = 87
ERROR_ACCESS_DENIED = 5
# Load kernel32.dll
k = ctypes.windll.kernel32
OpenProcess = k.OpenProcess
OpenProcess.restype = ctypes.c_void_p
# query pid exit code
h = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)
if h == None:
err = k.GetLastError()
if err == ERROR_INVALID_PARAMETER:
return False
if err == ERROR_ACCESS_DENIED:
return True
raise OSError(errno.EFAULT, "Unknown win32error: " + str(err))
code = ctypes.c_int()
k.GetExitCodeProcess(h, ctypes.byref(code))
k.CloseHandle(h)
return code.value == STILL_ACTIVE
|