blob: 289286e80c9082b28c59ed73f39f8365e1cfeefe [file] [log] [blame]
/*****************************************************************************\
* opt.c - options processing for sattach
*****************************************************************************
* 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.
* CODE-OCEC-09-009. All rights reserved.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#include "config.h"
#define _GNU_SOURCE
#include <ctype.h> /* isdigit */
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdarg.h> /* va_start */
#include <stdio.h>
#include <stdlib.h> /* getenv */
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "src/common/list.h"
#include "src/common/log.h"
#include "src/common/parse_time.h"
#include "src/common/proc_args.h"
#include "src/common/read_config.h" /* contains getnodename() */
#include "src/interfaces/mpi.h"
#include "src/common/slurm_protocol_api.h"
#include "src/common/slurm_rlimits_info.h"
#include "src/common/uid.h"
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
#include "src/sattach/opt.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
#define LONG_OPT_PTY 0x105
#define OPT_LONG_AUTOCOMP 0x106
/*---- global variables, defined in opt.h ----*/
opt_t opt;
int error_exit = 1;
/*---- 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 _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;
}
/*
* 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(error_exit);
}
if (result > INT_MAX) {
error ("Numeric argument %ld to big for %s.", result, what);
exit(error_exit);
}
return (int) result;
}
/*
* _opt_default(): used by initialize_and_process_args to set defaults
*/
static void _opt_default()
{
static slurm_step_io_fds_t fds = SLURM_STEP_IO_FDS_INITIALIZER;
uid_t uid = getuid();
if (!(opt.user = uid_to_string_or_null(uid)))
fatal("Invalid user id: %u", uid);
opt.uid = uid;
opt.gid = getgid();
opt.progname = NULL;
opt.quiet = 0;
opt.verbose = 0;
opt.euid = SLURM_AUTH_NOBODY;
opt.egid = SLURM_AUTH_NOBODY;
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;
opt.pty = 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(void)
{
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[] = {
{"autocomplete", required_argument, 0, OPT_LONG_AUTOCOMP},
{"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},
{"pty", no_argument, 0, LONG_OPT_PTY},
{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(error_exit);
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_slurm_version();
exit(0);
break;
case LONG_OPT_IN_FILTER:
if (xstrcmp(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 (xstrcmp(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 (xstrcmp(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;
case LONG_OPT_PTY:
#ifdef HAVE_PTY_H
opt.pty = true;
#else
error("--pty not currently supported on this system "
"type");
#endif
break;
case OPT_LONG_AUTOCOMP:
suggest_completion(long_options, optarg);
exit(0);
break;
default:
error("Unrecognized command line parameter %c",
opt_char);
exit(error_exit);
}
}
}
/*
* _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(error_exit);
}
opt.selected_step = slurm_parse_step_str(*(argv + optind));
if (opt.selected_step->step_id.step_id == NO_VAL) {
error("Failed to parse stepid from command line options");
_usage();
exit(error_exit);
}
if (!_opt_verify())
exit(error_exit);
}
/*
* _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;
}
if ((opt.selected_step->step_id.step_id == SLURM_EXTERN_CONT) ||
(opt.selected_step->step_id.step_id == SLURM_BATCH_SCRIPT)) {
error("Cannot be used with extern or batch steps");
verified = false;
}
/*
* set up standard IO filters
*/
if ((opt.input_filter_set || opt.output_filter_set ||
opt.error_filter_set) && opt.pty) {
error("don't specify both --pty and I/O filtering");
verified = false;
}
if (opt.input_filter_set)
opt.fds.input.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.selected_step->step_id.job_id);
info("step ID : %u", opt.selected_step->step_id.step_id);
info("user : `%s'", opt.user);
info("uid : %u", opt.uid);
info("gid : %u", 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"
);
}