Blame src/pmi/simple/simple_pmiutil.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/* Allow fprintf to logfile */
Packit Service c5cf8c
/* style: allow:fprintf:1 sig:0 */
Packit Service c5cf8c
Packit Service c5cf8c
/* Utility functions associated with PMI implementation, but not part of
Packit Service c5cf8c
   the PMI interface itself.  Reading and writing on pipes, signals, and parsing
Packit Service c5cf8c
   key=value messages
Packit Service c5cf8c
*/
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpichconf.h"
Packit Service c5cf8c
Packit Service c5cf8c
#include <stdio.h>
Packit Service c5cf8c
#ifdef HAVE_STDLIB_H
Packit Service c5cf8c
#include <stdlib.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#include <stdarg.h>
Packit Service c5cf8c
#ifdef HAVE_STRING_H
Packit Service c5cf8c
#include <string.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#ifdef HAVE_UNISTD_H
Packit Service c5cf8c
#include <unistd.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#include <errno.h>
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpl.h"
Packit Service c5cf8c
Packit Service c5cf8c
#include "pmi.h"
Packit Service c5cf8c
#include "simple_pmiutil.h"
Packit Service c5cf8c
Packit Service c5cf8c
#define MAXVALLEN 1024
Packit Service c5cf8c
#define MAXKEYLEN   32
Packit Service c5cf8c
Packit Service c5cf8c
/* These are not the keyvals in the keyval space that is part of the
Packit Service c5cf8c
   PMI specification.
Packit Service c5cf8c
   They are just part of this implementation's internal utilities.
Packit Service c5cf8c
*/
Packit Service c5cf8c
struct PMIU_keyval_pairs {
Packit Service c5cf8c
    char key[MAXKEYLEN];
Packit Service c5cf8c
    char value[MAXVALLEN];
Packit Service c5cf8c
};
Packit Service c5cf8c
static struct PMIU_keyval_pairs PMIU_keyval_tab[64] = { {{0}, {0}} };
Packit Service c5cf8c
Packit Service c5cf8c
static int PMIU_keyval_tab_idx = 0;
Packit Service c5cf8c
Packit Service c5cf8c
/* This is used to prepend printed output.  Set the initial value to
Packit Service c5cf8c
   "unset" */
