blob: dd0ccfb3e53f3c466cab7512a2db21567adcc94a [file] [log] [blame]
/*****************************************************************************\
* opt.c - options processing for sattach
* $Id$
*****************************************************************************
* Copyright (C) 2002-2006 The Regents of the University of California.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Mark Grondona <grondona1@llnl.gov>, et. al.
* UCRL-CODE-226842.
*
* This file is part of SLURM, a resource management program.
* For details, see <http://www.llnl.gov/linux/slurm/>.
*
* SLURM is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with SLURM; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
\*****************************************************************************/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h> /* strcpy, strncasecmp */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#if HAVE_GETOPT_H
# include <getopt.h>
#else
# include "src/common/getopt.h"
#endif
#include <fcntl.h>
#include <stdarg.h> /* va_start */
#include <stdio.h>
#include <stdlib.h> /* getenv */
#include <pwd.h> /* getpwuid */
#include <ctype.h> /* isdigit */
#include <sys/param.h> /* MAXPATHLEN */
#include <sys/stat.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include "src/common/list.h"
#include "src/common/log.h"
#include "src/common/parse_time.h"
#include "src/common/slurm_protocol_api.h"
#include "src/common/uid.h"
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
#include "src/common/slurm_rlimits_info.h"
#include "src/common/read_config.h" /* contains getnodename() */
#include "src/sattach/opt.h"
#include "src/common/mpi.h"
/* generic getopt_long flags, integers and *not* valid characters */
#define LONG_OPT_LAYOUT_ONLY 0x100
#define LONG_OPT_DEBUGGER_TEST 0x101
#define LONG_OPT_IN_FILTER 0x102
#define LONG_OPT_OUT_FILTER 0x103
#define LONG_OPT_ERR_FILTER 0x104
/*---- global variables, defined in opt.h ----*/
opt_t opt;
/*---- forward declarations of static functions ----*/
typedef struct env_vars env_vars_t;
static void _help(void);
/* fill in default options */
static void _opt_default(void);
/* set options based upon env vars */
static void _opt_env(void);
static void _opt_args(int argc, char **argv);
/* list known options and their settings */
static void _opt_list(void);
/* verify options sanity */
static bool _opt_verify(void);
static void _print_version(void);
static void _process_env_var(env_vars_t *e, const char *val);
/* Get a POSITIVE decimal integer from arg */
static int _get_pos_int(const char *arg, const char *what);
static void _usage(void);
/*---[ end forward declarations of static functions ]---------------------*/
int initialize_and_process_args(int argc, char *argv[])
{
/* initialize option defaults */
_opt_default();
/* initialize options with env vars */
_opt_env();
/* initialize options with argv */
_opt_args(argc, argv);
if (opt.verbose > 1)
_opt_list();
return 1;
}
static void _print_version(void)
{
printf("%s %s\n", PACKAGE, SLURM_VERSION);
}
/*
* print error message to stderr with opt.progname prepended
*/
#undef USE_ARGERROR
#if USE_ARGERROR
static void argerror(const char *msg, ...)
{
va_list ap;
char buf[256];
va_start(ap, msg);
vsnprintf(buf, sizeof(buf), msg, ap);
fprintf(stderr, "%s: %s\n",
opt.progname ? opt.progname : "sbatch", buf);
va_end(ap);
}
#else
# define argerror error
#endif /* USE_ARGERROR */
/*
* Get a POSITIVE decimal integer from arg.
*
* Returns the integer on success, exits program on failure.
*
*/
static int
_get_pos_int(const char *arg, const char *what)
{
char *p;
long int result = strtol(arg, &p, 10);
if (p == arg || !xstring_is_whitespace(p) || (result < 0L)) {
error ("Invalid numeric value \"%s\" for %s.", arg, what);
exit(1);
}
if (result > INT_MAX) {
error ("Numeric argument %ld to big for %s.", result, what);
exit(1);
}
return (int) result;
}
/*
* _opt_default(): used by initialize_and_process_args to set defaults
*/
static void _opt_default()
{
struct passwd *pw;
static slurm_step_io_fds_t fds = SLURM_STEP_IO_FDS_INITIALIZER;
if ((pw = getpwuid(getuid())) != NULL) {
strncpy(opt.user, pw->pw_name, MAX_USERNAME);
opt.uid = pw->pw_uid;
} else
error("who are you?");
opt.gid = getgid();
opt.progname = NULL;
opt.jobid = NO_VAL;
opt.jobid_set = false;
opt.quiet = 0;
opt.verbose = 0;
opt.euid = (uid_t) -1;
opt.egid = (gid_t) -1;
opt.labelio = false;
opt.ctrl_comm_ifhn = xshort_hostname();
memcpy(&opt.fds, &fds, sizeof(fds));
opt.layout_only = false;
opt.debugger_test = false;
opt.input_filter = (uint32_t)-1;
opt.input_filter_set = false;
opt.output_filter = (uint32_t)-1;
opt.output_filter_set = false;
opt.error_filter = (uint32_t)-1;
opt.error_filter_set = false;
}
/*---[ env var processing ]-----------------------------------------------*/
/*
* try to use a similar scheme as popt.
*
* in order to add a new env var (to be processed like an option):
*
* define a new entry into env_vars[], if the option is a simple int
* or string you may be able to get away with adding a pointer to the
* option to set. Otherwise, process var based on "type" in _opt_env.
*/
struct env_vars {
const char *var;
int type;
void *arg;
void *set_flag;
};
env_vars_t env_vars[] = {
{NULL, 0, NULL, NULL}
};
/*
* _opt_env(): used by initialize_and_process_args to set options via
* environment variables. See comments above for how to
* extend sattach to process different vars
*/
static void _opt_env()
{
char *val = NULL;
env_vars_t *e = env_vars;
while (e->var) {
if ((val = getenv(e->var)) != NULL)
_process_env_var(e, val);
e++;
}
}
static void
_process_env_var(env_vars_t *e, const char *val)
{
debug2("now processing env var %s=%s", e->var, val);
if (e->set_flag) {
*((bool *) e->set_flag) = true;
}
switch (e->type) {
default:
/* do nothing */
break;
}
}
void set_options(const int argc, char **argv)
{
int opt_char, option_index = 0;
static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"label", no_argument, 0, 'l'},
{"quiet", no_argument, 0, 'q'},
{"usage", no_argument, 0, 'u'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"layout", no_argument, 0, LONG_OPT_LAYOUT_ONLY},
{"debugger-test",no_argument, 0, LONG_OPT_DEBUGGER_TEST},
{"input-filter", required_argument,0, LONG_OPT_IN_FILTER},
{"output-filter",required_argument,0, LONG_OPT_OUT_FILTER},
{"error-filter", required_argument,0, LONG_OPT_ERR_FILTER},
{NULL}
};
char *opt_string = "+hlquvV";
opt.progname = xbasename(argv[0]);
optind = 0;
while((opt_char = getopt_long(argc, argv, opt_string,
long_options, &option_index)) != -1) {
switch (opt_char) {
case '?':
fprintf(stderr, "Try \"sattach --help\" for more "
"information\n");
exit(1);
break;
case 'h':
_help();
exit(0);
case 'l':
opt.labelio = true;
break;
case 'q':
opt.quiet++;
break;
case 'u':
_usage();
exit(0);
case 'v':
opt.verbose++;
break;
case 'V':
_print_version();
exit(0);
break;
case LONG_OPT_IN_FILTER:
if (strcmp(optarg, "-") != 0) {
opt.input_filter = (uint32_t)
_get_pos_int(optarg, "input-filter");
}
opt.input_filter_set = true;
break;
case LONG_OPT_OUT_FILTER:
if (strcmp(optarg, "-") != 0) {
opt.output_filter = (uint32_t)
_get_pos_int(optarg, "output-filter");
}
opt.output_filter_set = true;
break;
case LONG_OPT_ERR_FILTER:
if (strcmp(optarg, "-") != 0) {
opt.error_filter = (uint32_t)
_get_pos_int(optarg, "error-filter");
}
opt.error_filter_set = true;
break;
case LONG_OPT_LAYOUT_ONLY:
opt.layout_only = true;
break;
case LONG_OPT_DEBUGGER_TEST:
opt.debugger_test = true;
break;
default:
fatal("Unrecognized command line parameter %c",
opt_char);
}
}
}
static void _parse_jobid_stepid(char *jobid_str)
{
char *ptr, *job, *step;
long jobid, stepid;
verbose("jobid/stepid string = %s\n", jobid_str);
job = xstrdup(jobid_str);
ptr = index(job, '.');
if (ptr == NULL) {
error("Did not find a period in the step ID string");
_usage();
xfree(job);
exit(1);
} else {
*ptr = '\0';
step = ptr + 1;
}
jobid = strtol(job, &ptr, 10);
if (!xstring_is_whitespace(ptr)) {
error("\"%s\" does not look like a jobid", job);
_usage();
xfree(job);
exit(1);
}
stepid = strtol(step, &ptr, 10);
if (!xstring_is_whitespace(ptr)) {
error("\"%s\" does not look like a stepid", step);
_usage();
xfree(job);
exit(1);
}
opt.jobid = (uint32_t) jobid;
opt.stepid = (uint32_t) stepid;
xfree(job);
}
/*
* _opt_args() : set options via commandline args and popt
*/
static void _opt_args(int argc, char **argv)
{
char **rest = NULL;
int leftover;
set_options(argc, argv);
leftover = 0;
if (optind < argc) {
rest = argv + optind;
while (rest[leftover] != NULL)
leftover++;
}
if (leftover != 1) {
error("too many parameters");
_usage();
exit(1);
}
_parse_jobid_stepid(*(argv + optind));
if (!_opt_verify())
exit(1);
}
/*
* _opt_verify : perform some post option processing verification
*
*/
static bool _opt_verify(void)
{
bool verified = true;
if (opt.quiet && opt.verbose) {
error ("don't specify both --verbose (-v) and --quiet (-Q)");
verified = false;
}
/*
* set up standard IO filters
*/
if (opt.input_filter_set)
opt.fds.in.taskid = opt.input_filter;
if (opt.output_filter_set)
opt.fds.out.taskid = opt.output_filter;
if (opt.error_filter_set) {
opt.fds.err.taskid = opt.error_filter;
} else if (opt.output_filter_set) {
opt.fds.err.taskid = opt.output_filter;
}
return verified;
}
#define tf_(b) (b == true) ? "true" : "false"
static void _opt_list()
{
info("defined options for program `%s'", opt.progname);
info("--------------- ---------------------");
info("job ID : %u", opt.jobid);
info("step ID : %u", opt.stepid);
info("user : `%s'", opt.user);
info("uid : %ld", (long) opt.uid);
info("gid : %ld", (long) opt.gid);
info("verbose : %d", opt.verbose);
}
static void _usage(void)
{
printf("Usage: sattach [options] <jobid.stepid>\n");
}
static void _help(void)
{
printf("Usage: sattach [options] <jobid.stepid>\n");
printf(
" --input-filter=taskid send stdin to only the specified task\n"
" --output-filter=taskid only print stdout from the specified task\n"
" --error-filter=taskid only print stderr from the specified task\n"
" -l, --label prepend task number to lines of stdout & stderr\n"
" --layout print task layout info and exit (does not attach to tasks)\n"
" -q, --quiet quiet mode (suppress informational messages)\n"
" -v, --verbose verbose mode (multiple -v's increase verbosity)\n"
" -V, --version print the SLURM version and exit\n\n"
"Help options:\n"
" -h, --help print this help message\n"
" -u, --usage print a brief usage message\n"
);
}