getprogname.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /* Program name management.
  2. Copyright (C) 2016-2022 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. */
  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. # error #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. #if defined __sgi || defined __osf__
  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 || defined __osf__ /* IRIX or Tru64 */
  215. char filename[50];
  216. int fd;
  217. # if defined __sgi
  218. sprintf (filename, "/proc/pinfo/%d", (int) getpid ());
  219. # else
  220. sprintf (filename, "/proc/%d", (int) getpid ());
  221. # endif
  222. fd = open (filename, O_RDONLY | O_CLOEXEC);
  223. if (0 <= fd)
  224. {
  225. prpsinfo_t buf;
  226. int ioctl_ok = 0 <= ioctl (fd, PIOCPSINFO, &buf);
  227. close (fd);
  228. if (ioctl_ok)
  229. {
  230. char *name = buf.pr_fname;
  231. size_t namesize = sizeof buf.pr_fname;
  232. /* It may not be NUL-terminated. */
  233. char *namenul = memchr (name, '\0', namesize);
  234. size_t namelen = namenul ? namenul - name : namesize;
  235. char *namecopy = malloc (namelen + 1);
  236. if (namecopy)
  237. {
  238. namecopy[namelen] = '\0';
  239. return memcpy (namecopy, name, namelen);
  240. }
  241. }
  242. }
  243. return NULL;
  244. # elif defined __SCO_VERSION__ || defined __sysv5__ /* SCO OpenServer6/UnixWare */
  245. char buf[80];
  246. int fd;
  247. sprintf (buf, "/proc/%d/cmdline", getpid());
  248. fd = open (buf, O_RDONLY);
  249. if (0 <= fd)
  250. {
  251. size_t n = read (fd, buf, 79);
  252. if (n > 0)
  253. {
  254. buf[n] = '\0'; /* Guarantee null-termination */
  255. char *progname;
  256. progname = strrchr (buf, '/');
  257. if (progname)
  258. {
  259. progname = progname + 1; /* Skip the '/' */
  260. }
  261. else
  262. {
  263. progname = buf;
  264. }
  265. char *ret;
  266. ret = malloc (strlen (progname) + 1);
  267. if (ret)
  268. {
  269. strcpy (ret, progname);
  270. return ret;
  271. }
  272. }
  273. close (fd);
  274. }
  275. return "?";
  276. # else
  277. # error "getprogname module not ported to this OS"
  278. # endif
  279. }
  280. #endif
  281. /*
  282. * Hey Emacs!
  283. * Local Variables:
  284. * coding: utf-8
  285. * End:
  286. */