diff options
Diffstat (limited to 'daemons/dmeventd/libdevmapper-event.c')
-rw-r--r-- | daemons/dmeventd/libdevmapper-event.c | 484 |
1 files changed, 307 insertions, 177 deletions
diff --git a/daemons/dmeventd/libdevmapper-event.c b/daemons/dmeventd/libdevmapper-event.c index 1f8fbef..b5ae37f 100644 --- a/daemons/dmeventd/libdevmapper-event.c +++ b/daemons/dmeventd/libdevmapper-event.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * @@ -9,27 +9,28 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "dmlib.h" #include "libdevmapper-event.h" -//#include "libmultilog.h" #include "dmeventd.h" +#include "libdm/misc/dm-logging.h" +#include "base/memory/zalloc.h" + +#include "lib/misc/intl.h" -#include <errno.h> #include <fcntl.h> -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> #include <sys/file.h> #include <sys/types.h> #include <sys/stat.h> -#include <unistd.h> #include <sys/wait.h> #include <arpa/inet.h> /* for htonl, ntohl */ +#include <pthread.h> +#include <syslog.h> +#include <unistd.h> +static int _debug_level = 0; +static int _use_syslog = 0; static int _sequence_nr = 0; struct dm_event_handler { @@ -49,17 +50,17 @@ struct dm_event_handler { static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh) { - dm_free(dmevh->dev_name); - dm_free(dmevh->uuid); + free(dmevh->dev_name); + free(dmevh->uuid); dmevh->dev_name = dmevh->uuid = NULL; dmevh->major = dmevh->minor = 0; } struct dm_event_handler *dm_event_handler_create(void) { - struct dm_event_handler *dmevh = NULL; + struct dm_event_handler *dmevh; - if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) { + if (!(dmevh = zalloc(sizeof(*dmevh)))) { log_error("Failed to allocate event handler."); return NULL; } @@ -70,9 +71,9 @@ struct dm_event_handler *dm_event_handler_create(void) void dm_event_handler_destroy(struct dm_event_handler *dmevh) { _dm_event_handler_clear_dev_info(dmevh); - dm_free(dmevh->dso); - dm_free(dmevh->dmeventd_path); - dm_free(dmevh); + free(dmevh->dso); + free(dmevh->dmeventd_path); + free(dmevh); } int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path) @@ -80,10 +81,9 @@ int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const cha if (!dmeventd_path) /* noop */ return 0; - dm_free(dmevh->dmeventd_path); + free(dmevh->dmeventd_path); - dmevh->dmeventd_path = dm_strdup(dmeventd_path); - if (!dmevh->dmeventd_path) + if (!(dmevh->dmeventd_path = strdup(dmeventd_path))) return -ENOMEM; return 0; @@ -93,10 +93,10 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path) { if (!path) /* noop */ return 0; - dm_free(dmevh->dso); - dmevh->dso = dm_strdup(path); - if (!dmevh->dso) + free(dmevh->dso); + + if (!(dmevh->dso = strdup(path))) return -ENOMEM; return 0; @@ -109,9 +109,9 @@ int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *de _dm_event_handler_clear_dev_info(dmevh); - dmevh->dev_name = dm_strdup(dev_name); - if (!dmevh->dev_name) + if (!(dmevh->dev_name = strdup(dev_name))) return -ENOMEM; + return 0; } @@ -122,9 +122,9 @@ int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid) _dm_event_handler_clear_dev_info(dmevh); - dmevh->uuid = dm_strdup(uuid); - if (!dmevh->uuid) + if (!(dmevh->uuid = strdup(uuid))) return -ENOMEM; + return 0; } @@ -201,7 +201,7 @@ static int _check_message_id(struct dm_event_daemon_message *msg) if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) || (pid != getpid()) || (seq_nr != _sequence_nr)) { log_error("Ignoring out-of-sequence reply from dmeventd. " - "Expected %d:%d but received %s", getpid(), + "Expected %d:%d but received %s.", getpid(), _sequence_nr, msg->data); return 0; } @@ -224,7 +224,6 @@ static int _daemon_read(struct dm_event_fifos *fifos, unsigned bytes = 0; int ret, i; fd_set fds; - struct timeval tval = { 0, 0 }; size_t size = 2 * sizeof(uint32_t); /* status + size */ uint32_t *header = alloca(size); char *buf = (char *)header; @@ -232,66 +231,69 @@ static int _daemon_read(struct dm_event_fifos *fifos, while (bytes < size) { for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) { /* Watch daemon read FIFO for input. */ + struct timeval tval = { .tv_sec = 1 }; FD_ZERO(&fds); FD_SET(fifos->server, &fds); - tval.tv_sec = 1; - ret = select(fifos->server + 1, &fds, NULL, NULL, - &tval); + ret = select(fifos->server + 1, &fds, NULL, NULL, &tval); if (ret < 0 && errno != EINTR) { - log_error("Unable to read from event server"); - return 0; + log_error("Unable to read from event server."); + goto bad; } if ((ret == 0) && (i > 4) && !bytes) { log_error("No input from event server."); - return 0; + goto bad; } } if (ret < 1) { log_error("Unable to read from event server."); - return 0; + goto bad; } ret = read(fifos->server, buf + bytes, size); if (ret < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; - else { - log_error("Unable to read from event server."); - return 0; - } + + log_error("Unable to read from event server."); + goto bad; } bytes += ret; - if (header && (bytes == 2 * sizeof(uint32_t))) { + if (!msg->data && (bytes == 2 * sizeof(uint32_t))) { msg->cmd = ntohl(header[0]); - msg->size = ntohl(header[1]); - buf = msg->data = dm_malloc(msg->size); - size = msg->size; bytes = 0; - header = 0; + + if (!(size = msg->size = ntohl(header[1]))) + break; + + if (!(buf = msg->data = malloc(msg->size))) { + log_error("Unable to allocate message data."); + return 0; + } } } - if (bytes != size) { - dm_free(msg->data); - msg->data = NULL; - } - return bytes == size; + if (bytes == size) + return 1; + +bad: + free(msg->data); + msg->data = NULL; + + return 0; } /* Write message to daemon. */ static int _daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg) { - unsigned bytes = 0; - int ret = 0; + int ret; fd_set fds; - + size_t bytes = 0; size_t size = 2 * sizeof(uint32_t) + msg->size; uint32_t *header = alloca(size); char *buf = (char *)header; char drainbuf[128]; - struct timeval tval = { 0, 0 }; header[0] = htonl(msg->cmd); header[1] = htonl(msg->size); @@ -299,17 +301,25 @@ static int _daemon_write(struct dm_event_fifos *fifos, /* drain the answer fifo */ while (1) { + struct timeval tval = { .tv_usec = 100 }; FD_ZERO(&fds); FD_SET(fifos->server, &fds); - tval.tv_usec = 100; ret = select(fifos->server + 1, &fds, NULL, NULL, &tval); - if ((ret < 0) && (errno != EINTR)) { - log_error("Unable to talk to event daemon"); + if (ret < 0) { + if (errno == EINTR) + continue; + log_error("Unable to talk to event daemon."); return 0; } if (ret == 0) break; - ret = read(fifos->server, drainbuf, 127); + ret = read(fifos->server, drainbuf, sizeof(drainbuf)); + if (ret < 0) { + if ((errno == EINTR) || (errno == EAGAIN)) + continue; + log_error("Unable to talk to event daemon."); + return 0; + } } while (bytes < size) { @@ -319,7 +329,7 @@ static int _daemon_write(struct dm_event_fifos *fifos, FD_SET(fifos->client, &fds); ret = select(fifos->client + 1, NULL, &fds, NULL, NULL); if ((ret < 0) && (errno != EINTR)) { - log_error("Unable to talk to event daemon"); + log_error("Unable to talk to event daemon."); return 0; } } while (ret < 1); @@ -328,10 +338,9 @@ static int _daemon_write(struct dm_event_fifos *fifos, if (ret < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; - else { - log_error("Unable to talk to event daemon"); - return 0; - } + + log_error("Unable to talk to event daemon."); + return 0; } bytes += ret; @@ -345,9 +354,6 @@ int daemon_talk(struct dm_event_fifos *fifos, const char *dso_name, const char *dev_name, enum dm_event_mask evmask, uint32_t timeout) { - const char *dso = dso_name ? dso_name : "-"; - const char *dev = dev_name ? dev_name : "-"; - const char *fmt = "%d:%d %s %s %u %" PRIu32; int msg_size; memset(msg, 0, sizeof(*msg)); @@ -355,14 +361,17 @@ int daemon_talk(struct dm_event_fifos *fifos, * Set command and pack the arguments * into ASCII message string. */ - msg->cmd = cmd; - if (cmd == DM_EVENT_CMD_HELLO) - fmt = "%d:%d HELLO"; - if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr, - dso, dev, evmask, timeout)) < 0) { - log_error("_daemon_talk: message allocation failed"); + if ((msg_size = + ((cmd == DM_EVENT_CMD_HELLO) ? + dm_asprintf(&(msg->data), "%d:%d HELLO", getpid(), _sequence_nr) : + dm_asprintf(&(msg->data), "%d:%d %s %s %u %" PRIu32, + getpid(), _sequence_nr, + dso_name ? : "-", dev_name ? : "-", evmask, timeout))) + < 0) { + log_error("_daemon_talk: message allocation failed."); return -ENOMEM; } + msg->cmd = cmd; msg->size = msg_size; /* @@ -371,15 +380,14 @@ int daemon_talk(struct dm_event_fifos *fifos, */ if (!_daemon_write(fifos, msg)) { stack; - dm_free(msg->data); - msg->data = 0; + free(msg->data); + msg->data = NULL; return -EIO; } do { - - dm_free(msg->data); - msg->data = 0; + free(msg->data); + msg->data = NULL; if (!_daemon_read(fifos, msg)) { stack; @@ -412,28 +420,56 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos) char default_dmeventd_path[] = DMEVENTD_PATH; char *args[] = { dmeventd_path ? : default_dmeventd_path, NULL }; - if (stat(fifos->client_path, &statbuf)) - goto start_server; + /* + * FIXME Explicitly verify the code's requirement that client_path is secure: + * - All parent directories owned by root without group/other write access unless sticky. + */ - if (!S_ISFIFO(statbuf.st_mode)) { - log_error("%s is not a fifo.", fifos->client_path); + /* If client fifo path exists, only use it if it is root-owned fifo mode 0600 */ + if ((lstat(fifos->client_path, &statbuf) < 0)) { + if (errno == ENOENT) + /* Jump ahead if fifo does not already exist. */ + goto start_server; + else { + log_sys_error("stat", fifos->client_path); + return 0; + } + } else if (!S_ISFIFO(statbuf.st_mode)) { + log_error("%s must be a fifo.", fifos->client_path); + return 0; + } else if (statbuf.st_uid) { + log_error("%s must be owned by uid 0.", fifos->client_path); + return 0; + } else if (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO)) { + log_error("%s must have mode 0600.", fifos->client_path); return 0; } /* Anyone listening? If not, errno will be ENXIO */ fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK); if (fifos->client >= 0) { + /* Should never happen if all the above checks passed. */ + if ((fstat(fifos->client, &statbuf) < 0) || + !S_ISFIFO(statbuf.st_mode) || statbuf.st_uid || + (statbuf.st_mode & (S_IEXEC | S_IRWXG | S_IRWXO))) { + log_error("%s is no longer a secure root-owned fifo with mode 0600.", fifos->client_path); + if (close(fifos->client)) + log_sys_debug("close", fifos->client_path); + return 0; + } + /* server is running and listening */ if (close(fifos->client)) - log_sys_error("close", fifos->client_path); + log_sys_debug("close", fifos->client_path); return 1; - } else if (errno != ENXIO) { + } + if (errno != ENXIO && errno != ENOENT) { /* problem */ log_sys_error("open", fifos->client_path); return 0; } - start_server: +start_server: /* server is not running */ if ((args[0][0] == '/') && stat(args[0], &statbuf)) { @@ -448,11 +484,11 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos) else if (!pid) { execvp(args[0], args); - log_error("Unable to exec dmeventd: %s", strerror(errno)); + log_error("Unable to exec dmeventd: %s.", strerror(errno)); _exit(EXIT_FAILURE); } else { if (waitpid(pid, &status, 0) < 0) - log_error("Unable to start dmeventd: %s", + log_error("Unable to start dmeventd: %s.", strerror(errno)); else if (WEXITSTATUS(status)) log_error("Unable to start dmeventd."); @@ -468,10 +504,6 @@ int init_fifos(struct dm_event_fifos *fifos) /* FIXME? Is fifo the most suitable method? Why not share comms/daemon code with something else e.g. multipath? */ - /* FIXME Make these either configurable or depend directly on dmeventd_path */ - fifos->client_path = DM_EVENT_FIFO_CLIENT; - fifos->server_path = DM_EVENT_FIFO_SERVER; - /* Open the fifo used to read from the daemon. */ if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) { log_sys_error("open", fifos->server_path); @@ -481,32 +513,27 @@ int init_fifos(struct dm_event_fifos *fifos) /* Lock out anyone else trying to do communication with the daemon. */ if (flock(fifos->server, LOCK_EX) < 0) { log_sys_error("flock", fifos->server_path); - if (close(fifos->server)) - log_sys_error("close", fifos->server_path); - return 0; + goto bad; } /* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/ if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) { log_sys_error("open", fifos->client_path); - if (close(fifos->server)) - log_sys_error("close", fifos->server_path); - return 0; + goto bad; } return 1; +bad: + if (close(fifos->server)) + log_sys_debug("close", fifos->server_path); + fifos->server = -1; + + return 0; } /* Initialize client. */ static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos) { - /* init fifos */ - memset(fifos, 0, sizeof(*fifos)); - - /* FIXME Make these either configurable or depend directly on dmeventd_path */ - fifos->client_path = DM_EVENT_FIFO_CLIENT; - fifos->server_path = DM_EVENT_FIFO_SERVER; - if (!_start_daemon(dmeventd_path, fifos)) return_0; @@ -515,13 +542,16 @@ static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos) void fini_fifos(struct dm_event_fifos *fifos) { - if (flock(fifos->server, LOCK_UN)) - log_error("flock unlock %s", fifos->server_path); + if (fifos->client >= 0 && close(fifos->client)) + log_sys_debug("close", fifos->client_path); - if (close(fifos->client)) - log_sys_error("close", fifos->client_path); - if (close(fifos->server)) - log_sys_error("close", fifos->server_path); + if (fifos->server >= 0) { + if (flock(fifos->server, LOCK_UN)) + log_sys_debug("flock unlock", fifos->server_path); + + if (close(fifos->server)) + log_sys_debug("close", fifos->server_path); + } } /* Get uuid of a device */ @@ -531,7 +561,7 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh) struct dm_info info; if (!(dmt = dm_task_create(DM_DEVICE_INFO))) { - log_error("_get_device_info: dm_task creation for info failed"); + log_error("_get_device_info: dm_task creation for info failed."); return NULL; } @@ -549,19 +579,19 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh) /* FIXME Add name or uuid or devno to messages */ if (!dm_task_run(dmt)) { - log_error("_get_device_info: dm_task_run() failed"); + log_error("_get_device_info: dm_task_run() failed."); goto bad; } if (!dm_task_get_info(dmt, &info)) { - log_error("_get_device_info: failed to get info for device"); + log_error("_get_device_info: failed to get info for device."); goto bad; } if (!info.exists) { - log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found", - dmevh->uuid ? : "", - (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "", + log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found.", + dmevh->uuid ? : "", + (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "", (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "", (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? dmevh->major : 0, (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ":" : "", @@ -571,7 +601,6 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh) goto bad; } - return dmt; bad: @@ -585,21 +614,27 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag enum dm_event_mask evmask, uint32_t timeout) { int ret; - struct dm_event_fifos fifos; + struct dm_event_fifos fifos = { + .client = -1, + .server = -1, + /* FIXME Make these either configurable or depend directly on dmeventd_path */ + .client_path = DM_EVENT_FIFO_CLIENT, + .server_path = DM_EVENT_FIFO_SERVER + }; if (!_init_client(dmeventd_path, &fifos)) { - stack; - return -ESRCH; + ret = -ESRCH; + goto_out; } ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0); - dm_free(msg->data); + free(msg->data); msg->data = 0; if (!ret) ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout); - +out: /* what is the opposite of init? */ fini_fifos(&fifos); @@ -612,24 +647,30 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh) int ret = 1, err; const char *uuid; struct dm_task *dmt; - struct dm_event_daemon_message msg = { 0, 0, NULL }; + struct dm_event_daemon_message msg = { 0 }; - if (!(dmt = _get_device_info(dmevh))) { - stack; - return 0; - } + if (!(dmt = _get_device_info(dmevh))) + return_0; uuid = dm_task_get_uuid(dmt); + if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") && + !strstr(dmevh->dso, "libdevmapper-event-lvm2vdo.so") && + !strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") && + !strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") && + !strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so")) + log_warn("WARNING: %s: dmeventd plugins are deprecated.", dmevh->dso); + + if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg, dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { - log_error("%s: event registration failed: %s", + log_error("%s: event registration failed: %s.", dm_task_get_name(dmt), msg.data ? msg.data : strerror(-err)); ret = 0; } - dm_free(msg.data); + free(msg.data); dm_task_destroy(dmt); @@ -641,24 +682,22 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh) int ret = 1, err; const char *uuid; struct dm_task *dmt; - struct dm_event_daemon_message msg = { 0, 0, NULL }; + struct dm_event_daemon_message msg = { 0 }; - if (!(dmt = _get_device_info(dmevh))) { - stack; - return 0; - } + if (!(dmt = _get_device_info(dmevh))) + return_0; uuid = dm_task_get_uuid(dmt); if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg, dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { - log_error("%s: event deregistration failed: %s", + log_error("%s: event deregistration failed: %s.", dm_task_get_name(dmt), msg.data ? msg.data : strerror(-err)); ret = 0; } - dm_free(msg.data); + free(msg.data); dm_task_destroy(dmt); @@ -670,15 +709,11 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh) static char *_fetch_string(char **src, const int delimiter) { char *p, *ret; + size_t len = (p = strchr(*src, delimiter)) ? + (size_t)(p - *src) : strlen(*src); - if ((p = strchr(*src, delimiter))) - *p = 0; - - if ((ret = dm_strdup(*src))) - *src += strlen(ret) + 1; - - if (p) - *p = delimiter; + if ((ret = strndup(*src, len))) + *src += len + 1; return ret; } @@ -687,20 +722,18 @@ static char *_fetch_string(char **src, const int delimiter) static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name, char **uuid, enum dm_event_mask *evmask) { - char *id = NULL; + char *id; char *p = msg->data; if ((id = _fetch_string(&p, ' ')) && (*dso_name = _fetch_string(&p, ' ')) && (*uuid = _fetch_string(&p, ' '))) { *evmask = atoi(p); - - dm_free(id); + free(id); return 0; } - if (id) - dm_free(id); + free(id); return -ENOMEM; } @@ -714,21 +747,24 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) char *reply_dso = NULL, *reply_uuid = NULL; enum dm_event_mask reply_mask = 0; struct dm_task *dmt = NULL; - struct dm_event_daemon_message msg = { 0, 0, NULL }; + struct dm_event_daemon_message msg = { 0 }; struct dm_info info; if (!(dmt = _get_device_info(dmevh))) { - stack; - return 0; + log_debug("Device does not exists (uuid=%s, name=%s, %d:%d).", + dmevh->uuid, dmevh->dev_name, + dmevh->major, dmevh->minor); + ret = -ENODEV; + goto fail; } uuid = dm_task_get_uuid(dmt); - if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE : - DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path, - &msg, dmevh->dso, uuid, dmevh->mask, 0)) { + /* FIXME Distinguish errors connecting to daemon */ + if ((ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE : + DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path, + &msg, dmevh->dso, uuid, dmevh->mask, 0))) { log_debug("%s: device not registered.", dm_task_get_name(dmt)); - ret = -ENOENT; goto fail; } @@ -739,7 +775,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) dm_task_destroy(dmt); dmt = NULL; - dm_free(msg.data); + free(msg.data); msg.data = NULL; _dm_event_handler_clear_dev_info(dmevh); @@ -747,8 +783,8 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */ goto fail; } - dmevh->uuid = dm_strdup(reply_uuid); - if (!dmevh->uuid) { + + if (!(dmevh->uuid = strdup(reply_uuid))) { ret = -ENOMEM; goto fail; } @@ -761,14 +797,13 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) dm_event_handler_set_dso(dmevh, reply_dso); dm_event_handler_set_event_mask(dmevh, reply_mask); - dm_free(reply_dso); + free(reply_dso); reply_dso = NULL; - dm_free(reply_uuid); + free(reply_uuid); reply_uuid = NULL; - dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)); - if (!dmevh->dev_name) { + if (!(dmevh->dev_name = strdup(dm_task_get_name(dmt)))) { ret = -ENOMEM; goto fail; } @@ -786,9 +821,9 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) return ret; fail: - dm_free(msg.data); - dm_free(reply_dso); - dm_free(reply_uuid); + free(msg.data); + free(reply_dso); + free(reply_uuid); _dm_event_handler_clear_dev_info(dmevh); if (dmt) dm_task_destroy(dmt); @@ -808,23 +843,116 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next) int dm_event_get_version(struct dm_event_fifos *fifos, int *version) { char *p; - struct dm_event_daemon_message msg = { 0, 0, NULL }; + struct dm_event_daemon_message msg = { 0 }; if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)) return 0; p = msg.data; *version = 0; - p = strchr(p, ' '); /* Message ID */ - if (!p) return 0; - p = strchr(p + 1, ' '); /* HELLO */ - if (!p) return 0; - p = strchr(p + 1, ' '); /* HELLO, once more */ - if (p) + if (!p || !(p = strchr(p, ' '))) /* Message ID */ + return 0; + if (!(p = strchr(p + 1, ' '))) /* HELLO */ + return 0; + if ((p = strchr(p + 1, ' '))) /* HELLO, once more */ *version = atoi(p); + return 1; } +void dm_event_log_set(int debug_log_level, int use_syslog) +{ + _debug_level = debug_log_level; + _use_syslog = use_syslog; +} + +void dm_event_log(const char *subsys, int level, const char *file, + int line, int dm_errno_or_class, + const char *format, va_list ap) +{ + static int _abort_on_internal_errors = -1; + static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER; + static time_t start = 0; + const char *indent = ""; + FILE *stream = log_stderr(level) ? stderr : stdout; + int prio; + time_t now; + int log_with_debug = 0; + + if (subsys[0] == '#') { + /* Subsystems starting with '#' are logged + * only when debugging is enabled. */ + log_with_debug++; + subsys++; + } + + switch (log_level(level)) { + case _LOG_DEBUG: + /* Never shown without -ddd */ + if (_debug_level < 3) + return; + prio = LOG_DEBUG; + indent = " "; + break; + case _LOG_INFO: + if (log_with_debug && _debug_level < 2) + return; + prio = LOG_INFO; + indent = " "; + break; + case _LOG_NOTICE: + if (log_with_debug && _debug_level < 1) + return; + prio = LOG_NOTICE; + indent = " "; + break; + case _LOG_WARN: + prio = LOG_WARNING; + break; + case _LOG_ERR: + prio = LOG_ERR; + stream = stderr; + break; + default: + prio = LOG_CRIT; + } + + /* Serialize to keep lines readable */ + pthread_mutex_lock(&_log_mutex); + + if (_use_syslog) { + vsyslog(prio, format, ap); + } else { + now = time(NULL); + if (!start) + start = now; + now -= start; + if (_debug_level) + fprintf(stream, "[%2lld:%02lld] %8x:%-6s%s", + (long long)now / 60, (long long)now % 60, + // TODO: Maybe use shorter ID + // ((int)(pthread_self()) >> 6) & 0xffff, + (int)pthread_self(), subsys, + (_debug_level > 3) ? "" : indent); + if (_debug_level > 3) + fprintf(stream, "%28s:%4d %s", file, line, indent); + vfprintf(stream, _(format), ap); + fputc('\n', stream); + fflush(stream); + } + + pthread_mutex_unlock(&_log_mutex); + + if (_abort_on_internal_errors < 0) + /* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */ + _abort_on_internal_errors = + strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0"); + + if (_abort_on_internal_errors && + !strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1)) + abort(); +} + #if 0 /* left out for now */ static char *_skip_string(char *src, const int delimiter) @@ -837,7 +965,7 @@ static char *_skip_string(char *src, const int delimiter) int dm_event_set_timeout(const char *device_path, uint32_t timeout) { - struct dm_event_daemon_message msg = { 0, 0, NULL }; + struct dm_event_daemon_message msg = { 0 }; if (!device_exists(device_path)) return -ENODEV; @@ -849,22 +977,24 @@ int dm_event_set_timeout(const char *device_path, uint32_t timeout) int dm_event_get_timeout(const char *device_path, uint32_t *timeout) { int ret; - struct dm_event_daemon_message msg = { 0, 0, NULL }; + struct dm_event_daemon_message msg = { 0 }; if (!device_exists(device_path)) return -ENODEV; + if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path, 0, 0))) { char *p = _skip_string(msg.data, ' '); if (!p) { - log_error("malformed reply from dmeventd '%s'\n", + log_error("Malformed reply from dmeventd '%s'.", msg.data); + free(msg.data); return -EIO; } *timeout = atoi(p); } - if (msg.data) - dm_free(msg.data); + free(msg.data); + return ret; } #endif |