root/opal/util/output.c

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

DEFINITIONS

This source file includes following definitions.
  1. opal_output_init
  2. opal_output_open
  3. opal_output_reopen
  4. opal_output_switch
  5. opal_output_reopen_all
  6. opal_output_close
  7. opal_output
  8. opal_output_verbose
  9. opal_output_vverbose
  10. opal_output_string
  11. opal_output_vstring
  12. opal_output_set_verbosity
  13. opal_output_set_output_file_info
  14. opal_output_finalize
  15. construct
  16. destruct
  17. do_open
  18. open_file
  19. free_descriptor
  20. make_string
  21. output
  22. opal_output_get_verbosity

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2017 The University of Tennessee and The University
   7  *                         of Tennessee Research Foundation.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart,
  10  *                         University of Stuttgart.  All rights reserved.
  11  * Copyright (c) 2004-2006 The Regents of the University of California.
  12  *                         All rights reserved.
  13  * Copyright (c) 2007-2008 Cisco Systems, Inc.  All rights reserved.
  14  * Copyright (c) 2015      Los Alamos National Security, LLC. All rights
  15  *                         reserved.
  16  * Copyright (c) 2015      Research Organization for Information Science
  17  *                         and Technology (RIST). All rights reserved.
  18  * Copyright (c) 2017      IBM Corporation.  All rights reserved.
  19  * Copyright (c) 2017-2018 Intel, Inc. All rights reserved.
  20  * Copyright (c) 2018      Amazon.com, Inc. or its affiliates.  All Rights reserved.
  21  * Copyright (c) 2018      Triad National Security, LLC. All rights
  22  *                         reserved.
  23  * $COPYRIGHT$
  24  *
  25  * Additional copyrights may follow
  26  *
  27  * $HEADER$
  28  */
  29 
  30 #include "opal_config.h"
  31 
  32 #include <stdio.h>
  33 #include <stdarg.h>
  34 #include <stdlib.h>
  35 #ifdef HAVE_SYSLOG_H
  36 #include <syslog.h>
  37 #endif
  38 #include <string.h>
  39 #include <fcntl.h>
  40 #ifdef HAVE_UNISTD_H
  41 #include <unistd.h>
  42 #endif
  43 #ifdef HAVE_SYS_PARAM_H
  44 #include <sys/param.h>
  45 #endif
  46 
  47 #include "opal/util/opal_environ.h"
  48 #include "opal/util/output.h"
  49 #include "opal/util/string_copy.h"
  50 #include "opal/util/printf.h"
  51 #include "opal/threads/mutex.h"
  52 #include "opal/constants.h"
  53 #include "opal/mca/pmix/pmix.h"
  54 
  55 /*
  56  * Private data
  57  */
  58 static int verbose_stream = -1;
  59 static opal_output_stream_t verbose;
  60 static char *output_dir = NULL;
  61 static char *output_prefix = NULL;
  62 
  63 
  64 /*
  65  * Internal data structures and helpers for the generalized output
  66  * stream mechanism.
  67  */
  68 typedef struct {
  69     bool ldi_used;
  70     bool ldi_enabled;
  71     int ldi_verbose_level;
  72 
  73     bool ldi_syslog;
  74     int ldi_syslog_priority;
  75 
  76     char *ldi_syslog_ident;
  77     char *ldi_prefix;
  78     int ldi_prefix_len;
  79 
  80     char *ldi_suffix;
  81     int ldi_suffix_len;
  82 
  83     bool ldi_stdout;
  84     bool ldi_stderr;
  85 
  86     bool ldi_file;
  87     bool ldi_file_want_append;
  88     char *ldi_file_suffix;
  89     int ldi_fd;
  90     int ldi_file_num_lines_lost;
  91 } output_desc_t;
  92 
  93 /*
  94  * Private functions
  95  */
  96 static void construct(opal_object_t *stream);
  97 static void destruct(opal_object_t *stream);
  98 static int do_open(int output_id, opal_output_stream_t * lds);
  99 static int open_file(int i);
 100 static void free_descriptor(int output_id);
 101 static int make_string(char **no_newline_string, output_desc_t *ldi,
 102                        const char *format, va_list arglist);
 103 static int output(int output_id, const char *format, va_list arglist);
 104 static void opal_output_finalize (void);
 105 
 106 
 107 #define OPAL_OUTPUT_MAX_STREAMS 64
 108 #if defined(HAVE_SYSLOG)
 109 #define USE_SYSLOG 1
 110 #else
 111 #define USE_SYSLOG 0
 112 #endif
 113 
 114 /* global state */
 115 bool opal_output_redirected_to_syslog = false;
 116 int opal_output_redirected_syslog_pri = -1;
 117 
 118 /*
 119  * Local state
 120  */
 121 static bool initialized = false;
 122 static int default_stderr_fd = -1;
 123 static output_desc_t info[OPAL_OUTPUT_MAX_STREAMS];
 124 static char *temp_str = 0;
 125 static size_t temp_str_len = 0;
 126 static opal_mutex_t mutex;
 127 #if defined(HAVE_SYSLOG)
 128 static bool syslog_opened = false;
 129 #endif
 130 static char *redirect_syslog_ident = NULL;
 131 
 132 OBJ_CLASS_INSTANCE(opal_output_stream_t, opal_object_t, construct, destruct);
 133 
 134 /*
 135  * Setup the output stream infrastructure
 136  */
 137 bool opal_output_init(void)
 138 {
 139     int i;
 140     char hostname[OPAL_MAXHOSTNAMELEN];
 141     char *str;
 142 
 143     if (initialized) {
 144         return true;
 145     }
 146 
 147     str = getenv("OPAL_OUTPUT_STDERR_FD");
 148     if (NULL != str) {
 149         default_stderr_fd = atoi(str);
 150     }
 151     str = getenv("OPAL_OUTPUT_REDIRECT");
 152     if (NULL != str) {
 153         if (0 == strcasecmp(str, "syslog")) {
 154             opal_output_redirected_to_syslog = true;
 155         }
 156     }
 157     str = getenv("OPAL_OUTPUT_SYSLOG_PRI");
 158 #ifdef HAVE_SYSLOG_H
 159     if (NULL != str) {
 160         if (0 == strcasecmp(str, "info")) {
 161             opal_output_redirected_syslog_pri = LOG_INFO;
 162         } else if (0 == strcasecmp(str, "error")) {
 163             opal_output_redirected_syslog_pri = LOG_ERR;
 164         } else if (0 == strcasecmp(str, "warn")) {
 165             opal_output_redirected_syslog_pri = LOG_WARNING;
 166         } else {
 167             opal_output_redirected_syslog_pri = LOG_ERR;
 168         }
 169     } else {
 170         opal_output_redirected_syslog_pri = LOG_ERR;
 171     }
 172 #endif  /* HAVE_SYSLOG_H */
 173     str = getenv("OPAL_OUTPUT_SYSLOG_IDENT");
 174     if (NULL != str) {
 175         redirect_syslog_ident = strdup(str);
 176     }
 177 
 178     OBJ_CONSTRUCT(&verbose, opal_output_stream_t);
 179     if (opal_output_redirected_to_syslog) {
 180         verbose.lds_want_syslog = true;
 181         verbose.lds_syslog_priority = opal_output_redirected_syslog_pri;
 182         if (NULL != str) {
 183             verbose.lds_syslog_ident = strdup(redirect_syslog_ident);
 184         }
 185         verbose.lds_want_stderr = false;
 186         verbose.lds_want_stdout = false;
 187     } else {
 188         str = getenv("OPAL_OUTPUT_INTERNAL_TO_STDOUT");
 189         if (NULL != str && str[0] == '1') {
 190             verbose.lds_want_stdout = true;
 191         }
 192         else {
 193             verbose.lds_want_stderr = true;
 194         }
 195     }
 196     gethostname(hostname, sizeof(hostname));
 197     opal_asprintf(&verbose.lds_prefix, "[%s:%05d] ", hostname, getpid());
 198 
 199     for (i = 0; i < OPAL_OUTPUT_MAX_STREAMS; ++i) {
 200         info[i].ldi_used = false;
 201         info[i].ldi_enabled = false;
 202 
 203         info[i].ldi_syslog = opal_output_redirected_to_syslog;
 204         info[i].ldi_file = false;
 205         info[i].ldi_file_suffix = NULL;
 206         info[i].ldi_file_want_append = false;
 207         info[i].ldi_fd = -1;
 208         info[i].ldi_file_num_lines_lost = 0;
 209     }
 210 
 211     /* Initialize the mutex that protects the output */
 212 
 213     OBJ_CONSTRUCT(&mutex, opal_mutex_t);
 214     initialized = true;
 215 
 216     /* Set some defaults */
 217 
 218     opal_asprintf(&output_prefix, "output-pid%d-", getpid());
 219     output_dir = strdup(opal_tmp_directory());
 220 
 221     /* Open the default verbose stream */
 222     verbose_stream = opal_output_open(&verbose);
 223 
 224     /* make sure opal output is cleaned up on finalize */
 225     opal_finalize_register_cleanup (opal_output_finalize);
 226 
 227     return true;
 228 }
 229 
 230 
 231 /*
 232  * Open a stream
 233  */
 234 int opal_output_open(opal_output_stream_t * lds)
 235 {
 236     return do_open(-1, lds);
 237 }
 238 
 239 
 240 /*
 241  * Reset the parameters on a stream
 242  */
 243 int opal_output_reopen(int output_id, opal_output_stream_t * lds)
 244 {
 245     return do_open(output_id, lds);
 246 }
 247 
 248 
 249 /*
 250  * Enable and disable output streams
 251  */
 252 bool opal_output_switch(int output_id, bool enable)
 253 {
 254     bool ret = false;
 255 
 256     /* Setup */
 257 
 258     if (!initialized) {
 259         opal_output_init();
 260     }
 261 
 262     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS) {
 263         ret = info[output_id].ldi_enabled;
 264         info[output_id].ldi_enabled = enable;
 265     }
 266 
 267     return ret;
 268 }
 269 
 270 
 271 /*
 272  * Reopen all the streams; used during checkpoint/restart.
 273  */
 274 void opal_output_reopen_all(void)
 275 {
 276     char *str;
 277     char hostname[OPAL_MAXHOSTNAMELEN];
 278 
 279     str = getenv("OPAL_OUTPUT_STDERR_FD");
 280     if (NULL != str) {
 281         default_stderr_fd = atoi(str);
 282     } else {
 283         default_stderr_fd = -1;
 284     }
 285 
 286     gethostname(hostname, sizeof(hostname));
 287     if( NULL != verbose.lds_prefix ) {
 288         free(verbose.lds_prefix);
 289         verbose.lds_prefix = NULL;
 290     }
 291     opal_asprintf(&verbose.lds_prefix, "[%s:%05d] ", hostname, getpid());
 292 #if 0
 293     int i;
 294     opal_output_stream_t lds;
 295 
 296     for (i = 0; i < OPAL_OUTPUT_MAX_STREAMS; ++i) {
 297 
 298         /* scan till we find ldi_used == 0, which is the end-marker */
 299 
 300         if (!info[i].ldi_used) {
 301             break;
 302         }
 303 
 304         /*
 305          * set this to zero to ensure that opal_output_open will
 306          * return this same index as the output stream id
 307          */
 308         info[i].ldi_used = false;
 309 
 310 #if USE_SYSLOG
 311         lds.lds_want_syslog = info[i].ldi_syslog;
 312         lds.lds_syslog_priority = info[i].ldi_syslog_priority;
 313         lds.lds_syslog_ident = info[i].ldi_syslog_ident;
 314 #else
 315         lds.lds_want_syslog = false;
 316 #endif
 317         lds.lds_prefix = info[i].ldi_prefix;
 318         lds.lds_suffix = info[i].ldi_suffix;
 319         lds.lds_want_stdout = info[i].ldi_stdout;
 320         lds.lds_want_stderr = info[i].ldi_stderr;
 321         lds.lds_want_file = (-1 == info[i].ldi_fd) ? false : true;
 322         /* open all streams in append mode */
 323         lds.lds_want_file_append = true;
 324         lds.lds_file_suffix = info[i].ldi_file_suffix;
 325 
 326         /*
 327          * call opal_output_open to open the stream. The return value
 328          * is guaranteed to be i.  So we can ignore it.
 329          */
 330         opal_output_open(&lds);
 331     }
 332 #endif
 333 }
 334 
 335 
 336 /*
 337  * Close a stream
 338  */
 339 void opal_output_close(int output_id)
 340 {
 341     int i;
 342 
 343     /* Setup */
 344 
 345     if (!initialized || output_id < 0) {
 346         return;
 347     }
 348 
 349     /* If it's valid, used, enabled, and has an open file descriptor,
 350      * free the resources associated with the descriptor */
 351 
 352     OPAL_THREAD_LOCK(&mutex);
 353     if (output_id < OPAL_OUTPUT_MAX_STREAMS &&
 354         info[output_id].ldi_used && info[output_id].ldi_enabled) {
 355         free_descriptor(output_id);
 356 
 357         /* If no one has the syslog open, we should close it */
 358 
 359         for (i = 0; i < OPAL_OUTPUT_MAX_STREAMS; ++i) {
 360             if (info[i].ldi_used && info[i].ldi_syslog) {
 361                 break;
 362             }
 363         }
 364 
 365 #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H)
 366         if (i >= OPAL_OUTPUT_MAX_STREAMS && syslog_opened) {
 367             closelog();
 368         }
 369 #endif
 370     }
 371 
 372     OPAL_THREAD_UNLOCK(&mutex);
 373 }
 374 
 375 
 376 /*
 377  * Main function to send output to a stream
 378  */
 379 void opal_output(int output_id, const char *format, ...)
 380 {
 381     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS) {
 382         va_list arglist;
 383         va_start(arglist, format);
 384         output(output_id, format, arglist);
 385         va_end(arglist);
 386     }
 387 }
 388 
 389 
 390 /*
 391  * Send a message to a stream if the verbose level is high enough
 392  */
 393 void opal_output_verbose(int level, int output_id, const char *format, ...)
 394 {
 395     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS &&
 396         info[output_id].ldi_verbose_level >= level) {
 397         va_list arglist;
 398         va_start(arglist, format);
 399         output(output_id, format, arglist);
 400         va_end(arglist);
 401     }
 402 }
 403 
 404 
 405 /*
 406  * Send a message to a stream if the verbose level is high enough
 407  */
 408 void opal_output_vverbose(int level, int output_id, const char *format,
 409                           va_list arglist)
 410 {
 411     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS &&
 412         info[output_id].ldi_verbose_level >= level) {
 413         output(output_id, format, arglist);
 414     }
 415 }
 416 
 417 
 418 /*
 419  * Send a message to a string if the verbose level is high enough
 420  */
 421 char *opal_output_string(int level, int output_id, const char *format, ...)
 422 {
 423     int rc;
 424     char *ret = NULL;
 425 
 426     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS &&
 427         info[output_id].ldi_verbose_level >= level) {
 428         va_list arglist;
 429         va_start(arglist, format);
 430         rc = make_string(&ret, &info[output_id], format, arglist);
 431         va_end(arglist);
 432         if (OPAL_SUCCESS != rc) {
 433             ret = NULL;
 434         }
 435     }
 436 
 437     return ret;
 438 }
 439 
 440 
 441 /*
 442  * Send a message to a string if the verbose level is high enough
 443  */
 444 char *opal_output_vstring(int level, int output_id, const char *format,
 445                           va_list arglist)
 446 {
 447     int rc;
 448     char *ret = NULL;
 449 
 450     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS &&
 451         info[output_id].ldi_verbose_level >= level) {
 452         rc = make_string(&ret, &info[output_id], format, arglist);
 453         if (OPAL_SUCCESS != rc) {
 454             ret = NULL;
 455         }
 456     }
 457 
 458     return ret;
 459 }
 460 
 461 
 462 /*
 463  * Set the verbosity level of a stream
 464  */
 465 void opal_output_set_verbosity(int output_id, int level)
 466 {
 467     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS) {
 468         info[output_id].ldi_verbose_level = level;
 469     }
 470 }
 471 
 472 
 473 /*
 474  * Control where output flies will go
 475  */
 476 void opal_output_set_output_file_info(const char *dir,
 477                                       const char *prefix,
 478                                       char **olddir,
 479                                       char **oldprefix)
 480 {
 481     if (NULL != olddir) {
 482         *olddir = strdup(output_dir);
 483     }
 484     if (NULL != oldprefix) {
 485         *oldprefix = strdup(output_prefix);
 486     }
 487 
 488     if (NULL != dir) {
 489         free(output_dir);
 490         output_dir = strdup(dir);
 491     }
 492     if (NULL != prefix) {
 493         free(output_prefix);
 494         output_prefix = strdup(prefix);
 495     }
 496 }
 497 
 498 
 499 /*
 500  * Shut down the output stream system
 501  */
 502 static void opal_output_finalize(void)
 503 {
 504     if (initialized) {
 505         if (verbose_stream != -1) {
 506             opal_output_close(verbose_stream);
 507         }
 508         free(verbose.lds_prefix);
 509         verbose.lds_prefix = NULL;
 510 
 511         verbose_stream = -1;
 512 
 513         free (output_prefix);
 514         output_prefix = NULL;
 515 
 516         free (output_dir);
 517         output_dir = NULL;
 518 
 519         if(NULL != temp_str) {
 520             free(temp_str);
 521             temp_str = NULL;
 522             temp_str_len = 0;
 523         }
 524         OBJ_DESTRUCT(&verbose);
 525         OBJ_DESTRUCT(&mutex);
 526     }
 527 
 528     initialized = false;
 529 }
 530 
 531 /************************************************************************/
 532 
 533 /*
 534  * Constructor
 535  */
 536 static void construct(opal_object_t *obj)
 537 {
 538     opal_output_stream_t *stream = (opal_output_stream_t*) obj;
 539 
 540     stream->lds_verbose_level = 0;
 541     stream->lds_syslog_priority = 0;
 542     stream->lds_syslog_ident = NULL;
 543     stream->lds_prefix = NULL;
 544     stream->lds_suffix = NULL;
 545     stream->lds_is_debugging = false;
 546     stream->lds_want_syslog = false;
 547     stream->lds_want_stdout = false;
 548     stream->lds_want_stderr = false;
 549     stream->lds_want_file = false;
 550     stream->lds_want_file_append = false;
 551     stream->lds_file_suffix = NULL;
 552 }
 553 static void destruct(opal_object_t *obj)
 554 {
 555     opal_output_stream_t *stream = (opal_output_stream_t*) obj;
 556 
 557     if( NULL != stream->lds_file_suffix ) {
 558         free(stream->lds_file_suffix);
 559         stream->lds_file_suffix = NULL;
 560     }
 561 }
 562 
 563 /*
 564  * Back-end of open() and reopen().  Necessary to have it as a
 565  * back-end function so that we can do the thread locking properly
 566  * (especially upon reopen).
 567  */
 568 static int do_open(int output_id, opal_output_stream_t * lds)
 569 {
 570     int i;
 571     bool redirect_to_file = false;
 572     char *str, *sfx;
 573 
 574     /* Setup */
 575 
 576     if (!initialized) {
 577         opal_output_init();
 578     }
 579 
 580     str = getenv("OPAL_OUTPUT_REDIRECT");
 581     if (NULL != str && 0 == strcasecmp(str, "file")) {
 582         redirect_to_file = true;
 583     }
 584     sfx = getenv("OPAL_OUTPUT_SUFFIX");
 585 
 586     /* If output_id == -1, find an available stream, or return
 587      * OPAL_ERROR */
 588 
 589     if (-1 == output_id) {
 590         OPAL_THREAD_LOCK(&mutex);
 591         for (i = 0; i < OPAL_OUTPUT_MAX_STREAMS; ++i) {
 592             if (!info[i].ldi_used) {
 593                 break;
 594             }
 595         }
 596         if (i >= OPAL_OUTPUT_MAX_STREAMS) {
 597             OPAL_THREAD_UNLOCK(&mutex);
 598             return OPAL_ERR_OUT_OF_RESOURCE;
 599         }
 600     }
 601 
 602     /* Otherwise, we're reopening, so we need to free all previous
 603      * resources, close files, etc. */
 604 
 605     else {
 606         free_descriptor(output_id);
 607         i = output_id;
 608     }
 609 
 610     /* Special case: if we got NULL for lds, then just use the default
 611      * verbose */
 612 
 613     if (NULL == lds) {
 614         lds = &verbose;
 615     }
 616 
 617     /* Got a stream -- now initialize it and open relevant outputs */
 618 
 619     info[i].ldi_used = true;
 620     if (-1 == output_id) {
 621         OPAL_THREAD_UNLOCK(&mutex);
 622     }
 623     info[i].ldi_enabled = lds->lds_is_debugging ?
 624         (bool) OPAL_ENABLE_DEBUG : true;
 625     info[i].ldi_verbose_level = lds->lds_verbose_level;
 626 
 627 #if USE_SYSLOG
 628 #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H)
 629     if (opal_output_redirected_to_syslog) {
 630         info[i].ldi_syslog = true;
 631         info[i].ldi_syslog_priority = opal_output_redirected_syslog_pri;
 632         if (NULL != redirect_syslog_ident) {
 633             info[i].ldi_syslog_ident = strdup(redirect_syslog_ident);
 634             openlog(redirect_syslog_ident, LOG_PID, LOG_USER);
 635         } else {
 636             info[i].ldi_syslog_ident = NULL;
 637             openlog("opal", LOG_PID, LOG_USER);
 638         }
 639         syslog_opened = true;
 640     } else {
 641 #endif
 642         info[i].ldi_syslog = lds->lds_want_syslog;
 643         if (lds->lds_want_syslog) {
 644 
 645 #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H)
 646             if (NULL != lds->lds_syslog_ident) {
 647                 info[i].ldi_syslog_ident = strdup(lds->lds_syslog_ident);
 648                 openlog(lds->lds_syslog_ident, LOG_PID, LOG_USER);
 649             } else {
 650                 info[i].ldi_syslog_ident = NULL;
 651                 openlog("opal", LOG_PID, LOG_USER);
 652             }
 653 #endif
 654             syslog_opened = true;
 655             info[i].ldi_syslog_priority = lds->lds_syslog_priority;
 656         }
 657 
 658 #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H)
 659     }
 660 #endif
 661 
 662 #else
 663     info[i].ldi_syslog = false;
 664 #endif
 665 
 666     if (NULL != lds->lds_prefix) {
 667         info[i].ldi_prefix = strdup(lds->lds_prefix);
 668         info[i].ldi_prefix_len = (int)strlen(lds->lds_prefix);
 669     } else {
 670         info[i].ldi_prefix = NULL;
 671         info[i].ldi_prefix_len = 0;
 672     }
 673 
 674     if (NULL != lds->lds_suffix) {
 675         info[i].ldi_suffix = strdup(lds->lds_suffix);
 676         info[i].ldi_suffix_len = (int)strlen(lds->lds_suffix);
 677     } else {
 678         info[i].ldi_suffix = NULL;
 679         info[i].ldi_suffix_len = 0;
 680     }
 681 
 682     if (opal_output_redirected_to_syslog) {
 683         /* since all is redirected to syslog, ensure
 684          * we don't duplicate the output to the std places
 685          */
 686         info[i].ldi_stdout = false;
 687         info[i].ldi_stderr = false;
 688         info[i].ldi_file = false;
 689         info[i].ldi_fd = -1;
 690     } else {
 691         /* since we aren't redirecting to syslog, use what was
 692          * given to us
 693          */
 694         if (NULL != str && redirect_to_file) {
 695             info[i].ldi_stdout = false;
 696             info[i].ldi_stderr = false;
 697             info[i].ldi_file = true;
 698         } else {
 699             info[i].ldi_stdout = lds->lds_want_stdout;
 700             info[i].ldi_stderr = lds->lds_want_stderr;
 701 
 702             info[i].ldi_fd = -1;
 703             info[i].ldi_file = lds->lds_want_file;
 704         }
 705         if (NULL != sfx) {
 706             info[i].ldi_file_suffix = strdup(sfx);
 707         } else {
 708             info[i].ldi_file_suffix = (NULL == lds->lds_file_suffix) ? NULL :
 709                 strdup(lds->lds_file_suffix);
 710         }
 711         info[i].ldi_file_want_append = lds->lds_want_file_append;
 712         info[i].ldi_file_num_lines_lost = 0;
 713     }
 714 
 715     /* Special case: output_id == 0 == verbose_stream
 716      * This is the verbose stream, so update the internal 'verbose_stream'
 717      * to match the parameters set in the info[i]
 718      */
 719     if( verbose_stream == i ) {
 720         verbose.lds_want_syslog     = info[i].ldi_syslog;
 721         verbose.lds_syslog_priority = info[i].ldi_syslog_priority;
 722         verbose.lds_syslog_ident    = info[i].ldi_syslog_ident;
 723         verbose.lds_want_stdout     = info[i].ldi_stdout;
 724         verbose.lds_want_stderr     = info[i].ldi_stderr;
 725     }
 726 
 727     /* Don't open a file in the session directory now -- do that lazily
 728      * so that if there's no output, we don't have an empty file */
 729 
 730     return i;
 731 }
 732 
 733 
 734 static int open_file(int i)
 735 {
 736     int flags;
 737     char *filename;
 738     int n;
 739 
 740     /* first check to see if this file is already open
 741      * on someone else's stream - if so, we don't want
 742      * to open it twice
 743      */
 744     for (n=0; n < OPAL_OUTPUT_MAX_STREAMS; n++) {
 745         if (i == n) {
 746             continue;
 747         }
 748         if (!info[n].ldi_used) {
 749             continue;
 750         }
 751         if (!info[n].ldi_file) {
 752             continue;
 753         }
 754         if (NULL != info[i].ldi_file_suffix &&
 755             NULL != info[n].ldi_file_suffix) {
 756             if (0 != strcmp(info[i].ldi_file_suffix, info[n].ldi_file_suffix)) {
 757                 break;
 758             }
 759         }
 760         if (NULL == info[i].ldi_file_suffix &&
 761             NULL != info[n].ldi_file_suffix) {
 762             break;
 763         }
 764         if (NULL != info[i].ldi_file_suffix &&
 765             NULL == info[n].ldi_file_suffix) {
 766             break;
 767         }
 768         if (info[n].ldi_fd < 0) {
 769             break;
 770         }
 771         info[i].ldi_fd = info[n].ldi_fd;
 772         return OPAL_SUCCESS;
 773     }
 774 
 775     /* Setup the filename and open flags */
 776 
 777     if (NULL != output_dir) {
 778         filename = (char *) malloc(OPAL_PATH_MAX);
 779         if (NULL == filename) {
 780             return OPAL_ERR_OUT_OF_RESOURCE;
 781         }
 782         opal_string_copy(filename, output_dir, OPAL_PATH_MAX);
 783         strcat(filename, "/");
 784         if (NULL != output_prefix) {
 785             strcat(filename, output_prefix);
 786         }
 787         if (info[i].ldi_file_suffix != NULL) {
 788             strcat(filename, info[i].ldi_file_suffix);
 789         } else {
 790             info[i].ldi_file_suffix = NULL;
 791             strcat(filename, "output.txt");
 792         }
 793         flags = O_CREAT | O_RDWR;
 794         if (!info[i].ldi_file_want_append) {
 795             flags |= O_TRUNC;
 796         }
 797 
 798         /* Actually open the file */
 799         info[i].ldi_fd = open(filename, flags, 0644);
 800         if (-1 == info[i].ldi_fd) {
 801             info[i].ldi_used = false;
 802             free(filename);  /* release the filename in all cases */
 803             return OPAL_ERR_IN_ERRNO;
 804         }
 805 
 806         /* Make the file be close-on-exec to prevent child inheritance
 807          * problems */
 808         if (-1 == fcntl(info[i].ldi_fd, F_SETFD, 1)) {
 809             free(filename);  /* release the filename in all cases */
 810             return OPAL_ERR_IN_ERRNO;
 811         }
 812 
 813         /* register it to be ignored */
 814         if (NULL != opal_pmix.register_cleanup) {
 815             opal_pmix.register_cleanup(filename, false, true, false);
 816         }
 817         free(filename);  /* release the filename in all cases */
 818     }
 819 
 820     /* Return successfully even if the session dir did not exist yet;
 821      * we'll try opening it later */
 822 
 823     return OPAL_SUCCESS;
 824 }
 825 
 826 
 827 /*
 828  * Free all the resources associated with a descriptor.
 829  */
 830 static void free_descriptor(int output_id)
 831 {
 832     output_desc_t *ldi;
 833 
 834     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS &&
 835         info[output_id].ldi_used && info[output_id].ldi_enabled) {
 836         ldi = &info[output_id];
 837 
 838         if (-1 != ldi->ldi_fd) {
 839             close(ldi->ldi_fd);
 840         }
 841         ldi->ldi_used = false;
 842 
 843         /* If we strduped a prefix, suffix, or syslog ident, free it */
 844 
 845         if (NULL != ldi->ldi_prefix) {
 846             free(ldi->ldi_prefix);
 847         }
 848         ldi->ldi_prefix = NULL;
 849 
 850     if (NULL != ldi->ldi_suffix) {
 851         free(ldi->ldi_suffix);
 852     }
 853     ldi->ldi_suffix = NULL;
 854 
 855     if (NULL != ldi->ldi_file_suffix) {
 856             free(ldi->ldi_file_suffix);
 857         }
 858         ldi->ldi_file_suffix = NULL;
 859 
 860         if (NULL != ldi->ldi_syslog_ident) {
 861             free(ldi->ldi_syslog_ident);
 862         }
 863         ldi->ldi_syslog_ident = NULL;
 864     }
 865 }
 866 
 867 
 868 static int make_string(char **no_newline_string, output_desc_t *ldi,
 869                        const char *format, va_list arglist)
 870 {
 871     size_t len, total_len;
 872     bool want_newline = false;
 873 
 874     /* Make the formatted string */
 875 
 876     opal_vasprintf(no_newline_string, format, arglist);
 877     total_len = len = strlen(*no_newline_string);
 878     if ('\n' != (*no_newline_string)[len - 1]) {
 879         want_newline = true;
 880         ++total_len;
 881     } else if (NULL != ldi->ldi_suffix) {
 882         /* if we have a suffix, then we don't want a
 883          * newline to appear before it
 884          */
 885         (*no_newline_string)[len - 1] = '\0';
 886         want_newline = true; /* add newline to end after suffix */
 887         /* total_len won't change since we just moved the newline
 888          * to appear after the suffix
 889          */
 890     }
 891     if (NULL != ldi->ldi_prefix) {
 892         total_len += strlen(ldi->ldi_prefix);
 893     }
 894     if (NULL != ldi->ldi_suffix) {
 895         total_len += strlen(ldi->ldi_suffix);
 896     }
 897     if (temp_str_len < total_len + want_newline) {
 898         if (NULL != temp_str) {
 899             free(temp_str);
 900         }
 901         temp_str = (char *) malloc(total_len * 2);
 902         if (NULL == temp_str) {
 903             return OPAL_ERR_OUT_OF_RESOURCE;
 904         }
 905         temp_str_len = total_len * 2;
 906     }
 907     if (NULL != ldi->ldi_prefix && NULL != ldi->ldi_suffix) {
 908         if (want_newline) {
 909             snprintf(temp_str, temp_str_len, "%s%s%s\n",
 910                      ldi->ldi_prefix, *no_newline_string, ldi->ldi_suffix);
 911         } else {
 912             snprintf(temp_str, temp_str_len, "%s%s%s", ldi->ldi_prefix,
 913                      *no_newline_string, ldi->ldi_suffix);
 914         }
 915     } else if (NULL != ldi->ldi_prefix) {
 916         if (want_newline) {
 917             snprintf(temp_str, temp_str_len, "%s%s\n",
 918                      ldi->ldi_prefix, *no_newline_string);
 919         } else {
 920             snprintf(temp_str, temp_str_len, "%s%s", ldi->ldi_prefix,
 921                      *no_newline_string);
 922         }
 923     } else if (NULL != ldi->ldi_suffix) {
 924         if (want_newline) {
 925             snprintf(temp_str, temp_str_len, "%s%s\n",
 926                      *no_newline_string, ldi->ldi_suffix);
 927         } else {
 928             snprintf(temp_str, temp_str_len, "%s%s",
 929                      *no_newline_string, ldi->ldi_suffix);
 930         }
 931     } else {
 932         if (want_newline) {
 933             snprintf(temp_str, temp_str_len, "%s\n", *no_newline_string);
 934         } else {
 935             snprintf(temp_str, temp_str_len, "%s", *no_newline_string);
 936         }
 937     }
 938 
 939     return OPAL_SUCCESS;
 940 }
 941 
 942 /*
 943  * Do the actual output.  Take a va_list so that we can be called from
 944  * multiple different places, even functions that took "..." as input
 945  * arguments.
 946  */
 947 static int output(int output_id, const char *format, va_list arglist)
 948 {
 949     int rc = OPAL_SUCCESS;
 950     char *str, *out = NULL;
 951     output_desc_t *ldi;
 952 
 953     /* Setup */
 954 
 955     if (!initialized) {
 956         opal_output_init();
 957     }
 958 
 959     /* If it's valid, used, and enabled, output */
 960 
 961     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS &&
 962         info[output_id].ldi_used && info[output_id].ldi_enabled) {
 963         OPAL_THREAD_LOCK(&mutex);
 964         ldi = &info[output_id];
 965 
 966         /* Make the strings */
 967         if (OPAL_SUCCESS != (rc = make_string(&str, ldi, format, arglist))) {
 968             OPAL_THREAD_UNLOCK(&mutex);
 969             return rc;
 970         }
 971 
 972         /* Syslog output -- does not use the newline-appended string */
 973 #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H)
 974         if (ldi->ldi_syslog) {
 975             syslog(ldi->ldi_syslog_priority, "%s", str);
 976         }
 977 #endif
 978 
 979         /* All others (stdout, stderr, file) use temp_str, potentially
 980            with a newline appended */
 981 
 982         out = temp_str;
 983 
 984         /* stdout output */
 985         if (ldi->ldi_stdout) {
 986             write(fileno(stdout), out, (int)strlen(out));
 987             fflush(stdout);
 988         }
 989 
 990         /* stderr output */
 991         if (ldi->ldi_stderr) {
 992             write((-1 == default_stderr_fd) ?
 993                   fileno(stderr) : default_stderr_fd,
 994                   out, (int)strlen(out));
 995             fflush(stderr);
 996         }
 997 
 998         /* File output -- first check to see if the file opening was
 999          * delayed.  If so, try to open it.  If we failed to open it,
1000          * then just discard (there are big warnings in the
1001          * opal_output.h docs about this!). */
1002 
1003         if (ldi->ldi_file) {
1004             if (ldi->ldi_fd == -1) {
1005                 if (OPAL_SUCCESS != open_file(output_id)) {
1006                     ++ldi->ldi_file_num_lines_lost;
1007                 } else if (ldi->ldi_file_num_lines_lost > 0) {
1008                     char buffer[BUFSIZ];
1009                     char *out = buffer;
1010                     memset(buffer, 0, BUFSIZ);
1011                     snprintf(buffer, BUFSIZ - 1,
1012                              "[WARNING: %d lines lost because the Open MPI process session directory did\n not exist when opal_output() was invoked]\n",
1013                              ldi->ldi_file_num_lines_lost);
1014                    write(ldi->ldi_fd, buffer, (int)strlen(buffer));
1015                     ldi->ldi_file_num_lines_lost = 0;
1016                     if (out != buffer) {
1017                         free(out);
1018                     }
1019                 }
1020             }
1021             if (ldi->ldi_fd != -1) {
1022                 write(ldi->ldi_fd, out, (int)strlen(out));
1023             }
1024         }
1025         OPAL_THREAD_UNLOCK(&mutex);
1026         free(str);
1027     }
1028 
1029     return rc;
1030 }
1031 
1032 int opal_output_get_verbosity(int output_id)
1033 {
1034     if (output_id >= 0 && output_id < OPAL_OUTPUT_MAX_STREAMS && info[output_id].ldi_used) {
1035         return info[output_id].ldi_verbose_level;
1036     } else {
1037         return -1;
1038     }
1039 }

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