]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
55368fb8 | 2 | * Copyright (c) 2008, 2009, 2010 Nicira Networks. |
064af421 | 3 | * |
a14bc59f BP |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
064af421 | 7 | * |
a14bc59f BP |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
18 | #include "daemon.h" | |
19 | #include <errno.h> | |
20 | #include <fcntl.h> | |
21 | #include <stdlib.h> | |
22 | #include <string.h> | |
95440284 | 23 | #include <sys/wait.h> |
064af421 BP |
24 | #include <unistd.h> |
25 | #include "fatal-signal.h" | |
26 | #include "dirs.h" | |
ac718c9d | 27 | #include "lockfile.h" |
b8781ff0 | 28 | #include "socket-util.h" |
03fbffbd | 29 | #include "timeval.h" |
064af421 BP |
30 | #include "util.h" |
31 | ||
32 | #define THIS_MODULE VLM_daemon | |
33 | #include "vlog.h" | |
34 | ||
35 | /* Should we run in the background? */ | |
36 | static bool detach; | |
37 | ||
38 | /* Name of pidfile (null if none). */ | |
39 | static char *pidfile; | |
40 | ||
41 | /* Create pidfile even if one already exists and is locked? */ | |
e7bd7d78 | 42 | static bool overwrite_pidfile; |
064af421 | 43 | |
95440284 | 44 | /* Should we chdir to "/"? */ |
91a1e24d JP |
45 | static bool chdir_ = true; |
46 | ||
95440284 BP |
47 | /* File descriptors used by daemonize_start() and daemonize_complete(). */ |
48 | static int daemonize_fds[2]; | |
49 | ||
064af421 BP |
50 | /* Returns the file name that would be used for a pidfile if 'name' were |
51 | * provided to set_pidfile(). The caller must free the returned string. */ | |
52 | char * | |
53 | make_pidfile_name(const char *name) | |
54 | { | |
55 | return (!name ? xasprintf("%s/%s.pid", ovs_rundir, program_name) | |
56 | : *name == '/' ? xstrdup(name) | |
57 | : xasprintf("%s/%s", ovs_rundir, name)); | |
58 | } | |
59 | ||
60 | /* Sets up a following call to daemonize() to create a pidfile named 'name'. | |
61 | * If 'name' begins with '/', then it is treated as an absolute path. | |
62 | * Otherwise, it is taken relative to RUNDIR, which is $(prefix)/var/run by | |
63 | * default. | |
64 | * | |
65 | * If 'name' is null, then program_name followed by ".pid" is used. */ | |
66 | void | |
67 | set_pidfile(const char *name) | |
68 | { | |
69 | free(pidfile); | |
70 | pidfile = make_pidfile_name(name); | |
71 | } | |
72 | ||
73 | /* Returns an absolute path to the configured pidfile, or a null pointer if no | |
74 | * pidfile is configured. The caller must not modify or free the returned | |
75 | * string. */ | |
76 | const char * | |
77 | get_pidfile(void) | |
78 | { | |
79 | return pidfile; | |
80 | } | |
81 | ||
91a1e24d JP |
82 | /* Sets that we do not chdir to "/". */ |
83 | void | |
84 | set_no_chdir(void) | |
85 | { | |
86 | chdir_ = false; | |
87 | } | |
88 | ||
eb077b26 BP |
89 | /* Will we chdir to "/" as part of daemonizing? */ |
90 | bool | |
91 | is_chdir_enabled(void) | |
92 | { | |
93 | return chdir_; | |
94 | } | |
95 | ||
064af421 BP |
96 | /* Normally, die_if_already_running() will terminate the program with a message |
97 | * if a locked pidfile already exists. If this function is called, | |
98 | * die_if_already_running() will merely log a warning. */ | |
99 | void | |
100 | ignore_existing_pidfile(void) | |
101 | { | |
e7bd7d78 | 102 | overwrite_pidfile = true; |
064af421 BP |
103 | } |
104 | ||
105 | /* Sets up a following call to daemonize() to detach from the foreground | |
106 | * session, running this process in the background. */ | |
107 | void | |
108 | set_detach(void) | |
109 | { | |
110 | detach = true; | |
111 | } | |
112 | ||
eb077b26 BP |
113 | /* Will daemonize() really detach? */ |
114 | bool | |
115 | get_detach(void) | |
116 | { | |
117 | return detach; | |
118 | } | |
119 | ||
064af421 BP |
120 | /* If a pidfile has been configured and that pidfile already exists and is |
121 | * locked by a running process, returns the pid of the running process. | |
122 | * Otherwise, returns 0. */ | |
123 | static pid_t | |
124 | already_running(void) | |
125 | { | |
126 | pid_t pid = 0; | |
127 | if (pidfile) { | |
128 | int fd = open(pidfile, O_RDWR); | |
129 | if (fd >= 0) { | |
130 | struct flock lck; | |
131 | lck.l_type = F_WRLCK; | |
132 | lck.l_whence = SEEK_SET; | |
133 | lck.l_start = 0; | |
134 | lck.l_len = 0; | |
135 | if (fcntl(fd, F_GETLK, &lck) != -1 && lck.l_type != F_UNLCK) { | |
136 | pid = lck.l_pid; | |
137 | } | |
138 | close(fd); | |
139 | } | |
140 | } | |
141 | return pid; | |
142 | } | |
143 | ||
144 | /* If a locked pidfile exists, issue a warning message and, unless | |
145 | * ignore_existing_pidfile() has been called, terminate the program. */ | |
146 | void | |
147 | die_if_already_running(void) | |
148 | { | |
149 | pid_t pid = already_running(); | |
150 | if (pid) { | |
e7bd7d78 | 151 | if (!overwrite_pidfile) { |
064af421 BP |
152 | ovs_fatal(0, "%s: already running as pid %ld", |
153 | get_pidfile(), (long int) pid); | |
154 | } else { | |
155 | VLOG_WARN("%s: %s already running as pid %ld", | |
156 | get_pidfile(), program_name, (long int) pid); | |
157 | } | |
158 | } | |
159 | } | |
160 | ||
161 | /* If a pidfile has been configured, creates it and stores the running process' | |
162 | * pid init. Ensures that the pidfile will be deleted when the process | |
163 | * exits. */ | |
164 | static void | |
165 | make_pidfile(void) | |
166 | { | |
167 | if (pidfile) { | |
168 | /* Create pidfile via temporary file, so that observers never see an | |
169 | * empty pidfile or an unlocked pidfile. */ | |
170 | long int pid = getpid(); | |
171 | char *tmpfile; | |
172 | int fd; | |
173 | ||
174 | tmpfile = xasprintf("%s.tmp%ld", pidfile, pid); | |
175 | fatal_signal_add_file_to_unlink(tmpfile); | |
176 | fd = open(tmpfile, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
177 | if (fd >= 0) { | |
178 | struct flock lck; | |
179 | lck.l_type = F_WRLCK; | |
180 | lck.l_whence = SEEK_SET; | |
181 | lck.l_start = 0; | |
182 | lck.l_len = 0; | |
183 | if (fcntl(fd, F_SETLK, &lck) != -1) { | |
184 | char *text = xasprintf("%ld\n", pid); | |
185 | if (write(fd, text, strlen(text)) == strlen(text)) { | |
186 | fatal_signal_add_file_to_unlink(pidfile); | |
187 | if (rename(tmpfile, pidfile) < 0) { | |
188 | VLOG_ERR("failed to rename \"%s\" to \"%s\": %s", | |
189 | tmpfile, pidfile, strerror(errno)); | |
190 | fatal_signal_remove_file_to_unlink(pidfile); | |
191 | close(fd); | |
192 | } else { | |
193 | /* Keep 'fd' open to retain the lock. */ | |
194 | } | |
195 | free(text); | |
196 | } else { | |
197 | VLOG_ERR("%s: write failed: %s", tmpfile, strerror(errno)); | |
198 | close(fd); | |
199 | } | |
200 | } else { | |
201 | VLOG_ERR("%s: fcntl failed: %s", tmpfile, strerror(errno)); | |
202 | close(fd); | |
203 | } | |
204 | } else { | |
205 | VLOG_ERR("%s: create failed: %s", tmpfile, strerror(errno)); | |
206 | } | |
207 | fatal_signal_remove_file_to_unlink(tmpfile); | |
208 | free(tmpfile); | |
209 | } | |
210 | free(pidfile); | |
211 | pidfile = NULL; | |
212 | } | |
213 | ||
214 | /* If configured with set_pidfile() or set_detach(), creates the pid file and | |
215 | * detaches from the foreground session. */ | |
216 | void | |
217 | daemonize(void) | |
95440284 BP |
218 | { |
219 | daemonize_start(); | |
220 | daemonize_complete(); | |
221 | } | |
222 | ||
223 | /* If daemonization is configured, then starts daemonization, by forking and | |
224 | * returning in the child process. The parent process hangs around until the | |
225 | * child lets it know either that it completed startup successfully (by calling | |
226 | * daemon_complete()) or that it failed to start up (by exiting with a nonzero | |
227 | * exit code). */ | |
228 | void | |
229 | daemonize_start(void) | |
064af421 BP |
230 | { |
231 | if (detach) { | |
95440284 BP |
232 | pid_t pid; |
233 | ||
234 | if (pipe(daemonize_fds) < 0) { | |
064af421 BP |
235 | ovs_fatal(errno, "pipe failed"); |
236 | } | |
237 | ||
95440284 BP |
238 | pid = fork(); |
239 | if (pid > 0) { | |
240 | /* Running in parent process. */ | |
241 | char c; | |
242 | ||
243 | close(daemonize_fds[1]); | |
064af421 | 244 | fatal_signal_fork(); |
95440284 BP |
245 | if (read(daemonize_fds[0], &c, 1) != 1) { |
246 | int retval; | |
247 | int status; | |
248 | ||
249 | do { | |
250 | retval = waitpid(pid, &status, 0); | |
251 | } while (retval == -1 && errno == EINTR); | |
252 | ||
253 | if (retval == pid | |
254 | && WIFEXITED(status) | |
255 | && WEXITSTATUS(status)) { | |
256 | /* Child exited with an error. Convey the same error to | |
257 | * our parent process as a courtesy. */ | |
258 | exit(WEXITSTATUS(status)); | |
259 | } | |
260 | ||
064af421 BP |
261 | ovs_fatal(errno, "daemon child failed to signal startup"); |
262 | } | |
263 | exit(0); | |
95440284 BP |
264 | } else if (!pid) { |
265 | /* Running in child process. */ | |
266 | close(daemonize_fds[0]); | |
064af421 | 267 | make_pidfile(); |
03fbffbd | 268 | time_postfork(); |
ac718c9d | 269 | lockfile_postfork(); |
95440284 | 270 | } else { |
064af421 | 271 | ovs_fatal(errno, "could not fork"); |
064af421 BP |
272 | } |
273 | } else { | |
274 | make_pidfile(); | |
275 | } | |
276 | } | |
277 | ||
95440284 BP |
278 | /* If daemonization is configured, then this function notifies the parent |
279 | * process that the child process has completed startup successfully. */ | |
280 | void | |
281 | daemonize_complete(void) | |
282 | { | |
283 | if (detach) { | |
b8781ff0 | 284 | size_t bytes_written; |
55368fb8 | 285 | int null_fd; |
b8781ff0 BP |
286 | int error; |
287 | ||
288 | error = write_fully(daemonize_fds[1], "", 1, &bytes_written); | |
289 | if (error) { | |
290 | ovs_fatal(error, "could not write to pipe"); | |
291 | } | |
95440284 | 292 | |
95440284 BP |
293 | close(daemonize_fds[1]); |
294 | setsid(); | |
295 | if (chdir_) { | |
296 | ignore(chdir("/")); | |
297 | } | |
55368fb8 BP |
298 | |
299 | /* Close stdin, stdout, stderr. Otherwise if we're started from | |
300 | * e.g. an SSH session then we tend to hold that session open | |
301 | * artificially. */ | |
302 | null_fd = get_null_fd(); | |
303 | if (null_fd >= 0) { | |
304 | dup2(null_fd, STDIN_FILENO); | |
305 | dup2(null_fd, STDOUT_FILENO); | |
306 | dup2(null_fd, STDERR_FILENO); | |
307 | } | |
95440284 BP |
308 | } |
309 | } | |
310 | ||
064af421 BP |
311 | void |
312 | daemon_usage(void) | |
313 | { | |
314 | printf( | |
315 | "\nDaemon options:\n" | |
e7bd7d78 | 316 | " --detach run in background as daemon\n" |
91a1e24d | 317 | " --no-chdir do not chdir to '/'\n" |
e7bd7d78 JP |
318 | " --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" |
319 | " --overwrite-pidfile with --pidfile, start even if already " | |
320 | "running\n", | |
064af421 BP |
321 | ovs_rundir, program_name); |
322 | } | |
323 | ||
324 | /* Opens and reads a PID from 'pidfile'. Returns the nonnegative PID if | |
325 | * successful, otherwise a negative errno value. */ | |
326 | pid_t | |
327 | read_pidfile(const char *pidfile) | |
328 | { | |
329 | char line[128]; | |
330 | struct flock lck; | |
331 | FILE *file; | |
332 | int error; | |
333 | ||
334 | file = fopen(pidfile, "r"); | |
335 | if (!file) { | |
336 | error = errno; | |
337 | VLOG_WARN("%s: open: %s", pidfile, strerror(error)); | |
338 | goto error; | |
339 | } | |
340 | ||
341 | lck.l_type = F_WRLCK; | |
342 | lck.l_whence = SEEK_SET; | |
343 | lck.l_start = 0; | |
344 | lck.l_len = 0; | |
345 | if (fcntl(fileno(file), F_GETLK, &lck)) { | |
346 | error = errno; | |
347 | VLOG_WARN("%s: fcntl: %s", pidfile, strerror(error)); | |
348 | goto error; | |
349 | } | |
350 | if (lck.l_type == F_UNLCK) { | |
351 | error = ESRCH; | |
352 | VLOG_WARN("%s: pid file is not locked", pidfile); | |
353 | goto error; | |
354 | } | |
355 | ||
356 | if (!fgets(line, sizeof line, file)) { | |
357 | if (ferror(file)) { | |
358 | error = errno; | |
359 | VLOG_WARN("%s: read: %s", pidfile, strerror(error)); | |
360 | } else { | |
361 | error = ESRCH; | |
362 | VLOG_WARN("%s: read: unexpected end of file", pidfile); | |
363 | } | |
364 | goto error; | |
365 | } | |
366 | ||
367 | if (lck.l_pid != strtoul(line, NULL, 10)) { | |
368 | error = ESRCH; | |
369 | VLOG_WARN("l_pid (%ld) != %s pid (%s)", | |
370 | (long int) lck.l_pid, pidfile, line); | |
371 | goto error; | |
372 | } | |
373 | ||
374 | fclose(file); | |
375 | return lck.l_pid; | |
376 | ||
377 | error: | |
378 | if (file) { | |
379 | fclose(file); | |
380 | } | |
381 | return -error; | |
382 | } |