//!
//! Retrieves a given device information (assigned IPs and NMS).
//!
//! @param[in]  dev
//! @param[out] outips
//! @param[out] outnms
//! @param[out] len
//!
//! @return EUCA_OK on success and the out fields will be set properly. On failure the
//!         following error codes are returned:
//!         - EUCA_ERROR: if we fail to retrieve the interfaces addresses.
//!         - EUCA_INVALID_ERROR: if any parameter does not meet the preconditions
//!
//! @pre dev, outips, outnms and len must not be NULL.
//!
//! @note
//! @todo replace with a better version.
//!
int getdevinfo(char *dev, u32 ** outips, u32 ** outnms, int *len)
{
    int rc = 0;
    int count = 0;
    char host[NI_MAXHOST] = "";
    char buf[32] = "";
    void *tmpAddrPtr = NULL;
    struct ifaddrs *ifaddr = NULL;
    struct ifaddrs *ifa = NULL;
    struct sockaddr_in *ifs = NULL;

    if ((dev == NULL) || (outips == NULL) || (outnms == NULL) || (len == NULL))
        return (EUCA_INVALID_ERROR);

    if ((rc = getifaddrs(&ifaddr)) != 0) {
        return (EUCA_ERROR);
    }

    *outips = *outnms = NULL;
    *len = 0;

    count = 0;
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (!strcmp(dev, "all") || !strcmp(ifa->ifa_name, dev)) {
            if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
                if ((rc = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) == 0) {
                    count++;

                    //! @todo handle graceful out of memory condition and report it
                    *outips = EUCA_REALLOC(*outips, count, sizeof(u32));
                    *outnms = EUCA_REALLOC(*outnms, count, sizeof(u32));

                    (*outips)[count - 1] = dot2hex(host);

                    ifs = ((struct sockaddr_in *)ifa->ifa_netmask);
                    tmpAddrPtr = &ifs->sin_addr;
                    if (inet_ntop(AF_INET, tmpAddrPtr, buf, 32)) {
                        (*outnms)[count - 1] = dot2hex(buf);
                    }
                }
            }
        }
    }

    freeifaddrs(ifaddr);
    *len = count;
    return (EUCA_OK);
}
Beispiel #2
0
//!
//! appends string 'src' to 'dst', up to 'src_len' characters (unless set
//! to 0, in which case to the end of 'src'), enlarging the 'dst' as necessary
//! returns the concatenated string or NULL if memory could not be allocated
//! if 'src' is an empty string, 'dst' is returned.
//!
//! @param[in] dst the destination string to append to
//! @param[in] src the source string to add to 'dst'
//! @param[in] src_limit the number of character to append from 'src'
//!
//! @return the concatenated string or NULL if memory could not be allocated
//!         if 'src' is an empty string, 'dst' is returned.
//!
static char *c_wcappendn(char *dst, const char *src, size_t src_limit)
{
    size_t src_len = 0;
    size_t dst_len = 0;

    // Make sure we have a valid source
    if (src == NULL)
        return (dst);

    // Should not be empty
    if ((src_len = strlen(src)) < 1)
        return (dst);

    // Estimate the proper length
    if ((src_len > src_limit) && (src_limit > 0))
        src_len = src_limit;

    if (dst != NULL) {
        dst_len = strlen(dst);
        if ((dst = (char *)EUCA_REALLOC(dst, (dst_len + src_len + 1), sizeof(char))) == NULL) {
            return (NULL);
        }
    } else {
        if ((dst = (char *)EUCA_ALLOC((dst_len + src_len + 1), sizeof(char))) == NULL) {
            return (NULL);
        }
        *dst = '\0';
    }

    return (strncat(dst, src, src_len));
}
Beispiel #3
0
//!
//!
//!
//! @param[in] log_error
//! @param[in] format
//! @param[in] ...
//!
//! @return
//!
//! @pre
//!
//! @note
//!
static char *pruntf(boolean log_error, char *format, ...)
{
    va_list ap;
    FILE *IF = NULL;
    int rc = -1;
    int outsize = 1025;
    char cmd[1024] = { 0 };
    size_t bytes = 0;
    char *output = NULL;

    va_start(ap, format);
    vsnprintf(cmd, 1024, format, ap);

    strncat(cmd, " 2>&1", 1024 - 1);
    output = NULL;

    IF = popen(cmd, "r");
    if (!IF) {
        LOGERROR("cannot popen() cmd '%s' for read\n", cmd);
        va_end(ap);
        return (NULL);
    }

    output = EUCA_ALLOC(outsize, sizeof(char));
    if (output) {
        output[0] = '\0';              // make sure we return an empty string if there is no output
    }

    while ((output != NULL) && (bytes = fread(output + (outsize - 1025), 1, 1024, IF)) > 0) {
        output[(outsize - 1025) + bytes] = '\0';
        outsize += 1024;
        output = EUCA_REALLOC(output, outsize, sizeof(char));
    }

    if (output == NULL) {
        LOGERROR("failed to allocate mem for output\n");
        va_end(ap);
        pclose(IF);
        return (NULL);
    }

    rc = pclose(IF);
    if (rc) {
        //! @TODO improve this hacky special case: failure to find or detach non-existing loop device is not a failure
        if (strstr(cmd, "losetup") && strstr(output, ": No such device or address")) {
            rc = 0;
        } else {
            if (log_error) {
                LOGERROR("bad return code from cmd '%s'\n", cmd);
                LOGDEBUG("%s\n", output);
            }
            EUCA_FREE(output);
        }
    }
    va_end(ap);

    return (output);
}
/**
 * Appends pointer ptr to the end of the given pointer array arr. The array should
 * have been malloc'd. The allocation is adjusted as needed.
 * @param arr [i/o] arr pointer to an array of pointers
 * @param max_arr [i/o] max_arr the number of array entries.
 * @param ptr (in] pointer to be appended to the array.
 * @return 0 on success. 1 otherwise.
 */
