Home | History | Annotate | Line # | Download | only in import
      1 /* Program name management.
      2    Copyright (C) 2016-2022 Free Software Foundation, Inc.
      3 
      4    This program is free software: you can redistribute it and/or modify
      5    it under the terms of the GNU Lesser General Public License as published by
      6    the Free Software Foundation; either version 2.1 of the License, or
      7    (at your option) any later version.
      8 
      9    This program is distributed in the hope that it will be useful,
     10    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12    GNU Lesser General Public License for more details.
     13 
     14    You should have received a copy of the GNU Lesser General Public License
     15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
     16 
     17 #include <config.h>
     18 
     19 /* Specification.  */
     20 #include "getprogname.h"
     21 
     22 #include <errno.h> /* get program_invocation_name declaration */
     23 #include <stdlib.h> /* get __argv declaration */
     24 
     25 #ifdef _AIX
     26 # include <unistd.h>
     27 # include <procinfo.h>
     28 # include <string.h>
     29 #endif
     30 
     31 #ifdef __MVS__
     32 # ifndef _OPEN_SYS
     33 #  define _OPEN_SYS
     34 # endif
     35 # include <string.h>
     36 # include <sys/ps.h>
     37 #endif
     38 
     39 #ifdef __hpux
     40 # include <unistd.h>
     41 # include <sys/param.h>
     42 # include <sys/pstat.h>
     43 # include <string.h>
     44 #endif
     45 
     46 #if defined __sgi || defined __osf__
     47 # include <string.h>
     48 # include <unistd.h>
     49 # include <stdio.h>
     50 # include <fcntl.h>
     51 # include <sys/procfs.h>
     52 #endif
     53 
     54 #if defined __SCO_VERSION__ || defined __sysv5__
     55 # include <fcntl.h>
     56 # include <stdlib.h>
     57 # include <string.h>
     58 #endif
     59 
     60 #include "basename-lgpl.h"
     61 
     62 #ifndef HAVE_GETPROGNAME             /* not Mac OS X, FreeBSD, NetBSD, OpenBSD >= 5.4, Cygwin */
     63 char const *
     64 getprogname (void)
     65 {
     66 # if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME                /* glibc, BeOS */
     67   /* https://www.gnu.org/software/libc/manual/html_node/Error-Messages.html */
     68   return program_invocation_short_name;
     69 # elif HAVE_DECL_PROGRAM_INVOCATION_NAME                    /* glibc, BeOS */
     70   /* https://www.gnu.org/software/libc/manual/html_node/Error-Messages.html */
     71   return last_component (program_invocation_name);
     72 # elif HAVE_GETEXECNAME                                     /* Solaris */
     73   /* https://docs.oracle.com/cd/E19253-01/816-5168/6mbb3hrb1/index.html */
     74   const char *p = getexecname ();
     75   if (!p)
     76     p = "?";
     77   return last_component (p);
     78 # elif HAVE_DECL___ARGV                                     /* mingw, MSVC */
     79   /* https://docs.microsoft.com/en-us/cpp/c-runtime-library/argc-argv-wargv */
     80   const char *p = __argv && __argv[0] ? __argv[0] : "?";
     81   return last_component (p);
     82 # elif HAVE_VAR___PROGNAME                                  /* OpenBSD, Android, QNX */
     83   /* https://man.openbsd.org/style.9 */
     84   /* http://www.qnx.de/developers/docs/6.5.0/index.jsp?topic=%2Fcom.qnx.doc.neutrino_lib_ref%2Fp%2F__progname.html */
     85   /* Be careful to declare this only when we absolutely need it
     86      (OpenBSD 5.1), rather than when it's available.  Otherwise,
     87      its mere declaration makes program_invocation_short_name
     88      malfunction (have zero length) with Fedora 25's glibc.  */
     89   extern char *__progname;
     90   const char *p = __progname;
     91 #  if defined __ANDROID__
     92   return last_component (p);
     93 #  else
     94   return p && p[0] ? p : "?";
     95 #  endif
     96 # elif _AIX                                                 /* AIX */
     97   /* Idea by Bastien ROUCARIS,
     98      https://lists.gnu.org/r/bug-gnulib/2010-12/msg00095.html
     99      Reference: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/getprocs.htm
    100   */
    101   static char *p;
    102   static int first = 1;
    103   if (first)
    104     {
    105       first = 0;
    106       pid_t pid = getpid ();
    107       struct procentry64 procs;
    108       p = (0 < getprocs64 (&procs, sizeof procs, NULL, 0, &pid, 1)
    109            ? strdup (procs.pi_comm)
    110            : NULL);
    111       if (!p)
    112         p = "?";
    113     }
    114   return p;
    115 # elif defined __hpux
    116   static char *p;
    117   static int first = 1;
    118   if (first)
    119     {
    120       first = 0;
    121       pid_t pid = getpid ();
    122       struct pst_status status;
    123       if (pstat_getproc (&status, sizeof status, 0, pid) > 0)
    124         {
    125           char *ucomm = status.pst_ucomm;
    126           char *cmd = status.pst_cmd;
    127           if (strlen (ucomm) < PST_UCOMMLEN - 1)
    128             p = ucomm;
    129           else
    130             {
    131               /* ucomm is truncated to length PST_UCOMMLEN - 1.
    132                  Look at cmd instead.  */
    133               char *space = strchr (cmd, ' ');
    134               if (space != NULL)
    135                 *space = '\0';
    136               p = strrchr (cmd, '/');
    137               if (p != NULL)
    138                 p++;
    139               else
    140                 p = cmd;
    141               if (strlen (p) > PST_UCOMMLEN - 1
    142                   && memcmp (p, ucomm, PST_UCOMMLEN - 1) == 0)
    143                 /* p is less truncated than ucomm.  */
    144                 ;
    145               else
    146                 p = ucomm;
    147             }
    148           p = strdup (p);
    149         }
    150       else
    151         {
    152 #  if !defined __LP64__
    153           /* Support for 32-bit programs running in 64-bit HP-UX.
    154              The documented way to do this is to use the same source code
    155              as above, but in a compilation unit where '#define _PSTAT64 1'
    156              is in effect.  I prefer a single compilation unit; the struct
    157              size and the offsets are not going to change.  */
    158           char status64[1216];
    159           if (__pstat_getproc64 (status64, sizeof status64, 0, pid) > 0)
    160             {
    161               char *ucomm = status64 + 288;
    162               char *cmd = status64 + 168;
    163               if (strlen (ucomm) < PST_UCOMMLEN - 1)
    164                 p = ucomm;
    165               else
    166                 {
    167                   /* ucomm is truncated to length PST_UCOMMLEN - 1.
    168                      Look at cmd instead.  */
    169                   char *space = strchr (cmd, ' ');
    170                   if (space != NULL)
    171                     *space = '\0';
    172                   p = strrchr (cmd, '/');
    173                   if (p != NULL)
    174                     p++;
    175                   else
    176                     p = cmd;
    177                   if (strlen (p) > PST_UCOMMLEN - 1
    178                       && memcmp (p, ucomm, PST_UCOMMLEN - 1) == 0)
    179                     /* p is less truncated than ucomm.  */
    180                     ;
    181                   else
    182                     p = ucomm;
    183                 }
    184               p = strdup (p);
    185             }
    186           else
    187 #  endif
    188             p = NULL;
    189         }
    190       if (!p)
    191         p = "?";
    192     }
    193   return p;
    194 # elif __MVS__                                              /* z/OS */
    195   /* https://www.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/rtwgetp.htm */
    196   static char *p = "?";
    197   static int first = 1;
    198   if (first)
    199     {
    200       pid_t pid = getpid ();
    201       int token;
    202       W_PSPROC buf;
    203       first = 0;
    204       memset (&buf, 0, sizeof(buf));
    205       buf.ps_cmdptr    = (char *) malloc (buf.ps_cmdlen    = PS_CMDBLEN_LONG);
    206       buf.ps_conttyptr = (char *) malloc (buf.ps_conttylen = PS_CONTTYBLEN);
    207       buf.ps_pathptr   = (char *) malloc (buf.ps_pathlen   = PS_PATHBLEN);
    208       if (buf.ps_cmdptr && buf.ps_conttyptr && buf.ps_pathptr)
    209         {
    210           for (token = 0; token >= 0;
    211                token = w_getpsent (token, &buf, sizeof(buf)))
    212             {
    213               if (token > 0 && buf.ps_pid == pid)
    214                 {
    215                   char *s = strdup (last_component (buf.ps_pathptr));
    216                   if (s)
    217                     p = s;
    218                   break;
    219                 }
    220             }
    221         }
    222       free (buf.ps_cmdptr);
    223       free (buf.ps_conttyptr);
    224       free (buf.ps_pathptr);
    225     }
    226   return p;
    227 # elif defined __sgi || defined __osf__                     /* IRIX or Tru64 */
    228   char filename[50];
    229   int fd;
    230 
    231   # if defined __sgi
    232     sprintf (filename, "/proc/pinfo/%d", (int) getpid ());
    233   # else
    234     sprintf (filename, "/proc/%d", (int) getpid ());
    235   # endif
    236   fd = open (filename, O_RDONLY | O_CLOEXEC);
    237   if (0 <= fd)
    238     {
    239       prpsinfo_t buf;
    240       int ioctl_ok = 0 <= ioctl (fd, PIOCPSINFO, &buf);
    241       close (fd);
    242       if (ioctl_ok)
    243         {
    244           char *name = buf.pr_fname;
    245           size_t namesize = sizeof buf.pr_fname;
    246           /* It may not be NUL-terminated.  */
    247           char *namenul = memchr (name, '\0', namesize);
    248           size_t namelen = namenul ? namenul - name : namesize;
    249           char *namecopy = malloc (namelen + 1);
    250           if (namecopy)
    251             {
    252               namecopy[namelen] = '\0';
    253               return memcpy (namecopy, name, namelen);
    254             }
    255         }
    256     }
    257   return NULL;
    258 # elif defined __SCO_VERSION__ || defined __sysv5__                /* SCO OpenServer6/UnixWare */
    259   char buf[80];
    260   int fd;
    261   sprintf (buf, "/proc/%d/cmdline", getpid());
    262   fd = open (buf, O_RDONLY);
    263   if (0 <= fd)
    264     {
    265       size_t n = read (fd, buf, 79);
    266       if (n > 0)
    267         {
    268           buf[n] = '\0'; /* Guarantee null-termination */
    269           char *progname;
    270           progname = strrchr (buf, '/');
    271           if (progname)
    272             {
    273               progname = progname + 1; /* Skip the '/' */
    274             }
    275           else
    276             {
    277               progname = buf;
    278             }
    279           char *ret;
    280           ret = malloc (strlen (progname) + 1);
    281           if (ret)
    282             {
    283               strcpy (ret, progname);
    284               return ret;
    285             }
    286         }
    287       close (fd);
    288     }
    289   return "?";
    290 # else
    291 #  error "getprogname module not ported to this OS"
    292 # endif
    293 }
    294 
    295 #endif
    296 
    297 /*
    298  * Hey Emacs!
    299  * Local Variables:
    300  * coding: utf-8
    301  * End:
    302  */
    303