/* * cmdutil.c -- xce_test command-argument and RPC-error helpers (see * include/cmdutil.h). */ #include #include #include #include #include #include #include "cmdutil.h" #include "utils.h" /* xce_strerror_r */ #include "xce/errnox.h" /* strtol over [s, s + len): the whole span must be digits (optional * leading '-'), then range-checked. */ static int parse_span(const char* s, size_t len, long lo, long hi, long* out) { char buf[32]; char* end; long v; if ((s == NULL) || (len == 0)) { return -EINVAL; } for (size_t i = 0; i < len; i++) { if (!((s[i] >= '0' && s[i] <= '9') || (i == 0 && s[i] == '-'))) { return -EINVAL; } } if (len >= sizeof(buf)) { return -ERANGE; /* more digits than any long holds */ } memcpy(buf, s, len); buf[len] = '\0'; errno = 0; v = strtol(buf, &end, 10); if ((end == buf) || (*end != '\0')) { return -EINVAL; } if ((errno == ERANGE) || (v < lo) || (v > hi)) { return -ERANGE; } *out = v; return 0; } int cmdutil_parse_long(const char* s, long lo, long hi, long* out) { return parse_span(s, (s == NULL) ? 0 : strlen(s), lo, hi, out); } int cmdutil_split_host_tasks(const char* arg, char* host, size_t hostsz, int* ntasks) { const char* colon = strchr(arg, ':'); size_t hlen = (colon != NULL) ? (size_t)(colon - arg) : strlen(arg); long n = 1; if (hlen == 0) { return -EINVAL; } if (hlen >= hostsz) { return -ENAMETOOLONG; } if ((colon != NULL) && (cmdutil_parse_long(colon + 1, 1, INT_MAX, &n) < 0)) { return -EINVAL; } memcpy(host, arg, hlen); host[hlen] = '\0'; *ntasks = (int)n; return 0; } int cmdutil_parse_ntasks(const char* arg, uint32_t* min, uint32_t* max) { const char* comma = strchr(arg, ','); size_t mlen = (comma != NULL) ? (size_t)(comma - arg) : strlen(arg); long mn, mx; int rc; rc = parse_span(arg, mlen, 1, (long)UINT32_MAX, &mn); if (rc < 0) { return rc; } mx = mn; if (comma != NULL) { rc = cmdutil_parse_long(comma + 1, 1, (long)UINT32_MAX, &mx); if (rc < 0) { return rc; } if (mx < mn) { return -EINVAL; } } *min = (uint32_t)mn; *max = (uint32_t)mx; return 0; } int cmdutil_default_exdata(char** exdata, const char* path) { cJSON* root; cJSON* envs; if (*exdata != NULL) { return 0; } root = cJSON_CreateObject(); envs = cJSON_CreateObject(); if ((root == NULL) || (envs == NULL) || (cJSON_AddStringToObject(envs, "PATH", path ? path : "") == NULL)) { cJSON_Delete(root); cJSON_Delete(envs); return -ENOMEM; } cJSON_AddItemToObject(root, "sub_env_vars", envs); *exdata = cJSON_Print(root); cJSON_Delete(root); return (*exdata != NULL) ? 0 : -ENOMEM; } const char* cmdutil_errstr(int rc, char* buf, size_t bufsize) { int code = (rc < 0) ? -rc : rc; if (code >= XCE_ERRNO_BASE) { xce_strerror_r(code, buf, bufsize); } else { snprintf(buf, bufsize, "%s", strerror(code)); } return buf; } void cmdutil_rpc_error(const char* what, int rc) { char buf[128]; fprintf(stderr, "%s: %s\n", what, cmdutil_errstr(rc, buf, sizeof(buf))); errno = (rc < 0) ? -rc : rc; }