root/opal/mca/pmix/pmix4x/pmix/src/util/output.c

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

DEFINITIONS

This source file includes following definitions.
  1. pmix_output_init
  2. pmix_output_open
  3. pmix_output_reopen
  4. pmix_output_switch
  5. pmix_output_reopen_all
  6. pmix_output_close
  7. pmix_output
  8. pmix_output_verbose
  9. pmix_output_vverbose
  10. pmix_output_set_verbosity
  11. pmix_output_set_output_file_info
  12. pmix_output_hexdump
  13. pmix_output_finalize
  14. construct
  15. destruct
  16. do_open
  17. open_file
  18. free_descriptor
  19. make_string
  20. output
  21. pmix_output_get_verbosity

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

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