]> sourceware.org Git - lvm2.git/blame - daemons/common/daemon-server.c
Parse the incoming config tree in daemon-server.c, providing the
[lvm2.git] / daemons / common / daemon-server.c
CommitLineData
d7448a72
PR
1/*
2 * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
3 *
4 * This copyrighted material is made available to anyone wishing to use,
5 * modify, copy, or redistribute it subject to the terms and conditions
6 * of the GNU Lesser General Public License v.2.1.
7 *
8 * You should have received a copy of the GNU Lesser General Public License
9 * along with this program; if not, write to the Free Software Foundation,
10 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
11 */
12
13#include <dlfcn.h>
14#include <errno.h>
15#include <pthread.h>
16#include <sys/file.h>
17#include <sys/stat.h>
18#include <sys/wait.h>
19#include <sys/time.h>
20#include <sys/resource.h>
dc85d3fb
PR
21#include <netinet/in.h>
22#include <sys/un.h>
d7448a72
PR
23#include <unistd.h>
24#include <signal.h>
25
26#include <syslog.h>
dc85d3fb
PR
27#include "daemon-server.h"
28#include "libdevmapper.h"
d7448a72 29
dc85d3fb 30#if 0
d7448a72
PR
31/* Create a device monitoring thread. */
32static int _pthread_create(pthread_t *t, void *(*fun)(void *), void *arg, int stacksize)
33{
34 pthread_attr_t attr;
35 pthread_attr_init(&attr);
36 /*
37 * We use a smaller stack since it gets preallocated in its entirety
38 */
39 pthread_attr_setstacksize(&attr, stacksize);
40 return pthread_create(t, &attr, fun, arg);
41}
dc85d3fb 42#endif
d7448a72
PR
43
44static volatile sig_atomic_t _shutdown_requested = 0;
45
46static void _exit_handler(int sig __attribute__((unused)))
47{
48 _shutdown_requested = 1;
49}
50
51#ifdef linux
52# define OOM_ADJ_FILE "/proc/self/oom_adj"
dc85d3fb 53# include <stdio.h>
d7448a72
PR
54
55/* From linux/oom.h */
56# define OOM_DISABLE (-17)
57# define OOM_ADJUST_MIN (-16)
58
59/*
60 * Protection against OOM killer if kernel supports it
61 */
62static int _set_oom_adj(int val)
63{
64 FILE *fp;
65
66 struct stat st;
67
68 if (stat(OOM_ADJ_FILE, &st) == -1) {
69 if (errno == ENOENT)
70 perror(OOM_ADJ_FILE " not found");
71 else
72 perror(OOM_ADJ_FILE ": stat failed");
73 return 1;
74 }
75
76 if (!(fp = fopen(OOM_ADJ_FILE, "w"))) {
77 perror(OOM_ADJ_FILE ": fopen failed");
78 return 0;
79 }
80
81 fprintf(fp, "%i", val);
dc85d3fb 82 if (fclose(fp))
d7448a72
PR
83 perror(OOM_ADJ_FILE ": fclose failed");
84
85 return 1;
86}
87#endif
88
73ffd6e7
PR
89static int _open_socket(daemon_state s)
90{
91 int fd = -1;
92 struct sockaddr_un sockaddr;
93 mode_t old_mask;
94
95 (void) dm_prepare_selinux_context(s.socket_path, S_IFSOCK);
96 old_mask = umask(0077);
97
98 /* Open local socket */
99 fd = socket(PF_UNIX, SOCK_STREAM, 0);
100 if (fd < 0) {
dc85d3fb 101 perror("Can't create local socket.");
73ffd6e7
PR
102 goto error;
103 }
104
105 /* Set Close-on-exec & non-blocking */
106 if (fcntl(fd, F_SETFD, 1))
dc85d3fb 107 fprintf(stderr, "setting CLOEXEC on socket fd %d failed: %s\n", fd, strerror(errno));
73ffd6e7
PR
108 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
109
55e30071 110 fprintf(stderr, "[D] creating %s\n", s.socket_path);
73ffd6e7 111 memset(&sockaddr, 0, sizeof(sockaddr));
92658f56 112 strcpy(sockaddr.sun_path, s.socket_path);
73ffd6e7
PR
113 sockaddr.sun_family = AF_UNIX;
114
115 if (bind(fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
dc85d3fb 116 perror("can't bind local socket.");
73ffd6e7
PR
117 goto error;
118 }
119 if (listen(fd, 1) != 0) {
dc85d3fb 120 perror("listen local");
73ffd6e7
PR
121 goto error;
122 }
123
124out:
125 umask(old_mask);
126 (void) dm_prepare_selinux_context(NULL, 0);
127 return fd;
128
129error:
130 if (fd >= 0) {
131 close(fd);
92658f56 132 unlink(s.socket_path);
73ffd6e7
PR
133 fd = -1;
134 }
135 goto out;
136}
137
d7448a72
PR
138static void remove_lockfile(const char *file)
139{
140 if (unlink(file))
dc85d3fb 141 perror("unlink failed");
d7448a72
PR
142}
143
144static void _daemonise(void)
145{
146 int child_status;
147 int fd;
148 pid_t pid;
149 struct rlimit rlim;
150 struct timeval tval;
151 sigset_t my_sigset;
152
153 sigemptyset(&my_sigset);
154 if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
155 fprintf(stderr, "Unable to restore signals.\n");
156 exit(EXIT_FAILURE);
157 }
158 signal(SIGTERM, &_exit_handler);
159
160 switch (pid = fork()) {
161 case -1:
162 perror("fork failed:");
163 exit(EXIT_FAILURE);
164
165 case 0: /* Child */
166 break;
167
168 default:
169 /* Wait for response from child */
dc85d3fb 170 while (!waitpid(pid, &child_status, WNOHANG) && !_shutdown_requested) {
d7448a72
PR
171 tval.tv_sec = 0;
172 tval.tv_usec = 250000; /* .25 sec */
173 select(0, NULL, NULL, NULL, &tval);
174 }
175
176 if (_shutdown_requested) /* Child has signaled it is ok - we can exit now */
177 exit(0);
178
179 /* Problem with child. Determine what it is by exit code */
dc85d3fb 180 fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status));
d7448a72
PR
181 exit(WEXITSTATUS(child_status));
182 }
183
184 if (chdir("/"))
185 exit(1);
186
187 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
188 fd = 256; /* just have to guess */
189 else
190 fd = rlim.rlim_cur;
191
192 for (--fd; fd >= 0; fd--)
193 close(fd);
194
195 if ((open("/dev/null", O_RDONLY) < 0) ||
196 (open("/dev/null", O_WRONLY) < 0) ||
197 (open("/dev/null", O_WRONLY) < 0))
198 exit(1);
199
200 setsid();
201}
202
92658f56
PR
203struct thread_baton {
204 daemon_state s;
205 client_handle client;
206};
207
208void *client_thread(void *baton)
209{
210 struct thread_baton *b = baton;
211 request req;
212 while (1) {
213 if (!read_buffer(b->client.socket_fd, &req.buffer))
214 goto fail;
215
55e30071 216 req.cft = create_config_tree_from_string(req.buffer);
92658f56 217 response res = b->s.handler(b->s, b->client, req);
55e30071
PR
218 destroy_config_tree(req.cft);
219 dm_free(req.buffer);
92658f56
PR
220
221 if (!res.buffer) {
222 /* TODO fill in the buffer from res.cft */
223 }
224
225 write_buffer(b->client.socket_fd, res.buffer, strlen(res.buffer));
226
227 free(res.buffer);
92658f56
PR
228 }
229fail:
230 /* TODO what should we really do here? */
231 return NULL;
232}
233
234int handle_connect(daemon_state s)
235{
236 struct sockaddr_un sockaddr;
237 client_handle client;
238 socklen_t sl = sizeof(sockaddr);
239 int client_fd = accept(s.socket_fd, (struct sockaddr *) &sockaddr, &sl);
240 if (client_fd < 0)
241 return 0;
242
243 struct thread_baton *baton = malloc(sizeof(struct thread_baton));
244 if (!baton)
245 return 0;
246
247 client.socket_fd = client_fd;
248 client.read_buf = 0;
249 client.private = 0;
250 baton->s = s;
251 baton->client = client;
252
253 if (pthread_create(&baton->client.thread_id, NULL, client_thread, baton))
254 return 0;
255 return 1;
256}
257
dc85d3fb 258void daemon_start(daemon_state s)
d7448a72 259{
73ffd6e7 260 int failed = 0;
d7448a72
PR
261 /*
262 * Switch to C locale to avoid reading large locale-archive file used by
263 * some glibc (on some distributions it takes over 100MB). Some daemons
264 * need to use mlockall().
265 */
266 if (setenv("LANG", "C", 1))
267 perror("Cannot set LANG to C");
268
269 if (!s.foreground)
270 _daemonise();
271
272 /* TODO logging interface should be somewhat more elaborate */
273 openlog(s.name, LOG_PID, LOG_DAEMON);
274
275 (void) dm_prepare_selinux_context(s.pidfile, S_IFREG);
276
277 /*
73ffd6e7
PR
278 * NB. Take care to not keep stale locks around. Best not exit(...)
279 * after this point.
d7448a72
PR
280 */
281 if (dm_create_lockfile(s.pidfile) == 0)
282 exit(1);
283
284 (void) dm_prepare_selinux_context(NULL, 0);
285
286 /* Set normal exit signals to request shutdown instead of dying. */
287 signal(SIGINT, &_exit_handler);
288 signal(SIGHUP, &_exit_handler);
289 signal(SIGQUIT, &_exit_handler);
92658f56
PR
290 signal(SIGTERM, &_exit_handler);
291 signal(SIGPIPE, SIG_IGN);
d7448a72
PR
292
293#ifdef linux
294 if (s.avoid_oom && !_set_oom_adj(OOM_DISABLE) && !_set_oom_adj(OOM_ADJUST_MIN))
295 syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer");
296#endif
297
73ffd6e7
PR
298 if (s.socket_path) {
299 s.socket_fd = _open_socket(s);
300 if (s.socket_fd < 0)
301 failed = 1;
302 }
303
d7448a72
PR
304 /* Signal parent, letting them know we are ready to go. */
305 if (!s.foreground)
306 kill(getppid(), SIGTERM);
307
73ffd6e7 308 while (!_shutdown_requested && !failed) {
92658f56
PR
309 int status;
310 fd_set in;
311 FD_ZERO(&in);
312 FD_SET(s.socket_fd, &in);
313 if (select(FD_SETSIZE, &in, NULL, NULL, NULL) < 0 && errno != EINTR)
314 perror("select error");
315 if (FD_ISSET(s.socket_fd, &in))
316 if (!handle_connect(s))
317 syslog(LOG_ERR, "Failed to handle a client connection.");
d7448a72
PR
318 }
319
92658f56
PR
320 if (s.socket_fd >= 0)
321 unlink(s.socket_path);
322
d7448a72
PR
323 syslog(LOG_NOTICE, "%s shutting down", s.name);
324 closelog();
325 remove_lockfile(s.pidfile);
73ffd6e7
PR
326 if (failed)
327 exit(1);
d7448a72 328}
This page took 3.303679 seconds and 5 git commands to generate.