1/*
2 * Copyright © 2003 Felix Kuehling
3 * Copyright © 2018 Advanced Micro Devices, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
18 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 */
27
28#include "u_process.h"
29#include <string.h>
30#include <errno.h>
31#include <stdlib.h>
32
33#undef GET_PROGRAM_NAME
34
35#if defined(__linux__) && defined(HAVE_PROGRAM_INVOCATION_NAME)
36
37static char *path = NULL;
38
39static void __freeProgramPath()
40{
41   free(path);
42   path = NULL;
43}
44
45static const char *
46__getProgramName()
47{
48   char * arg = strrchr(program_invocation_name, '/');
49   if (arg) {
50      /* If the / character was found this is likely a linux path or
51       * an invocation path for a 64-bit wine program.
52       *
53       * However, some programs pass command line arguments into argv[0].
54       * Strip these arguments out by using the realpath only if it was
55       * a prefix of the invocation name.
56       */
57      if (!path) {
58         path = realpath("/proc/self/exe", NULL);
59         atexit(__freeProgramPath);
60      }
61
62      if (path && strncmp(path, program_invocation_name, strlen(path)) == 0) {
63         /* This shouldn't be null because path is a a prefix,
64          * but check it anyway since path is static. */
65         char * name = strrchr(path, '/');
66         if (name)
67            return name + 1;
68      }
69
70      return arg+1;
71   }
72
73   /* If there was no '/' at all we likely have a windows like path from
74    * a wine application.
75    */
76   arg = strrchr(program_invocation_name, '\\');
77   if (arg)
78      return arg+1;
79
80   return program_invocation_name;
81}
82#    define GET_PROGRAM_NAME() __getProgramName()
83#elif defined(HAVE_PROGRAM_INVOCATION_NAME)
84#    define GET_PROGRAM_NAME() program_invocation_short_name
85#elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)
86#    include <osreldate.h>
87#    if (__FreeBSD_version >= 440000)
88#        define GET_PROGRAM_NAME() getprogname()
89#    endif
90#elif defined(__NetBSD__) && defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000100)
91#    define GET_PROGRAM_NAME() getprogname()
92#elif defined(__DragonFly__)
93#    define GET_PROGRAM_NAME() getprogname()
94#elif defined(__APPLE__)
95#    define GET_PROGRAM_NAME() getprogname()
96#elif defined(ANDROID)
97#    define GET_PROGRAM_NAME() getprogname()
98#elif defined(__sun)
99/* Solaris has getexecname() which returns the full path - return just
100   the basename to match BSD getprogname() */
101#    include <libgen.h>
102
103static const char *
104__getProgramName()
105{
106    static const char *progname;
107
108    if (progname == NULL) {
109        const char *e = getexecname();
110        if (e != NULL) {
111            /* Have to make a copy since getexecname can return a readonly
112               string, but basename expects to be able to modify its arg. */
113            char *n = strdup(e);
114            if (n != NULL) {
115                progname = basename(n);
116            }
117        }
118    }
119    return progname;
120}
121
122#    define GET_PROGRAM_NAME() __getProgramName()
123#endif
124
125#if !defined(GET_PROGRAM_NAME)
126#    if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__UCLIBC__) || defined(ANDROID)
127/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU.
128 * Rogelio M.Serrano Jr. reported it's also working with UCLIBC. It's
129 * used as a last resort, if there is no documented facility available. */
130static const char *
131__getProgramName()
132{
133    extern const char *__progname;
134    char * arg = strrchr(__progname, '/');
135    if (arg)
136        return arg+1;
137    else
138        return __progname;
139}
140#        define GET_PROGRAM_NAME() __getProgramName()
141#    else
142#        define GET_PROGRAM_NAME() ""
143#        pragma message ( "Warning: Per application configuration won't work with your OS version." )
144#    endif
145#endif
146
147const char *
148util_get_process_name(void)
149{
150   return GET_PROGRAM_NAME();
151}
152