getprogname.c 9.1 KB

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