Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * execname.c - executable name handling functions
4 : : *
5 : : * Copyright © 2024 Guillem Jover <guillem@debian.org>
6 : : *
7 : : * This is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2 of the License, or
10 : : * (at your option) any later version.
11 : : *
12 : : * This is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include <config.h>
22 : : #include <compat.h>
23 : :
24 : : #ifdef HAVE_SYS_PARAM_H
25 : : #include <sys/param.h>
26 : : #endif
27 : : #ifdef HAVE_SYS_SYSCTL_H
28 : : #include <sys/sysctl.h>
29 : : #endif
30 : : #if defined(_AIX) && defined(HAVE_SYS_PROCFS_H)
31 : : #include <sys/procfs.h>
32 : : #endif
33 : :
34 : : #include <limits.h>
35 : : #include <errno.h>
36 : : #include <stdlib.h>
37 : : #include <stdio.h>
38 : : #include <unistd.h>
39 : :
40 : : #if defined(__APPLE__) && defined(__MACH__)
41 : : #include <libproc.h>
42 : : #endif
43 : :
44 : : #include <dpkg/dpkg.h>
45 : : #include <dpkg/file.h>
46 : : #include <dpkg/execname.h>
47 : :
48 : : #if defined(_AIX) && defined(HAVE_STRUCT_PSINFO)
49 : : static bool
50 : : proc_get_psinfo(pid_t pid, struct psinfo *psinfo)
51 : : {
52 : : char filename[64];
53 : : FILE *fp;
54 : :
55 : : sprintf(filename, "/proc/%d/psinfo", pid);
56 : : fp = fopen(filename, "r");
57 : : if (!fp)
58 : : return false;
59 : : if (fread(psinfo, sizeof(*psinfo), 1, fp) == 0) {
60 : : fclose(fp);
61 : : return false;
62 : : }
63 : : if (ferror(fp)) {
64 : : fclose(fp);
65 : : return false;
66 : : }
67 : :
68 : : fclose(fp);
69 : :
70 : : return true;
71 : : }
72 : : #endif
73 : :
74 : : /**
75 : : * Get the executable name for a PID.
76 : : *
77 : : * Tries to obtain the executable name or process name for a specific PID,
78 : : * if the executable name cannot be obtained then it will return NULL.
79 : : *
80 : : * @return A pointer to an allocated string with the executable name, or NULL.
81 : : */
82 : : char *
83 : 0 : dpkg_get_pid_execname(pid_t pid)
84 : : {
85 : 0 : const char *execname = NULL;
86 : : #if defined(__linux__)
87 : : char lname[32];
88 : : char lcontents[_POSIX_PATH_MAX + 1];
89 : : int nread;
90 : :
91 : 0 : sprintf(lname, "/proc/%d/exe", pid);
92 : 0 : nread = readlink(lname, lcontents, sizeof(lcontents) - 1);
93 [ # # ]: 0 : if (nread == -1)
94 : 0 : return NULL;
95 : :
96 : 0 : lcontents[nread] = '\0';
97 : 0 : execname = lcontents;
98 : : #elif defined(__GNU__)
99 : : struct proc_stat *ps;
100 : :
101 : : ps = get_proc_stat(pid, PSTAT_ARGS);
102 : : if (ps == NULL)
103 : : return NULL;
104 : :
105 : : /* On old Hurd systems we have to use the argv[0] value, because
106 : : * there is nothing better. */
107 : : execname = proc_stat_args(ps);
108 : :
109 : : #ifdef PSTAT_EXE
110 : : /* On new Hurd systems we can use the correct value, as long
111 : : * as it's not NULL nor empty, as it was the case on the first
112 : : * implementation. */
113 : : if (proc_stat_set_flags(ps, PSTAT_EXE) == 0 &&
114 : : proc_stat_flags(ps) & PSTAT_EXE &&
115 : : proc_stat_exe(ps) != NULL &&
116 : : proc_stat_exe(ps)[0] != '\0')
117 : : execname = proc_stat_exe(ps);
118 : : #endif
119 : : #elif defined(__sun)
120 : : char filename[64];
121 : : struct varbuf vb = VARBUF_INIT;
122 : :
123 : : sprintf(filename, "/proc/%d/execname", pid);
124 : : if (file_slurp(filename, &vb, NULL) < 0)
125 : : return NULL;
126 : :
127 : : return varbuf_detach(&vb);
128 : : #elif defined(__APPLE__) && defined(__MACH__)
129 : : char pathname[_POSIX_PATH_MAX];
130 : :
131 : : if (proc_pidpath(pid, pathname, sizeof(pathname)) < 0)
132 : : return NULL;
133 : :
134 : : execname = pathname;
135 : : #elif defined(_AIX) && defined(HAVE_STRUCT_PSINFO)
136 : : char filename[64];
137 : : struct psinfo psi;
138 : :
139 : : sprintf(filename, "/proc/%d/psinfo", pid);
140 : : if (!proc_get_psinfo(pid, &psi))
141 : : return NULL;
142 : :
143 : : execname = psi.pr_fname;
144 : : #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
145 : : int error, mib[4];
146 : : size_t len;
147 : : char pathname[PATH_MAX];
148 : :
149 : : mib[0] = CTL_KERN;
150 : : mib[1] = KERN_PROC;
151 : : mib[2] = KERN_PROC_PATHNAME;
152 : : mib[3] = pid;
153 : : len = sizeof(pathname);
154 : :
155 : : error = sysctl(mib, 4, pathname, &len, NULL, 0);
156 : : if (error != 0 && errno != ESRCH)
157 : : return NULL;
158 : : if (len == 0)
159 : : pathname[0] = '\0';
160 : : execname = pathname;
161 : : #else
162 : : return execname;
163 : : #endif
164 : :
165 : 0 : return m_strdup(execname);
166 : : }
|