(root)/
binutils-2.41/
gprofng/
libcollector/
linetrace.c
       1  /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
       2     Contributed by Oracle.
       3  
       4     This file is part of GNU Binutils.
       5  
       6     This program is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program; if not, write to the Free Software
      18     Foundation, 51 Franklin Street - Fifth Floor, Boston,
      19     MA 02110-1301, USA.  */
      20  
      21  /*
      22   *	Lineage events for process fork, exec, etc.
      23   */
      24  
      25  #include "config.h"
      26  #include <string.h>
      27  #include <elf.h>
      28  #include <regex.h>
      29  #include <sys/types.h>
      30  #include <sys/stat.h>
      31  #include <sys/mman.h>
      32  #include <limits.h>
      33  #include <spawn.h>
      34  
      35  #include "descendants.h"
      36  
      37  #define LT_MAXNAMELEN 1024
      38  #define LT_MAXPATHLEN 1024
      39  
      40  int __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
      41  int dbg_current_mode = FOLLOW_NONE; /* for debug only */
      42  unsigned line_key = COLLECTOR_TSD_INVALID_KEY;
      43  line_mode_t line_mode = LM_DORMANT;
      44  int user_follow_mode = FOLLOW_ON;
      45  int java_mode = 0;
      46  
      47  static char *user_follow_spec;
      48  static char new_lineage[LT_MAXNAMELEN];
      49  static char curr_lineage[LT_MAXNAMELEN];
      50  static char linetrace_exp_dir_name[LT_MAXPATHLEN + 1]; // experiment directory
      51  
      52  /* lineage tracking for descendants of this process */
      53  
      54  static int fork_linenum = 0;
      55  static int line_initted = 0;
      56  static collector_mutex_t fork_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
      57  static collector_mutex_t clone_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
      58  
      59  // For a given Linux, which lib functions have more than one GLIBC version? Do this:
      60  // objdump -T `find /lib /lib64 -name "*.so*"` | grep GLIBC | grep text | grep \(
      61  static pid_t (*__real_fork) (void) = NULL;
      62  static pid_t (*__real_vfork) (void) = NULL;
      63  static int (*__real_execve) (const char *file, char *const argv[],
      64  			     char *const envp[]) = NULL;
      65  static int (*__real_execvp) (const char *file, char *const argv[]) = NULL;
      66  static int (*__real_execv) (const char *file, char *const argv[]) = NULL;
      67  static int (*__real_execle) (const char *path, const char *arg, ...) = NULL;
      68  static int (*__real_execlp) (const char *file, const char *arg, ...) = NULL;
      69  static int (*__real_execl) (const char *file, const char *arg, ...) = NULL;
      70  static int (*__real_clone) (int (*fn) (void *), void *child_stack,
      71  			   int flags, void *arg, ...) = NULL;
      72  static int (*__real_grantpt) (int fd) = NULL;
      73  static char *(*__real_ptsname) (int fd) = NULL;
      74  static FILE *(*__real_popen) (const char *command, const char *type) = NULL;
      75  static int clone_linenum = 0;
      76  static FILE *(*__real_popen_2_17) (const char *command, const char *type) = NULL;
      77  static FILE *(*__real_popen_2_2_5) (const char *command, const char *type) = NULL;
      78  static FILE *(*__real_popen_2_1) (const char *command, const char *type) = NULL;
      79  static FILE *(*__real_popen_2_0) (const char *command, const char *type) = NULL;
      80  
      81  static int (*__real_posix_spawn_2_17) (pid_t *pid, const char *path,
      82  			       const posix_spawn_file_actions_t *file_actions,
      83  			       const posix_spawnattr_t *attrp,
      84  			       char *const argv[], char *const envp[]) = NULL;
      85  static int (*__real_posix_spawn_2_15) (pid_t *pid, const char *path,
      86  			       const posix_spawn_file_actions_t *file_actions,
      87  			       const posix_spawnattr_t *attrp,
      88  			       char *const argv[], char *const envp[]) = NULL;
      89  static int (*__real_posix_spawn_2_2_5) (pid_t *pid, const char *path,
      90  				const posix_spawn_file_actions_t *file_actions,
      91  				const posix_spawnattr_t *attrp,
      92  				char *const argv[], char *const envp[]) = NULL;
      93  static int (*__real_posix_spawn_2_2) (pid_t *pid, const char *path,
      94  			      const posix_spawn_file_actions_t *file_actions,
      95  			      const posix_spawnattr_t *attrp,
      96  			      char *const argv[], char *const envp[]) = NULL;
      97  
      98  static int (*__real_posix_spawnp_2_17) (pid_t *pid, const char *file,
      99  				const posix_spawn_file_actions_t *file_actions,
     100  				const posix_spawnattr_t *attrp,
     101  				char *const argv[], char *const envp[]) = NULL;
     102  static int (*__real_posix_spawnp_2_15) (pid_t *pid, const char *file,
     103  				const posix_spawn_file_actions_t *file_actions,
     104  				const posix_spawnattr_t *attrp,
     105  				char *const argv[], char *const envp[]) = NULL;
     106  static int (*__real_posix_spawnp_2_2_5) (pid_t *pid, const char *file,
     107  				 const posix_spawn_file_actions_t *file_actions,
     108  				 const posix_spawnattr_t *attrp,
     109  				 char *const argv[], char *const envp[]) = NULL;
     110  static int (*__real_posix_spawnp_2_2) (pid_t *pid, const char *file,
     111  			       const posix_spawn_file_actions_t *file_actions,
     112  			       const posix_spawnattr_t *attrp,
     113  			       char *const argv[], char *const envp[]) = NULL;
     114  static int (*__real_system) (const char *command) = NULL;
     115  static int (*__real_posix_spawn) (pid_t *pid, const char *path,
     116  				const posix_spawn_file_actions_t *file_actions,
     117  				const posix_spawnattr_t *attrp,
     118  				char *const argv[], char *const envp[]) = NULL;
     119  static int (*__real_posix_spawnp) (pid_t *pid, const char *file,
     120  				const posix_spawn_file_actions_t *file_actions,
     121  				const posix_spawnattr_t *attrp,
     122  				char *const argv[], char *const envp[]) = NULL;
     123  static int (*__real_setuid) (uid_t uid) = NULL;
     124  static int (*__real_seteuid) (uid_t euid) = NULL;
     125  static int (*__real_setreuid) (uid_t ruid, uid_t euid) = NULL;
     126  static int (*__real_setgid) (gid_t gid) = NULL;
     127  static int (*__real_setegid) (gid_t egid) = NULL;
     128  static int (*__real_setregid) (gid_t rgid, gid_t egid)= NULL;
     129  static void linetrace_dormant ();
     130  static int check_follow_fork ();
     131  static int check_follow_exec (const char *execfile);
     132  static int check_follow_combo (const char *execfile);
     133  static int path_collectable (const char *execfile);
     134  static char * build_experiment_path (char *instring, size_t instring_sz, const char *lineage_str);
     135  static int init_lineage_intf ();
     136  
     137  /* -------  "Previously dbx-visible" function prototypes ----------------- */
     138  static int linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *execfile);
     139  static char *lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname);
     140  static void linetrace_ext_fork_prologue (const char *variant, char * new_lineage, int *following_fork);
     141  static void linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * new_lineage, int *following_fork);
     142  static char **linetrace_ext_exec_prologue (const char *variant,
     143  					   const char* path, char *const argv[], char *const envp[], int *following_exec);
     144  static void linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec);
     145  static void linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo);
     146  static void linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo);
     147  
     148  #ifdef DEBUG
     149  static int
     150  get_combo_flag ()
     151  {
     152    int * guard = NULL;
     153    int combo_flag = ((line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0);
     154    return combo_flag;
     155  }
     156  #endif /* DEBUG */
     157  
     158  /* must be called for potentially live experiment */
     159  int
     160  __collector_ext_line_init (int *precord_this_experiment,
     161  			   const char * progspec, const char * progname)
     162  {
     163    *precord_this_experiment = 1;
     164    TprintfT (DBG_LT0, "__collector_ext_line_init(%s)\n", progspec);
     165    if (NULL_PTR (fork))
     166      if (init_lineage_intf ())
     167        {
     168  	TprintfT (DBG_LT0, "__collector_ext_line_init() ERROR: initialization failed.\n");
     169  	return COL_ERROR_LINEINIT;
     170        }
     171    /* check the follow spec */
     172    user_follow_spec = CALL_UTIL (getenv)(SP_COLLECTOR_FOLLOW_SPEC);
     173    if (user_follow_spec != NULL)
     174      {
     175        TprintfT (DBG_LT0, "collector: %s=%s\n", SP_COLLECTOR_FOLLOW_SPEC, user_follow_spec);
     176        if (!linetrace_follow_experiment (user_follow_spec, curr_lineage, progname))
     177  	{
     178  	  *precord_this_experiment = 0;
     179  	  TprintfT (DBG_LT0, "collector: -F =<regex> does not match, will NOT be followed\n");
     180  	}
     181        else
     182  	TprintfT (DBG_LT0, "collector: -F =<regex> matches, will be followed\n");
     183        user_follow_mode = FOLLOW_ALL;
     184      }
     185    __collector_env_save_preloads ();
     186    TprintfT (DBG_LT0, "__collector_ext_line_init(), progname=%s, followspec=%s, followthis=%d\n",
     187  	    progname, user_follow_spec ? user_follow_spec : "NULL",
     188  	    *precord_this_experiment);
     189    line_mode = LM_TRACK_LINEAGE; /* even if we don't follow, we report the interposition */
     190    line_initted = 1;
     191    return COL_ERROR_NONE;
     192  }
     193  
     194  /*
     195   * int __collector_ext_line_install(args)
     196   * Check args to determine which line events to follow.
     197   * Create tsd key for combo flag.
     198   */
     199  int
     200  __collector_ext_line_install (char *args, const char * expname)
     201  {
     202    if (!line_initted)
     203      {
     204        TprintfT (DBG_LT0, "__collector_ext_line_install(%s) ERROR: init hasn't be called yet\n", args);
     205        return COL_ERROR_EXPOPEN;
     206      }
     207    TprintfT (DBG_LT0, "__collector_ext_line_install(%s, %s)\n", args, expname);
     208    line_key = __collector_tsd_create_key (sizeof (int), NULL, NULL);
     209  
     210    /* determine experiment name */
     211    __collector_strlcpy (linetrace_exp_dir_name, expname, sizeof (linetrace_exp_dir_name));
     212    lineage_from_expname (curr_lineage, sizeof (curr_lineage), linetrace_exp_dir_name);
     213    user_follow_mode = CALL_UTIL (atoi)(args);
     214    TprintfT (DBG_LT0, "__collector_ext_line_install() user_follow_mode=0x%X, linetrace_exp_dir_name=%s\n",
     215  	    user_follow_mode, linetrace_exp_dir_name);
     216  
     217    // determine java mode
     218    char * java_follow_env = CALL_UTIL (getenv)(JAVA_TOOL_OPTIONS);
     219    if (java_follow_env != NULL && CALL_UTIL (strstr)(java_follow_env, COLLECTOR_JVMTI_OPTION))
     220      java_mode = 1;
     221  
     222    // backup collector specific env
     223    if (sp_env_backup == NULL)
     224      {
     225        sp_env_backup = __collector_env_backup ();
     226        TprintfT (DBG_LT0, "__collector_ext_line_install creating sp_env_backup -- 0x%p\n", sp_env_backup);
     227      }
     228    else
     229      TprintfT (DBG_LT0, "__collector_ext_line_install existing sp_env_backup -- 0x%p\n", sp_env_backup);
     230    if (user_follow_mode == FOLLOW_NONE)
     231      __collector_env_unset (NULL);
     232  
     233    char logmsg[256];
     234    logmsg[0] = '\0';
     235    if (user_follow_mode != FOLLOW_NONE)
     236      CALL_UTIL (strlcat)(logmsg, "fork|exec|combo", sizeof (logmsg));
     237    size_t slen = __collector_strlen (logmsg);
     238    if (slen > 0)
     239      logmsg[slen] = '\0';
     240    else
     241      CALL_UTIL (strlcat)(logmsg, "none", sizeof (logmsg));
     242  
     243    /* report which line events are followed */
     244    (void) __collector_log_write ("<setting %s=\"%s\"/>\n", SP_JCMD_LINETRACE, logmsg);
     245    TprintfT (DBG_LT0, "__collector_ext_line_install(%s): %s \n", expname, logmsg);
     246    return COL_ERROR_NONE;
     247  }
     248  
     249  char *
     250  lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname)
     251  {
     252    TprintfT (DBG_LT0, "lineage_from_expname(%s, %s)\n", lineage_str, expname);
     253    char *p = NULL;
     254    if (lstr_sz < 1 || !lineage_str || !expname)
     255      {
     256        TprintfT (DBG_LT0, "lineage_from_expname(): ERROR, null string\n");
     257        return NULL;
     258      }
     259    /* determine lineage from experiment name */
     260    p = __collector_strrchr (expname, '/');
     261    if ((p == NULL) || (*++p != '_'))
     262      {
     263        lineage_str[0] = 0;
     264        TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\".\" (founder)\n", expname);
     265      }
     266    else
     267      {
     268        size_t tmp = __collector_strlcpy (lineage_str, p, lstr_sz);
     269        if (tmp >= lstr_sz)
     270  	TprintfT (DBG_LT0, "lineage_from_expname(): ERROR: expt=%s lineage=\"%s\" truncated %ld characters\n",
     271  		  expname, lineage_str, (long) (tmp - lstr_sz));
     272        lineage_str[lstr_sz - 1] = 0;
     273        p = __collector_strchr (lineage_str, '.');
     274        if (p != NULL)
     275  	*p = '\0';
     276        TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\"%s\"\n", expname, lineage_str);
     277      }
     278    return lineage_str;
     279  }
     280  
     281  /*
     282   * void __collector_line_cleanup (void)
     283   * Disable logging. Clear backup ENV.
     284   */
     285  void
     286  __collector_line_cleanup (void)
     287  {
     288    if (line_mode == LM_CLOSED)
     289      {
     290        TprintfT (DBG_LT0, "__collector_line_cleanup(): WARNING, line is already closed\n");
     291        return;
     292      }
     293    else if (line_mode == LM_DORMANT)
     294      TprintfT (DBG_LT0, "__collector_line_cleanup(): ERROR, line is DORMANT\n");
     295    else
     296      TprintfT (DBG_LT0, "__collector_line_cleanup()\n");
     297    line_mode = LM_CLOSED;
     298    user_follow_mode = FOLLOW_NONE;
     299    dbg_current_mode = FOLLOW_NONE; /* for debug only */
     300    line_key = COLLECTOR_TSD_INVALID_KEY;
     301    java_mode = 0;
     302    if (sp_env_backup != NULL)
     303      {
     304        __collector_env_backup_free ();
     305        sp_env_backup = NULL;
     306      }
     307    return;
     308  }
     309  
     310  /*
     311   * void __collector_ext_line_close (void)
     312   *	Disable logging.  Cleans ENV vars. Clear backup ENV.
     313   */
     314  void
     315  __collector_ext_line_close (void)
     316  {
     317    TprintfT (DBG_LT0, "__collector_ext_line_close()\n");
     318    __collector_line_cleanup ();
     319    __collector_env_unset (NULL);
     320    return;
     321  }
     322  
     323  /*
     324   * void linetrace_dormant(void)
     325   *	Disable logging.  Preserve ENV vars.
     326   */
     327  static void
     328  linetrace_dormant (void)
     329  {
     330    if (line_mode == LM_DORMANT)
     331      {
     332        TprintfT (DBG_LT0, "linetrace_dormant() -- already dormant\n");
     333        return;
     334      }
     335    else if (line_mode == LM_CLOSED)
     336      {
     337        TprintfT (DBG_LT0, "linetrace_dormant(): ERROR, line is already CLOSED\n");
     338        return;
     339      }
     340    else
     341      TprintfT (DBG_LT0, "linetrace_dormant()\n");
     342    line_mode = LM_DORMANT;
     343    return;
     344  }
     345  
     346  static int
     347  check_follow_fork ()
     348  {
     349    int follow = (user_follow_mode != FOLLOW_NONE);
     350    TprintfT (DBG_LT0, "check_follow_fork()=%d\n", follow);
     351    return follow;
     352  }
     353  
     354  static int
     355  check_follow_exec (const char *execfile)
     356  {
     357    int follow = (user_follow_mode != FOLLOW_NONE);
     358    if (follow)
     359      {
     360        /* revise based on collectability of execfile */
     361        follow = path_collectable (execfile);
     362      }
     363    TprintfT (DBG_LT0, "check_follow_exec(%s)=%d\n", execfile, follow);
     364    return follow;
     365  }
     366  
     367  static int
     368  check_follow_combo (const char *execfile)
     369  {
     370    int follow = (user_follow_mode != FOLLOW_NONE);
     371    TprintfT (DBG_LT0, "check_follow_combo(%s)=%d\n", execfile, follow);
     372    return follow;
     373  }
     374  
     375  static int
     376  check_fd_dynamic (int fd)
     377  {
     378    TprintfT (DBG_LT0, "check_fd_dynamic(%d)\n", fd);
     379    off_t off = CALL_UTIL (lseek)(fd, (off_t) 0, SEEK_END);
     380    size_t sz = (size_t) 8192; /* one page should suffice */
     381    if (sz > off)
     382      sz = off;
     383    char *p = CALL_UTIL (mmap64_)((char *) 0, sz, PROT_READ, MAP_PRIVATE, fd, (off64_t) 0);
     384    if (p == MAP_FAILED)
     385      {
     386        TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: mmap failed for `%d'\n", fd);
     387        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     388  				    COL_WARN_NOFOLLOW, "mmap-failed");
     389        return 0;
     390      }
     391    char elfclass = p[EI_CLASS];
     392    if ((p[EI_MAG0] != ELFMAG0) ||
     393        (p[EI_MAG1] != ELFMAG1) ||
     394        (p[EI_MAG2] != ELFMAG2) ||
     395        (p[EI_MAG3] != ELFMAG3) ||
     396        (elfclass != ELFCLASS32 && elfclass != ELFCLASS64)
     397        )
     398      {
     399        TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' is not executable ELF!\n", fd);
     400        CALL_UTIL (munmap)(p, sz);
     401        return 1;
     402      }
     403    Elf32_Ehdr *ehdr32 = (Elf32_Ehdr*) p;
     404    Elf64_Ehdr *ehdr64 = (Elf64_Ehdr*) p;
     405    Elf64_Off e_phoff;
     406    Elf64_Half e_phnum;
     407    Elf64_Half e_phentsize;
     408    if (elfclass == ELFCLASS32)
     409      {
     410        e_phoff = ehdr32->e_phoff;
     411        e_phnum = ehdr32->e_phnum;
     412        e_phentsize = ehdr32->e_phentsize;
     413      }
     414    else
     415      {
     416        e_phoff = ehdr64->e_phoff;
     417        e_phnum = ehdr64->e_phnum;
     418        e_phentsize = ehdr64->e_phentsize;
     419      }
     420    if ((sizeof (Elf32_Ehdr) > sz) ||
     421        (sizeof (Elf64_Ehdr) > sz) ||
     422        (e_phoff + e_phentsize * (e_phnum - 1) > sz))
     423      {
     424        TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' ELF file did not fit in page!\n", fd);
     425  #if 0
     426        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     427  				    COL_WARN_RISKYFOLLOW, "ELF header size");
     428  #endif
     429        CALL_UTIL (munmap)(p, sz);
     430        return 1;
     431      }
     432    TprintfT (DBG_LT2, "check_fd_dynamic(): elfclass=%d, e_phoff=%lu e_phnum=%lu e_phentsize=%lu\n",
     433  	    (int) elfclass, (unsigned long) e_phoff, (unsigned long) e_phnum,
     434  	    (unsigned long) e_phentsize);
     435    int dynamic = 0;
     436    Elf64_Half i;
     437    for (i = 0; i < e_phnum; i++)
     438      {
     439        if (elfclass == ELFCLASS32)
     440  	{
     441  	  if (PT_DYNAMIC ==
     442  	      ((Elf32_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
     443  	    {
     444  	      dynamic = 1;
     445  	      break;
     446  	    }
     447  	}
     448        else
     449  	{
     450  	  if (PT_DYNAMIC ==
     451  	      ((Elf64_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
     452  	    {
     453  	      dynamic = 1;
     454  	      break;
     455  	    }
     456  	}
     457      }
     458    if (!dynamic)
     459      {
     460        TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: Command `%d' is not a dynamic executable!\n", fd);
     461  #if 0
     462        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     463  				    COL_WARN_NOFOLLOW, "!dynamic");
     464  #endif
     465      }
     466    else
     467      TprintfT (DBG_LT2, "check_fd_dynamic(): Command `%d' is a dynamic executable!\n", fd);
     468    CALL_UTIL (munmap)(p, sz);
     469    return dynamic;
     470  }
     471  
     472  static int
     473  check_dynamic (const char *execfile)
     474  {
     475    TprintfT (DBG_LT2, "check_dynamic(%s)\n", execfile);
     476    int fd = CALL_UTIL (open)(execfile, O_RDONLY);
     477    if (fd == -1)
     478      {
     479        TprintfT (DBG_LT0, "check_dynamic(): ERROR/WARNING: Command `%s' could not be opened!\n", execfile);
     480        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     481  				    COL_WARN_RISKYFOLLOW, "open");
     482        return 1; /* follow, though exec will presumably fail */
     483      }
     484    int ret = check_fd_dynamic (fd);
     485    CALL_UTIL (close)(fd);
     486    return ret;
     487  }
     488  
     489  static int
     490  path_collectable (const char *execfile)
     491  {
     492    TprintfT (DBG_LT0, "path_collectable(%s)\n", execfile);
     493    /* Check that execfile exists and is a collectable executable */
     494    /* logging warning when collection is likely to be unsuccessful */
     495    /* (if check isn't accurate, generally best not to include it) */
     496  
     497    if (execfile && !__collector_strchr (execfile, '/'))
     498      { /* got an unqualified name */
     499        /* XXXX locate execfile on PATH to be able to check it */
     500        TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't check unqualified executable `%s'\n", execfile);
     501  #if 0
     502        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     503  				    COL_WARN_RISKYFOLLOW, "path");
     504  #endif
     505        return 1; /* follow unqualified execfile unchecked */
     506      }
     507    struct stat sbuf;
     508    if (stat (execfile, &sbuf))
     509      { /* can't stat it */
     510        TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't stat `%s'\n", execfile);
     511  #if 0
     512        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     513  				    COL_WARN_RISKYFOLLOW, "stat");
     514  #endif
     515        return 1; /* follow, though exec will probably fail */
     516      }
     517    TprintfT (DBG_LT2, "path_collectable(%s) mode=0%o uid=%d gid=%d\n",
     518  	    execfile, sbuf.st_mode, sbuf.st_uid, sbuf.st_gid);
     519    if (((sbuf.st_mode & S_IXUSR) == 0) || ((sbuf.st_mode & S_IFMT) == S_IFDIR))
     520      {
     521        TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is NOT an executable file!\n", execfile);
     522  #if 0
     523        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     524  				    COL_WARN_RISKYFOLLOW, "mode");
     525  #endif
     526        return 1; /* follow, though exec will presumably fail */
     527      }
     528    /* XXXX setxid(root) is OK iff libcollector is registered as secure */
     529    /* XXXX setxid(non-root) is OK iff umask is accomodating */
     530    if (((sbuf.st_mode & S_ISUID) != 0) || ((sbuf.st_mode & S_ISGID) != 0))
     531      {
     532        TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is SetXID!\n", execfile);
     533  #if 0
     534        (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
     535  				    COL_WARN_RISKYFOLLOW, "setxid");
     536  #endif
     537        return 1; /* follow, though collection may be unreliable */
     538      }
     539    if (!check_dynamic (execfile))
     540      {
     541        TprintfT (DBG_LT0, "path_collectable(%s) WARNING/ERROR: not dynamic, not collectng!\n", execfile);
     542        return 0; /* don't follow, collection will fail unpredictably */
     543      }
     544    TprintfT (DBG_LT2, "path_collectable(%s) OK!\n", execfile);
     545    return 1; /* OK to follow */
     546  }
     547  
     548  static char *
     549  build_experiment_path (char * instring, size_t instring_sz, const char *lineage_str)
     550  {
     551    TprintfT (DBG_LT0, "build_experiment_path(,%ld, %s)\n",
     552  	    (long) instring_sz, lineage_str);
     553    const char *p = CALL_UTIL (strstr)(linetrace_exp_dir_name, DESCENDANT_EXPT_KEY);
     554    int basedir_sz;
     555    if (p)
     556      basedir_sz = p - linetrace_exp_dir_name + 4; /* +3 because of DESCENDANT_EXPT_KEY */
     557    else
     558      basedir_sz = __collector_strlen (linetrace_exp_dir_name) + 1;
     559    int additional_sz = __collector_strlen (lineage_str) + 4;
     560    if (basedir_sz + additional_sz > instring_sz)
     561      {
     562        TprintfT (DBG_LT0, "build_experiment_path(%s,%s): ERROR: path too long: %d > %ld\n",
     563  		linetrace_exp_dir_name, lineage_str,
     564  		basedir_sz + additional_sz, (long) instring_sz);
     565        *instring = 0;
     566        return NULL;
     567      }
     568    __collector_strlcpy (instring, linetrace_exp_dir_name, basedir_sz);
     569    size_t slen = __collector_strlen (instring);
     570    CALL_UTIL (snprintf)(instring + slen, instring_sz - slen, "/%s.er", lineage_str);
     571    assert (__collector_strlen (instring) + 1 == basedir_sz + additional_sz);
     572    return instring;
     573  }
     574  
     575  static void
     576  check_reuid_change (uid_t ruid, uid_t euid)
     577  {
     578    uid_t curr_ruid = getuid ();
     579    uid_t curr_euid = geteuid ();
     580    mode_t curr_umask = umask (0);
     581    umask (curr_umask); /* restore original umask */
     582    int W_oth = !(curr_umask & S_IWOTH);
     583    TprintfT (DBG_LT0, "check_reuid_change(%d,%d): umask=%03o\n", ruid, euid, curr_umask);
     584    TprintfT (DBG_LT0, "check_reuid_change(): umask W usr=%d grp=%d oth=%d\n",
     585  	    (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
     586    if (ruid != -1)
     587      {
     588        TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_ruid, ruid);
     589        if ((curr_euid == 0) && (ruid != 0) && !W_oth)
     590  	{
     591  	  /* changing to non-root ID, with umask blocking writes by other */
     592  	  TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after ruid change (%d->%d)\n",
     593  		    curr_ruid, ruid);
     594  	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o ruid %d->%d</event>\n",
     595  					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_ruid, ruid);
     596  	}
     597      }
     598    if (euid != -1)
     599      {
     600        TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_euid, euid);
     601        if ((curr_euid == 0) && (euid != 0) && !W_oth)
     602  	{
     603  	  /* changing to non-root ID, with umask blocking writes by other */
     604  	  TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after euid change (%d->%d)\n",
     605  		    curr_euid, euid);
     606  	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o euid %d->%d</event>\n",
     607  					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_euid, euid);
     608  	}
     609      }
     610  }
     611  
     612  static void
     613  check_regid_change (gid_t rgid, gid_t egid)
     614  {
     615    gid_t curr_rgid = getgid ();
     616    gid_t curr_egid = getegid ();
     617    uid_t curr_euid = geteuid ();
     618    mode_t curr_umask = umask (0);
     619    umask (curr_umask); /* restore original umask */
     620    int W_oth = !(curr_umask & S_IWOTH);
     621    TprintfT (DBG_LT0, "check_regid_change(%d,%d): umask=%03o euid=%d\n",
     622  	    rgid, egid, curr_umask, curr_euid);
     623    TprintfT (DBG_LT0, "umask W usr=%d grp=%d oth=%d\n",
     624  	    (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
     625    if (rgid != -1)
     626      {
     627        TprintfT (DBG_LT0, "check_regid_change(%d->%d)\n", curr_rgid, rgid);
     628        if ((curr_euid == 0) && (rgid != 0) && !W_oth)
     629  	{
     630  	  /* changing to non-root ID, with umask blocking writes by other */
     631  	  TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after rgid change (%d->%d)\n",
     632  		    curr_rgid, rgid);
     633  	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o rgid %d->%d</event>\n",
     634  					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_rgid, rgid);
     635  	}
     636      }
     637    if (egid != -1)
     638      {
     639        TprintfT (DBG_LT0, "check_regid_change(): check_egid_change(%d->%d)\n", curr_egid, egid);
     640        if ((curr_euid == 0) && (egid != 0) && !W_oth)
     641  	{
     642  	  /* changing to non-root ID, with umask blocking writes by other */
     643  	  TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after egid change (%d->%d)\n",
     644  		    curr_egid, egid);
     645  	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o egid %d->%d</event>\n",
     646  					SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_egid, egid);
     647  	}
     648      }
     649  }
     650  
     651  static int
     652  init_lineage_intf ()
     653  {
     654    void *dlflag;
     655    TprintfT (DBG_LT2, "init_lineage_intf()\n");
     656  
     657    static int nesting_check = 0;
     658    if (nesting_check >= 2)
     659      {
     660        /* segv before stack blows up */
     661        nesting_check /= (nesting_check - 2);
     662      }
     663    nesting_check++;
     664  
     665    __real_fork = dlsym (RTLD_NEXT, "fork");
     666    if (__real_fork == NULL)
     667      {
     668        __real_fork = dlsym (RTLD_DEFAULT, "fork");
     669        if (__real_fork == NULL)
     670  	return 1;
     671        dlflag = RTLD_DEFAULT;
     672      }
     673    else
     674      dlflag = RTLD_NEXT;
     675    TprintfT (DBG_LT2, "init_lineage_intf() using RTLD_%s\n",
     676  	    dlflag == RTLD_DEFAULT ? "DEFAULT" : "NEXT");
     677    __real_vfork = dlsym (dlflag, "vfork");
     678    __real_execve = dlsym (dlflag, "execve");
     679    __real_execvp = dlsym (dlflag, "execvp");
     680    __real_execv = dlsym (dlflag, "execv");
     681    __real_execle = dlsym (dlflag, "execle");
     682    __real_execlp = dlsym (dlflag, "execlp");
     683    __real_execl = dlsym (dlflag, "execl");
     684    __real_clone = dlsym (dlflag, "clone");
     685  
     686    __real_popen_2_17 = dlvsym (dlflag, "popen", "GLIBC_2.17");
     687    __real_popen_2_2_5 = dlvsym (dlflag, "popen", "GLIBC_2.2.5");
     688    __real_popen_2_1 = dlvsym (dlflag, "popen", "GLIBC_2.1");
     689    __real_popen_2_0 = dlvsym (dlflag, "popen", "GLIBC_2.0");
     690    if (__real_popen_2_17)
     691      __real_popen = __real_popen_2_17;
     692    else if (__real_popen_2_2_5)
     693      __real_popen = __real_popen_2_2_5;
     694    else if (__real_popen_2_1)
     695      __real_popen = __real_popen_2_1;
     696    else if (__real_popen_2_0)
     697      __real_popen = __real_popen_2_0;
     698    else
     699      __real_popen = dlsym (dlflag, "popen");
     700  
     701    __real_posix_spawn_2_17 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.17");
     702    __real_posix_spawn_2_15 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.15");
     703    __real_posix_spawn_2_2_5 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2.5");
     704    __real_posix_spawn_2_2 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2");
     705    if (__real_posix_spawn_2_17)
     706      __real_posix_spawn = __real_posix_spawn_2_17;
     707    else if (__real_posix_spawn_2_15)
     708      __real_posix_spawn = __real_posix_spawn_2_15;
     709    else if (__real_posix_spawn_2_2_5)
     710      __real_posix_spawn = __real_posix_spawn_2_2_5;
     711    else if (__real_posix_spawn_2_2)
     712      __real_posix_spawn = __real_posix_spawn_2_2;
     713    else
     714      __real_posix_spawn = dlsym (dlflag, "posix_spawn");
     715  
     716    __real_posix_spawnp_2_17 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.17");
     717    __real_posix_spawnp_2_15 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.15");
     718    __real_posix_spawnp_2_2_5 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2.5");
     719    __real_posix_spawnp_2_2 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2");
     720    if (__real_posix_spawnp_2_17)
     721      __real_posix_spawnp = __real_posix_spawnp_2_17;
     722    else if (__real_posix_spawnp_2_15)
     723      __real_posix_spawnp = __real_posix_spawnp_2_15;
     724    else if (__real_posix_spawnp_2_2_5)
     725      __real_posix_spawnp = __real_posix_spawnp_2_2_5;
     726    else if (__real_posix_spawnp_2_2)
     727      __real_posix_spawnp = __real_posix_spawnp_2_2;
     728    else
     729      __real_posix_spawnp = dlsym (dlflag, "posix_spawnp");
     730  
     731    __real_grantpt = dlsym (dlflag, "grantpt");
     732    __real_ptsname = dlsym (dlflag, "ptsname");
     733    __real_system = dlsym (dlflag, "system");
     734    __real_setuid = dlsym (dlflag, "setuid");
     735    __real_seteuid = dlsym (dlflag, "seteuid");
     736    __real_setreuid = dlsym (dlflag, "setreuid");
     737    __real_setgid = dlsym (dlflag, "setgid");
     738    __real_setegid = dlsym (dlflag, "setegid");
     739    __real_setregid = dlsym (dlflag, "setregid");
     740  
     741  #define PR_FUNC(f)  TprintfT (DBG_LT2, "linetrace.c: " #f ": @%p\n", f)
     742    PR_FUNC (__real_fork);
     743    PR_FUNC (__real_vfork);
     744    PR_FUNC (__real_execve);
     745    PR_FUNC (__real_execvp);
     746    PR_FUNC (__real_execv);
     747    PR_FUNC (__real_execle);
     748    PR_FUNC (__real_execlp);
     749    PR_FUNC (__real_execl);
     750    PR_FUNC (__real_clone);
     751    PR_FUNC (__real_grantpt);
     752    PR_FUNC (__real_ptsname);
     753    PR_FUNC (__real_popen);
     754    PR_FUNC (__real_popen_2_17);
     755    PR_FUNC (__real_popen_2_2_5);
     756    PR_FUNC (__real_popen_2_1);
     757    PR_FUNC (__real_popen_2_0);
     758    PR_FUNC (__real_posix_spawn_2_17);
     759    PR_FUNC (__real_posix_spawn_2_15);
     760    PR_FUNC (__real_posix_spawn_2_2_5);
     761    PR_FUNC (__real_posix_spawn_2_2);
     762    PR_FUNC (__real_posix_spawnp_2_17);
     763    PR_FUNC (__real_posix_spawnp_2_15);
     764    PR_FUNC (__real_posix_spawnp_2_2_5);
     765    PR_FUNC (__real_posix_spawnp_2_2);
     766    PR_FUNC (__real_system);
     767    PR_FUNC (__real_posix_spawn);
     768    PR_FUNC (__real_posix_spawnp);
     769    PR_FUNC (__real_setuid);
     770    PR_FUNC (__real_seteuid);
     771    PR_FUNC (__real_setreuid);
     772    PR_FUNC (__real_setgid);
     773    PR_FUNC (__real_setegid);
     774    PR_FUNC (__real_setregid);
     775  
     776    return 0;
     777  }
     778  
     779  /*------------------------------------------------------------------------ */
     780  /* Note: The following _prologue and _epilogue functions used to be dbx-visible.
     781  
     782     They are used to appropriately manage lineage-changing events, by
     783     quiescing and re-enabling/re-setting experiment collection before and after,
     784     and logging the lineage-change in the process/experiment undertaking it.
     785     As shown by the interposition functions for fork, exec, etc., which follow,
     786     the _prologue should be called immediately prior (such as a breakpoint
     787     action defined at function entry) and the _epilogue called immediately
     788     after (such as a breakpoint action defined at function return).
     789   */
     790  
     791  /*
     792     Notes on MT from Solaris 10 man pthread_atfork:
     793  
     794       All multithreaded applications that call fork() in  a  POSIX
     795       threads  program and do more than simply call exec(2) in the
     796       child of the fork need to ensure that the child is protected
     797       from deadlock.
     798  
     799       Since the "fork-one" model results in duplicating  only  the
     800       thread  that  called fork(), it is possible that at the time
     801       of the call another thread in the parent owns a  lock.  This
     802       thread  is  not  duplicated  in the child, so no thread will
     803       unlock this lock in the child.  Deadlock occurs if the  sin-
     804       gle thread in the child needs this lock.
     805  
     806       The problem is more serious with locks in libraries.   Since
     807       a  library writer does not know if the application using the
     808       library calls fork(), the library must protect  itself  from
     809       such  a  deadlock  scenario.   If the application that links
     810       with this library calls fork() and does not call  exec()  in
     811       the  child,  and if it needs a library lock that may be held
     812       by some other thread  in  the  parent  that  is  inside  the
     813       library  at  the time of the fork, the application deadlocks
     814       inside the library.
     815   */
     816  
     817  static void
     818  linetrace_ext_fork_prologue (const char *variant, char * n_lineage, int *following_fork)
     819  {
     820    TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
     821  	    variant, n_lineage, *following_fork);
     822    __collector_env_print ("fork_prologue start");
     823    if (dbg_current_mode != FOLLOW_NONE)
     824      TprintfT (DBG_LT0, "linetrace_ext_fork_prologue(%s) ERROR: dbg_current_mode=%d, changing to FOLLOW_FORK!\n",
     825  		variant, dbg_current_mode);
     826    dbg_current_mode = FOLLOW_ON;
     827    if (__collector_strncmp ((char *) variant, "clone", sizeof ("clone") - 1) == 0)
     828      {
     829        __collector_mutex_lock (&clone_lineage_lock);
     830        CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_C%d", curr_lineage, ++clone_linenum);
     831        __collector_mutex_unlock (&clone_lineage_lock);
     832      }
     833    else
     834      {
     835        __collector_mutex_lock (&fork_lineage_lock);
     836        CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_f%d", curr_lineage, ++fork_linenum);
     837        __collector_mutex_unlock (&fork_lineage_lock);
     838      }
     839    *following_fork = check_follow_fork ();
     840  
     841    /* write message before suspending, or it won't be written */
     842    hrtime_t ts = GETRELTIME ();
     843    TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
     844  	    variant, n_lineage, *following_fork);
     845    __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\"/>\n",
     846  			 SP_JCMD_DESC_START,
     847  			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
     848  			 variant, n_lineage, *following_fork);
     849    __collector_ext_dispatcher_thread_timer_suspend ();
     850    __collector_ext_hwc_lwp_suspend ();
     851    __collector_env_print ("fork_prologue end");
     852  }
     853  
     854  static void
     855  linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * n_lineage, int *following_fork)
     856  {
     857    if (dbg_current_mode == FOLLOW_NONE)
     858      TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) ERROR: dbg_current_mode=%d!\n",
     859  	      variant, dbg_current_mode);
     860    /* compute descendant experiment name */
     861    char new_exp_name[LT_MAXPATHLEN];
     862    /* save exp_name to global var */
     863    if (!build_experiment_path (new_exp_name, sizeof (new_exp_name), n_lineage))
     864      TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s): ERROR SP_COLLECTOR_EXPNAME not set\n", n_lineage);
     865    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s):%d() returned %d %s; child experiment name = %s\n",
     866  	    variant, *following_fork, ret, (ret ? "parent" : "child"), new_exp_name);
     867    if (ret == 0)
     868      {
     869        /* *************************************child */
     870        __collector_env_print ("fork_epilogue child at start");
     871        /* start a new line */
     872        fork_linenum = 0;
     873        __collector_mutex_init (&fork_lineage_lock);
     874        clone_linenum = 0;
     875        __collector_mutex_init (&clone_lineage_lock);
     876        __collector_env_update (NULL);
     877        __collector_env_print ("fork_epilogue child after env_update");
     878        __collector_clean_state ();
     879        __collector_env_print ("fork_epilogue child after clean_slate");
     880        __collector_line_cleanup ();
     881        __collector_env_print ("fork_epilogue child after line_cleanup");
     882        if (*following_fork)
     883  	{
     884  	  /* stop recording this experiment, but preserve env vars */
     885  	  linetrace_dormant ();
     886  	  __collector_env_print ("fork_epilogue child after linetrace_dormant");
     887  
     888  	  //static char exp_name_env[LT_MAXPATHLEN];
     889  	  char * exp_name_env = CALL_UTIL (calloc)(LT_MAXPATHLEN, 1);
     890  	  CALL_UTIL (snprintf)(exp_name_env, LT_MAXPATHLEN, "%s=%s", SP_COLLECTOR_EXPNAME, new_exp_name);
     891  	  CALL_UTIL (putenv)(exp_name_env);
     892  
     893  	  const char *params = CALL_UTIL (getenv)(SP_COLLECTOR_PARAMS);
     894  	  int ret;
     895  	  if (*new_exp_name == 0)
     896  	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
     897  		      SP_COLLECTOR_EXPNAME);
     898  	  else if (params == NULL)
     899  	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
     900  		      SP_COLLECTOR_PARAMS);
     901  	  else if ((ret = __collector_open_experiment (new_exp_name, params, SP_ORIGIN_FORK)))
     902  	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: '%s' open failed, ret=%d\n",
     903  		      new_exp_name, ret);
     904  	  else
     905  	    TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: opened(%s)\n", new_exp_name);
     906  	  TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) returning to *child*\n", variant);
     907  	}
     908        else
     909  	{
     910  	  /* disable current and further linetrace experiment resumption */
     911  	  TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) child calling line_close\n", variant);
     912  	  __collector_ext_line_close ();
     913  	}
     914        __collector_env_print ("fork_epilogue child at end");
     915        /* *************************************end child */
     916      }
     917    else
     918      {
     919        /* *************************************parent */
     920        __collector_env_print ("fork_epilogue parent at start");
     921        __collector_ext_dispatcher_thread_timer_resume ();
     922        __collector_ext_hwc_lwp_resume ();
     923        hrtime_t ts = GETRELTIME ();
     924        char msg[256 + LT_MAXPATHLEN];
     925        if (ret >= 0)
     926  	CALL_UTIL (snprintf)(msg, sizeof (msg), "pid=%d", ret);
     927        else
     928  	{
     929  	  /* delete stillborn experiment? */
     930  	  char errmsg[256];
     931  	  strerror_r (errno, errmsg, sizeof (errmsg));
     932  	  CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
     933  	}
     934        __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
     935  			     SP_JCMD_DESC_STARTED,
     936  			     (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
     937  			     variant, n_lineage, *following_fork, msg);
     938        /* environment remains set for collection */
     939        __collector_env_print ("fork_epilogue parent at end");
     940        /* *************************************end parent */
     941      }
     942    dbg_current_mode = FOLLOW_NONE;
     943    *following_fork = 0;
     944  }
     945  
     946  static char**
     947  linetrace_ext_exec_prologue_end (const char *variant, const char* cmd_string,
     948  				 char *const envp[], int following_exec)
     949  {
     950    char **coll_env;
     951    TprintfT (DBG_LT0, "linetrace_ext_exec_prologue_end; variant=%s; cmd_string=%s; follow=%d\n",
     952  	    variant, cmd_string, following_exec);
     953    /* write message before suspending, or it won't be written */
     954    hrtime_t ts = GETRELTIME ();
     955    __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
     956  			 SP_JCMD_EXEC_START,
     957  			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
     958  			 variant, new_lineage, following_exec, cmd_string);
     959    if (following_exec)
     960      {
     961        coll_env = __collector_env_allocate (envp, 0);
     962        __collector_env_update (coll_env);
     963        extern char **environ; /* the process' actual environment */
     964        if (environ == envp)   /* user selected process environment */
     965  	environ = coll_env;
     966      }
     967    else
     968      coll_env = (char**) envp;
     969    __collector_env_printall ("linetrace_ext_exec_prologue_end", coll_env);
     970    if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
     971      {
     972        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
     973        __collector_suspend_experiment ("suspend_for_exec");
     974        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
     975      }
     976    if (CALL_UTIL (strstr)(variant, "posix_spawn"))
     977      {
     978        __collector_ext_dispatcher_thread_timer_suspend ();
     979        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
     980        __collector_ext_hwc_lwp_suspend ();
     981        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
     982      }
     983    return (coll_env);
     984  }
     985  
     986  static char**
     987  linetrace_ext_exec_prologue (const char *variant,
     988  			     const char* path, char *const argv[],
     989  			     char *const envp[], int *following_exec)
     990  {
     991    char cmd_string[_POSIX_ARG_MAX] = {'\0'};
     992  
     993    if (dbg_current_mode != FOLLOW_NONE)
     994      TprintfT (DBG_LT0, "linetrace_ext_exec_prologue() ERROR: dbg_current_mode=%d, changing to FOLLOW_EXEC!\n", dbg_current_mode);
     995    dbg_current_mode = FOLLOW_ON;
     996    *following_exec = check_follow_exec (path);
     997    if (path != NULL)
     998      {
     999        /* escape any newline, " or \ characters in the exec command */
    1000        TprintfT (DBG_LT3, "linetrace_ext_exec_prologue(): arg0=%s\n", path);
    1001        /* leave space in log message for terminator (and header) */
    1002        __collector_strlcpy (cmd_string, path, sizeof (cmd_string));
    1003        size_t len;
    1004        unsigned argn = 0;
    1005        if (argv[0])
    1006  	{
    1007  	  char *p;
    1008  	  while (((p = argv[++argn]) != 0) &&
    1009  		 (len = __collector_strlen (cmd_string)) < sizeof (cmd_string) - 2)
    1010  	    {
    1011  	      cmd_string[len++] = ' ';
    1012  	      __collector_strlcpy (cmd_string + len, p, sizeof (cmd_string) - len);
    1013  	    }
    1014  	}
    1015      }
    1016    TprintfT (DBG_LT0, "linetrace_ext_exec_prologue(%s), lineage=%s, follow=%d, prog=%s, path=%s \n",
    1017  	    variant, new_lineage, *following_exec, cmd_string, path);
    1018    return linetrace_ext_exec_prologue_end (variant, cmd_string, envp, *following_exec);
    1019  }
    1020  
    1021  static void
    1022  linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec)
    1023  {
    1024    /* For exec, this routine is only entered if the exec failed */
    1025    /* However, posix_spawn() is expected to return */
    1026    if (dbg_current_mode == FOLLOW_NONE)
    1027      TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: dbg_current_mode=%d!\n", dbg_current_mode);
    1028    TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue(%s):%d returned: %d, errno=%d\n",
    1029  	    variant, *following_exec, ret, errno);
    1030    if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
    1031      {
    1032        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
    1033        __collector_resume_experiment ();
    1034        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
    1035      }
    1036    if (CALL_UTIL (strstr)(variant, "posix_spawn"))
    1037      {
    1038        __collector_ext_dispatcher_thread_timer_resume ();
    1039        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
    1040        __collector_ext_hwc_lwp_resume ();
    1041        __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
    1042      }
    1043    hrtime_t ts = GETRELTIME ();
    1044    char msg[256];
    1045    if (ret)
    1046      {
    1047        char errmsg[256];
    1048        strerror_r (errno, errmsg, sizeof (errmsg));
    1049        CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
    1050      }
    1051    else
    1052      CALL_UTIL (snprintf)(msg, sizeof (msg), "rc=%d", ret);
    1053    if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
    1054      __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
    1055  			   SP_JCMD_EXEC_ERROR,
    1056  			   (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
    1057  			   variant, new_lineage, *following_exec, msg);
    1058    if (envp == NULL)
    1059      TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: envp NULL after %s!\n", variant);
    1060    dbg_current_mode = FOLLOW_NONE;
    1061    *following_exec = 0;
    1062  }
    1063  
    1064  static void
    1065  linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo)
    1066  {
    1067    char cmd_string[_POSIX_ARG_MAX] = {'\0'};
    1068    char execfile[_POSIX_ARG_MAX] = {'\0'};
    1069  
    1070    if (dbg_current_mode != FOLLOW_NONE)
    1071      TprintfT (DBG_LT0, "linetrace_ext_combo_prologue() ERROR: dbg_current_mode=%d!  changing to FOLLOW_ON\n",
    1072  	      dbg_current_mode);
    1073    dbg_current_mode = FOLLOW_ON;
    1074    if (cmd != NULL)
    1075      {
    1076        /* extract executable name from combo command */
    1077        unsigned len = strcspn (cmd, " ");
    1078        __collector_strlcpy (execfile, cmd, len + 1);
    1079  
    1080        /* escape any newline, " or \ characters in the combo command */
    1081        /* leave space in log message for terminator (and header) */
    1082        __collector_strlcpy (cmd_string, cmd, sizeof (cmd_string));
    1083      }
    1084  
    1085    *following_combo = check_follow_combo (execfile);
    1086    TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(%s) follow=%d, prog=%s\n\n",
    1087  	    variant, *following_combo, cmd_string);
    1088  
    1089    /* Construct the lineage string for the new image */
    1090    new_lineage[0] = 0;
    1091    __collector_strcat (new_lineage, "XXX");
    1092  
    1093    /* write message before suspending, or it won't be written */
    1094    hrtime_t ts = GETRELTIME ();
    1095    __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
    1096  			 SP_JCMD_DESC_START,
    1097  			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
    1098  			 variant, new_lineage, *following_combo, cmd_string);
    1099    if (*following_combo)
    1100      {
    1101        __collector_env_update (NULL);
    1102        TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(): Following %s(\"%s\")\n", variant, execfile);
    1103      }
    1104    __collector_ext_dispatcher_thread_timer_suspend ();
    1105    __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
    1106    __collector_ext_hwc_lwp_suspend ();
    1107    __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
    1108  }
    1109  
    1110  static void
    1111  linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo)
    1112  {
    1113    if (dbg_current_mode == FOLLOW_NONE)
    1114      TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue() ERROR: dbg_current_mode=FOLLOW_NONE\n");
    1115    TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue(%s):%d() returned %d\n",
    1116  	    variant, *following_combo, ret);
    1117    __collector_ext_dispatcher_thread_timer_resume ();
    1118    __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
    1119    __collector_ext_hwc_lwp_resume ();
    1120    __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
    1121    hrtime_t ts = GETRELTIME ();
    1122    __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" follow=\"%d\" msg=\"rc=%d\"/>\n",
    1123  			 SP_JCMD_DESC_STARTED,
    1124  			 (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
    1125  			 variant, *following_combo, ret);
    1126  
    1127    dbg_current_mode = FOLLOW_NONE;
    1128    *following_combo = 0;
    1129  }
    1130  
    1131  /*------------------------------------------------------------- fork */
    1132  pid_t fork () __attribute__ ((weak, alias ("__collector_fork")));
    1133  pid_t _fork () __attribute__ ((weak, alias ("__collector_fork")));
    1134  
    1135  pid_t
    1136  __collector_fork (void)
    1137  {
    1138    pid_t ret;
    1139    if (NULL_PTR (fork))
    1140      {
    1141        TprintfT (DBG_LT0, "__collector_fork() calling init_lineage_intf()\n");
    1142        init_lineage_intf ();
    1143      }
    1144    __collector_env_print ("__collector_fork start");
    1145    int * guard = NULL;
    1146    int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
    1147    TprintfT (DBG_LT0, "__collector_fork() interposition: line_mode=%d combo=%d\n",
    1148  	    line_mode, combo_flag);
    1149    if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
    1150      {
    1151        TprintfT (DBG_LT0, "__collector_fork() not following, returning CALL_REAL(fork)()\n");
    1152        return CALL_REAL (fork)();
    1153      }
    1154    int following_fork = 0;
    1155    linetrace_ext_fork_prologue ("fork", new_lineage, &following_fork);
    1156  
    1157    /* since libpthread/fork ends up calling fork1, it's a combo */
    1158    PUSH_REENTRANCE (guard);
    1159    ret = CALL_REAL (fork)();
    1160    POP_REENTRANCE (guard);
    1161    linetrace_ext_fork_epilogue ("fork", ret, new_lineage, &following_fork);
    1162    return ret;
    1163  }
    1164  
    1165  /*------------------------------------------------------------- vfork */
    1166  /* vfork interposition in the usual sense is not possible, since vfork(2)
    1167     relies on specifics of the stack frames in the parent and child which
    1168     only work when the child's exec (or _exit) are in the same stack frame
    1169     as the vfork: this isn't the case when there's interposition on exec.
    1170     As a workaround, the interposing vfork calls fork1 instead of the real
    1171     vfork.  Note that fork1 is somewhat less efficient than vfork, and requires
    1172     additional memory, which may result in a change of application behaviour
    1173     when libcollector is loaded (even when collection is not active),
    1174     affecting not only direct use of vfork by the subject application,
    1175     but also indirect use through system, popen, and the other combos.
    1176   */
    1177  pid_t vfork () __attribute__ ((weak, alias ("__collector_vfork")));
    1178  pid_t _vfork () __attribute__ ((weak, alias ("__collector_vfork")));
    1179  
    1180  pid_t
    1181  __collector_vfork (void)
    1182  {
    1183    if (NULL_PTR (vfork))
    1184      init_lineage_intf ();
    1185  
    1186    int * guard = NULL;
    1187    int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
    1188  
    1189    TprintfT (DBG_LT0, "__collector_vfork() interposing: line_mode=%d combo=%d\n",
    1190  	    line_mode, combo_flag);
    1191    if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
    1192      return CALL_REAL (fork)();
    1193  
    1194    /* this warning is also appropriate for combos which use vfork,
    1195       however, let's assume this is achieved elsewhere */
    1196    (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
    1197  				COL_WARN_VFORK, "fork");
    1198  
    1199    char new_lineage[LT_MAXNAMELEN];
    1200    new_lineage[0] = 0;
    1201    int following_fork = 0;
    1202    linetrace_ext_fork_prologue ("vfork", new_lineage, &following_fork);
    1203  
    1204    pid_t ret = CALL_REAL (fork)();
    1205    linetrace_ext_fork_epilogue ("vfork", ret, new_lineage, &following_fork);
    1206    return ret;
    1207  }
    1208  
    1209  /*------------------------------------------------------------- execve */
    1210  int execve () __attribute__ ((weak, alias ("__collector_execve")));
    1211  
    1212  int
    1213  __collector_execve (const char* path, char *const argv[], char *const envp[])
    1214  {
    1215    static char **coll_env = NULL; /* environment for collection */
    1216    if (NULL_PTR (execve))
    1217      init_lineage_intf ();
    1218    int * guard = NULL;
    1219    int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
    1220    TprintfT (DBG_LT0,
    1221  	    "__collector_execve(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
    1222  	    path ? path : "NULL",
    1223  	    argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
    1224  	    envp ? (envp[0] ? envp[0] : "NULL") : "NULL",
    1225  	    line_mode, combo_flag);
    1226    if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
    1227      __collector_env_unset ((char**) envp);
    1228    if (line_mode != LM_TRACK_LINEAGE || combo_flag)
    1229      return CALL_REAL (execve)(path, argv, envp);
    1230  
    1231    int following_exec = 0;
    1232    coll_env = linetrace_ext_exec_prologue ("execve", path, argv, envp, &following_exec);
    1233    TprintfT (DBG_LT2, "__collector_execve(): coll_env=0x%p\n", coll_env);
    1234    __collector_env_printall ("__collector_execve", coll_env);
    1235    int ret = CALL_REAL (execve)(path, argv, coll_env);
    1236    linetrace_ext_exec_epilogue ("execve", envp, ret, &following_exec);
    1237    return ret;
    1238  }
    1239  
    1240  int execvp () __attribute__ ((weak, alias ("__collector_execvp")));
    1241  
    1242  int
    1243  __collector_execvp (const char* file, char *const argv[])
    1244  {
    1245    extern char **environ; /* the process' actual environment */
    1246    char ** envp = environ;
    1247    if (NULL_PTR (execvp))
    1248      init_lineage_intf ();
    1249    int * guard = NULL;
    1250    int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
    1251    TprintfT (DBG_LT0,
    1252  	    "__collector_execvp(file=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
    1253  	    file ? file : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
    1254  	    line_mode, combo_flag);
    1255    if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
    1256      __collector_env_unset ((char**) envp);
    1257    if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
    1258      return CALL_REAL (execvp)(file, argv);
    1259  
    1260    int following_exec = 0;
    1261  #ifdef DEBUG
    1262    char **coll_env = /* environment for collection */
    1263  #endif /* DEBUG */
    1264  	  linetrace_ext_exec_prologue ("execvp", file, argv, envp, &following_exec);
    1265    TprintfT (DBG_LT0, "__collector_execvp(): coll_env=0x%p\n", coll_env);
    1266  
    1267    int ret = CALL_REAL (execvp)(file, argv);
    1268    linetrace_ext_exec_epilogue ("execvp", envp, ret, &following_exec);
    1269    return ret;
    1270  }
    1271  
    1272  int execv () __attribute__ ((weak, alias ("__collector_execv")));
    1273  
    1274  int
    1275  __collector_execv (const char* path, char *const argv[])
    1276  {
    1277    int ret;
    1278    extern char **environ; /* the process' actual environment */
    1279    char ** envp = environ;
    1280    TprintfT (DBG_LT0, "__collector_execv(path=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
    1281  	    path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
    1282  	    line_mode, get_combo_flag ());
    1283  
    1284    ret = __collector_execve (path, argv, envp);
    1285    return ret;
    1286  }
    1287  
    1288  int execle (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execle")));
    1289  
    1290  int
    1291  __collector_execle (const char* path, const char *arg0, ...)
    1292  {
    1293    TprintfT (DBG_LT0,
    1294  	    "__collector_execle(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
    1295  	    path ? path : "NULL", arg0 ? arg0 : "NULL",
    1296  	    line_mode, get_combo_flag ());
    1297  
    1298    char **argp;
    1299    va_list args;
    1300    char **argvec;
    1301    register char **environmentp;
    1302    int nargs = 0;
    1303    char *nextarg;
    1304  
    1305    va_start (args, arg0);
    1306    while (va_arg (args, char *) != (char *) 0)
    1307      nargs++;
    1308  
    1309    /*
    1310     * save the environment pointer, which is at the end of the
    1311     * variable argument list
    1312     */
    1313    environmentp = va_arg (args, char **);
    1314    va_end (args);
    1315  
    1316    /*
    1317     * load the arguments in the variable argument list
    1318     * into the argument vector, and add the terminating null pointer
    1319     */
    1320    va_start (args, arg0);
    1321    /* workaround for bugid 1242839 */
    1322    argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
    1323    argp = argvec;
    1324    *argp++ = (char *) arg0;
    1325    while ((nextarg = va_arg (args, char *)) != (char *) 0)
    1326      *argp++ = nextarg;
    1327    va_end (args);
    1328    *argp = (char *) 0;
    1329    return __collector_execve (path, argvec, environmentp);
    1330  }
    1331  
    1332  int execlp (const char* file, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execlp")));
    1333  
    1334  int
    1335  __collector_execlp (const char* file, const char *arg0, ...)
    1336  {
    1337    TprintfT (DBG_LT0,
    1338  	    "__collector_execlp(file=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
    1339  	    file ? file : "NULL", arg0 ? arg0 : "NULL",
    1340  	    line_mode, get_combo_flag ());
    1341    char **argp;
    1342    va_list args;
    1343    char **argvec;
    1344    int nargs = 0;
    1345    char *nextarg;
    1346  
    1347    va_start (args, arg0);
    1348    while (va_arg (args, char *) != (char *) 0)
    1349      nargs++;
    1350    va_end (args);
    1351  
    1352    /*
    1353     * load the arguments in the variable argument list
    1354     * into the argument vector and add the terminating null pointer
    1355     */
    1356    va_start (args, arg0);
    1357  
    1358    /* workaround for bugid 1242839 */
    1359    argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
    1360    argp = argvec;
    1361    *argp++ = (char *) arg0;
    1362    while ((nextarg = va_arg (args, char *)) != (char *) 0)
    1363      *argp++ = nextarg;
    1364    va_end (args);
    1365    *argp = (char *) 0;
    1366    return __collector_execvp (file, argvec);
    1367  }
    1368  
    1369  int execl (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execl")));
    1370  
    1371  int
    1372  __collector_execl (const char* path, const char *arg0, ...)
    1373  {
    1374    TprintfT (DBG_LT0,
    1375  	    "__collector_execl(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
    1376  	    path ? path : "NULL", arg0 ? arg0 : "NULL",
    1377  	    line_mode, get_combo_flag ());
    1378    char **argp;
    1379    va_list args;
    1380    char **argvec;
    1381    extern char **environ;
    1382    int nargs = 0;
    1383    char *nextarg;
    1384    va_start (args, arg0);
    1385    while (va_arg (args, char *) != (char *) 0)
    1386      nargs++;
    1387    va_end (args);
    1388  
    1389    /*
    1390     * load the arguments in the variable argument list
    1391     * into the argument vector and add the terminating null pointer
    1392     */
    1393    va_start (args, arg0);
    1394  
    1395    /* workaround for bugid 1242839 */
    1396    argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
    1397    argp = argvec;
    1398    *argp++ = (char *) arg0;
    1399    while ((nextarg = va_arg (args, char *)) != (char *) 0)
    1400      *argp++ = nextarg;
    1401    va_end (args);
    1402    *argp = (char *) 0;
    1403    return __collector_execve (path, argvec, environ);
    1404  }
    1405  
    1406  #include <spawn.h>
    1407  
    1408  /*-------------------------------------------------------- posix_spawn */
    1409  // map interposed symbol versions
    1410  static int
    1411  gprofng_posix_spawn (int(real_posix_spawn) (),
    1412  		     pid_t *pidp, const char *path,
    1413  		     const posix_spawn_file_actions_t *file_actions,
    1414  		     const posix_spawnattr_t *attrp,
    1415  		     char *const argv[], char *const envp[])
    1416  {
    1417    int ret;
    1418    static char **coll_env = NULL; /* environment for collection */
    1419    if (real_posix_spawn == NULL)
    1420      {
    1421        TprintfT (DBG_LT0, "gprofng_posix_spawn (path=%s) interposin ERROR, posix_spawn() not found by dlsym\n",
    1422  		path ? path : "NULL");
    1423        return -1; /* probably should set errno */
    1424      }
    1425    int *guard = NULL;
    1426    int combo_flag = (line_mode == LM_TRACK_LINEAGE &&
    1427  		    CHCK_REENTRANCE (guard)) ? 1 : 0;
    1428    TprintfT (DBG_LT0, "gprofng_posix_spawn @%p (%s, argv[0]=%s, env[0]=%s)"
    1429  	    "line_mode=%d combo=%d\n", (real_posix_spawn), path ? path : "NULL",
    1430  	    (argv && argv[0]) ? argv[0] : "NULL",
    1431  	    (envp && envp[0]) ? envp[0] : "NULL", line_mode, combo_flag);
    1432    if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
    1433      __collector_env_unset ((char**) envp);
    1434  
    1435    if (line_mode != LM_TRACK_LINEAGE || combo_flag)
    1436      return (real_posix_spawn) (pidp, path, file_actions, attrp, argv, envp);
    1437    int following_exec = 0;
    1438    coll_env = linetrace_ext_exec_prologue ("posix_spawn", path, argv, envp,
    1439  					  &following_exec);
    1440    __collector_env_printall ("gprofng_posix_spawn", coll_env);
    1441    PUSH_REENTRANCE (guard);
    1442    ret = real_posix_spawn (pidp, path, file_actions, attrp, argv, coll_env);
    1443    POP_REENTRANCE (guard);
    1444    linetrace_ext_exec_epilogue ("posix_spawn", envp, ret, &following_exec);
    1445    return ret;
    1446  }
    1447  
    1448  #define DCL_POSIX_SPAWN(dcl_f) \
    1449  int dcl_f (pid_t *pidp, const char *path, \
    1450  	   const posix_spawn_file_actions_t *file_actions, \
    1451  	   const posix_spawnattr_t *attrp, \
    1452  	   char *const argv[], char *const envp[]) \
    1453    { \
    1454      if (__real_posix_spawn == NULL) \
    1455        init_lineage_intf (); \
    1456      return gprofng_posix_spawn (__real_posix_spawn, pidp, path, file_actions, \
    1457  				attrp, argv, envp); \
    1458    }
    1459  
    1460  
    1461  DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_17, posix_spawn@GLIBC_2.17)
    1462  DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_15, posix_spawn@GLIBC_2.15)
    1463  DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_2_5, posix_spawn@GLIBC_2.2.5)
    1464  DCL_FUNC_VER (DCL_POSIX_SPAWN, posix_spawn_2_2, posix_spawn@GLIBC_2.2)
    1465  DCL_POSIX_SPAWN (posix_spawn)
    1466  
    1467  /*-------------------------------------------------------- posix_spawnp */
    1468  static int
    1469  gprofng_posix_spawnp (int (real_posix_spawnp) (),
    1470                        pid_t *pidp, const char *path,
    1471                        const posix_spawn_file_actions_t *file_actions,
    1472                        const posix_spawnattr_t *attrp,
    1473                        char *const argv[], char *const envp[])
    1474  {
    1475    static char **coll_env = NULL; /* environment for collection */
    1476  
    1477    if (real_posix_spawnp == NULL)
    1478      {
    1479        TprintfT (DBG_LT0, "gprofng_posix_spawnp (path=%s) interposin ERROR\n",
    1480  		path ? path : "NULL");
    1481        return -1; /* probably should set errno */
    1482      }
    1483    int *guard = NULL;
    1484    int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
    1485    TprintfT (DBG_LT0, "gprofng_posix_spawnp @%p (path=%s, argv[0]=%s, env[0]=%s) line_mode=%d combo=%d\n",
    1486  	    real_posix_spawnp, path ? path : "NULL",
    1487  	    argv && argv[0] ? argv[0] : "NULL",
    1488  	    envp && envp[0] ? envp[0] : "NULL", line_mode, combo_flag);
    1489  
    1490    if (line_mode == LM_CLOSED) /* ensure collection environment is sanitized */
    1491      __collector_env_unset ((char**) envp);
    1492    if (line_mode != LM_TRACK_LINEAGE || combo_flag)
    1493      return (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, envp);
    1494    int following_exec = 0;
    1495    coll_env = linetrace_ext_exec_prologue ("posix_spawnp", path, argv, envp, &following_exec);
    1496    TprintfT (DBG_LT0, "__collector_posix_spawnp(): coll_env=0x%p\n", coll_env);
    1497    __collector_env_printall ("__collector_posix_spawnp", coll_env);
    1498    PUSH_REENTRANCE (guard);
    1499    int ret = real_posix_spawnp (pidp, path, file_actions, attrp, argv, coll_env);
    1500    POP_REENTRANCE (guard);
    1501    linetrace_ext_exec_epilogue ("posix_spawnp", envp, ret, &following_exec);
    1502    return ret;
    1503  }
    1504  
    1505  #define DCL_POSIX_SPAWNP(dcl_f) \
    1506  int dcl_f (pid_t *pidp, const char *path, \
    1507  	   const posix_spawn_file_actions_t *file_actions, \
    1508  	   const posix_spawnattr_t *attrp, \
    1509  	   char *const argv[], char *const envp[]) \
    1510    { \
    1511      if (__real_posix_spawnp == NULL) \
    1512        init_lineage_intf (); \
    1513      return gprofng_posix_spawnp (__real_posix_spawnp, pidp, path, \
    1514  				 file_actions, attrp, argv, envp); \
    1515    }
    1516  
    1517  DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_17, posix_spawnp@GLIBC_2.17)
    1518  DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_15, posix_spawnp@GLIBC_2.15)
    1519  DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_2_5, posix_spawnp@GLIBC_2.2.5)
    1520  DCL_FUNC_VER (DCL_POSIX_SPAWNP, posix_spawnp_2_2, posix_spawnp@GLIBC_2.2)
    1521  DCL_POSIX_SPAWNP (posix_spawnp)
    1522  
    1523  /*------------------------------------------------------------- system */
    1524  int system () __attribute__ ((weak, alias ("__collector_system")));
    1525  
    1526  int
    1527  __collector_system (const char *cmd)
    1528  {
    1529    if (NULL_PTR (system))
    1530      init_lineage_intf ();
    1531    TprintfT (DBG_LT0,
    1532  	    "__collector_system(cmd=%s) interposing: line_mode=%d combo=%d\n",
    1533  	    cmd ? cmd : "NULL", line_mode, get_combo_flag ());
    1534    int *guard = NULL;
    1535    if (line_mode == LM_TRACK_LINEAGE)
    1536      INIT_REENTRANCE (guard);
    1537    if (guard == NULL)
    1538      return CALL_REAL (system)(cmd);
    1539    int following_combo = 0;
    1540    linetrace_ext_combo_prologue ("system", cmd, &following_combo);
    1541    PUSH_REENTRANCE (guard);
    1542    int ret = CALL_REAL (system)(cmd);
    1543    POP_REENTRANCE (guard);
    1544    linetrace_ext_combo_epilogue ("system", ret, &following_combo);
    1545    return ret;
    1546  }
    1547  
    1548  /*------------------------------------------------------------- popen */
    1549  // map interposed symbol versions
    1550  #define DCL_POPEN(dcl_f) \
    1551    FILE *dcl_f (const char *cmd, const char *mode) \
    1552    { \
    1553      if (__real_popen == NULL) \
    1554        init_lineage_intf (); \
    1555      TprintfT (DBG_LT0, #dcl_f " (%s) interposing: line_mode=%d combo=%d\n", \
    1556  	      cmd ? cmd : "NULL", line_mode, get_combo_flag ()); \
    1557      int *guard = NULL; \
    1558      if (line_mode == LM_TRACK_LINEAGE) \
    1559        INIT_REENTRANCE (guard); \
    1560      if (guard == NULL) \
    1561        return __real_popen (cmd, mode); \
    1562      int following_combo = 0; \
    1563      linetrace_ext_combo_prologue ("popen", cmd, &following_combo); \
    1564      PUSH_REENTRANCE (guard); \
    1565      FILE *ret = __real_popen (cmd, mode); \
    1566      POP_REENTRANCE (guard); \
    1567      linetrace_ext_combo_epilogue ("popen", ret == NULL ? -1 : 0, \
    1568  				  &following_combo); \
    1569      return ret; \
    1570    }
    1571  
    1572  DCL_FUNC_VER (DCL_POPEN, popen_2_17, popen@GLIBC_2.17)
    1573  DCL_FUNC_VER (DCL_POPEN, popen_2_2_5, popen@GLIBC_2.2.5)
    1574  DCL_FUNC_VER (DCL_POPEN, popen_2_1, popen@GLIBC_2.1)
    1575  DCL_FUNC_VER (DCL_POPEN, popen_2_0, popen@GLIBC_2.0)
    1576  DCL_POPEN (popen)
    1577  
    1578  /*------------------------------------------------------------- grantpt */
    1579  int grantpt () __attribute__ ((weak, alias ("__collector_grantpt")));
    1580  
    1581  int
    1582  __collector_grantpt (const int fildes)
    1583  {
    1584    if (NULL_PTR (grantpt))
    1585      init_lineage_intf ();
    1586    TprintfT (DBG_LT0,
    1587  	    "__collector_grantpt(%d) interposing: line_mode=%d combo=%d\n",
    1588  	    fildes, line_mode, get_combo_flag ());
    1589    int *guard = NULL;
    1590    if (line_mode == LM_TRACK_LINEAGE)
    1591      INIT_REENTRANCE (guard);
    1592    if (guard == NULL)
    1593      return CALL_REAL (grantpt)(fildes);
    1594    int following_combo = 0;
    1595    linetrace_ext_combo_prologue ("grantpt", "/usr/lib/pt_chmod", &following_combo);
    1596    PUSH_REENTRANCE (guard);
    1597    int ret = CALL_REAL (grantpt)(fildes);
    1598    POP_REENTRANCE (guard);
    1599    linetrace_ext_combo_epilogue ("grantpt", ret, &following_combo);
    1600    return ret;
    1601  }
    1602  
    1603  /*------------------------------------------------------------- ptsname */
    1604  char *ptsname () __attribute__ ((weak, alias ("__collector_ptsname")));
    1605  
    1606  char *
    1607  __collector_ptsname (const int fildes)
    1608  {
    1609    if (NULL_PTR (ptsname))
    1610      init_lineage_intf ();
    1611    TprintfT (DBG_LT0,
    1612  	    "__collector_ptsname(%d) interposing: line_mode=%d combo=%d\n",
    1613  	    fildes, line_mode, get_combo_flag ());
    1614    int *guard = NULL;
    1615    if (line_mode == LM_TRACK_LINEAGE)
    1616      INIT_REENTRANCE (guard);
    1617    if (guard == NULL)
    1618      return CALL_REAL (ptsname)(fildes);
    1619    int following_combo = 0;
    1620    linetrace_ext_combo_prologue ("ptsname", "/usr/lib/pt_chmod", &following_combo);
    1621    PUSH_REENTRANCE (guard);
    1622    char *ret = CALL_REAL (ptsname)(fildes);
    1623    POP_REENTRANCE (guard);
    1624    linetrace_ext_combo_epilogue ("ptsname", (ret == NULL) ? (-1) : 1, &following_combo);
    1625    return ret;
    1626  }
    1627  
    1628  /*------------------------------------------------------------- clone */
    1629  /* clone can be fork-like or pthread_create-like, depending on whether
    1630   * the flag CLONE_VM is set. If CLONE_VM is not set, then we interpose
    1631   * clone in the way similar to interposing fork; if CLONE_VM is set,
    1632   * then we interpose clone in the way similar to interposing pthread_create.
    1633   * One special case is not handled: when CLONE_VM is set but CLONE_THREAD
    1634   * is not, if the parent process exits earlier than the child process,
    1635   * experiment will close, losing data from child process.
    1636   */
    1637  typedef struct __collector_clone_arg
    1638  {
    1639    int (*fn)(void *);
    1640    void * arg;
    1641    char * new_lineage;
    1642    int following_fork;
    1643  } __collector_clone_arg_t;
    1644  
    1645  static int
    1646  __collector_clone_fn (void *fn_arg)
    1647  {
    1648    int (*fn)(void *) = ((__collector_clone_arg_t*) fn_arg)->fn;
    1649    void * arg = ((__collector_clone_arg_t*) fn_arg)->arg;
    1650    char * new_lineage = ((__collector_clone_arg_t*) fn_arg)->new_lineage;
    1651    int following_fork = ((__collector_clone_arg_t*) fn_arg)->following_fork;
    1652    __collector_freeCSize (__collector_heap, fn_arg, sizeof (__collector_clone_arg_t));
    1653    linetrace_ext_fork_epilogue ("clone", 0, new_lineage, &following_fork);
    1654    return fn (arg);
    1655  }
    1656  
    1657  int clone (int (*fn)(void *), void *, int, void *, ...) __attribute__ ((weak, alias ("__collector_clone")));
    1658  
    1659  int
    1660  __collector_clone (int (*fn)(void *), void *child_stack, int flags, void *arg,
    1661  		   ... /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
    1662  {
    1663    int ret;
    1664    va_list va;
    1665    if (flags & CLONE_VM)
    1666      {
    1667        va_start (va, arg);
    1668        ret = __collector_ext_clone_pthread (fn, child_stack, flags, arg, va);
    1669        va_end (va);
    1670      }
    1671    else
    1672      {
    1673        if (NULL_PTR (clone))
    1674  	init_lineage_intf ();
    1675        int *guard = NULL;
    1676        int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
    1677        TprintfT (DBG_LT0, "__collector_clone() interposition: line_mode=%d combo=%d\n",
    1678  		line_mode, combo_flag);
    1679        char new_lineage[LT_MAXNAMELEN];
    1680        int following_fork = 0;
    1681        __collector_clone_arg_t *funcinfo = __collector_allocCSize (__collector_heap, sizeof (__collector_clone_arg_t), 1);
    1682        (*funcinfo).fn = fn;
    1683        (*funcinfo).arg = arg;
    1684        (*funcinfo).new_lineage = new_lineage;
    1685        (*funcinfo).following_fork = 0;
    1686        pid_t * ptid = NULL;
    1687        struct user_desc * tls = NULL;
    1688        pid_t * ctid = NULL;
    1689        int num_args = 0;
    1690        va_start (va, arg);
    1691        if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
    1692  	{
    1693  	  ptid = va_arg (va, pid_t *);
    1694  	  tls = va_arg (va, struct user_desc*);
    1695  	  ctid = va_arg (va, pid_t *);
    1696  	  num_args = 3;
    1697  	}
    1698        else if (flags & CLONE_SETTLS)
    1699  	{
    1700  	  ptid = va_arg (va, pid_t *);
    1701  	  tls = va_arg (va, struct user_desc*);
    1702  	  num_args = 2;
    1703  	}
    1704        else if (flags & CLONE_PARENT_SETTID)
    1705  	{
    1706  	  ptid = va_arg (va, pid_t *);
    1707  	  num_args = 1;
    1708  	}
    1709        if ((line_mode != LM_TRACK_LINEAGE) || combo_flag || funcinfo == NULL)
    1710  	{
    1711  	  switch (num_args)
    1712  	    {
    1713  	    case 3:
    1714  	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
    1715  	      break;
    1716  	    case 2:
    1717  	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
    1718  	      break;
    1719  	    case 1:
    1720  	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
    1721  	      break;
    1722  	    default:
    1723  	      ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
    1724  	      break;
    1725  	    }
    1726  
    1727  	  va_end (va);
    1728  	  return ret;
    1729  	}
    1730        linetrace_ext_fork_prologue ("clone", new_lineage, &following_fork);
    1731        (*funcinfo).following_fork = following_fork;
    1732        switch (num_args)
    1733  	{
    1734  	case 3:
    1735  	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls, ctid);
    1736  	  break;
    1737  	case 2:
    1738  	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls);
    1739  	  break;
    1740  	case 1:
    1741  	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid);
    1742  	  break;
    1743  	default:
    1744  	  ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo);
    1745  	  break;
    1746  	}
    1747        va_end (va);
    1748        if (ret < 0)
    1749  	__collector_freeCSize (__collector_heap, funcinfo, sizeof (__collector_clone_arg_t));
    1750        TprintfT (DBG_LT0, "__collector_clone() interposing: pid=%d\n", ret);
    1751        linetrace_ext_fork_epilogue ("clone", ret, new_lineage, &following_fork);
    1752      }
    1753    return ret;
    1754  }
    1755  
    1756  /*-------------------------------------------------------------------- setuid */
    1757  int setuid () __attribute__ ((weak, alias ("__collector_setuid")));
    1758  int _setuid () __attribute__ ((weak, alias ("__collector_setuid")));
    1759  
    1760  int
    1761  __collector_setuid (uid_t ruid)
    1762  {
    1763    if (NULL_PTR (setuid))
    1764      init_lineage_intf ();
    1765    TprintfT (DBG_LT0, "__collector_setuid(0x%x) interposing\n", ruid);
    1766    check_reuid_change (ruid, -1);
    1767    int ret = CALL_REAL (setuid)(ruid);
    1768    TprintfT (DBG_LT0, "__collector_setuid(0x%x) returning %d\n", ruid, ret);
    1769    return ret;
    1770  }
    1771  
    1772  /*------------------------------------------------------------------- seteuid */
    1773  int seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
    1774  int _seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
    1775  
    1776  int
    1777  __collector_seteuid (uid_t euid)
    1778  {
    1779    if (NULL_PTR (seteuid))
    1780      init_lineage_intf ();
    1781    TprintfT (DBG_LT0, "__collector_seteuid(0x%x) interposing\n", euid);
    1782    check_reuid_change (-1, euid);
    1783    int ret = CALL_REAL (seteuid)(euid);
    1784    TprintfT (DBG_LT0, "__collector_seteuid(0x%x) returning %d\n", euid, ret);
    1785    return ret;
    1786  }
    1787  
    1788  /*------------------------------------------------------------------ setreuid */
    1789  int setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
    1790  int _setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
    1791  
    1792  int
    1793  __collector_setreuid (uid_t ruid, uid_t euid)
    1794  {
    1795    if (NULL_PTR (setreuid))
    1796      init_lineage_intf ();
    1797    TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) interposing\n", ruid, euid);
    1798    check_reuid_change (ruid, euid);
    1799    int ret = CALL_REAL (setreuid)(ruid, euid);
    1800    TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) returning %d\n", ruid, euid, ret);
    1801    return ret;
    1802  }
    1803  
    1804  /*-------------------------------------------------------------------- setgid */
    1805  int setgid () __attribute__ ((weak, alias ("__collector_setgid")));
    1806  int _setgid () __attribute__ ((weak, alias ("__collector_setgid")));
    1807  
    1808  int
    1809  __collector_setgid (gid_t rgid)
    1810  {
    1811    if (NULL_PTR (setgid))
    1812      init_lineage_intf ();
    1813    TprintfT (DBG_LT0, "__collector_setgid(0x%x) interposing\n", rgid);
    1814    check_regid_change (rgid, -1);
    1815    int ret = CALL_REAL (setgid)(rgid);
    1816    TprintfT (DBG_LT0, "__collector_setgid(0x%x) returning %d\n", rgid, ret);
    1817    return ret;
    1818  }
    1819  
    1820  /*------------------------------------------------------------------- setegid */
    1821  int setegid () __attribute__ ((weak, alias ("__collector_setegid")));
    1822  int _setegid () __attribute__ ((weak, alias ("__collector_setegid")));
    1823  
    1824  int
    1825  __collector_setegid (gid_t egid)
    1826  {
    1827    if (NULL_PTR (setegid))
    1828      init_lineage_intf ();
    1829    TprintfT (DBG_LT0, "__collector_setegid(0x%x) interposing\n", egid);
    1830    check_regid_change (-1, egid);
    1831    int ret = CALL_REAL (setegid)(egid);
    1832    TprintfT (DBG_LT0, "__collector_setegid(0x%x) returning %d\n", egid, ret);
    1833    return ret;
    1834  }
    1835  
    1836  /*------------------------------------------------------------------ setregid */
    1837  int setregid () __attribute__ ((weak, alias ("__collector_setregid")));
    1838  int _setregid () __attribute__ ((weak, alias ("__collector_setregid")));
    1839  
    1840  int
    1841  __collector_setregid (gid_t rgid, gid_t egid)
    1842  {
    1843    if (NULL_PTR (setregid))
    1844      init_lineage_intf ();
    1845    TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) interposing\n", rgid, egid);
    1846    check_regid_change (rgid, egid);
    1847    int ret = CALL_REAL (setregid)(rgid, egid);
    1848    TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) returning %d\n", rgid, egid, ret);
    1849    return ret;
    1850  }
    1851  
    1852  /*------------------------------------------------------- selective following */
    1853  
    1854  static int
    1855  linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *progname)
    1856  {
    1857    regex_t regex_desc;
    1858    if (!follow_spec)
    1859      {
    1860        TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES NULL follow_spec\n");
    1861        return 1;
    1862      }
    1863    int ercode = regcomp (&regex_desc, follow_spec, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
    1864    if (ercode)
    1865      {
    1866        // syntax error in parsing string
    1867  #ifdef DEBUG
    1868        char errbuf[256];
    1869        regerror (ercode, &regex_desc, errbuf, sizeof (errbuf));
    1870        TprintfT (DBG_LT0, "linetrace_follow_experiment: regerror()=%s\n", errbuf);
    1871  #endif
    1872        return 1;
    1873      }
    1874    TprintfT (DBG_LT0, "linetrace_follow_experiment(): compiled spec='%s'\n", follow_spec);
    1875    if (lineage_str)
    1876      {
    1877        if (!regexec (&regex_desc, lineage_str, 0, NULL, 0))
    1878  	{
    1879  	  TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES lineage (follow_spec=%s,lineage=%s)\n",
    1880  		    follow_spec, lineage_str);
    1881  	  return 1;
    1882  	}
    1883      }
    1884    if (progname)
    1885      {
    1886        if (!regexec (&regex_desc, progname, 0, NULL, 0))
    1887  	{
    1888  	  TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES progname (follow_spec=%s,progname=%s)\n",
    1889  		    follow_spec, progname);
    1890  	  return 1;
    1891  	}
    1892      }
    1893    TprintfT (DBG_LT0, "linetrace_follow_experiment(): DOES NOT MATCH (follow_spec=%s,lineage=%s,progname=%s)\n",
    1894  	    follow_spec, lineage_str ? lineage_str : "NULL",
    1895  	    progname ? progname : "NULL");
    1896    return 0;
    1897  }