]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/pidref.c
pidref: add structure that can reference a pid via both pidfd and pid_t
[thirdparty/systemd.git] / src / basic / pidref.c
CommitLineData
3bda3f17
LP
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "errno-util.h"
4#include "fd-util.h"
5#include "missing_syscall.h"
6#include "parse-util.h"
7#include "pidref.h"
8#include "process-util.h"
9
10int pidref_set_pid(PidRef *pidref, pid_t pid) {
11 int fd;
12
13 assert(pidref);
14
15 if (pid < 0)
16 return -ESRCH;
17 if (pid == 0)
18 pid = getpid_cached();
19
20 fd = pidfd_open(pid, 0);
21 if (fd < 0) {
22 /* Graceful fallback in case the kernel doesn't support pidfds or is out of fds */
23 if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno) && !ERRNO_IS_RESOURCE(errno))
24 return -errno;
25
26 fd = -EBADF;
27 }
28
29 *pidref = (PidRef) {
30 .fd = fd,
31 .pid = pid,
32 };
33
34 return 0;
35}
36
37int pidref_set_pidstr(PidRef *pidref, const char *pid) {
38 pid_t nr;
39 int r;
40
41 assert(pidref);
42
43 r = parse_pid(pid, &nr);
44 if (r < 0)
45 return r;
46
47 return pidref_set_pid(pidref, nr);
48}
49
50int pidref_set_pidfd(PidRef *pidref, int fd) {
51 int r;
52
53 assert(pidref);
54
55 if (fd < 0)
56 return -EBADF;
57
58 int fd_copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
59 if (fd_copy < 0) {
60 pid_t pid;
61
62 if (!ERRNO_IS_RESOURCE(errno))
63 return -errno;
64
65 /* Graceful fallback if we are out of fds */
66 r = pidfd_get_pid(fd, &pid);
67 if (r < 0)
68 return r;
69
70 *pidref = (PidRef) {
71 .fd = -EBADF,
72 .pid = pid,
73 };
74
75 return 0;
76 }
77
78 return pidref_set_pidfd_consume(pidref, fd_copy);
79}
80
81int pidref_set_pidfd_take(PidRef *pidref, int fd) {
82 pid_t pid;
83 int r;
84
85 assert(pidref);
86
87 if (fd < 0)
88 return -EBADF;
89
90 r = pidfd_get_pid(fd, &pid);
91 if (r < 0)
92 return r;
93
94 *pidref = (PidRef) {
95 .fd = fd,
96 .pid = pid,
97 };
98
99 return 0;
100}
101
102int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
103 int r;
104
105 r = pidref_set_pidfd_take(pidref, fd);
106 if (r < 0)
107 safe_close(fd);
108
109 return r;
110}
111
112void pidref_done(PidRef *pidref) {
113 assert(pidref);
114
115 *pidref = (PidRef) {
116 .fd = safe_close(pidref->fd),
117 };
118}
119
120int pidref_kill(PidRef *pidref, int sig) {
121
122 if (!pidref)
123 return -ESRCH;
124
125 if (pidref->fd >= 0)
126 return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
127
128 if (pidref->pid > 0)
129 return RET_NERRNO(kill(pidref->pid, sig));
130
131 return -ESRCH;
132}
133
134int pidref_kill_and_sigcont(PidRef *pidref, int sig) {
135 int r;
136
137 r = pidref_kill(pidref, sig);
138 if (r < 0)
139 return r;
140
141 if (!IN_SET(sig, SIGCONT, SIGKILL))
142 (void) pidref_kill(pidref, SIGCONT);
143
144 return 0;
145}