static void cmd_write_remote_amp_assoc(struct bt_amp *amp, const void *data, uint8_t size) { const struct bt_hci_cmd_write_remote_amp_assoc *cmd = data; struct bt_hci_rsp_write_remote_amp_assoc rsp; int fd; if (cmd->phy_handle == 0x00) { cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC); return; } if (cmd->phy_handle != amp->phy_handle) { cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC); return; } switch (amp->phy_mode) { case PHY_MODE_INITIATOR: strcpy(amp->phylink_path, "amp"); fd = create_unix_server(amp->phylink_path); if (fd < 0) { cmd_status(amp, BT_HCI_ERR_UNSPECIFIED_ERROR, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC); return; } amp->local_assoc[0] = 0x01; memcpy(amp->local_assoc + 1, amp->phylink_path, strlen(amp->phylink_path) + 1); amp->local_assoc_len = strlen(amp->phylink_path) + 2; mainloop_add_fd(fd, EPOLLIN, accept_callback, amp, NULL); amp->phylink_fd = fd; break; case PHY_MODE_ACCEPTOR: if (cmd->assoc_fragment[0] != 0x01) { cmd_status(amp, BT_HCI_ERR_UNSPECIFIED_ERROR, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC); return; } memcpy(amp->phylink_path, cmd->assoc_fragment + 1, cmd->remain_assoc_len - 1); fd = connect_unix_client(amp->phylink_path); if (fd < 0) { cmd_status(amp, BT_HCI_ERR_UNSPECIFIED_ERROR, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC); return; } mainloop_add_fd(fd, EPOLLOUT, connect_callback, amp, NULL); amp->phylink_fd = fd; break; default: cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC); return; } rsp.status = BT_HCI_ERR_SUCCESS; rsp.phy_handle = amp->phy_handle; cmd_complete(amp, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC, &rsp, sizeof(rsp)); if (amp->phy_mode == PHY_MODE_INITIATOR) { struct bt_hci_evt_channel_selected evt; evt.phy_handle = amp->phy_handle; send_event(amp, BT_HCI_EVT_CHANNEL_SELECTED, &evt, sizeof(evt)); } }
gboolean cluster_connect_cpg(crm_cluster_t *cluster) { int rc = -1; int fd = 0; int retries = 0; uint32_t id = 0; crm_node_t *peer = NULL; cpg_handle_t handle = 0; struct mainloop_fd_callbacks cpg_fd_callbacks = { .dispatch = pcmk_cpg_dispatch, .destroy = cluster->destroy, }; cpg_callbacks_t cpg_callbacks = { .cpg_deliver_fn = cluster->cpg.cpg_deliver_fn, .cpg_confchg_fn = cluster->cpg.cpg_confchg_fn, /* .cpg_deliver_fn = pcmk_cpg_deliver, */ /* .cpg_confchg_fn = pcmk_cpg_membership, */ }; cpg_evicted = FALSE; cluster->group.length = 0; cluster->group.value[0] = 0; /* group.value is char[128] */ strncpy(cluster->group.value, crm_system_name, 127); cluster->group.value[127] = 0; cluster->group.length = 1 + QB_MIN(127, strlen(crm_system_name)); cs_repeat(retries, 30, rc = cpg_initialize(&handle, &cpg_callbacks)); if (rc != CS_OK) { crm_err("Could not connect to the Cluster Process Group API: %d\n", rc); goto bail; } id = get_local_nodeid(handle); if (id == 0) { crm_err("Could not get local node id from the CPG API"); goto bail; } cluster->nodeid = id; retries = 0; cs_repeat(retries, 30, rc = cpg_join(handle, &cluster->group)); if (rc != CS_OK) { crm_err("Could not join the CPG group '%s': %d", crm_system_name, rc); goto bail; } rc = cpg_fd_get(handle, &fd); if (rc != CS_OK) { crm_err("Could not obtain the CPG API connection: %d\n", rc); goto bail; } pcmk_cpg_handle = handle; cluster->cpg_handle = handle; mainloop_add_fd("corosync-cpg", G_PRIORITY_MEDIUM, fd, cluster, &cpg_fd_callbacks); bail: if (rc != CS_OK) { cpg_finalize(handle); return FALSE; } peer = crm_get_peer(id, NULL); crm_update_peer_proc(__FUNCTION__, peer, crm_proc_cpg, ONLINESTATUS); return TRUE; } gboolean send_cluster_message_cs(xmlNode * msg, gboolean local, crm_node_t * node, enum crm_ais_msg_types dest) { gboolean rc = TRUE; char *data = NULL; data = dump_xml_unformatted(msg); rc = send_cluster_text(crm_class_cluster, data, local, node, dest); free(data); return rc; } gboolean send_cluster_text(int class, const char *data, gboolean local, crm_node_t * node, enum crm_ais_msg_types dest) { static int msg_id = 0; static int local_pid = 0; static int local_name_len = 0; static const char *local_name = NULL; char *target = NULL; struct iovec *iov; AIS_Message *msg = NULL; enum crm_ais_msg_types sender = text2msg_type(crm_system_name); /* There are only 6 handlers registered to crm_lib_service in plugin.c */ CRM_CHECK(class < 6, crm_err("Invalid message class: %d", class); return FALSE); #if !SUPPORT_PLUGIN CRM_CHECK(dest != crm_msg_ais, return FALSE); #endif if(local_name == NULL) { local_name = get_local_node_name(); } if(local_name_len == 0 && local_name) { local_name_len = strlen(local_name); } if (data == NULL) { data = ""; } if (local_pid == 0) { local_pid = getpid(); } if (sender == crm_msg_none) { sender = local_pid; } msg = calloc(1, sizeof(AIS_Message)); msg_id++; msg->id = msg_id; msg->header.id = class; msg->header.error = CS_OK; msg->host.type = dest; msg->host.local = local; if (node) { if (node->uname) { target = strdup(node->uname); msg->host.size = strlen(node->uname); memset(msg->host.uname, 0, MAX_NAME); memcpy(msg->host.uname, node->uname, msg->host.size); } else { target = crm_strdup_printf("%u", node->id); } msg->host.id = node->id; } else { target = strdup("all"); } msg->sender.id = 0; msg->sender.type = sender; msg->sender.pid = local_pid; msg->sender.size = local_name_len; memset(msg->sender.uname, 0, MAX_NAME); if(local_name && msg->sender.size) { memcpy(msg->sender.uname, local_name, msg->sender.size); } msg->size = 1 + strlen(data); msg->header.size = sizeof(AIS_Message) + msg->size; if (msg->size < CRM_BZ2_THRESHOLD) { msg = realloc_safe(msg, msg->header.size); memcpy(msg->data, data, msg->size); } else { char *compressed = NULL; unsigned int new_size = 0; char *uncompressed = strdup(data); if (crm_compress_string(uncompressed, msg->size, 0, &compressed, &new_size)) { msg->header.size = sizeof(AIS_Message) + new_size; msg = realloc_safe(msg, msg->header.size); memcpy(msg->data, compressed, new_size); msg->is_compressed = TRUE; msg->compressed_size = new_size; } else { msg = realloc_safe(msg, msg->header.size); memcpy(msg->data, data, msg->size); } free(uncompressed); free(compressed); } iov = calloc(1, sizeof(struct iovec)); iov->iov_base = msg; iov->iov_len = msg->header.size; if (msg->compressed_size) { crm_trace("Queueing CPG message %u to %s (%d bytes, %d bytes compressed payload): %.200s", msg->id, target, iov->iov_len, msg->compressed_size, data); } else { crm_trace("Queueing CPG message %u to %s (%d bytes, %d bytes payload): %.200s", msg->id, target, iov->iov_len, msg->size, data); } free(target); #if SUPPORT_PLUGIN /* The plugin is the only time we dont use CPG messaging */ if(get_cluster_type() == pcmk_cluster_classic_ais) { return send_plugin_text(class, iov); } #endif send_cpg_iov(iov); return TRUE; } enum crm_ais_msg_types text2msg_type(const char *text) { int type = crm_msg_none; CRM_CHECK(text != NULL, return type); if (safe_str_eq(text, "ais")) { type = crm_msg_ais; } else if (safe_str_eq(text, "crm_plugin")) { type = crm_msg_ais; } else if (safe_str_eq(text, CRM_SYSTEM_CIB)) { type = crm_msg_cib; } else if (safe_str_eq(text, CRM_SYSTEM_CRMD)) { type = crm_msg_crmd; } else if (safe_str_eq(text, CRM_SYSTEM_DC)) { type = crm_msg_crmd; } else if (safe_str_eq(text, CRM_SYSTEM_TENGINE)) { type = crm_msg_te; } else if (safe_str_eq(text, CRM_SYSTEM_PENGINE)) { type = crm_msg_pe; } else if (safe_str_eq(text, CRM_SYSTEM_LRMD)) { type = crm_msg_lrmd; } else if (safe_str_eq(text, CRM_SYSTEM_STONITHD)) { type = crm_msg_stonithd; } else if (safe_str_eq(text, "stonith-ng")) { type = crm_msg_stonith_ng; } else if (safe_str_eq(text, "attrd")) { type = crm_msg_attrd; } else { /* This will normally be a transient client rather than * a cluster daemon. Set the type to the pid of the client */ int scan_rc = sscanf(text, "%d", &type); if (scan_rc != 1 || type <= crm_msg_stonith_ng) { /* Ensure its sane */ type = crm_msg_none; } } return type; }
int main(int argc, char *argv[]) { int opt; int sec = BT_SECURITY_LOW; uint16_t mtu = 0; uint8_t dst_type = BDADDR_LE_PUBLIC; bool dst_addr_given = false; bdaddr_t src_addr, dst_addr; int dev_id = -1; int fd; sigset_t mask; struct client *cli; while ((opt = getopt_long(argc, argv, "+hvs:m:t:d:i:", main_options, NULL)) != -1) { switch (opt) { case 'h': usage(); return EXIT_SUCCESS; case 'v': verbose = true; break; case 's': if (strcmp(optarg, "low") == 0) sec = BT_SECURITY_LOW; else if (strcmp(optarg, "medium") == 0) sec = BT_SECURITY_MEDIUM; else if (strcmp(optarg, "high") == 0) sec = BT_SECURITY_HIGH; else { fprintf(stderr, "Invalid security level\n"); return EXIT_FAILURE; } break; case 'm': { int arg; arg = atoi(optarg); if (arg <= 0) { fprintf(stderr, "Invalid MTU: %d\n", arg); return EXIT_FAILURE; } if (arg > UINT16_MAX) { fprintf(stderr, "MTU too large: %d\n", arg); return EXIT_FAILURE; } mtu = (uint16_t)arg; break; } case 't': if (strcmp(optarg, "random") == 0) dst_type = BDADDR_LE_RANDOM; else if (strcmp(optarg, "public") == 0) dst_type = BDADDR_LE_PUBLIC; else { fprintf(stderr, "Allowed types: random, public\n"); return EXIT_FAILURE; } break; case 'd': if (str2ba(optarg, &dst_addr) < 0) { fprintf(stderr, "Invalid remote address: %s\n", optarg); return EXIT_FAILURE; } dst_addr_given = true; break; case 'i': dev_id = hci_devid(optarg); if (dev_id < 0) { perror("Invalid adapter"); return EXIT_FAILURE; } break; default: fprintf(stderr, "Invalid option: %c\n", opt); return EXIT_FAILURE; } } if (!argc) { usage(); return EXIT_SUCCESS; } argc -= optind; argv += optind; optind = 0; if (argc) { usage(); return EXIT_SUCCESS; } if (dev_id == -1) bacpy(&src_addr, BDADDR_ANY); else if (hci_devba(dev_id, &src_addr) < 0) { perror("Adapter not available"); return EXIT_FAILURE; } if (!dst_addr_given) { fprintf(stderr, "Destination address required!\n"); return EXIT_FAILURE; } mainloop_init(); fd = l2cap_le_att_connect(&src_addr, &dst_addr, dst_type, sec); if (fd < 0) return EXIT_FAILURE; cli = client_create(fd, mtu); if (!cli) { close(fd); return EXIT_FAILURE; } if (mainloop_add_fd(fileno(stdin), EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLERR, prompt_read_cb, cli, NULL) < 0) { fprintf(stderr, "Failed to initialize console\n"); return EXIT_FAILURE; } sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); mainloop_set_signal(&mask, signal_cb, NULL, NULL); print_prompt(); mainloop_run(); printf("\n\nShutting down...\n"); client_destroy(cli); return EXIT_SUCCESS; }
int mainloop_run(void) { unsigned int i; if (signal_data) { if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0) return 1; signal_data->fd = signalfd(-1, &signal_data->mask, SFD_NONBLOCK | SFD_CLOEXEC); if (signal_data->fd < 0) return 1; if (mainloop_add_fd(signal_data->fd, EPOLLIN, signal_callback, signal_data, NULL) < 0) { close(signal_data->fd); return 1; } } while (!epoll_terminate) { struct epoll_event events[MAX_EPOLL_EVENTS]; int n, nfds; nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1); if (nfds < 0) continue; for (n = 0; n < nfds; n++) { struct mainloop_data *data = events[n].data.ptr; data->callback(data->fd, events[n].events, data->user_data); } } if (signal_data) { mainloop_remove_fd(signal_data->fd); close(signal_data->fd); if (signal_data->destroy) signal_data->destroy(signal_data->user_data); } for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) { struct mainloop_data *data = mainloop_list[i]; mainloop_list[i] = NULL; if (data) { epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL); if (data->destroy) data->destroy(data->user_data); free(data); } } close(epoll_fd); epoll_fd = 0; return 0; }
gboolean services_os_action_execute(svc_action_t * op, gboolean synchronous) { int rc, lpc; int stdout_fd[2]; int stderr_fd[2]; if (pipe(stdout_fd) < 0) { crm_err("pipe() failed"); } if (pipe(stderr_fd) < 0) { crm_err("pipe() failed"); } op->pid = fork(); switch (op->pid) { case -1: crm_err("fork() failed"); close(stdout_fd[0]); close(stdout_fd[1]); close(stderr_fd[0]); close(stderr_fd[1]); return FALSE; case 0: /* Child */ /* Man: The call setpgrp() is equivalent to setpgid(0,0) * _and_ compiles on BSD variants too * need to investigate if it works the same too. */ setpgid(0, 0); close(stdout_fd[0]); close(stderr_fd[0]); if (STDOUT_FILENO != stdout_fd[1]) { if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) { crm_err("dup2() failed (stdout)"); } close(stdout_fd[1]); } if (STDERR_FILENO != stderr_fd[1]) { if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) { crm_err("dup2() failed (stderr)"); } close(stderr_fd[1]); } /* close all descriptors except stdin/out/err and channels to logd */ for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) { close(lpc); } /* Setup environment correctly */ add_OCF_env_vars(op); /* execute the RA */ execvp(op->opaque->exec, op->opaque->args); switch (errno) { /* see execve(2) */ case ENOENT: /* No such file or directory */ case EISDIR: /* Is a directory */ rc = PCMK_OCF_NOT_INSTALLED; #if SUPPORT_NAGIOS if (safe_str_eq(op->standard, "nagios")) { rc = NAGIOS_NOT_INSTALLED; } #endif break; case EACCES: /* permission denied (various errors) */ rc = PCMK_OCF_INSUFFICIENT_PRIV; #if SUPPORT_NAGIOS if (safe_str_eq(op->standard, "nagios")) { rc = NAGIOS_INSUFFICIENT_PRIV; } #endif break; default: rc = PCMK_OCF_UNKNOWN_ERROR; break; } _exit(rc); } /* Only the parent reaches here */ close(stdout_fd[1]); close(stderr_fd[1]); op->opaque->stdout_fd = stdout_fd[0]; set_fd_opts(op->opaque->stdout_fd, O_NONBLOCK); op->opaque->stderr_fd = stderr_fd[0]; set_fd_opts(op->opaque->stderr_fd, O_NONBLOCK); if (synchronous) { int status = 0; int timeout = (1 + op->timeout) / 1000; crm_trace("Waiting for %d", op->pid); while ((op->timeout < 0 || timeout > 0) && waitpid(op->pid, &status, WNOHANG) <= 0) { sleep(1); read_output(op->opaque->stdout_fd, op); read_output(op->opaque->stderr_fd, op); timeout--; } crm_trace("Child done: %d", op->pid); if (timeout == 0) { int killrc = kill(op->pid, 9 /*SIGKILL*/); op->rc = PCMK_OCF_UNKNOWN_ERROR; op->status = PCMK_LRM_OP_TIMEOUT; crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout); if (killrc && errno != ESRCH) { crm_err("kill(%d, KILL) failed: %d", op->pid, errno); } } else if (WIFEXITED(status)) { op->status = PCMK_LRM_OP_DONE; op->rc = WEXITSTATUS(status); crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc); } else if (WIFSIGNALED(status)) { int signo = WTERMSIG(status); op->status = PCMK_LRM_OP_ERROR; crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo); } #ifdef WCOREDUMP if (WCOREDUMP(status)) { crm_err("Managed %s process %d dumped core", op->id, op->pid); } #endif read_output(op->opaque->stdout_fd, op); read_output(op->opaque->stderr_fd, op); } else { crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec); mainloop_add_child(op->pid, op->timeout, op->id, op, operation_finished); op->opaque->stdout_gsource = mainloop_add_fd(op->id, G_PRIORITY_LOW, op->opaque->stdout_fd, op, &stdout_callbacks); op->opaque->stderr_gsource = mainloop_add_fd(op->id, G_PRIORITY_LOW, op->opaque->stderr_fd, op, &stderr_callbacks); } return TRUE; }
int main(int argc, char *argv[]) { const char *bredr_path = NULL, *amp_path = NULL, *proto = NULL; bool flowctl = true, raw_device = false; int exit_status, count = 0, proto_id = HCI_UART_H4; unsigned int speed = B115200; for (;;) { int opt; opt = getopt_long(argc, argv, "B:A:P:S:NRvh", main_options, NULL); if (opt < 0) break; switch (opt) { case 'B': bredr_path = optarg; break; case 'A': amp_path = optarg; break; case 'P': proto = optarg; break; case 'S': speed = tty_get_speed(atoi(optarg)); if (!speed) { fprintf(stderr, "Invalid speed: %s\n", optarg); return EXIT_FAILURE; } break; case 'N': flowctl = false; break; case 'R': raw_device = true; break; case 'v': printf("%s\n", VERSION); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; default: return EXIT_FAILURE; } } if (argc - optind > 0) { fprintf(stderr, "Invalid command line parameters\n"); return EXIT_FAILURE; } mainloop_init(); if (proto) { unsigned int i; for (i = 0; proto_table[i].name; i++) { if (!strcmp(proto_table[i].name, proto)) { proto_id = proto_table[i].id; break; } } if (!proto_table[i].name) { fprintf(stderr, "Invalid protocol\n"); return EXIT_FAILURE; } } if (bredr_path) { unsigned long flags; int fd; printf("Attaching Primary controller to %s\n", bredr_path); flags = (1 << HCI_UART_RESET_ON_INIT); if (raw_device) flags = (1 << HCI_UART_RAW_DEVICE); fd = attach_proto(bredr_path, proto_id, speed, flowctl, flags); if (fd >= 0) { mainloop_add_fd(fd, 0, uart_callback, NULL, NULL); count++; } } if (amp_path) { unsigned long flags; int fd; printf("Attaching AMP controller to %s\n", amp_path); flags = (1 << HCI_UART_RESET_ON_INIT) | (1 << HCI_UART_CREATE_AMP); if (raw_device) flags = (1 << HCI_UART_RAW_DEVICE); fd = attach_proto(amp_path, proto_id, speed, flowctl, flags); if (fd >= 0) { mainloop_add_fd(fd, 0, uart_callback, NULL, NULL); count++; } } if (count < 1) { fprintf(stderr, "No controller attached\n"); return EXIT_FAILURE; } exit_status = mainloop_run_with_signal(signal_callback, NULL); return exit_status; }
static void action_synced_wait(svc_action_t * op, sigset_t *mask) { int status = 0; int timeout = op->timeout; int sfd = -1; time_t start = -1; struct pollfd fds[3]; int wait_rc = 0; #ifdef HAVE_SYS_SIGNALFD_H sfd = signalfd(-1, mask, SFD_NONBLOCK); if (sfd < 0) { crm_perror(LOG_ERR, "signalfd() failed"); } #else sfd = sigchld_pipe[0]; #endif fds[0].fd = op->opaque->stdout_fd; fds[0].events = POLLIN; fds[0].revents = 0; fds[1].fd = op->opaque->stderr_fd; fds[1].events = POLLIN; fds[1].revents = 0; fds[2].fd = sfd; fds[2].events = POLLIN; fds[2].revents = 0; crm_trace("Waiting for %d", op->pid); start = time(NULL); do { int poll_rc = poll(fds, 3, timeout); if (poll_rc > 0) { if (fds[0].revents & POLLIN) { svc_read_output(op->opaque->stdout_fd, op, FALSE); } if (fds[1].revents & POLLIN) { svc_read_output(op->opaque->stderr_fd, op, TRUE); } if (fds[2].revents & POLLIN) { #ifdef HAVE_SYS_SIGNALFD_H struct signalfd_siginfo fdsi; ssize_t s; s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo)); if (s != sizeof(struct signalfd_siginfo)) { crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd); } else if (fdsi.ssi_signo == SIGCHLD) { #else if (1) { /* Clear out the sigchld pipe. */ char ch; while (read(sfd, &ch, 1) == 1); #endif wait_rc = waitpid(op->pid, &status, WNOHANG); if (wait_rc < 0){ crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid); } else if (wait_rc > 0) { break; } } } } else if (poll_rc == 0) { timeout = 0; break; } else if (poll_rc < 0) { if (errno != EINTR) { crm_perror(LOG_ERR, "poll() failed"); break; } } timeout = op->timeout - (time(NULL) - start) * 1000; } while ((op->timeout < 0 || timeout > 0)); crm_trace("Child done: %d", op->pid); if (wait_rc <= 0) { int killrc = kill(op->pid, SIGKILL); op->rc = PCMK_OCF_UNKNOWN_ERROR; if (op->timeout > 0 && timeout <= 0) { op->status = PCMK_LRM_OP_TIMEOUT; crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout); } else { op->status = PCMK_LRM_OP_ERROR; } if (killrc && errno != ESRCH) { crm_err("kill(%d, KILL) failed: %d", op->pid, errno); } /* * From sigprocmask(2): * It is not possible to block SIGKILL or SIGSTOP. Attempts to do so are silently ignored. * * This makes it safe to skip WNOHANG here */ waitpid(op->pid, &status, 0); } else if (WIFEXITED(status)) { op->status = PCMK_LRM_OP_DONE; op->rc = WEXITSTATUS(status); crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc); } else if (WIFSIGNALED(status)) { int signo = WTERMSIG(status); op->status = PCMK_LRM_OP_ERROR; crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo); } #ifdef WCOREDUMP if (WCOREDUMP(status)) { crm_err("Managed %s process %d dumped core", op->id, op->pid); } #endif svc_read_output(op->opaque->stdout_fd, op, FALSE); svc_read_output(op->opaque->stderr_fd, op, TRUE); close(op->opaque->stdout_fd); close(op->opaque->stderr_fd); #ifdef HAVE_SYS_SIGNALFD_H close(sfd); #endif } /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */ /* For a synchronous 'op', returns FALSE if 'op' fails */ gboolean services_os_action_execute(svc_action_t * op, gboolean synchronous) { int stdout_fd[2]; int stderr_fd[2]; struct stat st; sigset_t *pmask; #ifdef HAVE_SYS_SIGNALFD_H sigset_t mask; sigset_t old_mask; #define sigchld_cleanup() do { \ if (sigismember(&old_mask, SIGCHLD) == 0) { \ if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { \ crm_perror(LOG_ERR, "sigprocmask() failed to unblock sigchld"); \ } \ } \ } while (0) #else struct sigaction sa; struct sigaction old_sa; #define sigchld_cleanup() do { \ if (sigaction(SIGCHLD, &old_sa, NULL) < 0) { \ crm_perror(LOG_ERR, "sigaction() failed to remove sigchld handler"); \ } \ close(sigchld_pipe[0]); \ close(sigchld_pipe[1]); \ sigchld_pipe[0] = sigchld_pipe[1] = -1; \ } while(0) #endif /* Fail fast */ if(stat(op->opaque->exec, &st) != 0) { int rc = errno; crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!synchronous) { return operation_finalize(op); } return FALSE; } if (pipe(stdout_fd) < 0) { int rc = errno; crm_err("pipe(stdout_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!synchronous) { return operation_finalize(op); } return FALSE; } if (pipe(stderr_fd) < 0) { int rc = errno; close(stdout_fd[0]); close(stdout_fd[1]); crm_err("pipe(stderr_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!synchronous) { return operation_finalize(op); } return FALSE; } if (synchronous) { #ifdef HAVE_SYS_SIGNALFD_H sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigemptyset(&old_mask); if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { crm_perror(LOG_ERR, "sigprocmask() failed to block sigchld"); } pmask = &mask; #else if(pipe(sigchld_pipe) == -1) { crm_perror(LOG_ERR, "pipe() failed"); } set_fd_opts(sigchld_pipe[0], O_NONBLOCK); set_fd_opts(sigchld_pipe[1], O_NONBLOCK); sa.sa_handler = sigchld_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); if (sigaction(SIGCHLD, &sa, &old_sa) < 0) { crm_perror(LOG_ERR, "sigaction() failed to set sigchld handler"); } pmask = NULL; #endif } op->pid = fork(); switch (op->pid) { case -1: { int rc = errno; close(stdout_fd[0]); close(stdout_fd[1]); close(stderr_fd[0]); close(stderr_fd[1]); crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); services_handle_exec_error(op, rc); if (!synchronous) { return operation_finalize(op); } sigchld_cleanup(); return FALSE; } case 0: /* Child */ close(stdout_fd[0]); close(stderr_fd[0]); if (STDOUT_FILENO != stdout_fd[1]) { if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) { crm_err("dup2() failed (stdout)"); } close(stdout_fd[1]); } if (STDERR_FILENO != stderr_fd[1]) { if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) { crm_err("dup2() failed (stderr)"); } close(stderr_fd[1]); } if (synchronous) { sigchld_cleanup(); } action_launch_child(op); CRM_ASSERT(0); /* action_launch_child is effectively noreturn */ } /* Only the parent reaches here */ close(stdout_fd[1]); close(stderr_fd[1]); op->opaque->stdout_fd = stdout_fd[0]; set_fd_opts(op->opaque->stdout_fd, O_NONBLOCK); op->opaque->stderr_fd = stderr_fd[0]; set_fd_opts(op->opaque->stderr_fd, O_NONBLOCK); if (synchronous) { action_synced_wait(op, pmask); sigchld_cleanup(); } else { crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec); mainloop_child_add_with_flags(op->pid, op->timeout, op->id, op, (op->flags & SVC_ACTION_LEAVE_GROUP) ? mainloop_leave_pid_group : 0, operation_finished); op->opaque->stdout_gsource = mainloop_add_fd(op->id, G_PRIORITY_LOW, op->opaque->stdout_fd, op, &stdout_callbacks); op->opaque->stderr_gsource = mainloop_add_fd(op->id, G_PRIORITY_LOW, op->opaque->stderr_fd, op, &stderr_callbacks); services_add_inflight_op(op); } return TRUE; }
gboolean cluster_connect_quorum(gboolean(*dispatch) (unsigned long long, gboolean), void (*destroy) (gpointer)) { int rc = -1; int fd = 0; int quorate = 0; uint32_t quorum_type = 0; struct mainloop_fd_callbacks quorum_fd_callbacks; quorum_fd_callbacks.dispatch = pcmk_quorum_dispatch; quorum_fd_callbacks.destroy = destroy; crm_debug("Configuring Pacemaker to obtain quorum from Corosync"); rc = quorum_initialize(&pcmk_quorum_handle, &quorum_callbacks, &quorum_type); if (rc != CS_OK) { crm_err("Could not connect to the Quorum API: %d", rc); goto bail; } else if (quorum_type != QUORUM_SET) { crm_err("Corosync quorum is not configured"); goto bail; } rc = quorum_getquorate(pcmk_quorum_handle, &quorate); if (rc != CS_OK) { crm_err("Could not obtain the current Quorum API state: %d", rc); goto bail; } if (quorate) { crm_notice("Quorum acquired"); } else { crm_warn("Quorum lost"); } quorum_app_callback = dispatch; crm_have_quorum = quorate; rc = quorum_trackstart(pcmk_quorum_handle, CS_TRACK_CHANGES | CS_TRACK_CURRENT); if (rc != CS_OK) { crm_err("Could not setup Quorum API notifications: %d", rc); goto bail; } rc = quorum_fd_get(pcmk_quorum_handle, &fd); if (rc != CS_OK) { crm_err("Could not obtain the Quorum API connection: %d", rc); goto bail; } mainloop_add_fd("quorum", G_PRIORITY_HIGH, fd, dispatch, &quorum_fd_callbacks); corosync_initialize_nodelist(NULL, FALSE, NULL); bail: if (rc != CS_OK) { quorum_finalize(pcmk_quorum_handle); return FALSE; } return TRUE; }