Blame src/pmi/simple/simple_pmiutil.c

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