root/orte/mca/iof/base/iof_base_setup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. orte_iof_base_setup_prefork
  2. orte_iof_base_setup_child
  3. orte_iof_base_setup_parent
  4. orte_iof_base_setup_output_files

   1 /*
   2  * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
   3  *                         University Research and Technology
   4  *                         Corporation.  All rights reserved.
   5  * Copyright (c) 2004-2008 The University of Tennessee and The University
   6  *                         of Tennessee Research Foundation.  All rights
   7  *                         reserved.
   8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
   9  *                         University of Stuttgart.  All rights reserved.
  10  * Copyright (c) 2004-2005 The Regents of the University of California.
  11  *                         All rights reserved.
  12  * Copyright (c) 2008      Cisco Systems, Inc.  All rights reserved.
  13  * Copyright (c) 2016-2018 Intel, Inc.  All rights reserved.
  14  * Copyright (c) 2017      IBM Corporation.  All rights reserved.
  15  * Copyright (c) 2017      Research Organization for Information Science
  16  *                         and Technology (RIST). All rights reserved.
  17  * $COPYRIGHT$
  18  *
  19  * Additional copyrights may follow
  20  *
  21  * $HEADER$
  22  *
  23  * These symbols are in a file by themselves to provide nice linker
  24  * semantics.  Since linkers generally pull in symbols by object
  25  * files, keeping these symbols as the only symbols in this file
  26  * prevents utility programs such as "ompi_info" from having to import
  27  * entire components just to query their version and parameters.
  28  */
  29 
  30 #include "orte_config.h"
  31 #include "orte/constants.h"
  32 
  33 #include <stdlib.h>
  34 #ifdef HAVE_UNISTD_H
  35 #include <unistd.h>
  36 #endif
  37 #include <errno.h>
  38 #include <sys/types.h>
  39 #ifdef HAVE_SYS_WAIT_H
  40 #include <sys/wait.h>
  41 #endif
  42 #include <signal.h>
  43 #ifdef HAVE_UTIL_H
  44 #include <util.h>
  45 #endif
  46 #ifdef HAVE_PTY_H
  47 #include <pty.h>
  48 #endif
  49 #ifdef HAVE_FCNTL_H
  50 #include <fcntl.h>
  51 #endif
  52 #ifdef HAVE_TERMIOS_H
  53 #include <termios.h>
  54 # ifdef HAVE_TERMIO_H
  55 #  include <termio.h>
  56 # endif
  57 #endif
  58 #ifdef HAVE_LIBUTIL_H
  59 #include <libutil.h>
  60 #endif
  61 
  62 #include "opal/util/opal_pty.h"
  63 #include "opal/util/opal_environ.h"
  64 #include "opal/util/os_dirpath.h"
  65 #include "opal/util/output.h"
  66 #include "opal/util/argv.h"
  67 #include "opal/util/printf.h"
  68 
  69 #include "orte/mca/errmgr/errmgr.h"
  70 #include "orte/util/name_fns.h"
  71 #include "orte/runtime/orte_globals.h"
  72 
  73 #include "orte/mca/iof/iof.h"
  74 #include "orte/mca/iof/base/base.h"
  75 #include "orte/mca/iof/base/iof_base_setup.h"
  76 
  77 int
  78 orte_iof_base_setup_prefork(orte_iof_base_io_conf_t *opts)
  79 {
  80     int ret = -1;
  81 
  82     fflush(stdout);
  83 
  84     /* first check to make sure we can do ptys */
  85 #if OPAL_ENABLE_PTY_SUPPORT
  86     if (opts->usepty) {
  87         /**
  88          * It has been reported that on MAC OS X 10.4 and prior one cannot
  89          * safely close the writing side of a pty before completly reading
  90          * all data inside.
  91          * There seems to be two issues: first all pending data is
  92          * discarded, and second it randomly generate kernel panics.
  93          * Apparently this issue was fixed in 10.5 so by now we use the
  94          * pty exactly as we use the pipes.
  95          * This comment is here as a reminder.
  96          */
  97         ret = opal_openpty(&(opts->p_stdout[0]), &(opts->p_stdout[1]),
  98                            (char*)NULL, (struct termios*)NULL, (struct winsize*)NULL);
  99     }
 100 #else
 101     opts->usepty = 0;
 102 #endif
 103 
 104     if (ret < 0) {
 105         opts->usepty = 0;
 106         if (pipe(opts->p_stdout) < 0) {
 107             ORTE_ERROR_LOG(ORTE_ERR_SYS_LIMITS_PIPES);
 108             return ORTE_ERR_SYS_LIMITS_PIPES;
 109         }
 110     }
 111     if (opts->connect_stdin) {
 112         if (pipe(opts->p_stdin) < 0) {
 113             ORTE_ERROR_LOG(ORTE_ERR_SYS_LIMITS_PIPES);
 114             return ORTE_ERR_SYS_LIMITS_PIPES;
 115         }
 116     }
 117     if( !orte_iof_base.redirect_app_stderr_to_stdout ) {
 118         if (pipe(opts->p_stderr) < 0) {
 119             ORTE_ERROR_LOG(ORTE_ERR_SYS_LIMITS_PIPES);
 120             return ORTE_ERR_SYS_LIMITS_PIPES;
 121         }
 122     }
 123 #if OPAL_PMIX_V1
 124     if (pipe(opts->p_internal) < 0) {
 125         ORTE_ERROR_LOG(ORTE_ERR_SYS_LIMITS_PIPES);
 126         return ORTE_ERR_SYS_LIMITS_PIPES;
 127     }
 128 #endif
 129     return ORTE_SUCCESS;
 130 }
 131 
 132 
 133 int
 134 orte_iof_base_setup_child(orte_iof_base_io_conf_t *opts, char ***env)
 135 {
 136     int ret;
 137 #if OPAL_PMIX_V1
 138     char *str;
 139 #endif
 140 
 141     if (opts->connect_stdin) {
 142         close(opts->p_stdin[1]);
 143     }
 144     close(opts->p_stdout[0]);
 145     if( !orte_iof_base.redirect_app_stderr_to_stdout ) {
 146         close(opts->p_stderr[0]);
 147     }
 148 #if OPAL_PMIX_V1
 149     close(opts->p_internal[0]);
 150 #endif
 151 
 152     if (opts->usepty) {
 153         /* disable echo */
 154         struct termios term_attrs;
 155         if (tcgetattr(opts->p_stdout[1], &term_attrs) < 0) {
 156             return ORTE_ERR_PIPE_SETUP_FAILURE;
 157         }
 158         term_attrs.c_lflag &= ~ (ECHO | ECHOE | ECHOK |
 159                                  ECHOCTL | ECHOKE | ECHONL);
 160         term_attrs.c_iflag &= ~ (ICRNL | INLCR | ISTRIP | INPCK | IXON);
 161         term_attrs.c_oflag &= ~ (
 162 #ifdef OCRNL
 163                                  /* OS X 10.3 does not have this
 164                                     value defined */
 165                                  OCRNL |
 166 #endif
 167                                  ONLCR);
 168         if (tcsetattr(opts->p_stdout[1], TCSANOW, &term_attrs) == -1) {
 169             return ORTE_ERR_PIPE_SETUP_FAILURE;
 170         }
 171         ret = dup2(opts->p_stdout[1], fileno(stdout));
 172         if (ret < 0) {
 173             return ORTE_ERR_PIPE_SETUP_FAILURE;
 174         }
 175         if( orte_iof_base.redirect_app_stderr_to_stdout ) {
 176             ret = dup2(opts->p_stdout[1], fileno(stderr));
 177             if (ret < 0) {
 178                 return ORTE_ERR_PIPE_SETUP_FAILURE;
 179             }
 180         }
 181         close(opts->p_stdout[1]);
 182     } else {
 183         if(opts->p_stdout[1] != fileno(stdout)) {
 184             ret = dup2(opts->p_stdout[1], fileno(stdout));
 185             if (ret < 0) {
 186                 return ORTE_ERR_PIPE_SETUP_FAILURE;
 187             }
 188             if( orte_iof_base.redirect_app_stderr_to_stdout ) {
 189                 ret = dup2(opts->p_stdout[1], fileno(stderr));
 190                 if (ret < 0) {
 191                     return ORTE_ERR_PIPE_SETUP_FAILURE;
 192                 }
 193             }
 194             close(opts->p_stdout[1]);
 195         }
 196     }
 197     if (opts->connect_stdin) {
 198         if(opts->p_stdin[0] != fileno(stdin)) {
 199             ret = dup2(opts->p_stdin[0], fileno(stdin));
 200             if (ret < 0) {
 201                 return ORTE_ERR_PIPE_SETUP_FAILURE;
 202             }
 203             close(opts->p_stdin[0]);
 204         }
 205     } else {
 206         int fd;
 207 
 208         /* connect input to /dev/null */
 209         fd = open("/dev/null", O_RDONLY, 0);
 210         if(fd != fileno(stdin)) {
 211             dup2(fd, fileno(stdin));
 212             close(fd);
 213         }
 214     }
 215 
 216     if(opts->p_stderr[1] != fileno(stderr)) {
 217         if( !orte_iof_base.redirect_app_stderr_to_stdout ) {
 218             ret = dup2(opts->p_stderr[1], fileno(stderr));
 219             if (ret < 0) return ORTE_ERR_PIPE_SETUP_FAILURE;
 220             close(opts->p_stderr[1]);
 221         }
 222     }
 223 
 224 #if OPAL_PMIX_V1
 225     if (!orte_map_stddiag_to_stderr && !orte_map_stddiag_to_stdout ) {
 226         /* Set an environment variable that the new child process can use
 227            to get the fd of the pipe connected to the INTERNAL IOF tag. */
 228         opal_asprintf(&str, "%d", opts->p_internal[1]);
 229         if (NULL != str) {
 230             opal_setenv("OPAL_OUTPUT_STDERR_FD", str, true, env);
 231             free(str);
 232         }
 233     } else if( orte_map_stddiag_to_stdout ) {
 234         opal_setenv("OPAL_OUTPUT_INTERNAL_TO_STDOUT", "1", true, env);
 235     }
 236 #endif
 237 
 238     return ORTE_SUCCESS;
 239 }
 240 
 241 
 242 int
 243 orte_iof_base_setup_parent(const orte_process_name_t* name,
 244                            orte_iof_base_io_conf_t *opts)
 245 {
 246     int ret;
 247 
 248     /* connect stdin endpoint */
 249     if (opts->connect_stdin) {
 250         /* and connect the pty to stdin */
 251         ret = orte_iof.pull(name, ORTE_IOF_STDIN, opts->p_stdin[1]);
 252         if(ORTE_SUCCESS != ret) {
 253             ORTE_ERROR_LOG(ret);
 254             return ret;
 255         }
 256     }
 257 
 258     /* connect read ends to IOF */
 259     ret = orte_iof.push(name, ORTE_IOF_STDOUT, opts->p_stdout[0]);
 260     if(ORTE_SUCCESS != ret) {
 261         ORTE_ERROR_LOG(ret);
 262         return ret;
 263     }
 264 
 265     if( !orte_iof_base.redirect_app_stderr_to_stdout ) {
 266         ret = orte_iof.push(name, ORTE_IOF_STDERR, opts->p_stderr[0]);
 267         if(ORTE_SUCCESS != ret) {
 268             ORTE_ERROR_LOG(ret);
 269             return ret;
 270         }
 271     }
 272 
 273 #if OPAL_PMIX_V1
 274     ret = orte_iof.push(name, ORTE_IOF_STDDIAG, opts->p_internal[0]);
 275     if(ORTE_SUCCESS != ret) {
 276         ORTE_ERROR_LOG(ret);
 277         return ret;
 278     }
 279 #endif
 280 
 281     return ORTE_SUCCESS;
 282 }
 283 
 284 int orte_iof_base_setup_output_files(const orte_process_name_t* dst_name,
 285                                      orte_job_t *jobdat,
 286                                      orte_iof_proc_t *proct)
 287 {
 288     int rc;
 289     char *dirname, *outdir, *outfile;
 290     int np, numdigs, fdout, i;
 291     char *p, **s;
 292     bool usejobid = true;
 293 
 294     /* see if we are to output to a file */
 295     dirname = NULL;
 296     if (orte_get_attribute(&jobdat->attributes, ORTE_JOB_OUTPUT_TO_FILE, (void**)&dirname, OPAL_STRING) &&
 297         NULL != dirname) {
 298         np = jobdat->num_procs / 10;
 299         /* determine the number of digits required for max vpid */
 300         numdigs = 1;
 301         while (np > 0) {
 302             numdigs++;
 303             np = np / 10;
 304         }
 305         /* check for a conditional in the directory name */
 306         if (NULL != (p = strchr(dirname, ':'))) {
 307             *p = '\0';
 308             ++p;
 309             /* could me more than one directive */
 310             s = opal_argv_split(p, ',');
 311             for (i=0; NULL != s[i]; i++) {
 312                 if (0 == strcasecmp(s[i], "nojobid")) {
 313                     usejobid = false;
 314                 } else if (0 == strcasecmp(s[i], "nocopy")) {
 315                     proct->copy = false;
 316                 }
 317             }
 318         }
 319 
 320         /* construct the directory where the output files will go */
 321         if (usejobid) {
 322             opal_asprintf(&outdir, "%s/%d/rank.%0*lu", dirname,
 323                      (int)ORTE_LOCAL_JOBID(proct->name.jobid),
 324                      numdigs, (unsigned long)proct->name.vpid);
 325         } else {
 326             opal_asprintf(&outdir, "%s/rank.%0*lu", dirname,
 327                      numdigs, (unsigned long)proct->name.vpid);
 328         }
 329         /* ensure the directory exists */
 330         if (OPAL_SUCCESS != (rc = opal_os_dirpath_create(outdir, S_IRWXU|S_IRGRP|S_IXGRP))) {
 331             ORTE_ERROR_LOG(rc);
 332             free(outdir);
 333             return rc;
 334         }
 335         if (NULL != proct->revstdout && NULL == proct->revstdout->sink) {
 336             /* setup the stdout sink */
 337             opal_asprintf(&outfile, "%s/stdout", outdir);
 338             fdout = open(outfile, O_CREAT|O_RDWR|O_TRUNC, 0644);
 339             free(outfile);
 340             if (fdout < 0) {
 341                 /* couldn't be opened */
 342                 ORTE_ERROR_LOG(ORTE_ERR_FILE_OPEN_FAILURE);
 343                 return ORTE_ERR_FILE_OPEN_FAILURE;
 344             }
 345             /* define a sink to that file descriptor */
 346             ORTE_IOF_SINK_DEFINE(&proct->revstdout->sink, dst_name,
 347                                  fdout, ORTE_IOF_STDOUT,
 348                                  orte_iof_base_write_handler);
 349         }
 350 
 351         if (NULL != proct->revstderr && NULL == proct->revstderr->sink) {
 352             /* if they asked for stderr to be combined with stdout, then we
 353              * only create one file and tell the IOF to put both streams
 354              * into it. Otherwise, we create separate files for each stream */
 355             if (orte_get_attribute(&jobdat->attributes, ORTE_JOB_MERGE_STDERR_STDOUT, NULL, OPAL_BOOL)) {
 356                 /* just use the stdout sink */
 357                 OBJ_RETAIN(proct->revstdout->sink);
 358                 proct->revstdout->sink->tag = ORTE_IOF_STDMERGE;  // show that it is merged
 359                 proct->revstderr->sink = proct->revstdout->sink;
 360             } else {
 361                 opal_asprintf(&outfile, "%s/stderr", outdir);
 362                 fdout = open(outfile, O_CREAT|O_RDWR|O_TRUNC, 0644);
 363                 free(outfile);
 364                 if (fdout < 0) {
 365                     /* couldn't be opened */
 366                     ORTE_ERROR_LOG(ORTE_ERR_FILE_OPEN_FAILURE);
 367                     return ORTE_ERR_FILE_OPEN_FAILURE;
 368                 }
 369                 /* define a sink to that file descriptor */
 370                 ORTE_IOF_SINK_DEFINE(&proct->revstderr->sink, dst_name,
 371                                      fdout, ORTE_IOF_STDERR,
 372                                      orte_iof_base_write_handler);
 373             }
 374         }
 375 #if OPAL_PMIX_V1
 376         if (NULL != proct->revstddiag && NULL == proct->revstddiag->sink) {
 377             /* always tie the sink for stddiag to stderr */
 378             OBJ_RETAIN(proct->revstderr->sink);
 379             proct->revstddiag->sink = proct->revstderr->sink;
 380         }
 381 #endif
 382     }
 383 
 384     return ORTE_SUCCESS;
 385 }

/* [<][>][^][v][top][bottom][index][help] */