static int do_a_command(FILE *input, BSOCK *UA_sock) { unsigned int i; int status; int found; int len; char *cmd; found = 0; status = 1; Dmsg1(120, "Command: %s\n", UA_sock->msg); if (argc == 0) { return 1; } cmd = argk[0]+1; if (*cmd == '#') { /* comment */ return 1; } len = strlen(cmd); for (i=0; i<comsize; i++) { /* search for command */ if (bstrncasecmp(cmd, _(commands[i].key), len)) { status = (*commands[i].func)(input, UA_sock); /* go execute command */ found = 1; break; } } if (!found) { pm_strcat(&UA_sock->msg, _(": is an invalid command\n")); UA_sock->msglen = strlen(UA_sock->msg); sendit(UA_sock->msg); } return status; }
static inline backend_interface_mapping_t *lookup_backend_interface_mapping(const char *interface_name) { backend_interface_mapping_t *backend_interface_mapping; for (backend_interface_mapping = backend_interface_mappings; backend_interface_mapping->interface_name != NULL; backend_interface_mapping++) { Dmsg3(100, "db_init_database: Trying to find mapping of given interfacename %s to mapping interfacename %s, partly_compare = %s\n", interface_name, backend_interface_mapping->interface_name, (backend_interface_mapping->partly_compare) ? "true" : "false"); /* * See if this is a match. */ if (backend_interface_mapping->partly_compare) { if (bstrncasecmp(interface_name, backend_interface_mapping->interface_name, strlen(backend_interface_mapping->interface_name))) { return backend_interface_mapping; } } else { if (bstrcasecmp(interface_name, backend_interface_mapping->interface_name)) { return backend_interface_mapping; } } } return NULL; }
/* * Execute a command from the UA */ bool do_a_dot_command(UAContext *ua) { int i; int len; bool ok = false; bool found = false; BSOCK *user = ua->UA_sock; Dmsg1(1400, "Dot command: %s\n", user->msg); if (ua->argc == 0) { return false; } len = strlen(ua->argk[0]); if (len == 1) { if (ua->api) user->signal(BNET_CMD_BEGIN); if (ua->api) user->signal(BNET_CMD_OK); return true; /* no op */ } for (i=0; i<comsize; i++) { /* search for command */ if (bstrncasecmp(ua->argk[0], _(commands[i].key), len)) { /* Check if this command is authorized in RunScript */ if (ua->runscript && !commands[i].use_in_rs) { ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]); break; } bool gui = ua->gui; /* Check if command permitted, but "quit" is always OK */ if (!bstrcmp(ua->argk[0], NT_(".quit")) && !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) { break; } Dmsg1(100, "Cmd: %s\n", ua->cmd); ua->gui = true; if (ua->api) user->signal(BNET_CMD_BEGIN); ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */ if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED); ua->gui = gui; found = true; break; } } if (!found) { ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n")); ok = false; } return ok; }
static bool strunit_to_uint64(char *str, uint64_t *value, const char **mod) { int i, mod_len; double val; char mod_str[20]; char num_str[50]; const int64_t mult[] = {1, /* byte */ 1024, /* kilobyte */ 1000, /* kb kilobyte */ 1048576, /* megabyte */ 1000000, /* mb megabyte */ 1073741824, /* gigabyte */ 1000000000}; /* gb gigabyte */ if (!get_modifier(str, num_str, sizeof(num_str), mod_str, sizeof(mod_str))) { return 0; } /* Now find the multiplier corresponding to the modifier */ mod_len = strlen(mod_str); if (mod_len == 0) { i = 0; /* default with no modifier = 1 */ } else { for (i=0; mod[i]; i++) { if (bstrncasecmp(mod_str, mod[i], mod_len)) { break; } } if (mod[i] == NULL) { return false; } } Dmsg2(900, "str=%s: mult=%d\n", str, mult[i]); errno = 0; val = strtod(num_str, NULL); if (errno != 0 || val < 0) { return false; } *value = (utime_t)(val * mult[i]); return true; }
/* * Convert a string duration to utime_t (64 bit seconds) * Returns false: if error true: if OK, and value stored in value */ bool duration_to_utime(char *str, utime_t *value) { int i, mod_len; double val, total = 0.0; char mod_str[20]; char num_str[50]; /* * The "n" = mins and months appears before minutes so that m maps to months. */ static const char *mod[] = { "n", "seconds", "months", "minutes", "mins", "hours", "days", "weeks", "quarters", "years", (char *)NULL }; static const int32_t mult[] = { 60, 1, 60 * 60 * 24 * 30, 60, 60, 3600, 3600 * 24, 3600 * 24 * 7, 3600 * 24 * 91, 3600 * 24 * 365, 0 }; while (*str) { if (!get_modifier(str, num_str, sizeof(num_str), mod_str, sizeof(mod_str))) { return false; } /* Now find the multiplier corresponding to the modifier */ mod_len = strlen(mod_str); if (mod_len == 0) { i = 1; /* default to seconds */ } else { for (i=0; mod[i]; i++) { if (bstrncasecmp(mod_str, mod[i], mod_len)) { break; } } if (mod[i] == NULL) { return false; } } Dmsg2(900, "str=%s: mult=%d\n", num_str, mult[i]); errno = 0; val = strtod(num_str, NULL); if (errno != 0 || val < 0) { return false; } total += val * mult[i]; } *value = (utime_t)total; return true; }
/* * Open a volume using libdroplet. */ int object_store_device::d_open(const char *pathname, int flags, int mode) { dpl_status_t status; dpl_vfile_flag_t dpl_flags; dpl_option_t dpl_options; #if 1 Mmsg1(errmsg, _("Object Storage devices are not yet supported, please disable %s\n"), dev_name); return -1; #endif /* * Initialize the droplet library when its not done previously. */ P(mutex); if (droplet_reference_count == 0) { status = dpl_init(); if (status != DPL_SUCCESS) { V(mutex); return -1; } dpl_set_log_func(object_store_logfunc); droplet_reference_count++; } V(mutex); if (!m_object_configstring) { int len; char *bp, *next_option; bool done; if (!dev_options) { Mmsg0(errmsg, _("No device options configured\n")); Emsg0(M_FATAL, 0, errmsg); return -1; } m_object_configstring = bstrdup(dev_options); bp = m_object_configstring; while (bp) { next_option = strchr(bp, ','); if (next_option) { *next_option++ = '\0'; } done = false; for (int i = 0; !done && device_options[i].name; i++) { /* * Try to find a matching device option. */ if (bstrncasecmp(bp, device_options[i].name, device_options[i].compare_size)) { switch (device_options[i].type) { case argument_profile: m_profile = bp + device_options[i].compare_size; done = true; break; case argument_bucket: m_object_bucketname = bp + device_options[i].compare_size; done = true; break; default: break; } } } if (!done) { Mmsg1(errmsg, _("Unable to parse device option: %s\n"), bp); Emsg0(M_FATAL, 0, errmsg); goto bail_out; } bp = next_option; } if (!m_profile) { Mmsg0(errmsg, _("No droplet profile configured\n")); Emsg0(M_FATAL, 0, errmsg); goto bail_out; } /* * Strip any .profile prefix from the libdroplet profile name. */ len = strlen(m_profile); if (len > 8 && bstrcasecmp(m_profile + (len - 8), ".profile")) { m_profile[len - 8] = '\0'; } } /* * See if we need to setup a new context for this device. */ if (!m_ctx) { char *bp; /* * See if this is a path. */ bp = strrchr(m_object_configstring, '/'); if (!bp) { /* * Only a profile name. */ m_ctx = dpl_ctx_new(NULL, m_object_configstring); } else { if (bp == m_object_configstring) { /* * Profile in root of filesystem */ m_ctx = dpl_ctx_new("/", bp + 1); } else { /* * Profile somewhere else. */ *bp++ = '\0'; m_ctx = dpl_ctx_new(m_object_configstring, bp); } } /* * If we failed to allocate a new context fail the open. */ if (!m_ctx) { Mmsg1(errmsg, _("Failed to create a new context using config %s\n"), dev_options); return -1; } /* * Login if that is needed for this backend. */ status = dpl_login(m_ctx); switch (status) { case DPL_SUCCESS: break; case DPL_ENOTSUPP: /* * Backend doesn't support login which is fine. */ break; default: Mmsg2(errmsg, _("Failed to login for voume %s using dpl_login(): ERR=%s.\n"), getVolCatName(), dpl_status_str(status)); return -1; } /* * If a bucketname was defined set it in the context. */ if (m_object_bucketname) { m_ctx->cur_bucket = m_object_bucketname; } } /* * See if we don't have a file open already. */ if (m_vfd) { dpl_close(m_vfd); m_vfd = NULL; } /* * Create some options for libdroplet. * * DPL_OPTION_NOALLOC - we provide the buffer to copy the data into * no need to let the library allocate memory we * need to free after copying the data. */ memset(&dpl_options, 0, sizeof(dpl_options)); dpl_options.mask |= DPL_OPTION_NOALLOC; if (flags & O_CREAT) { dpl_flags = DPL_VFILE_FLAG_CREAT | DPL_VFILE_FLAG_RDWR; status = dpl_open(m_ctx, /* context */ getVolCatName(), /* locator */ dpl_flags, /* flags */ &dpl_options, /* options */ NULL, /* condition */ NULL, /* metadata */ NULL, /* sysmd */ NULL, /* query_params */ NULL, /* stream_status */ &m_vfd); } else { dpl_flags = DPL_VFILE_FLAG_RDWR; status = dpl_open(m_ctx, /* context */ getVolCatName(), /* locator */ dpl_flags, /* flags */ &dpl_options, /* options */ NULL, /* condition */ NULL, /* metadata */ NULL, /* sysmd */ NULL, /* query_params */ NULL, /* stream_status */ &m_vfd); } switch (status) { case DPL_SUCCESS: m_offset = 0; return 0; default: Mmsg2(errmsg, _("Failed to open %s using dpl_open(): ERR=%s.\n"), getVolCatName(), dpl_status_str(status)); m_vfd = NULL; return droplet_errno_to_system_errno(status); } bail_out: return -1; }
/* * Displays Resources * * show all * show <resource-keyword-name> e.g. show directors * show <resource-keyword-name>=<name> e.g. show director=HeadMan * show disabled shows disabled jobs * */ int show_cmd(UAContext *ua, const char *cmd) { int i, j, type, len; int recurse; char *res_name; RES *res = NULL; Dmsg1(20, "show: %s\n", ua->UA_sock->msg); LockRes(); for (i=1; i<ua->argc; i++) { if (bstrcasecmp(ua->argk[i], _("disabled"))) { show_disabled_jobs(ua); goto bail_out; } type = 0; res_name = ua->argk[i]; if (!ua->argv[i]) { /* was a name given? */ /* No name, dump all resources of specified type */ recurse = 1; len = strlen(res_name); for (j=0; avail_resources[j].res_name; j++) { if (bstrncasecmp(res_name, _(avail_resources[j].res_name), len)) { type = avail_resources[j].type; if (type > 0) { res = res_head[type-r_first]; } else { res = NULL; } break; } } } else { /* Dump a single resource with specified name */ recurse = 0; len = strlen(res_name); for (j=0; avail_resources[j].res_name; j++) { if (bstrncasecmp(res_name, _(avail_resources[j].res_name), len)) { type = avail_resources[j].type; res = (RES *)GetResWithName(type, ua->argv[i]); if (!res) { type = -3; } break; } } } switch (type) { case -1: /* all */ for (j=r_first; j<=r_last; j++) { dump_resource(j, res_head[j-r_first], bsendmsg, ua); } break; case -2: ua->send_msg(_("Keywords for the show command are:\n")); for (j=0; avail_resources[j].res_name; j++) { ua->error_msg("%s\n", _(avail_resources[j].res_name)); } goto bail_out; case -3: ua->error_msg(_("%s resource %s not found.\n"), res_name, ua->argv[i]); goto bail_out; case 0: ua->error_msg(_("Resource %s not found\n"), res_name); goto bail_out; default: dump_resource(recurse?type:-type, res, bsendmsg, ua); break; } } bail_out: UnlockRes(); return 1; }
/* * Parse a gluster definition into something we can use for setting * up the right connection to a gluster management server and get access * to a gluster volume. * * Syntax: * * gluster[+transport]://[server[:port]]/volname[/dir][?socket=...] * * 'gluster' is the protocol. * * 'transport' specifies the transport type used to connect to gluster * management daemon (glusterd). Valid transport types are tcp, unix * and rdma. If a transport type isn't specified, then tcp type is assumed. * * 'server' specifies the server where the volume file specification for * the given volume resides. This can be either hostname, ipv4 address * or ipv6 address. ipv6 address needs to be within square brackets [ ]. * If transport type is 'unix', then 'server' field should not be specifed. * The 'socket' field needs to be populated with the path to unix domain * socket. * * 'port' is the port number on which glusterd is listening. This is optional * and if not specified, QEMU will send 0 which will make gluster to use the * default port. If the transport type is unix, then 'port' should not be * specified. * * 'volname' is the name of the gluster volume which contains the backup images. * * 'dir' is an optional directory on the 'volname' * * Examples: * * gluster://1.2.3.4/testvol[/dir] * gluster+tcp://1.2.3.4/testvol[/dir] * gluster+tcp://1.2.3.4:24007/testvol[/dir] * gluster+tcp://[1:2:3:4:5:6:7:8]/testvol[/dir] * gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol[/dir] * gluster+tcp://server.domain.com:24007/testvol[/dir] * gluster+unix:///testvol[/dir]?socket=/tmp/glusterd.socket * gluster+rdma://1.2.3.4:24007/testvol[/dir] */ static inline bool parse_gfapi_devicename(char *devicename, char **transport, char **servername, char **volumename, char **dir, int *serverport) { char *bp; /* * Make sure its a URI that starts with gluster. */ if (!bstrncasecmp(devicename, "gluster", 7)) { return false; } /* * Parse any explicit protocol. */ bp = strchr(devicename, '+'); if (bp) { *transport = ++bp; bp = strchr(bp, ':'); if (bp) { *bp++ = '\0'; } else { goto bail_out; } } else { *transport = NULL; bp = strchr(devicename, ':'); if (!bp) { goto bail_out; } } /* * When protocol is not UNIX parse servername and portnr. */ if (!*transport || !bstrcasecmp(*transport, "unix")) { /* * Parse servername of gluster management server. */ bp = strchr(bp, '/'); /* * Validate URI. */ if (!bp || !*bp == '/') { goto bail_out; } /* * Skip the two // */ *bp++ = '\0'; bp++; *servername = bp; /* * Parse any explicit server portnr. * We search reverse in the string for a : what indicates * a port specification but in that string there may not contain a ']' * because then we searching in a IPv6 string. */ bp = strrchr(bp, ':'); if (bp && !strchr(bp, ']')) { char *port; *bp++ = '\0'; port = bp; bp = strchr(bp, '/'); if (!bp) { goto bail_out; } *bp++ = '\0'; *serverport = str_to_int64(port); *volumename = bp; /* * See if there is a dir specified. */ bp = strchr(bp, '/'); if (bp) { *bp++ = '\0'; *dir = bp; } } else { *serverport = 0; bp = *servername; /* * Parse the volume name. */ bp = strchr(bp, '/'); if (!bp) { goto bail_out; } *bp++ = '\0'; *volumename = bp; /* * See if there is a dir specified. */ bp = strchr(bp, '/'); if (bp) { *bp++ = '\0'; *dir = bp; } } } else { /* * For UNIX serverport is zero. */ *serverport = 0; /* * Validate URI. */ if (*bp != '/' || *(bp + 1) != '/') { goto bail_out; } /* * Skip the two // */ *bp++ = '\0'; bp++; /* * For UNIX URIs the server part of the URI needs to be empty. */ if (*bp++ != '/') { goto bail_out; } *volumename = bp; /* * See if there is a dir specified. */ bp = strchr(bp, '/'); if (bp) { *bp++ = '\0'; *dir = bp; } /* * Parse any socket parameters. */ bp = strchr(bp, '?'); if (bp) { if (bstrncasecmp(bp + 1, "socket=", 7)) { *bp = '\0'; *servername = bp + 8; } } } return true; bail_out: return false; }
/* * Parse the plugin definition passed in. * * The definition is in this form: * * bpipe:file=<filepath>:read=<readprogram>:write=<writeprogram> */ static bRC parse_plugin_definition(bpContext *ctx, void *value) { int i, cnt; char *plugin_definition, *bp, *argument, *argument_value; plugin_ctx *p_ctx = (plugin_ctx *)ctx->pContext; bool keep_existing; bool compatible = true; if (!p_ctx || !value) { return bRC_Error; } keep_existing = (p_ctx->plugin_options) ? true : false; /* * Parse the plugin definition. * Make a private copy of the whole string. */ plugin_definition = bstrdup((char *)value); bp = strchr(plugin_definition, ':'); if (!bp) { Jmsg(ctx, M_FATAL, "bpipe-fd: Illegal plugin definition %s\n", plugin_definition); Dmsg(ctx, dbglvl, "bpipe-fd: Illegal plugin definition %s\n", plugin_definition); goto bail_out; } /* * Skip the first ':' */ bp++; /* * See if we are parsing a new plugin definition e.g. one with keywords. */ argument = bp; while (argument) { if (strlen(argument) == 0) { break; } for (i = 0; plugin_arguments[i].name; i++) { if (bstrncasecmp(argument, plugin_arguments[i].name, strlen(plugin_arguments[i].name))) { compatible = false; break; } } if (!plugin_arguments[i].name && !compatible) { /* * Parsing something fishy ? e.g. partly with known keywords. */ Jmsg(ctx, M_FATAL, "bpipe-fd: Found mixing of old and new syntax, please fix your plugin definition\n", plugin_definition); Dmsg(ctx, dbglvl, "bpipe-fd: Found mixing of old and new syntax, please fix your plugin definition\n", plugin_definition); goto bail_out; } argument = strchr(argument, ':'); if (argument) { argument++; } } /* * Start processing the definition, if compatible is left set we are pretending that we are * parsing a plugin definition in the old syntax and hope for the best. */ cnt = 1; while (bp) { if (strlen(bp) == 0) { break; } argument = bp; if (compatible) { char **str_destination = NULL; /* * See if there are more arguments and setup for the next run. */ do { bp = strchr(bp, ':'); if (bp) { if (*(bp - 1) != '\\') { *bp++ = '\0'; break; } else { bp++; } } } while (bp); /* * See which field this is in the argument string. */ switch (cnt) { case 1: str_destination = &p_ctx->fname; break; case 2: str_destination = &p_ctx->reader; break; case 3: str_destination = &p_ctx->writer; break; default: break; } if (str_destination) { if (keep_existing) { /* * Keep the first value, ignore any next setting. */ set_string_if_null(str_destination, argument); } else { /* * Overwrite any existing value. */ set_string(str_destination, argument); } } } else { /* * Each argument is in the form: * <argument> = <argument_value> * * So we setup the right pointers here, argument to the beginning * of the argument, argument_value to the beginning of the argument_value. */ argument_value = strchr(bp, '='); *argument_value++ = '\0'; /* * See if there are more arguments and setup for the next run. */ bp = argument_value; do { bp = strchr(bp, ':'); if (bp) { if (*(bp - 1) != '\\') { *bp++ = '\0'; break; } else { bp++; } } } while (bp); for (i = 0; plugin_arguments[i].name; i++) { if (bstrncasecmp(argument, plugin_arguments[i].name, plugin_arguments[i].cmp_length)) { char **str_destination = NULL; switch (plugin_arguments[i].type) { case argument_file: str_destination = &p_ctx->fname; break; case argument_reader: str_destination = &p_ctx->reader; break; case argument_writer: str_destination = &p_ctx->writer; break; default: break; } if (str_destination) { if (keep_existing) { /* * Keep the first value, ignore any next setting. */ set_string_if_null(str_destination, argument_value); } else { /* * Overwrite any existing value. */ set_string(str_destination, argument_value); } } /* * When we have a match break the loop. */ break; } } /* * Got an invalid keyword ? */ if (!plugin_arguments[i].name) { Jmsg(ctx, M_FATAL, "bpipe-fd: Illegal argument %s with value %s in plugin definition\n", argument, argument_value); Dmsg(ctx, dbglvl, "bpipe-fd: Illegal argument %s with value %s in plugin definition\n", argument, argument_value); goto bail_out; } } cnt++; } free(plugin_definition); return bRC_OK; bail_out: free(plugin_definition); return bRC_Error; }