void *append_ptrarr(void *arr, int *max_arr, void *ptr) {
    arr = EUCA_REALLOC(arr, *max_arr + 1, sizeof (void *));
    if (arr == NULL) {
        LOGFATAL("out of memory: failed to (re)allocate array of pointers\n");
        LOGFATAL("Shutting down eucanetd.\n");
        get_stack_trace();
        exit (1);
    }
    void **parr = arr;
    parr[*max_arr] = ptr;
    (*max_arr)++;
    return (arr);    
}
Beispiel #5
0
//!
//!
//!
//! @param[in] fp
//!
//! @return a pointer to the file output string
//!
//! @pre \li The fp field MUST not be NULL.
//!      \li The file handles must have previously been opened.
//!
//! @post The file remains open regardless of the result.
//!
//! @note caller is responsible to free the returned memory
//!
char *fp2str(FILE * fp)
{
#define INCREMENT              512

    int buf_max = INCREMENT;
    int buf_current = 0;
    void *new_buf = NULL;
    char *last_read = NULL;
    char *buf = NULL;

    if (fp == NULL)
        return (NULL);

    do {
        // create/enlarge the buffer
        if ((new_buf = EUCA_REALLOC(buf, buf_max, sizeof(char))) == NULL) {
            // free partial buffer
            EUCA_FREE(buf);
            return (NULL);
        }

        memset((new_buf + buf_current), 0, (INCREMENT * sizeof(char)));

        buf = new_buf;
        LOGEXTREME("enlarged buf to %d\n", buf_max);

        do {                           // read in until EOF or buffer is full
            last_read = fgets(buf + buf_current, buf_max - buf_current, fp);
            if (last_read != NULL) {
                buf_current = strlen(buf);
            } else if (!feof(fp)) {
                LOGERROR("failed while reading from file handle\n");
                EUCA_FREE(buf);
                return (NULL);
            }

            LOGEXTREME("read %d characters so far (max=%d, last=%s)\n", buf_current, buf_max, last_read ? "no" : "yes");
        } while (last_read && (buf_max > (buf_current + 1)));   // +1 is needed for fgets() to put \0

        // in case it is full
        buf_max += INCREMENT;
    } while (last_read);

    return (buf);

#undef INCREMENT
}
Beispiel #6
0
//!
//!
//!
//! @param[in]  pMeta a pointer to the node controller (NC) metadata structure
//! @param[in]  serviceIds a list of service info.
//! @param[in]  serviceIdsLen the number of service info in the serviceIds list
//! @param[out] outStatuses list of service status
//! @param[out] outStatusesLen number of service status in the outStatuses list
//!
//! @return
//!
//! @pre
//!
//! @note
//!
int doDescribeServices(ncMetadata * pMeta, serviceInfoType * serviceIds, int serviceIdsLen, serviceStatusType ** outStatuses, int *outStatusesLen)
{
    int rc = 0;
    int i = 0;
    int j = 0;
    int port = 0;
    char uri[MAX_PATH] = { 0 };
    char uriType[32] = { 0 };
    char host[MAX_PATH] = { 0 };
    char path[MAX_PATH] = { 0 };
    serviceStatusType *myStatus = NULL;
    int do_report_cluster = 1;         // always do report on the cluster, otherwise CC won't get ENABLED
    int do_report_nodes = 0;
    int do_report_all = 0;
    char *my_partition = NULL;

    rc = initialize(pMeta, TRUE);      // DescribeServices is the only authoritative source of epoch
    if (rc) {
        return (1);
    }

    LOGDEBUG("invoked: userId=%s, serviceIdsLen=%d\n", SP(pMeta ? pMeta->userId : "UNKNOWN"), serviceIdsLen);

    //! @TODO for now, return error if list of services is passed in as parameter
    /*
       if (serviceIdsLen > 0) {
       LOGERROR("DescribeServices(): received non-zero number of input services, returning fail\n");
       *outStatusesLen = 0;
       *outStatuses = NULL;
       return(1);
       }
     */
    sem_mywait(CONFIG);
    {
        if (!strcmp(config->ccStatus.serviceId.name, "self")) {
            for (i = 0; i < serviceIdsLen; i++) {
                LOGDEBUG("received input serviceId[%d]\n", i);
                if (strlen(serviceIds[i].type)) {
                    if (!strcmp(serviceIds[i].type, "cluster")) {
                        snprintf(uri, MAX_PATH, "%s", serviceIds[i].uris[0]);
                        rc = tokenize_uri(uri, uriType, host, &port, path);
                        if (strlen(host)) {
                            LOGDEBUG("setting local serviceId to input serviceId (type=%s name=%s partition=%s)\n",
                                     SP(serviceIds[i].type), SP(serviceIds[i].name), SP(serviceIds[i].partition));
                            memcpy(&(config->ccStatus.serviceId), &(serviceIds[i]), sizeof(serviceInfoType));
                        }
                    } else if (!strcmp(serviceIds[i].type, "node")) {
                        do_report_nodes = 1;    // report on node services if requested explicitly
                    }
                }
            }
        }
    }
    sem_mypost(CONFIG);
    if (serviceIdsLen < 1) {           // if the describe request is not specific, report on everything
        do_report_cluster = 1;
        do_report_nodes = 1;
        do_report_all = 1;
    } else {                           // if the describe request is specific, identify which types are requested
        do_report_cluster = 0;
        do_report_nodes = 0;
        do_report_all = 0;
        for (i = 0; i < serviceIdsLen; i++) {
            LOGDEBUG("received input serviceId[%d]: %s %s %s %s\n", i, serviceIds[i].type, serviceIds[i].partition, serviceIds[i].name, serviceIds[i].uris[0]);
            if (strlen(serviceIds[i].type)) {
                if (!strcmp(serviceIds[i].type, "cluster")) {
                    do_report_cluster = 1;  // report on cluster services if requested explicitly
                } else if (!strcmp(serviceIds[i].type, "node")) {
                    do_report_nodes++; // count number of and report on node services if requested explicitly
                }
            }
        }
    }

    for (i = 0; i < 16; i++) {
        if (strlen(config->services[i].type)) {
            LOGDEBUG("internal serviceInfos type=%s name=%s partition=%s urisLen=%d\n", config->services[i].type,
                     config->services[i].name, config->services[i].partition, config->services[i].urisLen);
            if (!strcmp(config->services[i].type, "cluster")) {
                my_partition = config->services[i].partition;
            }
            for (j = 0; j < MAX_SERVICE_URIS; j++) {
                if (strlen(config->services[i].uris[j])) {
                    LOGDEBUG("internal serviceInfos\t uri[%d]:%s\n", j, config->services[i].uris[j]);
                }
            }
        }
    }

    for (i = 0; i < 16; i++) {
        if (strlen(config->disabledServices[i].type)) {
            LOGDEBUG("internal disabled serviceInfos type=%s name=%s partition=%s urisLen=%d\n", config->disabledServices[i].type,
                     config->disabledServices[i].name, config->disabledServices[i].partition, config->disabledServices[i].urisLen);
            for (j = 0; j < MAX_SERVICE_URIS; j++) {
                if (strlen(config->disabledServices[i].uris[j])) {
                    LOGDEBUG("internal disabled serviceInfos\t uri[%d]:%s\n", j, config->disabledServices[i].uris[j]);
                }
            }
        }
    }

    for (i = 0; i < 16; i++) {
        if (strlen(config->notreadyServices[i].type)) {
            LOGDEBUG("internal not ready serviceInfos type=%s name=%s partition=%s urisLen=%d\n", config->notreadyServices[i].type,
                     config->notreadyServices[i].name, config->notreadyServices[i].partition, config->notreadyServices[i].urisLen);
            for (j = 0; j < MAX_SERVICE_URIS; j++) {
                if (strlen(config->notreadyServices[i].uris[j])) {
                    LOGDEBUG("internal not ready serviceInfos\t uri[%d]:%s\n", j, config->notreadyServices[i].uris[j]);
                }
            }
        }
    }

    *outStatusesLen = 0;
    *outStatuses = NULL;

    if (do_report_cluster) {
        (*outStatusesLen) += 1;
        *outStatuses = EUCA_ZALLOC(1, sizeof(serviceStatusType));
        if (!*outStatuses) {
            LOGFATAL("out of memory!\n");
            unlock_exit(1);
        }

        myStatus = *outStatuses;
        snprintf(myStatus->localState, 32, "%s", config->ccStatus.localState);  // ENABLED, DISABLED, STOPPED, NOTREADY
        snprintf(myStatus->details, 1024, "%s", config->ccStatus.details);  // string that gets printed by 'euca-describe-services -E'
        myStatus->localEpoch = config->ccStatus.localEpoch;
        memcpy(&(myStatus->serviceId), &(config->ccStatus.serviceId), sizeof(serviceInfoType));
        LOGDEBUG("external services\t uri[%d]: %s %s %s %s %s\n",
                 0, myStatus->serviceId.type, myStatus->serviceId.partition, myStatus->serviceId.name, myStatus->localState, myStatus->serviceId.uris[0]);
    }

    if (do_report_nodes) {
        extern ccResourceCache *resourceCache;
        ccResourceCache resourceCacheLocal;

        sem_mywait(RESCACHE);
        memcpy(&resourceCacheLocal, resourceCache, sizeof(ccResourceCache));
        sem_mypost(RESCACHE);

        if (resourceCacheLocal.numResources > 0 && my_partition != NULL) {  // parition is unknown at early stages of CC initialization
            for (int idIdx = 0; idIdx < serviceIdsLen; idIdx++) {
                if (do_report_all || !strcmp(serviceIds[idIdx].type, "node")) {
                    for (int rIdx = 0; rIdx < resourceCacheLocal.numResources; rIdx++) {
                        ccResource *r = resourceCacheLocal.resources + rIdx;
                        if (do_report_all || (strlen(serviceIds[idIdx].name) && strlen(r->ip) && !strcmp(serviceIds[idIdx].name, r->ip))) {

                            // we have a node that we want to report about
                            (*outStatusesLen) += 1;
                            *outStatuses = EUCA_REALLOC(*outStatuses, *outStatusesLen, sizeof(serviceStatusType));
                            if (*outStatuses == NULL) {
                                LOGFATAL("out of memory! (outStatusesLen=%d)\n", *outStatusesLen);
                                unlock_exit(1);
                            }
                            myStatus = *outStatuses + *outStatusesLen - 1;
                            {
                                int resState = r->state;
                                int resNcState = r->ncState;
                                char *state = "BUGGY";
                                char *msg = "";
                                if (resState == RESUP) {
                                    if (resNcState == ENABLED) {
                                        state = "ENABLED";
                                        msg = "the node is operating normally";
                                    } else if (resNcState == STOPPED) {
                                        state = "STOPPED";
                                        msg = "the node is not accepting new instances";
                                    } else if (resNcState == NOTREADY) {
                                        state = "NOTREADY";
                                        if (strnlen(r->nodeMessage, 1024)) {
                                            msg = r->nodeMessage;
                                        } else {
                                            msg = "the node is currently experiencing problems and needs attention";
                                        }
                                    }
                                } else if (resState == RESASLEEP || resState == RESWAKING) {
                                    state = "NOTREADY";
                                    msg = "the node is currently in the sleep state";
                                } else if (resState == RESDOWN) {
                                    state = "NOTREADY";
                                    if (strnlen(r->nodeMessage, 1024)) {
                                        msg = r->nodeMessage;
                                    } else {
                                        msg = "the node is not responding to the cluster controller";
                                    }
                                }
                                snprintf(myStatus->localState, 32, "%s", state);
                                snprintf(myStatus->details, 1024, "%s", msg);   // string that gets printed by 'euca-describe-services -E'
                            }
                            myStatus->localEpoch = config->ccStatus.localEpoch;
                            sprintf(myStatus->serviceId.type, "node");
                            sprintf(myStatus->serviceId.name, r->hostname);
                            sprintf(myStatus->serviceId.partition, config->ccStatus.serviceId.partition);
                            sprintf(myStatus->serviceId.uris[0], r->ncURL);
                            myStatus->serviceId.urisLen = 1;
                            LOGDEBUG("external services\t uri[%d]: %s %s %s %s %s\n",
                                     idIdx, myStatus->serviceId.type, myStatus->serviceId.partition, myStatus->serviceId.name, myStatus->localState, myStatus->serviceId.uris[0]);
                        }
                    }
                }
            }
        }
    }

    LOGDEBUG("done\n");
    return (0);
}
Beispiel #7
0
//!
//!
//!
//! @param[in] log_error
//! @param[in] format
//! @param[in] ...
//!
//! @return
//!
//! @pre
//!
//! @note
//!
static char *execlp_output(boolean log_error, ...)
{
    va_list ap;
    int ntokens = 0;
    char cmd[256] = "";                // for logging, OK if command gets truncated

    // run through arguments once to count them
    va_start(ap, log_error);
    {
        char *s;
        while ((s = va_arg(ap, char *)) != NULL) {
            ntokens++;
        }
    }
    va_end(ap);
    if (ntokens < 1) {
        LOGERROR("internal error: too few arguments to %s\n", __func__);
        return NULL;
    }
    // allocate an array and run through arguments again, copying them into the array
    char **argv = EUCA_ZALLOC(ntokens + 1, sizeof(char *)); // one extra for the terminating NULL
    va_start(ap, log_error);
    {
        for (int i = 0; i < ntokens; i++) {
            argv[i] = strdup(va_arg(ap, char *));

            // append tokens to 'cmd', strictly for logging purposes
            int left_in_cmd = sizeof(cmd) - strlen(cmd);
            if (left_in_cmd > 1)       // has room for at least one character and '\0'
                snprintf(cmd + strlen(cmd), left_in_cmd, "%s%s%s%s", (i > 0) ? (" ") : (""),    // add space in front all but the first argument
                         (i == 0 || argv[i][0] == '-') ? ("") : ("'"),  // add quoates around non-flags
                         argv[i], (i == 0 || argv[i][0] == '-') ? ("") : ("'"));
        }
    }
    va_end(ap);

    char *output = NULL;

    // set up a pipe for getting stdout and stderror from child process
    int filedes[2];
    if (pipe(filedes)) {
        LOGERROR("failed to create a pipe\n");
        goto free;
    }
    LOGTRACE("executing: %s\n", cmd);

    pid_t cpid = fork();
    int rc = -1;
    if (cpid == -1) {
        LOGERROR("failed to fork\n");
        close(filedes[0]);
        close(filedes[1]);
        goto free;
    } else if (cpid == 0) {            // child
        close(filedes[0]);
        if (dup2(filedes[1], STDOUT_FILENO) == -1) {
            LOGERROR("failed to dup2\n");
            exit(-1);
        }
        if (dup2(filedes[1], STDERR_FILENO) == -1) {
            LOGERROR("failed to dup2\n");
            exit(-1);
        }
        exit(execvp(argv[0], argv));
    }
    // parent reads stdout and stdin from child into a string
    close(filedes[1]);

    int outsize = OUTPUT_ALLOC_CHUNK;  // allocate in chunks of this size
    int nextchar = 0;                  // offset of the next usable char
    int bytesread;
    output = EUCA_ALLOC(outsize, sizeof(char));
    if (output) {
        output[0] = '\0';              // return an empty string if there is no output
    }

    while ((output != NULL) && (bytesread = read(filedes[0], output + nextchar, outsize - nextchar - 1)) > 0) {
        nextchar += bytesread;
        output[nextchar] = '\0';
        if (nextchar + 1 == outsize) {
            outsize += OUTPUT_ALLOC_CHUNK;
            if (outsize > MAX_OUTPUT_BYTES) {
                LOGERROR("internal error: output from command is too long\n");
                EUCA_FREE(output);
                break;
            }
            output = EUCA_REALLOC(output, outsize, sizeof(char));
        }
    }
    if (output == NULL) {
        LOGERROR("failed to allocate mem for output\n");
    }
    close(filedes[0]);

    {                                  // wait for the child to reap status
        int status;
        rc = waitpid(cpid, &status, 0);
        if (rc == -1) {
            LOGERROR("failed to wait for child process\n");
        } else if (WIFEXITED(status)) {
            rc = WEXITSTATUS(status);
            if (rc) {
                LOGERROR("child return non-zero status (%d)\n", rc);
            }
        } else {
            LOGERROR("child process did not terminate normally\n");
            rc = -1;
        }
    }

    if (rc) {
        // there were problems above
        if ((output != NULL) && strstr(cmd, "losetup") && strstr(output, ": No such device or address")) {
            rc = 0;
        } else {
            if (log_error) {
                LOGERROR("bad return code from cmd %s\n", cmd);
                LOGDEBUG("%s\n", output);
            }
            EUCA_FREE(output);         // will be set to NULL
        }
    }

free:
    for (int i = 0; i < ntokens; i++) {
        EUCA_FREE(argv[i]);
    }
    EUCA_FREE(argv);

    return output;
}