getprogname.c 9.9 KB

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