/* Returns -1 on error, 0 on success. Sets exit_val to exit value of 4-backend, sets output to the output from running the command, and sets err to the reason for error. */ int fsab_start_local_kb(const unsigned char *kb_name, int *exit_val, unsigned char **output, int *err) { fsa_error(LOG_DEBUG, "starting kb '%s'", kb_name); /* set defaults to indicate no output or retval yet */ *exit_val = -1; *output = NULL; fsa_kb_info *ki = fsab_get_local_kb_info(kb_name, err); if (ki == NULL) { /* failed to read metadata.nt, therefore kb doesn't exist */ *err = ADM_ERR_KB_GET_INFO; return -1; } if (*err == ADM_ERR_KB_NOT_EXISTS) { fsa_kb_info_free(ki); return -1; } /* check whether kb is running */ if (ki->status == KB_STATUS_RUNNING) { fs_error(LOG_INFO, "cannot start %s, already started", kb_name); *err = ADM_ERR_KB_STATUS_RUNNING; fsa_kb_info_free(ki); return -1; } fsa_kb_info_free(ki); char *cmdname = "4s-backend"; char *args[1] = {(char *)kb_name}; return exec_fs_cmd(cmdname, 1, args, exit_val, output, err); }
/* Return 0 on normal operation, -1 or error */ int fsab_delete_local_kb(const unsigned char *kb_name, int *exit_val, unsigned char **output, int *err) { fsa_error(LOG_DEBUG, "deleting kb '%s'", kb_name); fsa_kb_info *ki = fsab_get_local_kb_info(kb_name, err); if (ki == NULL) { return -1; } /* if kb does not exist, nothing to do */ if (*err == ADM_ERR_KB_NOT_EXISTS) { fsa_error(LOG_DEBUG, "kb '%s' does not exist, nothing to delete", kb_name); fsa_kb_info_free(ki); return 0; } /* if kb exists, attempt to stop it unless it is definitely stopped */ if (ki->status != KB_STATUS_STOPPED) { /* ignore errors, we're deleting store anyway */ fsab_stop_local_kb(kb_name, err); } fsa_kb_info_free(ki); /* use 4s-backend-destroy to delete the store */ char *cmdname = "4s-backend-destroy"; char *args[1] = {(char *)kb_name}; return exec_fs_cmd(cmdname, 1, args, exit_val, output, err); }
static void handle_cmd_get_kb_info_all(int client_fd) { int rv, len; fsa_kb_info *ki; unsigned char *response; /* get info on all running/stopped kbs on this host */ int err; ki = fsab_get_local_kb_info_all(&err); if (ki == NULL) { send_error_message(client_fd, "failed to get local kb info"); return; } /* encode response to send back to client */ response = fsap_encode_rsp_get_kb_info_all(ki, &len); fsa_kb_info_free(ki); /* done with kb info now */ if (response == NULL) { send_error_message(client_fd, "failed to encode response"); return; } fsa_error(LOG_DEBUG, "response size is %d bytes", len); /* send entire response back to client */ rv = fsa_sendall(client_fd, response, &len); free(response); /* done with response buffer */ if (rv == -1) { fsa_error(LOG_ERR, "failed to send response to client: %s", strerror(errno)); return; } fsa_error(LOG_DEBUG, "%d bytes sent to client", len); }
void fsa_kb_info_free(fsa_kb_info *ki) { if (ki == NULL) { return; } free(ki->name); free(ki->ipaddr); free(ki->p_segments_data); fsa_kb_info_free(ki->next); free(ki); }
/* get all local info about a kb. Uses errno to differentiate between returning NULL when there are no kbs, and NULL due to a read error */ fsa_kb_info *fsab_get_local_kb_info(const unsigned char *kb_name, int *err) { int rv; fsa_kb_info *ki = fsa_kb_info_new(); rv = fsab_kb_info_init(ki, kb_name, err); if (rv == -1) { fsa_error(LOG_ERR, "failed to get local kb info for kb %s", kb_name); fsa_kb_info_free(ki); return NULL; } return ki; }
/* get all information about a specific kb on this host, send to client */ static void handle_cmd_get_kb_info(int client_fd, uint16_t datasize) { int rv, len, err; fsa_kb_info *ki; unsigned char *response; unsigned char *kb_name; kb_name = get_string_from_client(client_fd, datasize); if (kb_name == NULL) { /* errors already logged/handled */ return; } /* should already have been checked by client */ if (!fsa_is_valid_kb_name((const char *)kb_name)) { fsa_error(LOG_CRIT, "Invalid kb name received from client"); send_error_message(client_fd, "kb name invalid"); free(kb_name); return; } ki = fsab_get_local_kb_info(kb_name, &err); free(kb_name); /* done with kb_name */ if (ki == NULL || err == ADM_ERR_KB_NOT_EXISTS) { send_error_message(client_fd, "failed to get local kb info"); return; } /* encode message for client */ response = fsap_encode_rsp_get_kb_info(ki, &len); fsa_kb_info_free(ki); if (response == NULL) { send_error_message(client_fd, "failed to encode kb info"); return; } fsa_error(LOG_DEBUG, "response size is %d bytes", len); /* send entire response back to client */ rv = fsa_sendall(client_fd, response, &len); free(response); /* done with response buffer */ if (rv == -1) { fsa_error(LOG_ERR, "failed to send response to client: %s", strerror(errno)); return; } fsa_error(LOG_DEBUG, "%d bytes sent to client", len); }
/* get info on all kbs on this host */ fsa_kb_info *fsab_get_local_kb_info_all(int *err) { struct dirent *entry; DIR *dp; fsa_kb_info *first_ki = NULL; fsa_kb_info *cur_ki = NULL; int rv; dp = opendir(FS_STORE_ROOT); if (dp == NULL) { fsa_error(LOG_ERR, "failed to open directory '%s': %s", FS_STORE_ROOT, strerror(errno)); *err = ADM_ERR_GENERIC; return NULL; } while ((entry = readdir(dp)) != NULL) { if (entry->d_name[0] == '.') { /* skip ., .., and hidden dirs */ continue; } cur_ki = fsa_kb_info_new(); rv = fsab_kb_info_init(cur_ki, (unsigned char *)entry->d_name, err); if (rv == -1) { fsa_error(LOG_ERR, "failed to initialise kb info for %s", entry->d_name); fsa_kb_info_free(cur_ki); continue; } else { cur_ki->next = first_ki; first_ki = cur_ki; } } closedir(dp); /* set errno to differentiate between no kbs, and error */ *err = 0; return first_ki; }
/* Return 0 on normal operation, -1 or error */ int fsab_create_local_kb(const fsa_kb_setup_args *ksargs, int *exit_val, unsigned char **output, int *err) { fsa_error(LOG_DEBUG, "creating kb '%s'", ksargs->name); /* check whether kb exists already, and it's state */ fsa_kb_info *ki = fsab_get_local_kb_info(ksargs->name, err); /* if KB exists */ if (ki != NULL && *err != ADM_ERR_KB_NOT_EXISTS) { /* do not overwrite existing kb */ if (!ksargs->delete_existing) { *err = ADM_ERR_KB_EXISTS; fsa_error(LOG_DEBUG, "kb '%s' exists, and delete_existing=0, doing nothing", ksargs->name); fsa_kb_info_free(ki); return -1; } else { /* ok to overwrite, so stop first, ignoring errors */ fsab_stop_local_kb(ksargs->name, err); } } fsa_kb_info_free(ki); /* kb should either not exist or be stopped by now */ /* max args length is 11 */ char *args[11]; int n_args = 0; char node_id_str[4]; /* holds uint8 */ char cluster_size_str[4]; /* holds uint8 */ char num_segments_str[6]; /* holds uint16 */ sprintf(node_id_str, "%d", ksargs->node_id); sprintf(cluster_size_str, "%d", ksargs->cluster_size); sprintf(num_segments_str, "%d", ksargs->num_segments); args[n_args++] = "--node"; args[n_args++] = node_id_str; args[n_args++] = "--cluster"; args[n_args++] = cluster_size_str; args[n_args++] = "--segments"; args[n_args++] = num_segments_str; if (ksargs->password != NULL) { args[n_args++] = "--password"; args[n_args++] = (char *)ksargs->password; } if (ksargs->mirror_segments) { args[n_args++] = "--mirror"; } if (ksargs->model_files) { args[n_args++] = "--model-files"; } args[n_args++] = (char *)ksargs->name; /* use 4s-backend-setup to delete the store */ char *cmdname = "4s-backend-setup"; return exec_fs_cmd(cmdname, n_args, args, exit_val, output, err); }
/* return 0 on success, -1 otherwise, and sets err */ int fsab_stop_local_kb(const unsigned char *kb_name, int *err) { fs_error(LOG_DEBUG, "stopping kb '%s'", kb_name); fsa_kb_info *ki = fsab_get_local_kb_info(kb_name, err); if (ki == NULL) { return -1; } if (*err == ADM_ERR_KB_NOT_EXISTS) { fsa_kb_info_free(ki); return -1; } /* check whether kb is running */ if (ki->status == KB_STATUS_STOPPED) { fs_error(LOG_INFO, "cannot stop %s, already stopped", kb_name); *err = ADM_ERR_KB_STATUS_STOPPED; fsa_kb_info_free(ki); return -1; } else if (ki->status == KB_STATUS_UNKNOWN) { fs_error(LOG_ERR, "cannot stop %s, runtime status unknown", kb_name); *err = ADM_ERR_KB_STATUS_UNKNOWN; fsa_kb_info_free(ki); return -1; } /* sanity check */ if (ki->status != KB_STATUS_RUNNING) { *err = ADM_ERR_GENERIC; fsa_kb_info_free(ki); return -1; } /* only need pid from here on */ int pid = ki->pid; fsa_kb_info_free(ki); /* check that we've got a sensible pid of the running store */ if (pid == 0) { fs_error(LOG_ERR, "cannot stop %s, no pid found", kb_name); *err = ADM_ERR_GENERIC; return -1; } /* send sigterm to 4s-backend process, returns 0 or -1, sets errno */ int rv = kill(pid, SIGTERM); if (rv != 0) { *err = ADM_ERR_SEE_ERRNO; return -1; } /* poll for few seconds until process is dead */ long int nanosecs = 50000000L; /* 0.05s */ int n_tries = 200; /* 10s total */ struct timespec req = {0, nanosecs}; while (n_tries > 0) { rv = kill(pid, 0); if (rv == -1 && errno == ESRCH) { /* process with pid not found, kill successful */ return 0; } /* ignore errors */ nanosleep(&req, NULL); n_tries -= 1; } *err = ADM_ERR_KILL_FAILED; return -1; }
static void start_or_stop_kb_all(int client_fd, int action) { int rv, err; int n_kbs = 0; int max_kb_len = 0; /* get all local kbs */ fsa_kb_info *ki = fsab_get_local_kb_info_all(&err); if (ki == NULL) { if (err == 0) { /* no kbs on this host */ send_expect_n_kb(client_fd, 0, 0); } else { send_error_message(client_fd, "failed to read store information"); } return; } /* count number of kbs */ for (fsa_kb_info *p = ki; p != NULL; p = p->next) { int kb_len = strlen((char *)p->name); if (kb_len > max_kb_len) { max_kb_len = kb_len; } n_kbs += 1; } /* tell client to expect a message for each */ rv = send_expect_n_kb(client_fd, n_kbs, max_kb_len); if (rv == -1) { /* failed to send message to client, so give up */ fsa_kb_info_free(ki); return; } int exit_val; /* ignored for now */ unsigned char *msg = NULL; /* sent back to client */ int return_val; /* sent back to client */ int len; /* response length */ unsigned char *response = NULL; /* response buffer */ for (fsa_kb_info *p = ki; p != NULL; p = p->next) { if (action == STOP_STORES) { rv = fsab_stop_local_kb(p->name, &err); } else if (action == START_STORES) { rv = fsab_start_local_kb(p->name, &exit_val, &msg, &err); } if (rv < 0) { return_val = err; } else { return_val = ADM_ERR_OK; } /* encode message for client */ if (action == STOP_STORES) { response = fsap_encode_rsp_stop_kb(return_val, p->name, msg, &len); } else if (action == START_STORES) { response = fsap_encode_rsp_start_kb(return_val, p->name, msg, &len); } if (msg != NULL) { free(msg); msg = NULL; } fsa_error(LOG_DEBUG, "response size is %d bytes", len); /* send entire response back to client */ rv = fsa_sendall(client_fd, response, &len); free(response); /* done with response buffer */ response = NULL; if (rv == -1) { fsa_error(LOG_ERR, "failed to send response to client: %s", strerror(errno)); continue; } fsa_error(LOG_DEBUG, "%d bytes sent to client", len); } fsa_kb_info_free(ki); }
static int cmd_list_stores(void) { /* verbose listing moved to separate function for clarity */ if (verbosity >= V_VERBOSE) { return cmd_list_stores_verbose(); } fsa_node_addr *nodes = get_nodes_from_cmd_line(); if (nodes == NULL) { /* error messages already printed */ return 1; } GHashTable *kb_hash = g_hash_table_new(g_str_hash, g_str_equal); fsa_node_addr *node = nodes; fsa_node_addr *tmp_node = NULL; fsa_kb_info *kis; fsa_kb_info *ki; fsa_kb_info *next_ki; int node_num = 0; int name_len; int max_name_len = 10; /* track lengths of kb names */ /* connect to each node separately */ while (node != NULL) { /* only pass a single node to fetch_kb_info, so break linked list */ tmp_node = node->next; node->next = NULL; kis = fsaf_fetch_kb_info(NULL, node); /* restore next item in list */ node->next = tmp_node; if (kis != NULL) { /* insert each kb info record into hash table */ ki = kis; while (ki != NULL) { /* will be breaking the linked list, so track next */ next_ki = ki->next; /* will return NULL if key not found */ ki->next = g_hash_table_lookup(kb_hash, ki->name); g_hash_table_insert(kb_hash, ki->name, ki); /* used to align columns when printing */ name_len = strlen((char *)ki->name); if (name_len > max_name_len) { max_name_len = name_len; } ki = next_ki; } } node_num += 1; node = node->next; } /* sort hash keys, print info for each kb in turn */ GList *kb_name_list = g_hash_table_get_keys(kb_hash); kb_name_list = g_list_sort(kb_name_list, (GCompareFunc)strcmp); char *kb_name; int n_total, n_running, n_stopped, n_unknown; int comma = 0; int print_store_header = 1; if (kb_name_list == NULL) { printf("No stores found\n"); } while (kb_name_list != NULL) { if (print_store_header) { if (colour_flag) { printf(ANSI_COLOUR_BLUE); } printf("%-*s store_status backend_status\n", max_name_len, "store_name"); if (colour_flag) { printf(ANSI_COLOUR_RESET); } print_store_header = 0; } n_running = n_stopped = n_unknown = 0; kb_name = kb_name_list->data; kis = g_hash_table_lookup(kb_hash, kb_name); for (ki = kis; ki != NULL; ki = ki->next) { switch (ki->status) { case KB_STATUS_RUNNING: n_running += 1; break; case KB_STATUS_STOPPED: n_stopped += 1; break; case KB_STATUS_UNKNOWN: n_unknown += 1; break; default: break; } } n_total = n_running + n_stopped + n_unknown; /* output info for this kb */ printf("%-*s ", max_name_len, kb_name); if (n_running == n_total) { print_colour("available ", ANSI_COLOUR_GREEN); } else { print_colour("unavailable ", ANSI_COLOUR_RED); } comma = 0; if (n_running > 0) { printf("%d/%d ", n_running, n_total); print_colour("running", ANSI_COLOUR_GREEN); comma = 1; } if (n_stopped > 0) { if (comma) { printf(", "); } printf("%d/%d ", n_stopped, n_total); print_colour("stopped", ANSI_COLOUR_RED); comma = 1; } if (n_unknown > 0) { if (comma) { printf(", "); } printf("%d/%d ", n_unknown, n_total); print_colour("unknown", ANSI_COLOUR_YELLOW); } printf("\n"); /* done with data in hash entry now */ fsa_kb_info_free(kis); kb_name_list = g_list_next(kb_name_list); } kb_name_list = g_list_first(kb_name_list); g_list_free(kb_name_list); fsa_node_addr_free(nodes); g_hash_table_destroy(kb_hash); return 0; }
static int cmd_list_stores_verbose(void) { fsa_node_addr *nodes = get_nodes_from_cmd_line(); if (nodes == NULL) { /* error messages already printed */ return 1; } fsa_node_addr *node = nodes; fsa_node_addr *tmp_node = NULL; fsa_kb_info *ki; fsa_kb_info *kis; int node_num = 0; int info_header_printed = 0; int print_node_header = 1; /* connect to each node separately */ while (node != NULL) { print_node_line(node_num, node->host, print_node_header); print_node_header = 0; /* only pass a single node to fetch_kb_info, so break linked list */ tmp_node = node->next; node->next = NULL; kis = fsaf_fetch_kb_info(NULL, node); /* restore next item in list */ node->next = tmp_node; /* TODO: better error handling, differentiate between err and no * stores */ if (kis != NULL) { /* get column widths */ int max_name = 10; int max_segs = 10; int curlen; for (ki = kis; ki != NULL; ki = ki->next) { curlen = strlen((char *)ki->name); if (curlen > max_name) { max_name = curlen; } curlen = ki->p_segments_len * 3; if (curlen > max_segs) { max_segs = curlen; } } /* print header */ if (!info_header_printed) { if (colour_flag) { printf(ANSI_COLOUR_BLUE); } printf(" %-*s status port number_of_segments\n", max_name, "store_name"); if (colour_flag) { printf(ANSI_COLOUR_RESET); } info_header_printed = 1; } /* print kb info */ for (ki = kis; ki != NULL; ki = ki->next) { printf(" %-*s ", max_name, ki->name); const char *kistat = fsa_kb_info_status_to_string(ki->status); if (ki->status == KB_STATUS_RUNNING) { print_colour(kistat, ANSI_COLOUR_GREEN); } else if (ki->status == KB_STATUS_STOPPED) { print_colour(kistat, ANSI_COLOUR_RED); } else { print_colour(kistat, ANSI_COLOUR_YELLOW); } printf(" "); if (ki->port > 0) { printf("%-5d ", ki->port); } else { printf(" "); } if (ki->p_segments_len > 0) { if (verbosity == V_VERBOSE) { for (int i = 0; i < ki->p_segments_len; i++) { printf("%d", ki->p_segments_data[i]); if (i == ki->p_segments_len-1) { printf(" of %d", ki->num_segments); } else { printf(","); } } } else { /* print summary of segments */ printf("%d of %d", ki->p_segments_len, ki->num_segments); } } printf("\n"); } } fsa_kb_info_free(kis); node_num += 1; node = node->next; } fsa_node_addr_free(nodes); return 0; }