po: Update German man pages translation
[dpkg.git] / lib / dpkg / execname.c
blob44044aac5b1fb52da9e8ce3238e9a926e5d46274
1 /*
2 * libdpkg - Debian packaging suite library routines
3 * execname.c - executable name handling functions
5 * Copyright © 2024 Guillem Jover <guillem@debian.org>
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.
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.
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/>.
21 #include <config.h>
22 #include <compat.h>
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
34 #include <limits.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <unistd.h>
40 #if defined(__GNU__)
41 #include <hurd.h>
42 #include <ps.h>
43 #endif
45 #if defined(__APPLE__) && defined(__MACH__)
46 #include <libproc.h>
47 #endif
49 #include <dpkg/dpkg.h>
50 #if defined(__sun)
51 #include <dpkg/file.h>
52 #endif
53 #include <dpkg/execname.h>
55 #if defined(_AIX) && defined(HAVE_STRUCT_PSINFO)
56 static bool
57 proc_get_psinfo(pid_t pid, struct psinfo *psinfo)
59 char filename[64];
60 FILE *fp;
62 sprintf(filename, "/proc/%d/psinfo", pid);
63 fp = fopen(filename, "r");
64 if (!fp)
65 return false;
66 if (fread(psinfo, sizeof(*psinfo), 1, fp) == 0) {
67 fclose(fp);
68 return false;
70 if (ferror(fp)) {
71 fclose(fp);
72 return false;
75 fclose(fp);
77 return true;
79 #endif
81 /**
82 * Get the executable name for a PID.
84 * Tries to obtain the executable name or process name for a specific PID,
85 * if the executable name cannot be obtained then it will return NULL.
87 * @return A pointer to an allocated string with the executable name, or NULL.
89 char *
90 dpkg_get_pid_execname(pid_t pid)
92 char *execname = NULL;
93 #if defined(__linux__)
94 char lname[32];
95 char lcontents[_POSIX_PATH_MAX + 1];
96 int nread;
98 sprintf(lname, "/proc/%d/exe", pid);
99 nread = readlink(lname, lcontents, sizeof(lcontents) - 1);
100 if (nread == -1)
101 return NULL;
103 lcontents[nread] = '\0';
104 execname = lcontents;
105 #elif defined(__GNU__)
106 struct ps_context *pc;
107 struct proc_stat *ps;
108 error_t err;
110 if (pid < 0)
111 return NULL;
113 err = ps_context_create(getproc(), &pc);
114 if (err)
115 return NULL;
117 err = ps_context_find_proc_stat(pc, pid, &ps);
118 if (err)
119 return NULL;
121 /* On old Hurd systems we have to use the argv[0] value, because
122 * there is nothing better. */
123 if (proc_stat_set_flags(ps, PSTAT_ARGS) == 0 &&
124 (proc_stat_flags(ps) & PSTAT_ARGS))
125 execname = proc_stat_args(ps);
127 #ifdef PSTAT_EXE
128 /* On new Hurd systems we can use the correct value, as long
129 * as it's not NULL nor empty, as it was the case on the first
130 * implementation. */
131 if (proc_stat_set_flags(ps, PSTAT_EXE) == 0 &&
132 proc_stat_flags(ps) & PSTAT_EXE &&
133 proc_stat_exe(ps) != NULL &&
134 proc_stat_exe(ps)[0] != '\0')
135 execname = proc_stat_exe(ps);
136 #endif
138 ps_context_free(pc);
139 #elif defined(__sun)
140 char filename[64];
141 struct varbuf vb = VARBUF_INIT;
143 sprintf(filename, "/proc/%d/execname", pid);
144 if (file_slurp(filename, &vb, NULL) < 0)
145 return NULL;
147 return varbuf_detach(&vb);
148 #elif defined(__APPLE__) && defined(__MACH__)
149 char pathname[_POSIX_PATH_MAX];
151 if (proc_pidpath(pid, pathname, sizeof(pathname)) < 0)
152 return NULL;
154 execname = pathname;
155 #elif defined(_AIX) && defined(HAVE_STRUCT_PSINFO)
156 char filename[64];
157 struct psinfo psi;
159 sprintf(filename, "/proc/%d/psinfo", pid);
160 if (!proc_get_psinfo(pid, &psi))
161 return NULL;
163 execname = psi.pr_fname;
164 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
165 int error, mib[4];
166 size_t len;
167 char pathname[PATH_MAX];
169 mib[0] = CTL_KERN;
170 mib[1] = KERN_PROC;
171 mib[2] = KERN_PROC_PATHNAME;
172 mib[3] = pid;
173 len = sizeof(pathname);
175 error = sysctl(mib, 4, pathname, &len, NULL, 0);
176 if (error != 0 && errno != ESRCH)
177 return NULL;
178 if (len == 0)
179 pathname[0] = '\0';
180 execname = pathname;
181 #else
182 return execname;
183 #endif
185 return m_strdup(execname);