2 * Copyright (C) 2008 Novell, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Author: Jim Fehlig <jfehlig@novell.com>
38 #include <arpa/inet.h>
39 #include <sys/types.h>
42 #include <libxml/parser.h>
43 #include <libxml/xpath.h>
50 * vhostmd will periodically write metrics to a disk. The metrics
51 * to write, how often, and where to write them are all adjustable
52 * via the vhostmd.xml configuration file.
54 * Currently, the disk format is quite simple: a raw, memory-backed
56 * - 4 byte signature, big endian
57 * - 4 byte busy flag, big endian
58 * - 4 byte content checksum, big endian
59 * - 4 byte content length, big endian
63 #define MDISK_SIZE_MIN 1024
64 #define MDISK_SIZE_MAX (256 * 1024 * 1024)
65 #define MDISK_SIGNATURE 0x6d766264 /* 'mvbd' */
67 typedef struct _mdisk_header
75 #define MDISK_HEADER_SIZE (sizeof(mdisk_header))
78 * Macro for determining usable size of metrics disk
80 #define MDISK_SIZE (mdisk_size - MDISK_HEADER_SIZE)
86 #define XENSTORE (1 << 1)
88 /* Global variables */
90 static int mdisk_size = MDISK_SIZE_MIN;
91 static int update_period = 5;
92 static char *def_mdisk_path = "/dev/shm/vhostmd0";
93 static char *mdisk_path = NULL;
94 static char *pid_file = "/var/run/vhostmd.pid";
95 static metric *metrics = NULL;
96 static mdisk_header md_header =
103 static char *search_path = NULL;
104 static int transports = 0;
107 /**********************************************************************
108 * Basic daemon support functions
109 *********************************************************************/
111 static void sig_handler(int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED,
112 void *context ATTRIBUTE_UNUSED)
125 static int write_pid_file(const char *pfile)
130 if (pfile[0] == '\0')
133 if ((fd = open(pfile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
134 vu_log(VHOSTMD_ERR, "Failed to open pid file '%s' : %s",
135 pfile, strerror(errno));
139 if (!(fh = fdopen(fd, "w"))) {
140 vu_log(VHOSTMD_ERR, "Failed to fdopen pid file '%s' : %s",
141 pfile, strerror(errno));
146 if (fprintf(fh, "%lu\n", (unsigned long)getpid()) < 0) {
147 vu_log(VHOSTMD_ERR, "Failed to write to pid file '%s' : %s",
148 pfile, strerror(errno));
153 if (fclose(fh) == EOF) {
154 vu_log(VHOSTMD_ERR, "Failed to close pid file '%s' : %s",
155 pfile, strerror(errno));
162 static int daemonize(void)
172 if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0)
174 if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0)
176 if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
178 if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
180 if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
182 if (close(stdinfd) < 0)
185 if (close(stdoutfd) < 0)
189 if (chdir ("/") == -1)
220 /* We wait to make sure the next child forked successfully */
221 if ((got = waitpid(pid, &status, 0)) < 0 ||
222 got != pid || status != 0) {
230 /**********************************************************************
231 * Config file parsing functions
232 *********************************************************************/
234 /* Parse a XML group metric node and return success indication */
235 static int parse_group_metric(xmlDocPtr xml ATTRIBUTE_UNUSED,
236 xmlXPathContextPtr ctxt, xmlNodePtr node, metric *mdef)
238 xmlXPathObjectPtr obj = NULL;
239 xmlChar *path = NULL;
246 free(mdef->type_str);
248 mdef->type_str = NULL;
251 path = xmlGetNodePath(node);
253 vu_log(VHOSTMD_WARN, "parse_group_metric: node path not found");
256 asprintf(&cp, "%s/variable", path);
258 obj = xmlXPathEval( BAD_CAST cp, ctxt);
259 if ((obj == NULL) || (obj->type != XPATH_NODESET)) {
260 vu_log(VHOSTMD_WARN, "parse_group_metric: variable set not found");
264 mdef->cnt = xmlXPathNodeSetGetLength(obj->nodesetval);
265 vu_log(VHOSTMD_INFO, "parse_group_metric: number of variable nodes: %d", mdef->cnt);
266 for (i = 0; i < mdef->cnt; i++) {
267 xmlNode *n = obj->nodesetval->nodeTab[i];
268 if ((prop = xmlGetProp(n, BAD_CAST "name")) == NULL) {
269 vu_log(VHOSTMD_WARN, "parse_group_metric: metric name not specified");
272 vu_append_string(&mdef->name, prop);
275 if ((prop = xmlGetProp(n, BAD_CAST "type")) == NULL) {
276 vu_log(VHOSTMD_WARN, "parse_group_metric: metric type not specified");
279 vu_append_string(&mdef->type_str, prop);
287 xmlXPathFreeObject(obj);
291 /* Parse a XML metric node and return a metric definition */
292 static metric *parse_metric(xmlDocPtr xml, xmlXPathContextPtr ctxt, xmlNodePtr node)
296 xmlChar *mtype = NULL;
297 xmlChar *mcontext = NULL;
300 mdef = calloc(1, sizeof(metric));
302 vu_log(VHOSTMD_WARN, "Unable to allocate memory for "
303 "metrics definition");
307 /* Get the metric type attribute */
308 if ((mtype = xmlGetProp(node, BAD_CAST "type")) == NULL) {
309 vu_log(VHOSTMD_WARN, "metric type not specified");
313 if (metric_type_from_str(mtype, &(mdef->type))) {
314 vu_log(VHOSTMD_WARN, "Unsupported metric type %s", mtype);
317 mdef->type_str = strdup((char *)mtype);
319 /* Get the metric context attribute */
320 if ((mcontext = xmlGetProp(node, BAD_CAST "context")) == NULL) {
321 vu_log(VHOSTMD_WARN, "metric context not specified");
324 if (xmlStrEqual(mcontext, BAD_CAST "host"))
325 mdef->ctx = METRIC_CONTEXT_HOST;
326 else if (xmlStrEqual(mcontext, BAD_CAST "vm"))
327 mdef->ctx = METRIC_CONTEXT_VM;
329 vu_log(VHOSTMD_WARN, "Unsupported metric context (%s) :"
330 "supported contexts (host) and (vm)", mcontext);
334 /* Get the metric name and the action */
335 cur = node->xmlChildrenNode;
338 str = xmlNodeListGetString(xml, cur->xmlChildrenNode, 1);
339 if (str && xmlStrEqual(cur->name, BAD_CAST "name")) {
340 mdef->name= strdup((char *)str);
342 if (str && xmlStrEqual(cur->name, BAD_CAST "action")) {
343 mdef->action = strdup((char *)str);
350 if (mdef->name == NULL) {
351 vu_log(VHOSTMD_WARN, "Metric name not specified");
354 if (mdef->action == NULL) {
355 vu_log(VHOSTMD_WARN, "Metric action not specified");
359 vu_log(VHOSTMD_INFO, "Adding %s metric '%s'",
360 mdef->ctx == METRIC_CONTEXT_HOST ? "host" : "vm",
362 vu_log(VHOSTMD_INFO, "\t action: %s", mdef->action);
365 if (mdef->type == M_GROUP) {
366 if (parse_group_metric(xml, ctxt, node, mdef) == -1) {
380 free(mdef->type_str);
389 /* Parse metrics nodes contained in XML doc */
390 static int parse_metrics(xmlDocPtr xml,
391 xmlXPathContextPtr ctxt)
393 xmlXPathObjectPtr obj;
400 vu_log(VHOSTMD_ERR, "Invalid parameter to parse_metrics");
404 relnode = ctxt->node;
406 obj = xmlXPathEval( BAD_CAST "//vhostmd/metrics/metric", ctxt);
407 if ((obj == NULL) || (obj->type != XPATH_NODESET)) {
408 xmlXPathFreeObject(obj);
409 vu_log(VHOSTMD_WARN, "No metrics found or malformed definition");
413 num = xmlXPathNodeSetGetLength(obj->nodesetval);
414 vu_log(VHOSTMD_INFO, "Number of metrics nodes: %d", num);
415 for (i = 0; i < num; i++) {
416 mdef = parse_metric(xml, ctxt, obj->nodesetval->nodeTab[i]);
418 mdef->next = metrics;
422 vu_log(VHOSTMD_WARN, "Unable to parse metric node, ignoring ...");
427 xmlXPathFreeObject(obj);
428 ctxt->node = relnode;
432 static int parse_transports(xmlDocPtr xml,
433 xmlXPathContextPtr ctxt)
435 xmlXPathObjectPtr obj;
443 vu_log(VHOSTMD_ERR, "Invalid parameter to parse_transports");
447 relnode = ctxt->node;
449 obj = xmlXPathEval( BAD_CAST "//vhostmd/globals/transport", ctxt);
450 if ((obj == NULL) || (obj->type != XPATH_NODESET)) {
451 xmlXPathFreeObject(obj);
452 vu_log(VHOSTMD_WARN, "No transport found or malformed definition");
456 num = xmlXPathNodeSetGetLength(obj->nodesetval);
457 for (i = 0; i < num; i++) {
458 cur = obj->nodesetval->nodeTab[i]->xmlChildrenNode;
459 str = xmlNodeListGetString(xml, cur, 1);
461 if (strncasecmp((char *)str, "vbd", strlen("vbd")) == 0)
463 if (strncasecmp((char *)str, "xenstore", strlen("xenstore")) == 0) {
465 transports |= XENSTORE;
467 vu_log (VHOSTMD_ERR, "No support for xenstore transport in this vhostmd");
474 xmlXPathFreeObject(obj);
475 ctxt->node = relnode;
476 /* Should not happen */
483 static int validate_config_file(const char *filename)
485 xmlDocPtr doc = NULL;
486 xmlParserCtxtPtr pctxt = NULL;
487 xmlNode *root_element = NULL;
490 pctxt = xmlNewParserCtxt();
491 if (!pctxt || !pctxt->sax) {
492 vu_log(VHOSTMD_ERR, "%s(): failed to allocate parser context \n", __FUNCTION__);
496 doc = xmlCtxtReadFile(pctxt, filename, NULL, XML_PARSE_DTDVALID);
498 vu_log(VHOSTMD_ERR, "%s(): could not read file:%s \n", __FUNCTION__, filename);
501 if (pctxt->valid == 0) {
502 vu_log(VHOSTMD_ERR, "%s(): Failed to validate :%s \n", __FUNCTION__, filename);
506 root_element = xmlDocGetRootElement(doc);
508 vu_log(VHOSTMD_ERR, "%s(): could not locate root element\n", __FUNCTION__);
512 if (xmlStrncmp((const xmlChar*)"vhostmd", root_element->name, strlen("vhostmd")) != 0) {
513 vu_log(VHOSTMD_ERR, "%s(): Incorrect root element name:%s\n", __FUNCTION__,
521 //xmlFreeNode(root_element);
525 xmlFreeParserCtxt(pctxt);
530 /* Parse vhostmd configuration file */
531 static int parse_config_file(const char *filename)
533 xmlParserCtxtPtr pctxt = NULL;
534 xmlDocPtr xml = NULL;
535 xmlXPathContextPtr ctxt = NULL;
537 //config_file_element *element = NULL;
542 /* Set up a parser context so we can catch the details of XML errors. */
543 pctxt = xmlNewParserCtxt();
544 if (!pctxt || !pctxt->sax)
547 xml = xmlCtxtReadFile(pctxt, filename, NULL,
548 XML_PARSE_NOENT | XML_PARSE_NONET |
549 XML_PARSE_NOWARNING);
551 vu_log(VHOSTMD_ERR, "libxml failed to parse config file %s",
556 if ((root = xmlDocGetRootElement(xml)) == NULL) {
557 vu_log(VHOSTMD_ERR, "Config file %s missing root element",
562 if (!xmlStrEqual(root->name, BAD_CAST "vhostmd")) {
563 vu_log(VHOSTMD_ERR, "Config file contains incorrect root element");
567 ctxt = xmlXPathNewContext(xml);
569 vu_log(VHOSTMD_ERR, "Unable to allocate memory");
575 /* Get global settings */
576 mdisk_path = vu_xpath_string("string(./globals/disk/path[1])", ctxt);
577 if (mdisk_path == NULL)
578 mdisk_path = strdup(def_mdisk_path);
580 unit = vu_xpath_string("string(./globals/disk/size[1]/@unit)", ctxt);
581 if (vu_xpath_long("string(./globals/disk/size[1])", ctxt, &l) == 0) {
582 mdisk_size = vu_val_by_unit(unit, (int)l);
585 vu_log(VHOSTMD_ERR, "Unable to parse metrics disk size");
589 if (vu_xpath_long("string(./globals/update_period[1])", ctxt, &l) == 0) {
590 update_period = (int)l;
593 vu_log(VHOSTMD_ERR, "Unable to parse update period");
597 if ((search_path = vu_xpath_string("string(./globals/path[1])", ctxt)) != NULL) {
598 setenv("PATH", search_path, 1);
601 if (parse_transports(xml, ctxt) == -1) {
602 vu_log(VHOSTMD_ERR, "Unable to parse transports");
606 /* Parse requested metrics definitions */
607 if (parse_metrics(xml, ctxt)) {
608 vu_log(VHOSTMD_ERR, "Unable to parse metrics definition "
609 "in vhostmd config file");
617 xmlXPathFreeContext(ctxt);
619 xmlFreeParserCtxt(pctxt);
623 /**********************************************************************
624 * daemon-specific functions
625 *********************************************************************/
627 /* Ensure valid config settings, returning non-zero of failure */
628 static int check_config(void)
630 /* check valid disk path */
632 vu_log(VHOSTMD_ERR, "Metrics disk path not specified");
636 /* check valid disk size */
637 if (mdisk_size < MDISK_SIZE_MIN || mdisk_size > MDISK_SIZE_MAX) {
638 vu_log(VHOSTMD_ERR, "Specified metrics disk size "
639 "(%d) not within supported range: (%d - %d)",
640 mdisk_size, MDISK_SIZE_MIN, MDISK_SIZE_MAX);
644 /* check valid update period */
645 if (update_period < 1) {
646 vu_log(VHOSTMD_ERR, "Specified update period (%d) less "
647 "than minimum supported (1)",
652 vu_log(VHOSTMD_INFO, "Using metrics disk path %s", mdisk_path);
653 vu_log(VHOSTMD_INFO, "Using metrics disk size %d", mdisk_size);
654 vu_log(VHOSTMD_INFO, "Using update period of %d seconds",
660 static int metrics_disk_busy(int fd, int busy)
662 md_header.busy = (uint32_t)(htonl(busy));
664 lseek(fd, offsetof(mdisk_header, busy), SEEK_SET);
665 write(fd, &(md_header.busy), sizeof(uint32_t));
669 static int metrics_disk_header_update(int fd, vu_buffer *buf)
673 md_header.sig = htonl(MDISK_SIGNATURE);
674 md_header.length = 0;
675 sum = md_header.sum = 0;
678 md_header.length = htonl(buf->use);
679 md_header.sum = sum = htonl(vu_buffer_checksum(buf));
682 if (lseek(fd, offsetof(mdisk_header, sig), SEEK_SET) == -1)
684 if (write(fd, &(md_header.sig), sizeof(uint32_t)) != sizeof(uint32_t)) {
685 vu_log(VHOSTMD_ERR, "Error writing metrics disk header sig: %s",
690 if (lseek(fd, offsetof(mdisk_header, sum), SEEK_SET) == -1)
692 if (write(fd, &sum, sizeof(uint32_t)) != sizeof(uint32_t)) {
693 vu_log(VHOSTMD_ERR, "Error writing metrics disk header sum: %s",
698 if (lseek(fd, offsetof(mdisk_header, length), SEEK_SET) == -1)
700 if (write(fd, &(md_header.length), sizeof(uint32_t)) != sizeof(uint32_t)) {
701 vu_log(VHOSTMD_ERR, "Error writing metrics disk header length: %s",
711 static int metrics_disk_update(int fd, vu_buffer *buf)
713 if (buf->use > MDISK_SIZE) {
714 vu_log(VHOSTMD_ERR, "Metrics data is larger than metrics disk");
718 metrics_disk_busy(fd, 1);
719 metrics_disk_header_update(fd, buf);
720 lseek(fd, MDISK_HEADER_SIZE, SEEK_SET);
721 write(fd, buf->content, buf->use);
722 metrics_disk_busy(fd, 0);
727 static int metrics_free()
748 static void metrics_disk_close(int fd)
760 static int metrics_disk_create(void)
767 int size = mdisk_size - MDISK_HEADER_SIZE;
769 /* create directory */
770 if ((tmp = strrchr(mdisk_path, '/'))) {
771 dir = strndup(mdisk_path, tmp - mdisk_path);
773 vu_log(VHOSTMD_ERR, "Unable to allocate memory");
777 if ((mkdir(dir, 0700) < 0) && (errno != EEXIST)) {
778 vu_log(VHOSTMD_ERR, "Unable to create directory '%s' "
779 "for metrics disk: %s", dir, strerror(errno));
784 /* buffer for zero filling disk to requested size */
785 buf = calloc(1, MDISK_SIZE_MIN);
787 vu_log(VHOSTMD_ERR, "Unable to allocate memory");
792 fd = open(mdisk_path, O_RDWR | O_CREAT | O_TRUNC,
793 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
795 vu_log(VHOSTMD_ERR, "Failed to open metrics disk: %s",
800 /* write header, mark disk as busy */
801 metrics_disk_busy(fd, 1);
802 if (metrics_disk_header_update(fd, NULL)) {
803 vu_log(VHOSTMD_ERR, "Error writing metrics disk header");
807 /* truncate to a possible new size */
808 ftruncate(fd, mdisk_size);
810 /* zero fill metrics data */
811 lseek(fd, MDISK_HEADER_SIZE, SEEK_SET);
812 for (i = 0; i < size / MDISK_SIZE_MIN; i++)
813 if (write(fd, buf, MDISK_SIZE_MIN) != MDISK_SIZE_MIN) {
814 vu_log(VHOSTMD_ERR, "Error creating disk of requested "
815 "size: %s", strerror(errno));
818 if (write(fd, buf, size % MDISK_SIZE_MIN) <
819 size % MDISK_SIZE_MIN ) {
820 vu_log(VHOSTMD_ERR, "Error creating disk of requested "
821 "size: %s", strerror(errno));
836 static int metrics_host_get(vu_buffer *buf)
841 if (m->ctx != METRIC_CONTEXT_HOST) {
846 if (metric_xml(m, buf))
847 vu_log(VHOSTMD_ERR, "Error retrieving metric %s", m->name);
854 static int metrics_vm_get(vu_vm *vm, vu_buffer *buf)
859 if (m->ctx != METRIC_CONTEXT_VM) {
864 if (metric_xml(m, buf))
865 vu_log(VHOSTMD_ERR, "Error retrieving metric %s", m->name);
872 static int metrics_vms_get(vu_buffer *buf, int **ids)
879 num_vms = vu_num_vms();
885 *ids = calloc(num_vms, sizeof(int));
887 vu_log (VHOSTMD_ERR, "calloc: %m");
891 num_vms = vu_get_vms(*ids, num_vms);
892 for (i = 0; i < num_vms; i++) {
895 vm = vu_get_vm((*ids)[i]);
899 metrics_vm_get(vm, buf);
907 /* Main run loop for vhostmd */
908 static int vhostmd_run(int diskfd)
912 vu_buffer *buf = NULL;
914 if (vu_buffer_create(&buf, MDISK_SIZE_MIN - MDISK_HEADER_SIZE)) {
915 vu_log(VHOSTMD_ERR, "Unable to allocate memory");
920 vu_buffer_add(buf, "<metrics>\n", -1);
921 if (metrics_host_get(buf))
922 vu_log(VHOSTMD_ERR, "Failed to collect host metrics "
925 if ((num_vms = metrics_vms_get(buf, &ids)) == -1)
926 vu_log(VHOSTMD_ERR, "Failed to collect vm metrics "
929 vu_buffer_add(buf, "</metrics>\n", -1);
930 if (transports & VBD)
931 metrics_disk_update(diskfd, buf);
933 if (transports & XENSTORE)
934 metrics_xenstore_update(buf->content, ids, num_vms);
938 sleep(update_period);
939 vu_buffer_erase(buf);
941 vu_buffer_delete(buf);
945 static void usage(const char *argv0)
953 -v | --verbose Verbose messages.\n\
954 -c | --connect <uri> Set the libvirt URI.\n\
955 -d | --no-daemonize Process will not daemonize - useful for debugging.\n\
956 -f | --config <file> Configuration file.\n\
957 -p | --pid-file <file> PID file.\n\
958 -u | --user <user> Drop root privs and run as <user>.\n\
960 Host metrics gathering daemon:\n\
965 int main(int argc, char *argv[])
967 struct sigaction sig_action;
968 const char *pfile = NULL;
969 const char *cfile = SYSCONF_DIR "/vhostmd/vhostmd.conf";
971 int no_daemonize = 0;
974 const char *user = NULL;
976 struct option opts[] = {
977 { "verbose", no_argument, &verbose, 1},
978 { "no-daemonize", no_argument, &no_daemonize, 1},
979 { "config", required_argument, NULL, 'f'},
980 { "pid-file", required_argument, NULL, 'p'},
981 { "user", required_argument, NULL, 'u'},
983 { "connect", required_argument, NULL, 'c'},
985 { "help", no_argument, NULL, '?' },
993 c = getopt_long(argc, argv, "c:df:p:u:v", opts, &optidx);
1000 /* Got one of the flags */
1019 libvirt_uri = optarg;
1026 fprintf(stderr, "hostmetricsd: unknown option: %c\n", c);
1031 vu_log_init(no_daemonize, verbose);
1033 if (!no_daemonize) {
1034 if (daemonize() < 0) {
1035 vu_log(VHOSTMD_ERR, "Failed to fork as daemon: %s",
1041 /* If running as root and no PID file is set, use the default */
1042 if (pfile == NULL &&
1044 pid_file[0] != '\0')
1047 /* If we have a pidfile set, claim it now, exiting if already taken */
1048 if (pfile != NULL &&
1049 write_pid_file(pfile) < 0)
1052 sig_action.sa_sigaction = sig_handler;
1053 sig_action.sa_flags = SA_SIGINFO;
1054 sigemptyset(&sig_action.sa_mask);
1056 sigaction(SIGHUP, &sig_action, NULL);
1057 sigaction(SIGINT, &sig_action, NULL);
1058 sigaction(SIGQUIT, &sig_action, NULL);
1059 sigaction(SIGTERM, &sig_action, NULL);
1063 if (validate_config_file(cfile)) {
1065 vu_log(VHOSTMD_ERR, "Config file: %s, fails DTD validation ", cfile);
1069 if (parse_config_file(cfile)) {
1071 vu_log(VHOSTMD_ERR, "Please ensure configuration file "
1072 "%s exists and is valid", cfile);
1078 if (check_config()) {
1079 vu_log(VHOSTMD_ERR, "Configuration file %s contains invalid "
1080 "setting(s)", cfile);
1085 if (xen_metrics(&metrics)) {
1086 vu_log(VHOSTMD_ERR, "Unable to load xen specific metrics, ignoring");
1090 if ((mdisk_fd = metrics_disk_create()) < 0) {
1091 vu_log(VHOSTMD_ERR, "Failed to create metrics disk %s", mdisk_path);
1095 /* Drop root privileges if requested. Note: We do this after
1096 * opening the metrics disk, parsing the config file, etc.
1102 pw = getpwnam (user);
1104 vu_log (VHOSTMD_ERR, "No entry in password file for user %s: %m",
1109 if (pw->pw_uid == 0 || pw->pw_gid == 0) {
1110 vu_log (VHOSTMD_ERR, "Cannot switch to root using the '-u' command line flag.");
1114 if (setgid (pw->pw_gid) == -1) {
1115 vu_log (VHOSTMD_ERR, "setgid: %d: %m", pw->pw_gid);
1119 if (initgroups (user, pw->pw_gid) == -1) {
1120 vu_log (VHOSTMD_ERR, "initgroups: %m");
1124 if (setuid (pw->pw_uid) == -1) {
1125 vu_log (VHOSTMD_ERR, "setuid: %d: %m", pw->pw_uid);
1129 vu_log (VHOSTMD_INFO, "Switched to uid:gid %d:%d",
1130 pw->pw_uid, pw->pw_gid);
1133 ret = vhostmd_run(mdisk_fd);
1136 metrics_disk_close(mdisk_fd);
1141 vu_vm_connect_close();