static void *dyn_config_start(void *arg) { struct tcmu_config *cfg = arg; int monitor, wd, len; char buf[BUF_LEN]; pthread_cleanup_push(dyn_config_cleanup, arg); monitor = inotify_init(); if (monitor == -1) { tcmu_err("Failed to init inotify %m\n"); return NULL; } wd = inotify_add_watch(monitor, cfg->path, IN_ALL_EVENTS); if (wd == -1) { tcmu_err("Failed to add \"%s\" to inotify %m\n", cfg->path); return NULL; } tcmu_info("Inotify is watching \"%s\", wd: %d, mask: IN_ALL_EVENTS\n", cfg->path, wd); while (1) { struct inotify_event *event; char *p; len = read(monitor, buf, BUF_LEN); if (len == -1) { tcmu_warn("Failed to read inotify: %m\n"); continue; } for (p = buf; p < buf + len;) { event = (struct inotify_event *)p; tcmu_info("event->mask: 0x%x\n", event->mask); if (event->wd != wd) continue; /* * If force to write to the unwritable or crashed * config file, the vi/vim will try to move and * delete the config file and then recreate it again * via the *.swp */ if ((event->mask & IN_IGNORED) && !access(cfg->path, F_OK)) wd = inotify_add_watch(monitor, cfg->path, IN_ALL_EVENTS); /* Try to reload the config file */ if (event->mask & IN_MODIFY || event->mask & IN_IGNORED) tcmu_reload_config(cfg); p += sizeof(struct inotify_event) + event->len; } } pthread_cleanup_pop(1); return NULL; }
int main(int argc, char **argv) { struct tcmulib_context *tcmulib_ctx; struct pollfd pollfds[16]; int i; int ret; if (tcmu_setup_log()) { fprintf(stderr, "Could not setup tcmu logger.\n"); exit(1); } /* If any TCMU devices that exist that match subtype, handler->added() will now be called from within tcmulib_initialize(). */ tcmulib_ctx = tcmulib_initialize(&foo_handler, 1); if (tcmulib_ctx <= 0) { tcmu_err("tcmulib_initialize failed with %p\n", tcmulib_ctx); exit(1); } while (1) { pollfds[0].fd = tcmulib_get_master_fd(tcmulib_ctx); pollfds[0].events = POLLIN; pollfds[0].revents = 0; for (i = 0; i < dev_array_len; i++) { pollfds[i+1].fd = tcmu_get_dev_fd(tcmu_dev_array[i]); pollfds[i+1].events = POLLIN; pollfds[i+1].revents = 0; } /* Use ppoll instead poll to avoid poll call reschedules during signal * handling. If we were removing a device, then the uio device's memory * could be freed, but the poll would be rescheduled and end up accessing * the released device. */ ret = ppoll(pollfds, dev_array_len+1, NULL, NULL); if (ret == -1) { tcmu_err("ppoll() returned %d, exiting\n", ret); exit(EXIT_FAILURE); } if (pollfds[0].revents) { /* If any tcmu devices have been added or removed, the added() and removed() handler callbacks will be called from within this. */ tcmulib_master_fd_ready(tcmulib_ctx); /* Since devices (may) have changed, re-poll() instead of processing per-device fds. */ continue; } for (i = 0; i < dev_array_len; i++) { if (pollfds[i+1].revents) { struct tcmulib_cmd *cmd; struct tcmu_device *dev = tcmu_dev_array[i]; tcmulib_processing_start(dev); while ((cmd = tcmulib_get_next_command(dev)) != NULL) { ret = foo_handle_cmd(dev, cmd->cdb, cmd->iovec, cmd->iov_cnt, cmd->sense_buf); tcmulib_command_complete(dev, cmd, ret); } tcmulib_processing_complete(dev); } } } return 0; }
static void tcmu_parse_option(char **cur, const char *end) { struct tcmu_conf_option *option; tcmu_option_type type; char *p = *cur, *q = *cur, *r, *s; while (isblank(*p)) p++; TCMU_TO_LINE_END(q, end); *q = '\0'; *cur = q + 1; /* parse the boolean type option */ s = r = strchr(p, '='); if (!r) { /* boolean type option at file end or line end */ r = p; while (!isblank(*r) && r < q) r++; *r = '\0'; option = tcmu_get_option(p); if (!option) option = tcmu_register_option(p, TCMU_OPT_BOOL); if (option) option->opt_bool = true; return; } while (isblank(*r) || *r == '=') r--; r++; *r = '\0'; option = tcmu_get_option(p); if (!option) { r = s; while (isblank(*r) || *r == '=') r++; if (*r == '"' || *r == '\'') { type = TCMU_OPT_STR; } else if (isdigit(*r)) { type = TCMU_OPT_INT; } else { tcmu_err("option type %d not supported!\n"); return; } option = tcmu_register_option(p, type); if (!option) return; } /* parse the int/string type options */ switch (option->type) { case TCMU_OPT_INT: while (!isdigit(*s)) s++; r = s; while (isdigit(*r)) r++; *r= '\0'; option->opt_int = atoi(s); break; case TCMU_OPT_STR: s++; while (isblank(*s)) s++; /* skip first " or ' if exist */ if (*s == '"' || *s == '\'') s++; r = q - 1; while (isblank(*r)) r--; /* skip last " or ' if exist */ if (*r == '"' || *r == '\'') *r = '\0'; option->opt_str = strdup(s); break; default: tcmu_err("option type %d not supported!\n"); break; } }