Show More
@@ -30,6 +30,27 b' def runservice(opts, parentfn=None, init' | |||||
30 | runargs=None, appendpid=False): |
|
30 | runargs=None, appendpid=False): | |
31 | '''Run a command as a service.''' |
|
31 | '''Run a command as a service.''' | |
32 |
|
32 | |||
|
33 | # When daemonized on Windows, redirect stdout/stderr to the lockfile (which | |||
|
34 | # gets cleaned up after the child is up and running), so that the parent can | |||
|
35 | # read and print the error if this child dies early. See 594dd384803c. On | |||
|
36 | # other platforms, the child can write to the parent's stdio directly, until | |||
|
37 | # it is redirected prior to runfn(). | |||
|
38 | if pycompat.iswindows and opts['daemon_postexec']: | |||
|
39 | for inst in opts['daemon_postexec']: | |||
|
40 | if inst.startswith('unlink:'): | |||
|
41 | lockpath = inst[7:] | |||
|
42 | if os.path.exists(lockpath): | |||
|
43 | procutil.stdout.flush() | |||
|
44 | procutil.stderr.flush() | |||
|
45 | ||||
|
46 | fd = os.open(lockpath, | |||
|
47 | os.O_WRONLY | os.O_APPEND | os.O_BINARY) | |||
|
48 | try: | |||
|
49 | os.dup2(fd, 1) | |||
|
50 | os.dup2(fd, 2) | |||
|
51 | finally: | |||
|
52 | os.close(fd) | |||
|
53 | ||||
33 | def writepid(pid): |
|
54 | def writepid(pid): | |
34 | if opts['pid_file']: |
|
55 | if opts['pid_file']: | |
35 | if appendpid: |
|
56 | if appendpid: | |
@@ -61,6 +82,12 b' def runservice(opts, parentfn=None, init' | |||||
61 | return not os.path.exists(lockpath) |
|
82 | return not os.path.exists(lockpath) | |
62 | pid = procutil.rundetached(runargs, condfn) |
|
83 | pid = procutil.rundetached(runargs, condfn) | |
63 | if pid < 0: |
|
84 | if pid < 0: | |
|
85 | # If the daemonized process managed to write out an error msg, | |||
|
86 | # report it. | |||
|
87 | if pycompat.iswindows and os.path.exists(lockpath): | |||
|
88 | with open(lockpath) as log: | |||
|
89 | for line in log: | |||
|
90 | procutil.stderr.write(line) | |||
64 | raise error.Abort(_('child process failed to start')) |
|
91 | raise error.Abort(_('child process failed to start')) | |
65 | writepid(pid) |
|
92 | writepid(pid) | |
66 | finally: |
|
93 | finally: | |
@@ -81,10 +108,11 b' def runservice(opts, parentfn=None, init' | |||||
81 | os.setsid() |
|
108 | os.setsid() | |
82 | except AttributeError: |
|
109 | except AttributeError: | |
83 | pass |
|
110 | pass | |
|
111 | ||||
|
112 | lockpath = None | |||
84 | for inst in opts['daemon_postexec']: |
|
113 | for inst in opts['daemon_postexec']: | |
85 | if inst.startswith('unlink:'): |
|
114 | if inst.startswith('unlink:'): | |
86 | lockpath = inst[7:] |
|
115 | lockpath = inst[7:] | |
87 | os.unlink(lockpath) |
|
|||
88 | elif inst.startswith('chdir:'): |
|
116 | elif inst.startswith('chdir:'): | |
89 | os.chdir(inst[6:]) |
|
117 | os.chdir(inst[6:]) | |
90 | elif inst != 'none': |
|
118 | elif inst != 'none': | |
@@ -107,6 +135,11 b' def runservice(opts, parentfn=None, init' | |||||
107 | if logfile and logfilefd not in (0, 1, 2): |
|
135 | if logfile and logfilefd not in (0, 1, 2): | |
108 | os.close(logfilefd) |
|
136 | os.close(logfilefd) | |
109 |
|
137 | |||
|
138 | # Only unlink after redirecting stdout/stderr, so Windows doesn't | |||
|
139 | # complain about a sharing violation. | |||
|
140 | if lockpath: | |||
|
141 | os.unlink(lockpath) | |||
|
142 | ||||
110 | if runfn: |
|
143 | if runfn: | |
111 | return runfn() |
|
144 | return runfn() | |
112 |
|
145 |
General Comments 0
You need to be logged in to leave comments.
Login now