/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
/*
* (C) 2001 by Argonne National Laboratory.
* See COPYRIGHT in top-level directory.
*/
/*
* This file contains a simple implementation of the name server routines,
* using a file written to a shared file system to communication the
* data.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "mpiimpl.h"
#include "namepub.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
/*
=== BEGIN_MPI_T_CVAR_INFO_BLOCK ===
categories:
- name : PROCESS_MANAGER
description : cvars that control the client-side process manager code
cvars:
- name : MPIR_CVAR_NAMESERV_FILE_PUBDIR
category : PROCESS_MANAGER
alt-env : MPIR_CVAR_NAMEPUB_DIR
type : string
default : NULL
class : none
verbosity : MPI_T_VERBOSITY_USER_BASIC
scope : MPI_T_SCOPE_ALL_EQ
description : >-
Sets the directory to use for MPI service publishing in the
file nameserv implementation. Allows the user to override
where the publish and lookup information is placed for
connect/accept based applications.
=== END_MPI_T_CVAR_INFO_BLOCK ===
*/
/* For writing the name/service pair */
/* style: allow:fprintf:1 sig:0 */
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
/* Define the name service handle */
#define MPID_MAX_NAMEPUB 64
struct MPID_NS_Handle {
int nactive; /* Number of active files */
int mypid; /* My process id */
char dirname[MAXPATHLEN]; /* Directory for all files */
char *(filenames[MPID_MAX_NAMEPUB]); /* All created files */
};
/* Create a structure that we will use to remember files created for
publishing. */
#undef FUNCNAME
#define FUNCNAME MPID_NS_Create
#undef FCNAME
#define FCNAME MPL_QUOTE(FUNCNAME)
int MPID_NS_Create(const MPIR_Info * info_ptr, MPID_NS_Handle * handle_ptr)
{
const char *dirname;
struct stat st;
int err, ret;
*handle_ptr = (MPID_NS_Handle) MPL_malloc(sizeof(struct MPID_NS_Handle), MPL_MEM_PM);
/* --BEGIN ERROR HANDLING-- */
if (!*handle_ptr) {
err =
MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER,
"**nomem", 0);
return err;
}
/* --END ERROR HANDLING-- */
(*handle_ptr)->nactive = 0;
(*handle_ptr)->mypid = getpid();
/* Get the dirname. Could use an info value of NAMEPUB_CONTACT */
dirname = MPIR_CVAR_NAMESERV_FILE_PUBDIR;
if (!dirname) {
/* user did not specify a directory, try using HOME */
ret = MPL_env2str("HOME", &dirname);
if (!ret) {
/* HOME not found ; use current directory */
dirname = ".";
}
}
MPL_strncpy((*handle_ptr)->dirname, dirname, MAXPATHLEN);
MPL_strnapp((*handle_ptr)->dirname, "/.mpinamepub/", MAXPATHLEN);
/* Make the directory if necessary */
/* FIXME : Determine if the directory exists before trying to create it */
if (stat((*handle_ptr)->dirname, &st) || !S_ISDIR(st.st_mode)) {
/* This mode is rwx by owner only. */
if (mkdir((*handle_ptr)->dirname, 0000700)) {
/* FIXME : An error. Ignore most ?
* For example, ignore EEXIST? */
;
}
}
return 0;
}
#undef FUNCNAME
#define FUNCNAME MPID_NS_Publish
#undef FCNAME
#define FCNAME MPL_QUOTE(FUNCNAME)
int MPID_NS_Publish(MPID_NS_Handle handle, const MPIR_Info * info_ptr,
const char service_name[], const char port[])
{
FILE *fp;
char filename[MAXPATHLEN];
int err;
/* Determine file and directory name. The file name is from
* the service name */
MPL_strncpy(filename, handle->dirname, MAXPATHLEN);
MPL_strnapp(filename, service_name, MAXPATHLEN);
/* Add the file name to the known files now, in case there is
* a failure during open or writing */
if (handle->nactive < MPID_MAX_NAMEPUB) {
handle->filenames[handle->nactive++] = MPL_strdup(filename);
} else {
/* --BEGIN ERROR HANDLING-- */
err = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
FCNAME, __LINE__, MPI_ERR_OTHER, "**nomem", 0);
return err;
/* --END ERROR HANDLING-- */
}
/* Now, open the file and write out the port name */
fp = fopen(filename, "w");
/* --BEGIN ERROR HANDLING-- */
if (!fp) {
char *reason;
/* Generate a better error message */
/* Check for errno =
* EACCES (access denied to file or a dir),
* ENAMETOOLONG (name too long)
* ENOENT (no such directory)
* ENOTDIR (a name in the path that should have been a directory
* wasn't)
* ELOOP (too many symbolic links in path)
* ENOMEM (insufficient kernel memory available)
* There are a few others that aren't covered here
*/
#ifdef HAVE_STRERROR
reason = strerror(errno);
#else
/* FIXME : This should use internationalization calls */
switch (errno) {
case EACCES:
reason = "Access denied to some element of the path";
break;
case ENAMETOOLONG:
reason = "File name is too long";
break;
case ENOENT:
reason = "A directory specified in the path does not exist";
break;
case ENOTDIR:
reason =
"A name specified in the path exists, but is not a directory and is used where a directory is required";
break;
case ENOMEM:
reason "Insufficient kernel memory available";
default:
MPL_snprintf(rstr, sizeof(rstr), "errno = %d", errno);
}
#endif
err = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
MPI_ERR_OTHER, "**namepubfile",
"**namepubfile %s %s %s", service_name, filename, reason);
return err;
}
/* --END ERROR HANDLING-- */
/* Should also add date? */
fprintf(fp, "%s\n%d\n", port, handle->mypid);
fclose(fp);
return 0;
}
#undef FUNCNAME
#define FUNCNAME MPID_NS_Lookup
#undef FCNAME
#define FCNAME MPL_QUOTE(FUNCNAME)
int MPID_NS_Lookup(MPID_NS_Handle handle, const MPIR_Info * info_ptr,
const char service_name[], char port[])
{
FILE *fp;
char filename[MAXPATHLEN];
int mpi_errno = MPI_SUCCESS;
/* Determine file and directory name. The file name is from
* the service name */
MPL_strncpy(filename, handle->dirname, MAXPATHLEN);
MPL_strnapp(filename, service_name, MAXPATHLEN);
fp = fopen(filename, "r");
if (!fp) {
/* --BEGIN ERROR HANDLING-- */
port[0] = 0;
MPIR_ERR_SET1(mpi_errno, MPI_ERR_NAME,
"**namepubnotpub", "**namepubnotpub %s", service_name);
/* --END ERROR HANDLING-- */
} else {
/* The first line is the name, the second is the
* process that published. We just read the name */
if (!fgets(port, MPI_MAX_PORT_NAME, fp)) {
/* --BEGIN ERROR HANDLING-- */
port[0] = 0;
MPIR_ERR_SET1(mpi_errno, MPI_ERR_NAME,
"**namepubnotfound", "**namepubnotfound %s", service_name);
/* --END ERROR HANDLING-- */
} else {
char *nl;
/* Remove the newline, if any. We use fgets instead of fscanf
* to allow port names to contain blanks */
nl = strchr(port, '\n');
if (nl)
*nl = 0;
/* printf("Read %s from %s\n", port, filename); */
}
fclose(fp);
}
return mpi_errno;
}
#undef FUNCNAME
#define FUNCNAME MPID_NS_Unpublish
#undef FCNAME
#define FCNAME MPL_QUOTE(FUNCNAME)
int MPID_NS_Unpublish(MPID_NS_Handle handle, const MPIR_Info * info_ptr, const char service_name[])
{
char filename[MAXPATHLEN];
int err;
int i;
/* Remove the file corresponding to the service name */
/* Determine file and directory name. The file name is from
* the service name */
MPL_strncpy(filename, handle->dirname, MAXPATHLEN);
MPL_strnapp(filename, service_name, MAXPATHLEN);
/* Find the filename from the list of published files */
for (i = 0; i < handle->nactive; i++) {
if (handle->filenames[i] && strcmp(filename, handle->filenames[i]) == 0) {
/* unlink the file only if we find it */
unlink(filename);
MPL_free(handle->filenames[i]);
handle->filenames[i] = 0;
break;
}
}
if (i == handle->nactive) {
/* --BEGIN ERROR HANDLING-- */
/* Error: this name was not found */
err = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
MPI_ERR_SERVICE, "**namepubnotpub",
"**namepubnotpub %s", service_name);
return err;
/* --END ERROR HANDLING-- */
}
/* Later, we can reduce the number of active and compress the list */
return 0;
}
#undef FUNCNAME
#define FUNCNAME MPID_NS_Free
#undef FCNAME
#define FCNAME MPL_QUOTE(FUNCNAME)
int MPID_NS_Free(MPID_NS_Handle * handle_ptr)
{
int i;
MPID_NS_Handle handle = *handle_ptr;
for (i = 0; i < handle->nactive; i++) {
if (handle->filenames[i]) {
/* Remove the file if it still exists */
unlink(handle->filenames[i]);
MPL_free(handle->filenames[i]);
}
}
MPL_free(*handle_ptr);
*handle_ptr = 0;
return 0;
}