]>
Commit | Line | Data |
---|---|---|
064af421 BP |
1 | /* |
2 | * Copyright (c) 2008, 2009 Nicira Networks. | |
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> | |
23 | #include <unistd.h> | |
24 | #include "fatal-signal.h" | |
25 | #include "dirs.h" | |
26 | #include "util.h" | |
27 | ||
28 | #define THIS_MODULE VLM_daemon | |
29 | #include "vlog.h" | |
30 | ||
31 | /* Should we run in the background? */ | |
32 | static bool detach; | |
33 | ||
34 | /* Name of pidfile (null if none). */ | |
35 | static char *pidfile; | |
36 | ||
37 | /* Create pidfile even if one already exists and is locked? */ | |
38 | static bool force; | |
39 | ||
40 | /* Returns the file name that would be used for a pidfile if 'name' were | |
41 | * provided to set_pidfile(). The caller must free the returned string. */ | |
42 | char * | |
43 | make_pidfile_name(const char *name) | |
44 | { | |
45 | return (!name ? xasprintf("%s/%s.pid", ovs_rundir, program_name) | |
46 | : *name == '/' ? xstrdup(name) | |
47 | : xasprintf("%s/%s", ovs_rundir, name)); | |
48 | } | |
49 | ||
50 | /* Sets up a following call to daemonize() to create a pidfile named 'name'. | |
51 | * If 'name' begins with '/', then it is treated as an absolute path. | |
52 | * Otherwise, it is taken relative to RUNDIR, which is $(prefix)/var/run by | |
53 | * default. | |
54 | * | |
55 | * If 'name' is null, then program_name followed by ".pid" is used. */ | |
56 | void | |
57 | set_pidfile(const char *name) | |
58 | { | |
59 | free(pidfile); | |
60 | pidfile = make_pidfile_name(name); | |
61 | } | |
62 | ||
63 | /* Returns an absolute path to the configured pidfile, or a null pointer if no | |
64 | * pidfile is configured. The caller must not modify or free the returned | |
65 | * string. */ | |
66 | const char * | |
67 | get_pidfile(void) | |
68 | { | |
69 | return pidfile; | |
70 | } | |
71 | ||
72 | /* Normally, die_if_already_running() will terminate the program with a message | |
73 | * if a locked pidfile already exists. If this function is called, | |
74 | * die_if_already_running() will merely log a warning. */ | |
75 | void | |
76 | ignore_existing_pidfile(void) | |
77 | { | |
78 | force = true; | |
79 | } | |
80 | ||
81 | /* Sets up a following call to daemonize() to detach from the foreground | |
82 | * session, running this process in the background. */ | |
83 | void | |
84 | set_detach(void) | |
85 | { | |
86 | detach = true; | |
87 | } | |
88 | ||
89 | /* If a pidfile has been configured and that pidfile already exists and is | |
90 | * locked by a running process, returns the pid of the running process. | |
91 | * Otherwise, returns 0. */ | |
92 | static pid_t | |
93 | already_running(void) | |
94 | { | |
95 | pid_t pid = 0; | |
96 | if (pidfile) { | |
97 | int fd = open(pidfile, O_RDWR); | |
98 | if (fd >= 0) { | |
99 | struct flock lck; | |
100 | lck.l_type = F_WRLCK; | |
101 | lck.l_whence = SEEK_SET; | |
102 | lck.l_start = 0; | |
103 | lck.l_len = 0; | |
104 | if (fcntl(fd, F_GETLK, &lck) != -1 && lck.l_type != F_UNLCK) { | |
105 | pid = lck.l_pid; | |
106 | } | |
107 | close(fd); | |
108 | } | |
109 | } | |
110 | return pid; | |
111 | } | |
112 | ||
113 | /* If a locked pidfile exists, issue a warning message and, unless | |
114 | * ignore_existing_pidfile() has been called, terminate the program. */ | |
115 | void | |
116 | die_if_already_running(void) | |
117 | { | |
118 | pid_t pid = already_running(); | |
119 | if (pid) { | |
120 | if (!force) { | |
121 | ovs_fatal(0, "%s: already running as pid %ld", | |
122 | get_pidfile(), (long int) pid); | |
123 | } else { | |
124 | VLOG_WARN("%s: %s already running as pid %ld", | |
125 | get_pidfile(), program_name, (long int) pid); | |
126 | } | |
127 | } | |
128 | } | |
129 | ||
130 | /* If a pidfile has been configured, creates it and stores the running process' | |
131 | * pid init. Ensures that the pidfile will be deleted when the process | |
132 | * exits. */ | |
133 | static void | |
134 | make_pidfile(void) | |
135 | { | |
136 | if (pidfile) { | |
137 | /* Create pidfile via temporary file, so that observers never see an | |
138 | * empty pidfile or an unlocked pidfile. */ | |
139 | long int pid = getpid(); | |
140 | char *tmpfile; | |
141 | int fd; | |
142 | ||
143 | tmpfile = xasprintf("%s.tmp%ld", pidfile, pid); | |
144 | fatal_signal_add_file_to_unlink(tmpfile); | |
145 | fd = open(tmpfile, O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
146 | if (fd >= 0) { | |
147 | struct flock lck; | |
148 | lck.l_type = F_WRLCK; | |
149 | lck.l_whence = SEEK_SET; | |
150 | lck.l_start = 0; | |
151 | lck.l_len = 0; | |
152 | if (fcntl(fd, F_SETLK, &lck) != -1) { | |
153 | char *text = xasprintf("%ld\n", pid); | |
154 | if (write(fd, text, strlen(text)) == strlen(text)) { | |
155 | fatal_signal_add_file_to_unlink(pidfile); | |
156 | if (rename(tmpfile, pidfile) < 0) { | |
157 | VLOG_ERR("failed to rename \"%s\" to \"%s\": %s", | |
158 | tmpfile, pidfile, strerror(errno)); | |
159 | fatal_signal_remove_file_to_unlink(pidfile); | |
160 | close(fd); | |
161 | } else { | |
162 | /* Keep 'fd' open to retain the lock. */ | |
163 | } | |
164 | free(text); | |
165 | } else { | |
166 | VLOG_ERR("%s: write failed: %s", tmpfile, strerror(errno)); | |
167 | close(fd); | |
168 | } | |
169 | } else { | |
170 | VLOG_ERR("%s: fcntl failed: %s", tmpfile, strerror(errno)); | |
171 | close(fd); | |
172 | } | |
173 | } else { | |
174 | VLOG_ERR("%s: create failed: %s", tmpfile, strerror(errno)); | |
175 | } | |
176 | fatal_signal_remove_file_to_unlink(tmpfile); | |
177 | free(tmpfile); | |
178 | } | |
179 | free(pidfile); | |
180 | pidfile = NULL; | |
181 | } | |
182 | ||
183 | /* If configured with set_pidfile() or set_detach(), creates the pid file and | |
184 | * detaches from the foreground session. */ | |
185 | void | |
186 | daemonize(void) | |
187 | { | |
188 | if (detach) { | |
189 | char c = 0; | |
190 | int fds[2]; | |
191 | if (pipe(fds) < 0) { | |
192 | ovs_fatal(errno, "pipe failed"); | |
193 | } | |
194 | ||
195 | switch (fork()) { | |
196 | default: | |
197 | /* Parent process: wait for child to create pidfile, then exit. */ | |
198 | close(fds[1]); | |
199 | fatal_signal_fork(); | |
200 | if (read(fds[0], &c, 1) != 1) { | |
201 | ovs_fatal(errno, "daemon child failed to signal startup"); | |
202 | } | |
203 | exit(0); | |
204 | ||
205 | case 0: | |
206 | /* Child process. */ | |
207 | close(fds[0]); | |
208 | make_pidfile(); | |
209 | write(fds[1], &c, 1); | |
210 | close(fds[1]); | |
211 | setsid(); | |
212 | chdir("/"); | |
213 | break; | |
214 | ||
215 | case -1: | |
216 | /* Error. */ | |
217 | ovs_fatal(errno, "could not fork"); | |
218 | break; | |
219 | } | |
220 | } else { | |
221 | make_pidfile(); | |
222 | } | |
223 | } | |
224 | ||
225 | void | |
226 | daemon_usage(void) | |
227 | { | |
228 | printf( | |
229 | "\nDaemon options:\n" | |
230 | " -D, --detach run in background as daemon\n" | |
231 | " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" | |
232 | " -f, --force with -P, start even if already running\n", | |
233 | ovs_rundir, program_name); | |
234 | } | |
235 | ||
236 | /* Opens and reads a PID from 'pidfile'. Returns the nonnegative PID if | |
237 | * successful, otherwise a negative errno value. */ | |
238 | pid_t | |
239 | read_pidfile(const char *pidfile) | |
240 | { | |
241 | char line[128]; | |
242 | struct flock lck; | |
243 | FILE *file; | |
244 | int error; | |
245 | ||
246 | file = fopen(pidfile, "r"); | |
247 | if (!file) { | |
248 | error = errno; | |
249 | VLOG_WARN("%s: open: %s", pidfile, strerror(error)); | |
250 | goto error; | |
251 | } | |
252 | ||
253 | lck.l_type = F_WRLCK; | |
254 | lck.l_whence = SEEK_SET; | |
255 | lck.l_start = 0; | |
256 | lck.l_len = 0; | |
257 | if (fcntl(fileno(file), F_GETLK, &lck)) { | |
258 | error = errno; | |
259 | VLOG_WARN("%s: fcntl: %s", pidfile, strerror(error)); | |
260 | goto error; | |
261 | } | |
262 | if (lck.l_type == F_UNLCK) { | |
263 | error = ESRCH; | |
264 | VLOG_WARN("%s: pid file is not locked", pidfile); | |
265 | goto error; | |
266 | } | |
267 | ||
268 | if (!fgets(line, sizeof line, file)) { | |
269 | if (ferror(file)) { | |
270 | error = errno; | |
271 | VLOG_WARN("%s: read: %s", pidfile, strerror(error)); | |
272 | } else { | |
273 | error = ESRCH; | |
274 | VLOG_WARN("%s: read: unexpected end of file", pidfile); | |
275 | } | |
276 | goto error; | |
277 | } | |
278 | ||
279 | if (lck.l_pid != strtoul(line, NULL, 10)) { | |
280 | error = ESRCH; | |
281 | VLOG_WARN("l_pid (%ld) != %s pid (%s)", | |
282 | (long int) lck.l_pid, pidfile, line); | |
283 | goto error; | |
284 | } | |
285 | ||
286 | fclose(file); | |
287 | return lck.l_pid; | |
288 | ||
289 | error: | |
290 | if (file) { | |
291 | fclose(file); | |
292 | } | |
293 | return -error; | |
294 | } |