📄 libdevmapper-event.c
字号:
if (!S_ISFIFO(statbuf.st_mode)) { log_error("%s is not a fifo.", 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) { /* server is running and listening */ close(fifos->client); return 1; } else if (errno != ENXIO) { /* problem */ log_error("%s: Can't open client fifo %s: %s", __func__, fifos->client_path, strerror(errno)); stack; return 0; } start_server: /* server is not running */ pid = fork(); if (pid < 0) log_error("Unable to fork."); else if (!pid) { execvp(DMEVENTD_PATH, NULL); exit(EXIT_FAILURE); } else { if (waitpid(pid, &status, 0) < 0) log_error("Unable to start dmeventd: %s", strerror(errno)); else if (WEXITSTATUS(status)) log_error("Unable to start dmeventd."); else ret = 1; } return ret;}/* Initialize client. */static int _init_client(struct dm_event_fifos *fifos){ /* FIXME? Is fifo the most suitable method? Why not share comms/daemon code with something else e.g. multipath? */ /* init fifos */ memset(fifos, 0, sizeof(*fifos)); fifos->client_path = DM_EVENT_FIFO_CLIENT; fifos->server_path = DM_EVENT_FIFO_SERVER; if (!_start_daemon(fifos)) { stack; return 0; } /* Open the fifo used to read from the daemon. */ if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) { log_error("%s: open server fifo %s", __func__, fifos->server_path); stack; return 0; } /* Lock out anyone else trying to do communication with the daemon. */ if (flock(fifos->server, LOCK_EX) < 0) { log_error("%s: flock %s", __func__, fifos->server_path); close(fifos->server); return 0; }/* 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_error("%s: Can't open client fifo %s: %s", __func__, fifos->client_path, strerror(errno)); close(fifos->server); stack; return 0; } return 1;}static void _dtr_client(struct dm_event_fifos *fifos){ if (flock(fifos->server, LOCK_UN)) log_error("flock unlock %s", fifos->server_path); close(fifos->client); close(fifos->server);}/* Get uuid of a device */static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh){ struct dm_task *dmt; struct dm_info info; if (!(dmt = dm_task_create(DM_DEVICE_INFO))) { log_error("_get_device_info: dm_task creation for info failed"); return NULL; } if (dmevh->uuid) dm_task_set_uuid(dmt, dmevh->uuid); else if (dmevh->dev_name) dm_task_set_name(dmt, dmevh->dev_name); else if (dmevh->major && dmevh->minor) { dm_task_set_major(dmt, dmevh->major); dm_task_set_minor(dmt, dmevh->minor); } /* FIXME Add name or uuid or devno to messages */ if (!dm_task_run(dmt)) { log_error("_get_device_info: dm_task_run() failed"); goto failed; } if (!dm_task_get_info(dmt, &info)) { log_error("_get_device_info: failed to get info for device"); goto failed; } if (!info.exists) { log_error("_get_device_info: device not found"); goto failed; } return dmt;failed: dm_task_destroy(dmt); return NULL;}/* Handle the event (de)registration call and return negative error codes. */static int _do_event(int cmd, struct dm_event_daemon_message *msg, const char *dso_name, const char *dev_name, enum dm_event_mask evmask, uint32_t timeout){ int ret; struct dm_event_fifos fifos; if (!_init_client(&fifos)) { stack; return -ESRCH; } ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0); if (msg->data) dm_free(msg->data); msg->data = 0; if (!ret) ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout); /* what is the opposite of init? */ _dtr_client(&fifos); return ret;}/* External library interface. */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 }; if (!(dmt = _get_device_info(dmevh))) { stack; return 0; } uuid = dm_task_get_uuid(dmt); if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg, dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { log_error("%s: event registration failed: %s", dm_task_get_name(dmt), msg.data ? msg.data : strerror(-err)); ret = 0; } if (msg.data) dm_free(msg.data); dm_task_destroy(dmt); return ret;}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 }; if (!(dmt = _get_device_info(dmevh))) { stack; return 0; } uuid = dm_task_get_uuid(dmt); if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg, dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) { log_error("%s: event deregistration failed: %s", dm_task_get_name(dmt), msg.data ? msg.data : strerror(-err)); ret = 0; } if (msg.data) dm_free(msg.data); dm_task_destroy(dmt); return ret;}/* Fetch a string off src and duplicate it into *dest. *//* FIXME: move to separate module to share with the daemon. */static char *_fetch_string(char **src, const int delimiter){ char *p, *ret; if ((p = strchr(*src, delimiter))) *p = 0; if ((ret = dm_strdup(*src))) *src += strlen(ret) + 1; if (p) *p = delimiter; return ret;}/* Parse a device message from the daemon. */static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name, char **uuid, enum dm_event_mask *evmask){ char *id = NULL; char *p = msg->data; if ((id = _fetch_string(&p, ' ')) && (*dso_name = _fetch_string(&p, ' ')) && (*uuid = _fetch_string(&p, ' '))) { *evmask = atoi(p); dm_free(id); return 0; } if (id) dm_free(id); return -ENOMEM;}/* * Returns 0 if handler found; error (-ENOMEM, -ENOENT) otherwise. */int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next){ int ret = 0; const char *uuid = NULL; 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 }; if (!(dmt = _get_device_info(dmevh))) { stack; return 0; } uuid = dm_task_get_uuid(dmt); if (!(ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE : DM_EVENT_CMD_GET_REGISTERED_DEVICE, &msg, dmevh->dso, uuid, dmevh->mask, 0))) { /* FIXME this will probably horribly break if we get ill-formatted reply */ ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask); } else { ret = -ENOENT; goto fail; } dm_task_destroy(dmt); dmt = NULL; if (msg.data) { dm_free(msg.data); msg.data = NULL; } _dm_event_handler_clear_dev_info(dmevh); dmevh->uuid = dm_strdup(reply_uuid); if (!dmevh->uuid) { ret = -ENOMEM; goto fail; } if (!(dmt = _get_device_info(dmevh))) { ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */ goto fail; } dm_event_handler_set_dso(dmevh, reply_dso); dm_event_handler_set_event_mask(dmevh, reply_mask); if (reply_dso) dm_free(reply_dso); if (reply_uuid) dm_free(reply_uuid); dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)); if (!dmevh->dev_name) { ret = -ENOMEM; goto fail; } struct dm_info info; if (!dm_task_get_info(dmt, &info)) { ret = -1; goto fail; } dmevh->major = info.major; dmevh->minor = info.minor; dm_task_destroy(dmt); return ret; fail: if (msg.data) dm_free(msg.data); if (reply_dso) dm_free(reply_dso); if (reply_uuid) dm_free(reply_uuid); _dm_event_handler_clear_dev_info(dmevh); if (dmt) dm_task_destroy(dmt); return ret;}#if 0 /* left out for now */static char *_skip_string(char *src, const int delimiter){ src = srtchr(src, delimiter); if (src && *(src + 1)) return src + 1; return NULL;}int dm_event_set_timeout(const char *device_path, uint32_t timeout){ struct dm_event_daemon_message msg = { 0, 0, NULL }; if (!device_exists(device_path)) return -ENODEV; return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg, NULL, device_path, 0, timeout);}int dm_event_get_timeout(const char *device_path, uint32_t *timeout){ int ret; struct dm_event_daemon_message msg = { 0, 0, NULL }; 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", msg.data); return -EIO; } *timeout = atoi(p); } if (msg.data) dm_free(msg.data); return ret;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -