📄 libdevmapper-event.c
字号:
/* * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * 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 */#include "lib.h"#include "libdevmapper-event.h"//#include "libmultilog.h"#include "dmeventd.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 */static int _sequence_nr = 0;struct dm_event_handler { char *dso; char *dev_name; char *uuid; int major; int minor; uint32_t timeout; enum dm_event_mask mask;};static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh){ if (dmevh->dev_name) dm_free(dmevh->dev_name); if (dmevh->uuid) dm_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; if (!(dmevh = dm_malloc(sizeof(*dmevh)))) return NULL; dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL; dmevh->major = dmevh->minor = 0; dmevh->mask = 0; dmevh->timeout = 0; return dmevh;}void dm_event_handler_destroy(struct dm_event_handler *dmevh){ _dm_event_handler_clear_dev_info(dmevh); if (dmevh->dso) dm_free(dmevh->dso); dm_free(dmevh);}int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path){ if (!path) /* noop */ return 0; if (dmevh->dso) dm_free(dmevh->dso); dmevh->dso = dm_strdup(path); if (!dmevh->dso) return -ENOMEM; return 0;}int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name){ if (!dev_name) return 0; _dm_event_handler_clear_dev_info(dmevh); dmevh->dev_name = dm_strdup(dev_name); if (!dmevh->dev_name) return -ENOMEM; return 0;}int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid){ if (!uuid) return 0; _dm_event_handler_clear_dev_info(dmevh); dmevh->uuid = dm_strdup(uuid); if (!dmevh->dev_name) return -ENOMEM; return 0;}void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major){ int minor = dmevh->minor; _dm_event_handler_clear_dev_info(dmevh); dmevh->major = major; dmevh->minor = minor;}void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor){ int major = dmevh->major; _dm_event_handler_clear_dev_info(dmevh); dmevh->major = major; dmevh->minor = minor;}void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh, enum dm_event_mask evmask){ dmevh->mask = evmask;}void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout){ dmevh->timeout = timeout;}const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh){ return dmevh->dso;}const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh){ return dmevh->dev_name;}const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh){ return dmevh->uuid;}int dm_event_handler_get_major(const struct dm_event_handler *dmevh){ return dmevh->major;}int dm_event_handler_get_minor(const struct dm_event_handler *dmevh){ return dmevh->minor;}int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh){ return dmevh->timeout;}enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh){ return dmevh->mask;}static int _check_message_id(struct dm_event_daemon_message *msg){ int pid, seq_nr; 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(), _sequence_nr, msg->data); return 0; } return 1;}/* * daemon_read * @fifos * @msg * * Read message from daemon. * * Returns: 0 on failure, 1 on success */static int _daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg){ unsigned bytes = 0; int ret, i; fd_set fds; struct timeval tval = { 0, 0 }; size_t size = 2 * sizeof(uint32_t); /* status + size */ char *buf = alloca(size); int header = 1; while (bytes < size) { for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) { /* Watch daemon read FIFO for input. */ FD_ZERO(&fds); FD_SET(fifos->server, &fds); tval.tv_sec = 1; ret = select(fifos->server + 1, &fds, NULL, NULL, &tval); if (ret < 0 && errno != EINTR) { log_error("Unable to read from event server"); return 0; } } if (ret < 1) { log_error("Unable to read from event server."); return 0; } 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; } } bytes += ret; if (bytes == 2 * sizeof(uint32_t) && header) { msg->cmd = ntohl(*((uint32_t *)buf)); msg->size = ntohl(*((uint32_t *)buf + 1)); buf = msg->data = dm_malloc(msg->size); size = msg->size; bytes = 0; header = 0; } } if (bytes != size) { if (msg->data) dm_free(msg->data); msg->data = NULL; } return bytes == size;}/* 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; fd_set fds; size_t size = 2 * sizeof(uint32_t) + msg->size; char *buf = alloca(size); char drainbuf[128]; struct timeval tval = { 0, 0 }; *((uint32_t *)buf) = htonl(msg->cmd); *((uint32_t *)buf + 1) = htonl(msg->size); memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size); /* drain the answer fifo */ while (1) { 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"); return 0; } if (ret == 0) break; read(fifos->server, drainbuf, 127); } while (bytes < size) { do { /* Watch daemon write FIFO to be ready for output. */ FD_ZERO(&fds); 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"); return 0; } } while (ret < 1); ret = write(fifos->client, ((char *) buf) + bytes, size - bytes); if (ret < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else { log_error("Unable to talk to event daemon"); return 0; } } bytes += ret; } return bytes == size;}static int _daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg, int cmd, 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)); /* * 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"); return -ENOMEM; } msg->size = msg_size; /* * Write command and message to and * read status return code from daemon. */ if (!_daemon_write(fifos, msg)) { stack; dm_free(msg->data); msg->data = 0; return -EIO; } do { if (msg->data) dm_free(msg->data); msg->data = 0; if (!_daemon_read(fifos, msg)) { stack; return -EIO; } } while (!_check_message_id(msg)); _sequence_nr++; return (int32_t) msg->cmd;}/* * start_daemon * * This function forks off a process (dmeventd) that will handle * the events. I am currently test opening one of the fifos to * ensure that the daemon is running and listening... I thought * this would be less expensive than fork/exec'ing every time. * Perhaps there is an even quicker/better way (no, checking the * lock file is _not_ a better way). * * Returns: 1 on success, 0 otherwise */static int _start_daemon(struct dm_event_fifos *fifos){ int pid, ret = 0; int status; struct stat statbuf; if (stat(fifos->client_path, &statbuf)) goto start_server;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -