]> sourceware.org Git - lvm2.git/blame - daemons/common/daemon-server.c
Start filling in some of the common daemon (server-side) functionality, taking
[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>
21#include <unistd.h>
22#include <signal.h>
23
24#include <syslog.h>
25
26/* Create a device monitoring thread. */
27static int _pthread_create(pthread_t *t, void *(*fun)(void *), void *arg, int stacksize)
28{
29 pthread_attr_t attr;
30 pthread_attr_init(&attr);
31 /*
32 * We use a smaller stack since it gets preallocated in its entirety
33 */
34 pthread_attr_setstacksize(&attr, stacksize);
35 return pthread_create(t, &attr, fun, arg);
36}
37
38static volatile sig_atomic_t _shutdown_requested = 0;
39
40static void _exit_handler(int sig __attribute__((unused)))
41{
42 _shutdown_requested = 1;
43}
44
45#ifdef linux
46# define OOM_ADJ_FILE "/proc/self/oom_adj"
47
48/* From linux/oom.h */
49# define OOM_DISABLE (-17)
50# define OOM_ADJUST_MIN (-16)
51
52/*
53 * Protection against OOM killer if kernel supports it
54 */
55static int _set_oom_adj(int val)
56{
57 FILE *fp;
58
59 struct stat st;
60
61 if (stat(OOM_ADJ_FILE, &st) == -1) {
62 if (errno == ENOENT)
63 perror(OOM_ADJ_FILE " not found");
64 else
65 perror(OOM_ADJ_FILE ": stat failed");
66 return 1;
67 }
68
69 if (!(fp = fopen(OOM_ADJ_FILE, "w"))) {
70 perror(OOM_ADJ_FILE ": fopen failed");
71 return 0;
72 }
73
74 fprintf(fp, "%i", val);
75 if (dm_fclose(fp))
76 perror(OOM_ADJ_FILE ": fclose failed");
77
78 return 1;
79}
80#endif
81
82static void remove_lockfile(const char *file)
83{
84 if (unlink(file))
85 perror(file ": unlink failed");
86}
87
88static void _daemonise(void)
89{
90 int child_status;
91 int fd;
92 pid_t pid;
93 struct rlimit rlim;
94 struct timeval tval;
95 sigset_t my_sigset;
96
97 sigemptyset(&my_sigset);
98 if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
99 fprintf(stderr, "Unable to restore signals.\n");
100 exit(EXIT_FAILURE);
101 }
102 signal(SIGTERM, &_exit_handler);
103
104 switch (pid = fork()) {
105 case -1:
106 perror("fork failed:");
107 exit(EXIT_FAILURE);
108
109 case 0: /* Child */
110 break;
111
112 default:
113 /* Wait for response from child */
114 while (!waitpid(pid, &child_status, WNOHANG) && !_exit_now) {
115 tval.tv_sec = 0;
116 tval.tv_usec = 250000; /* .25 sec */
117 select(0, NULL, NULL, NULL, &tval);
118 }
119
120 if (_shutdown_requested) /* Child has signaled it is ok - we can exit now */
121 exit(0);
122
123 /* Problem with child. Determine what it is by exit code */
124 switch (WEXITSTATUS(child_status)) {
125 case EXIT_DESC_CLOSE_FAILURE:
126 case EXIT_DESC_OPEN_FAILURE:
127 case EXIT_FIFO_FAILURE:
128 case EXIT_CHDIR_FAILURE:
129 default:
130 fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status));
131 break;
132 }
133
134 exit(WEXITSTATUS(child_status));
135 }
136
137 if (chdir("/"))
138 exit(1);
139
140 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
141 fd = 256; /* just have to guess */
142 else
143 fd = rlim.rlim_cur;
144
145 for (--fd; fd >= 0; fd--)
146 close(fd);
147
148 if ((open("/dev/null", O_RDONLY) < 0) ||
149 (open("/dev/null", O_WRONLY) < 0) ||
150 (open("/dev/null", O_WRONLY) < 0))
151 exit(1);
152
153 setsid();
154}
155
156void daemon_start(daemon_state s, handle_request r)
157{
158 /*
159 * Switch to C locale to avoid reading large locale-archive file used by
160 * some glibc (on some distributions it takes over 100MB). Some daemons
161 * need to use mlockall().
162 */
163 if (setenv("LANG", "C", 1))
164 perror("Cannot set LANG to C");
165
166 if (!s.foreground)
167 _daemonise();
168
169 /* TODO logging interface should be somewhat more elaborate */
170 openlog(s.name, LOG_PID, LOG_DAEMON);
171
172 (void) dm_prepare_selinux_context(s.pidfile, S_IFREG);
173
174 /*
175 * NB. Past this point, exit is not allowed. You have to return to this
176 * function at all costs. More or less.
177 */
178 if (dm_create_lockfile(s.pidfile) == 0)
179 exit(1);
180
181 (void) dm_prepare_selinux_context(NULL, 0);
182
183 /* Set normal exit signals to request shutdown instead of dying. */
184 signal(SIGINT, &_exit_handler);
185 signal(SIGHUP, &_exit_handler);
186 signal(SIGQUIT, &_exit_handler);
187
188#ifdef linux
189 if (s.avoid_oom && !_set_oom_adj(OOM_DISABLE) && !_set_oom_adj(OOM_ADJUST_MIN))
190 syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer");
191#endif
192
193 /* Signal parent, letting them know we are ready to go. */
194 if (!s.foreground)
195 kill(getppid(), SIGTERM);
196
197 while (!_shutdown_requested) {
198 /* TODO: do work */
199 }
200
201 syslog(LOG_NOTICE, "%s shutting down", s.name);
202 closelog();
203 remove_lockfile(s.pidfile);
204}
This page took 0.043373 seconds and 5 git commands to generate.