Packit Service c5cf8c
static char PMIU_print_id[PMIU_IDSIZE] = "unset";
Packit Service c5cf8c
Packit Service c5cf8c
void PMIU_Set_rank(int PMI_rank)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPL_snprintf(PMIU_print_id, PMIU_IDSIZE, "cli_%d", PMI_rank);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
void PMIU_SetServer(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPL_strncpy(PMIU_print_id, "server", PMIU_IDSIZE);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Note that vfprintf is part of C89 */
Packit Service c5cf8c
Packit Service c5cf8c
/* style: allow:fprintf:1 sig:0 */
Packit Service c5cf8c
/* style: allow:vfprintf:1 sig:0 */
Packit Service c5cf8c
/* This should be combined with the message routines */
Packit Service c5cf8c
void PMIU_printf(int print_flag, const char *fmt, ...)
Packit Service c5cf8c
{
Packit Service c5cf8c
    va_list ap;
Packit Service c5cf8c
    static FILE *logfile = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    /* In some cases when we are debugging, the handling of stdout or
Packit Service c5cf8c
     * stderr may be unreliable.  In that case, we make it possible to
Packit Service c5cf8c
     * select an output file. */
Packit Service c5cf8c
    if (!logfile) {
Packit Service c5cf8c
        char *p;
Packit Service c5cf8c
        p = getenv("PMI_USE_LOGFILE");
Packit Service c5cf8c
        if (p) {
Packit Service c5cf8c
            char filename[1024];
Packit Service c5cf8c
            p = getenv("PMI_ID");
Packit Service c5cf8c
            if (p) {
Packit Service c5cf8c
                MPL_snprintf(filename, sizeof(filename), "testclient-%s.out", p);
Packit Service c5cf8c
                logfile = fopen(filename, "w");
Packit Service c5cf8c
            } else {
Packit Service c5cf8c
                logfile = fopen("testserver.out", "w");
Packit Service c5cf8c
            }
Packit Service c5cf8c
        } else
Packit Service c5cf8c
            logfile = stderr;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (print_flag) {
Packit Service c5cf8c
        /* MPL_error_printf("[%s]: ", PMIU_print_id); */
Packit Service c5cf8c
        /* FIXME: Decide what role PMIU_printf should have (if any) and
Packit Service c5cf8c
         * select the appropriate MPIU routine */
Packit Service c5cf8c
        fprintf(logfile, "[%s]: ", PMIU_print_id);
Packit Service c5cf8c
        va_start(ap, fmt);
Packit Service c5cf8c
        vfprintf(logfile, fmt, ap);
Packit Service c5cf8c
        va_end(ap);
Packit Service c5cf8c
        fflush(logfile);
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#define MAX_READLINE 1024
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Return the next newline-terminated string of maximum length maxlen.
Packit Service c5cf8c
 * This is a buffered version, and reads from fd as necessary.  A
Packit Service c5cf8c
 */
Packit Service c5cf8c
int PMIU_readline(int fd, char *buf, int maxlen)
Packit Service c5cf8c
{
Packit Service c5cf8c
    static char readbuf[MAX_READLINE];
Packit Service c5cf8c
    static char *nextChar = 0, *lastChar = 0;   /* lastChar is really one past
Packit Service c5cf8c
                                                 * last char */
Packit Service c5cf8c
    static int lastfd = -1;
Packit Service c5cf8c
    ssize_t n;
Packit Service c5cf8c
    int curlen;
Packit Service c5cf8c
    char *p, ch;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Note: On the client side, only one thread at a time should
Packit Service c5cf8c
     * be calling this, and there should only be a single fd.
Packit Service c5cf8c
     * Server side code should not use this routine (see the
Packit Service c5cf8c
     * replacement version in src/pm/util/pmiserv.c) */
Packit Service c5cf8c
    if (nextChar != lastChar && fd != lastfd) {
Packit Service c5cf8c
        MPL_internal_error_printf("Panic - buffer inconsistent\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    p = buf;
Packit Service c5cf8c
    curlen = 1; /* Make room for the null */
Packit Service c5cf8c
    while (curlen < maxlen) {
Packit Service c5cf8c
        if (nextChar == lastChar) {
Packit Service c5cf8c
            lastfd = fd;
Packit Service c5cf8c
            do {
Packit Service c5cf8c
                n = read(fd, readbuf, sizeof(readbuf) - 1);
Packit Service c5cf8c
            } while (n == -1 && errno == EINTR);
Packit Service c5cf8c
            if (n == 0) {
Packit Service c5cf8c
                /* EOF */
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            } else if (n < 0) {
Packit Service c5cf8c
                /* Error.  Return a negative value if there is no
Packit Service c5cf8c
                 * data.  Save the errno in case we need to return it
Packit Service c5cf8c
                 * later. */
Packit Service c5cf8c
                if (curlen == 1) {
Packit Service c5cf8c
                    curlen = 0;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            nextChar = readbuf;
Packit Service c5cf8c
            lastChar = readbuf + n;
Packit Service c5cf8c
            /* Add a null at the end just to make it easier to print
Packit Service c5cf8c
             * the read buffer */
Packit Service c5cf8c
            readbuf[n] = 0;
Packit Service c5cf8c
            /* FIXME: Make this an optional output */
Packit Service c5cf8c
            /* printf("Readline %s\n", readbuf); */
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        ch = *nextChar++;
Packit Service c5cf8c
        *p++ = ch;
Packit Service c5cf8c
        curlen++;
Packit Service c5cf8c
        if (ch == '\n')
Packit Service c5cf8c
            break;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* We null terminate the string for convenience in printing */
Packit Service c5cf8c
    *p = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Return the number of characters, not counting the null */
Packit Service c5cf8c
    return curlen - 1;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMIU_writeline(int fd, char *buf)
Packit Service c5cf8c
{
Packit Service c5cf8c
    ssize_t size, n;
Packit Service c5cf8c
Packit Service c5cf8c
    size = strlen(buf);
Packit Service c5cf8c
    if (size > PMIU_MAXLINE) {
Packit Service c5cf8c
        buf[PMIU_MAXLINE - 1] = '\0';
Packit Service c5cf8c
        PMIU_printf(1, "write_line: message string too big: :%s:\n", buf);
Packit Service c5cf8c
    } else if (buf[strlen(buf) - 1] != '\n')    /* error:  no newline at end */
Packit Service c5cf8c
        PMIU_printf(1, "write_line: message string doesn't end in newline: :%s:\n", buf);
Packit Service c5cf8c
    else {
Packit Service c5cf8c
        do {
Packit Service c5cf8c
            n = write(fd, buf, size);
Packit Service c5cf8c
        } while (n == -1 && errno == EINTR);
Packit Service c5cf8c
Packit Service c5cf8c
        if (n < 0) {
Packit Service c5cf8c
            PMIU_printf(1, "write_line error; fd=%d buf=:%s:\n", fd, buf);
Packit Service c5cf8c
            perror("system msg for write_line failure ");
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (n < size)
Packit Service c5cf8c
            PMIU_printf(1, "write_line failed to write entire message\n");
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Given an input string st, parse it into internal storage that can be
Packit Service c5cf8c
 * queried by routines such as PMIU_getval.
Packit Service c5cf8c
 */
Packit Service c5cf8c
int PMIU_parse_keyvals(char *st)
Packit Service c5cf8c
{
Packit Service c5cf8c
    char *p, *keystart, *valstart;
Packit Service c5cf8c
    int offset;
Packit Service c5cf8c
Packit Service c5cf8c
    if (!st)
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
Packit Service c5cf8c
    PMIU_keyval_tab_idx = 0;
Packit Service c5cf8c
    p = st;
Packit Service c5cf8c
    while (1) {
Packit Service c5cf8c
        while (*p == ' ')
Packit Service c5cf8c
            p++;
Packit Service c5cf8c
        /* got non-blank */
Packit Service c5cf8c
        if (*p == '=') {
Packit Service c5cf8c
            PMIU_printf(1, "PMIU_parse_keyvals:  unexpected = at character %d in %s\n", p - st, st);
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (*p == '\n' || *p == '\0')
Packit Service c5cf8c
            return PMI_SUCCESS; /* normal exit */
Packit Service c5cf8c
        /* got normal character */
Packit Service c5cf8c
        keystart = p;   /* remember where key started */
Packit Service c5cf8c
        while (*p != ' ' && *p != '=' && *p != '\n' && *p != '\0')
Packit Service c5cf8c
            p++;
Packit Service c5cf8c
        if (*p == ' ' || *p == '\n' || *p == '\0') {
Packit Service c5cf8c
            PMIU_printf(1,
Packit Service c5cf8c
                        "PMIU_parse_keyvals: unexpected key delimiter at character %d in %s\n",
Packit Service c5cf8c
                        p - st, st);
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* Null terminate the key */
Packit Service c5cf8c
        *p = 0;
Packit Service c5cf8c
        /* store key */
Packit Service c5cf8c
        MPL_strncpy(PMIU_keyval_tab[PMIU_keyval_tab_idx].key, keystart, MAXKEYLEN);
Packit Service c5cf8c
Packit Service c5cf8c
        valstart = ++p; /* start of value */
Packit Service c5cf8c
        while (*p != ' ' && *p != '\n' && *p != '\0')
Packit Service c5cf8c
            p++;
Packit Service c5cf8c
        /* store value */
Packit Service c5cf8c
        MPL_strncpy(PMIU_keyval_tab[PMIU_keyval_tab_idx].value, valstart, MAXVALLEN);
Packit Service c5cf8c
        offset = (int) (p - valstart);
Packit Service c5cf8c
        /* When compiled with -fPIC, the pgcc compiler generates incorrect
Packit Service c5cf8c
         * code if "p - valstart" is used instead of using the
Packit Service c5cf8c
         * intermediate offset */
Packit Service c5cf8c
        PMIU_keyval_tab[PMIU_keyval_tab_idx].value[offset] = '\0';
Packit Service c5cf8c
        PMIU_keyval_tab_idx++;
Packit Service c5cf8c
        if (*p == ' ')
Packit Service c5cf8c
            continue;
Packit Service c5cf8c
        if (*p == '\n' || *p == '\0')
Packit Service c5cf8c
            return PMI_SUCCESS; /* value has been set to empty */
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
void PMIU_dump_keyvals(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i;
Packit Service c5cf8c
    for (i = 0; i < PMIU_keyval_tab_idx; i++)
Packit Service c5cf8c
        PMIU_printf(1, "  %s=%s\n", PMIU_keyval_tab[i].key, PMIU_keyval_tab[i].value);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
char *PMIU_getval(const char *keystr, char *valstr, int vallen)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, rc;
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < PMIU_keyval_tab_idx; i++) {
Packit Service c5cf8c
        if (strcmp(keystr, PMIU_keyval_tab[i].key) == 0) {
Packit Service c5cf8c
            rc = MPL_strncpy(valstr, PMIU_keyval_tab[i].value, vallen);
Packit Service c5cf8c
            if (rc != 0) {
Packit Service c5cf8c
                PMIU_printf(1, "MPL_strncpy failed in PMIU_getval\n");
Packit Service c5cf8c
                return NULL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            return valstr;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    valstr[0] = '\0';
Packit Service c5cf8c
    return NULL;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
void PMIU_chgval(const char *keystr, char *valstr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i;
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < PMIU_keyval_tab_idx; i++) {
Packit Service c5cf8c
        if (strcmp(keystr, PMIU_keyval_tab[i].key) == 0) {
Packit Service c5cf8c
            MPL_strncpy(PMIU_keyval_tab[i].value, valstr, MAXVALLEN - 1);
Packit Service c5cf8c
            PMIU_keyval_tab[i].value[MAXVALLEN - 1] = '\0';
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
}