1 /*
2  * virdaemon.c: shared daemon setup code
3  *
4  * Copyright (C) 2020 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library;  If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #ifndef WIN32
26 # include <sys/wait.h>
27 #endif
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <stdbool.h>
31 
32 #include "virdaemon.h"
33 #include "virutil.h"
34 #include "virfile.h"
35 #include "virlog.h"
36 #include "viralloc.h"
37 
38 #include "configmake.h"
39 
40 #ifndef WIN32
41 
42 int
virDaemonForkIntoBackground(const char * argv0)43 virDaemonForkIntoBackground(const char *argv0)
44 {
45     int statuspipe[2];
46     pid_t pid;
47 
48     if (virPipeQuiet(statuspipe) < 0)
49         return -1;
50 
51     pid = fork();
52     switch (pid) {
53     case 0:
54         {
55             /* intermediate child */
56             int stdinfd = -1;
57             int stdoutfd = -1;
58             int nextpid;
59 
60             VIR_FORCE_CLOSE(statuspipe[0]);
61 
62             if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
63                 goto cleanup;
64             if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
65                 goto cleanup;
66             if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
67                 goto cleanup;
68             if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
69                 goto cleanup;
70             if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
71                 goto cleanup;
72             if (VIR_CLOSE(stdinfd) < 0)
73                 goto cleanup;
74             if (VIR_CLOSE(stdoutfd) < 0)
75                 goto cleanup;
76 
77             if (setsid() < 0)
78                 goto cleanup;
79 
80             nextpid = fork();
81             switch (nextpid) {
82             case 0: /* grandchild */
83                 return statuspipe[1];
84             case -1: /* error */
85                 goto cleanup;
86             default: /* intermediate child succeeded */
87                 _exit(EXIT_SUCCESS);
88             }
89 
90          cleanup:
91             VIR_FORCE_CLOSE(stdoutfd);
92             VIR_FORCE_CLOSE(stdinfd);
93             VIR_FORCE_CLOSE(statuspipe[1]);
94             _exit(EXIT_FAILURE);
95 
96         }
97 
98     case -1: /* error in parent */
99         goto error;
100 
101     default:
102         {
103             /* parent */
104             int got, exitstatus = 0;
105             int ret;
106             char status;
107 
108             VIR_FORCE_CLOSE(statuspipe[1]);
109 
110             /* We wait to make sure the first child forked successfully */
111             if ((got = waitpid(pid, &exitstatus, 0)) < 0 ||
112                 got != pid ||
113                 exitstatus != 0) {
114                 goto error;
115             }
116 
117             /* If we got here, then the grandchild was spawned, so we
118              * must exit. Block until the second child initializes
119              * successfully */
120             ret = saferead(statuspipe[0], &status, 1);
121 
122             VIR_FORCE_CLOSE(statuspipe[0]);
123 
124             if (ret != 1) {
125                 fprintf(stderr,
126                         _("%s: error: unable to determine if daemon is "
127                           "running: %s\n"), argv0,
128                         g_strerror(errno));
129                 exit(EXIT_FAILURE);
130             } else if (status != 0) {
131                 fprintf(stderr,
132                         _("%s: error: %s. Check /var/log/messages or run without "
133                           "--daemon for more info.\n"), argv0,
134                         virDaemonErrTypeToString(status));
135                 exit(EXIT_FAILURE);
136             }
137             _exit(EXIT_SUCCESS);
138         }
139     }
140 
141  error:
142     VIR_FORCE_CLOSE(statuspipe[0]);
143     VIR_FORCE_CLOSE(statuspipe[1]);
144     return -1;
145 }
146 
147 
148 /*
149  * Set up the logging environment
150  * By default if daemonized all errors go to the logfile libvirtd.log,
151  * but if verbose or error debugging is asked for then also output
152  * informational and debug messages. Default size if 64 kB.
153  */
154 void
virDaemonSetupLogging(const char * daemon_name,unsigned int log_level,char * log_filters,char * log_outputs,bool privileged,bool verbose,bool godaemon)155 virDaemonSetupLogging(const char *daemon_name,
156                       unsigned int log_level,
157                       char *log_filters,
158                       char *log_outputs,
159                       bool privileged,
160                       bool verbose,
161                       bool godaemon)
162 {
163     virLogReset();
164 
165     /*
166      * Libvirtd's order of precedence is:
167      * cmdline > environment > config
168      *
169      * Given the precedence, we must process the variables in the opposite
170      * order, each one overriding the previous.
171      */
172     if (log_level != 0)
173         virLogSetDefaultPriority(log_level);
174 
175     /* In case the config is empty, both filters and outputs will become empty,
176      * however we can't start with empty outputs, thus we'll need to define and
177      * setup a default one.
178      */
179     ignore_value(virLogSetFilters(log_filters));
180     ignore_value(virLogSetOutputs(log_outputs));
181 
182     /* If there are some environment variables defined, use those instead */
183     virLogSetFromEnv();
184 
185     /*
186      * Command line override for --verbose
187      */
188     if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
189         virLogSetDefaultPriority(VIR_LOG_INFO);
190 
191     /* Define the default output. This is only applied if there was no setting
192      * from either the config or the environment.
193      */
194     virLogSetDefaultOutput(daemon_name, godaemon, privileged);
195 
196     if (virLogGetNbOutputs() == 0)
197         virLogSetOutputs(virLogGetDefaultOutput());
198 }
199 
200 
201 int
virDaemonUnixSocketPaths(const char * sock_prefix,bool privileged,char * unix_sock_dir,char ** sockfile,char ** rosockfile,char ** admsockfile)202 virDaemonUnixSocketPaths(const char *sock_prefix,
203                          bool privileged,
204                          char *unix_sock_dir,
205                          char **sockfile,
206                          char **rosockfile,
207                          char **admsockfile)
208 {
209     int ret = -1;
210     char *rundir = NULL;
211 
212     if (unix_sock_dir) {
213         if (sockfile)
214             *sockfile = g_strdup_printf("%s/%s-sock", unix_sock_dir, sock_prefix);
215 
216         if (privileged) {
217             if (rosockfile)
218                 *rosockfile = g_strdup_printf("%s/%s-sock-ro",
219                                               unix_sock_dir, sock_prefix);
220             if (admsockfile)
221                 *admsockfile = g_strdup_printf("%s/%s-admin-sock",
222                                                unix_sock_dir, sock_prefix);
223         }
224     } else {
225         if (privileged) {
226             if (sockfile)
227                 *sockfile = g_strdup_printf("%s/libvirt/%s-sock",
228                                             RUNSTATEDIR, sock_prefix);
229             if (rosockfile)
230                 *rosockfile = g_strdup_printf("%s/libvirt/%s-sock-ro",
231                                               RUNSTATEDIR, sock_prefix);
232             if (admsockfile)
233                 *admsockfile = g_strdup_printf("%s/libvirt/%s-admin-sock",
234                                                RUNSTATEDIR, sock_prefix);
235         } else {
236             mode_t old_umask;
237 
238             rundir = virGetUserRuntimeDirectory();
239 
240             old_umask = umask(077);
241             if (g_mkdir_with_parents(rundir, 0777) < 0) {
242                 umask(old_umask);
243                 goto cleanup;
244             }
245             umask(old_umask);
246 
247             if (sockfile)
248                 *sockfile = g_strdup_printf("%s/%s-sock", rundir, sock_prefix);
249             if (admsockfile)
250                 *admsockfile = g_strdup_printf("%s/%s-admin-sock", rundir, sock_prefix);
251         }
252     }
253 
254     ret = 0;
255  cleanup:
256     VIR_FREE(rundir);
257     return ret;
258 }
259 
260 #else /* WIN32 */
261 
virDaemonForkIntoBackground(const char * argv0 G_GNUC_UNUSED)262 int virDaemonForkIntoBackground(const char *argv0 G_GNUC_UNUSED)
263 {
264     errno = ENOTSUP;
265     return -1;
266 }
267 
virDaemonSetupLogging(const char * daemon_name G_GNUC_UNUSED,unsigned int log_level G_GNUC_UNUSED,char * log_filters G_GNUC_UNUSED,char * log_outputs G_GNUC_UNUSED,bool privileged G_GNUC_UNUSED,bool verbose G_GNUC_UNUSED,bool godaemon G_GNUC_UNUSED)268 void virDaemonSetupLogging(const char *daemon_name G_GNUC_UNUSED,
269                            unsigned int log_level G_GNUC_UNUSED,
270                            char *log_filters G_GNUC_UNUSED,
271                            char *log_outputs G_GNUC_UNUSED,
272                            bool privileged G_GNUC_UNUSED,
273                            bool verbose G_GNUC_UNUSED,
274                            bool godaemon G_GNUC_UNUSED)
275 {
276     /* NOOP */
277     errno = ENOTSUP;
278     return;
279 }
280 
virDaemonUnixSocketPaths(const char * sock_prefix G_GNUC_UNUSED,bool privileged G_GNUC_UNUSED,char * unix_sock_dir G_GNUC_UNUSED,char ** sockfile G_GNUC_UNUSED,char ** rosockfile G_GNUC_UNUSED,char ** adminSockfile G_GNUC_UNUSED)281 int virDaemonUnixSocketPaths(const char *sock_prefix G_GNUC_UNUSED,
282                              bool privileged G_GNUC_UNUSED,
283                              char *unix_sock_dir G_GNUC_UNUSED,
284                              char **sockfile G_GNUC_UNUSED,
285                              char **rosockfile G_GNUC_UNUSED,
286                              char **adminSockfile G_GNUC_UNUSED)
287 {
288     errno = ENOTSUP;
289     return -1;
290 }
291 
292 #endif /* WIN32 */
293