]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-daemon/sd-daemon.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/socket.h>
25 #include <netinet/in.h>
37 #include "path-util.h"
38 #include "socket-util.h"
39 #include "sd-daemon.h"
41 _public_
int sd_listen_fds(int unset_environment
) {
47 e
= getenv("LISTEN_PID");
53 r
= parse_pid(e
, &pid
);
58 if (getpid() != pid
) {
63 e
= getenv("LISTEN_FDS");
73 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ (int) n
; fd
++) {
74 r
= fd_cloexec(fd
, true);
82 if (unset_environment
) {
83 unsetenv("LISTEN_PID");
84 unsetenv("LISTEN_FDS");
90 _public_
int sd_is_fifo(int fd
, const char *path
) {
93 assert_return(fd
>= 0, -EBADF
);
95 if (fstat(fd
, &st_fd
) < 0)
98 if (!S_ISFIFO(st_fd
.st_mode
))
104 if (stat(path
, &st_path
) < 0) {
106 if (errno
== ENOENT
|| errno
== ENOTDIR
)
113 st_path
.st_dev
== st_fd
.st_dev
&&
114 st_path
.st_ino
== st_fd
.st_ino
;
120 _public_
int sd_is_special(int fd
, const char *path
) {
123 assert_return(fd
>= 0, -EBADF
);
125 if (fstat(fd
, &st_fd
) < 0)
128 if (!S_ISREG(st_fd
.st_mode
) && !S_ISCHR(st_fd
.st_mode
))
134 if (stat(path
, &st_path
) < 0) {
136 if (errno
== ENOENT
|| errno
== ENOTDIR
)
142 if (S_ISREG(st_fd
.st_mode
) && S_ISREG(st_path
.st_mode
))
144 st_path
.st_dev
== st_fd
.st_dev
&&
145 st_path
.st_ino
== st_fd
.st_ino
;
146 else if (S_ISCHR(st_fd
.st_mode
) && S_ISCHR(st_path
.st_mode
))
147 return st_path
.st_rdev
== st_fd
.st_rdev
;
155 static int sd_is_socket_internal(int fd
, int type
, int listening
) {
158 assert_return(fd
>= 0, -EBADF
);
159 assert_return(type
>= 0, -EINVAL
);
161 if (fstat(fd
, &st_fd
) < 0)
164 if (!S_ISSOCK(st_fd
.st_mode
))
169 socklen_t l
= sizeof(other_type
);
171 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &other_type
, &l
) < 0)
174 if (l
!= sizeof(other_type
))
177 if (other_type
!= type
)
181 if (listening
>= 0) {
183 socklen_t l
= sizeof(accepting
);
185 if (getsockopt(fd
, SOL_SOCKET
, SO_ACCEPTCONN
, &accepting
, &l
) < 0)
188 if (l
!= sizeof(accepting
))
191 if (!accepting
!= !listening
)
198 _public_
int sd_is_socket(int fd
, int family
, int type
, int listening
) {
201 assert_return(fd
>= 0, -EBADF
);
202 assert_return(family
>= 0, -EINVAL
);
204 r
= sd_is_socket_internal(fd
, type
, listening
);
209 union sockaddr_union sockaddr
= {};
210 socklen_t l
= sizeof(sockaddr
);
212 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
215 if (l
< sizeof(sa_family_t
))
218 return sockaddr
.sa
.sa_family
== family
;
224 _public_
int sd_is_socket_inet(int fd
, int family
, int type
, int listening
, uint16_t port
) {
225 union sockaddr_union sockaddr
= {};
226 socklen_t l
= sizeof(sockaddr
);
229 assert_return(fd
>= 0, -EBADF
);
230 assert_return(IN_SET(family
, 0, AF_INET
, AF_INET6
), -EINVAL
);
232 r
= sd_is_socket_internal(fd
, type
, listening
);
236 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
239 if (l
< sizeof(sa_family_t
))
242 if (sockaddr
.sa
.sa_family
!= AF_INET
&&
243 sockaddr
.sa
.sa_family
!= AF_INET6
)
247 if (sockaddr
.sa
.sa_family
!= family
)
251 if (sockaddr
.sa
.sa_family
== AF_INET
) {
252 if (l
< sizeof(struct sockaddr_in
))
255 return htons(port
) == sockaddr
.in
.sin_port
;
257 if (l
< sizeof(struct sockaddr_in6
))
260 return htons(port
) == sockaddr
.in6
.sin6_port
;
267 _public_
int sd_is_socket_unix(int fd
, int type
, int listening
, const char *path
, size_t length
) {
268 union sockaddr_union sockaddr
= {};
269 socklen_t l
= sizeof(sockaddr
);
272 assert_return(fd
>= 0, -EBADF
);
274 r
= sd_is_socket_internal(fd
, type
, listening
);
278 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
281 if (l
< sizeof(sa_family_t
))
284 if (sockaddr
.sa
.sa_family
!= AF_UNIX
)
289 length
= strlen(path
);
293 return l
== offsetof(struct sockaddr_un
, sun_path
);
296 /* Normal path socket */
298 (l
>= offsetof(struct sockaddr_un
, sun_path
) + length
+ 1) &&
299 memcmp(path
, sockaddr
.un
.sun_path
, length
+1) == 0;
301 /* Abstract namespace socket */
303 (l
== offsetof(struct sockaddr_un
, sun_path
) + length
) &&
304 memcmp(path
, sockaddr
.un
.sun_path
, length
) == 0;
310 _public_
int sd_is_mq(int fd
, const char *path
) {
313 /* Check that the fd is valid */
314 assert_return(fcntl(fd
, F_GETFD
) >= 0, -errno
);
316 if (mq_getattr(fd
, &attr
) < 0) {
318 /* A non-mq fd (or an invalid one, but we ruled that out above) */
324 char fpath
[PATH_MAX
];
327 assert_return(path_is_absolute(path
), -EINVAL
);
329 if (fstat(fd
, &a
) < 0)
332 strncpy(stpcpy(fpath
, "/dev/mqueue"), path
, sizeof(fpath
) - 12);
333 fpath
[sizeof(fpath
)-1] = 0;
335 if (stat(fpath
, &b
) < 0)
338 if (a
.st_dev
!= b
.st_dev
||
339 a
.st_ino
!= b
.st_ino
)
346 _public_
int sd_pid_notify_with_fds(pid_t pid
, int unset_environment
, const char *state
, const int *fds
, unsigned n_fds
) {
347 union sockaddr_union sockaddr
= {
348 .sa
.sa_family
= AF_UNIX
,
350 struct iovec iovec
= {
351 .iov_base
= (char*) state
,
353 struct msghdr msghdr
= {
356 .msg_name
= &sockaddr
,
358 _cleanup_close_
int fd
= -1;
359 struct cmsghdr
*cmsg
= NULL
;
369 if (n_fds
> 0 && !fds
) {
374 e
= getenv("NOTIFY_SOCKET");
378 /* Must be an abstract socket, or an absolute path */
379 if ((e
[0] != '@' && e
[0] != '/') || e
[1] == 0) {
384 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
390 iovec
.iov_len
= strlen(state
);
392 strncpy(sockaddr
.un
.sun_path
, e
, sizeof(sockaddr
.un
.sun_path
));
393 if (sockaddr
.un
.sun_path
[0] == '@')
394 sockaddr
.un
.sun_path
[0] = 0;
396 msghdr
.msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(e
);
397 if (msghdr
.msg_namelen
> sizeof(struct sockaddr_un
))
398 msghdr
.msg_namelen
= sizeof(struct sockaddr_un
);
400 have_pid
= pid
!= 0 && pid
!= getpid();
402 if (n_fds
> 0 || have_pid
) {
403 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
404 msghdr
.msg_controllen
= (n_fds
? CMSG_SPACE(sizeof(int) * n_fds
) : 0) +
405 CMSG_SPACE(sizeof(struct ucred
)) * have_pid
;
406 msghdr
.msg_control
= alloca(msghdr
.msg_controllen
);
408 cmsg
= CMSG_FIRSTHDR(&msghdr
);
410 cmsg
->cmsg_level
= SOL_SOCKET
;
411 cmsg
->cmsg_type
= SCM_RIGHTS
;
412 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * n_fds
);
414 memcpy(CMSG_DATA(cmsg
), fds
, sizeof(int) * n_fds
);
417 assert_se(cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
));
423 cmsg
->cmsg_level
= SOL_SOCKET
;
424 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
425 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
427 ucred
= (struct ucred
*) CMSG_DATA(cmsg
);
429 ucred
->uid
= getuid();
430 ucred
->gid
= getgid();
434 /* First try with fake ucred data, as requested */
435 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
440 /* If that failed, try with our own ucred instead */
442 msghdr
.msg_controllen
-= CMSG_SPACE(sizeof(struct ucred
));
443 if (msghdr
.msg_controllen
== 0)
444 msghdr
.msg_control
= NULL
;
446 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
455 if (unset_environment
)
456 unsetenv("NOTIFY_SOCKET");
461 _public_
int sd_pid_notify(pid_t pid
, int unset_environment
, const char *state
) {
462 return sd_pid_notify_with_fds(pid
, unset_environment
, state
, NULL
, 0);
465 _public_
int sd_notify(int unset_environment
, const char *state
) {
466 return sd_pid_notify_with_fds(0, unset_environment
, state
, NULL
, 0);
469 _public_
int sd_pid_notifyf(pid_t pid
, int unset_environment
, const char *format
, ...) {
470 _cleanup_free_
char *p
= NULL
;
476 va_start(ap
, format
);
477 r
= vasprintf(&p
, format
, ap
);
484 return sd_pid_notify(pid
, unset_environment
, p
);
487 _public_
int sd_notifyf(int unset_environment
, const char *format
, ...) {
488 _cleanup_free_
char *p
= NULL
;
494 va_start(ap
, format
);
495 r
= vasprintf(&p
, format
, ap
);
502 return sd_pid_notify(0, unset_environment
, p
);
505 _public_
int sd_booted(void) {
506 /* We test whether the runtime unit file directory has been
507 * created. This takes place in mount-setup.c, so is
508 * guaranteed to happen very early during boot. */
510 return laccess("/run/systemd/system/", F_OK
) >= 0;
513 _public_
int sd_watchdog_enabled(int unset_environment
, uint64_t *usec
) {
514 const char *s
, *p
= ""; /* p is set to dummy value to do unsetting */
518 s
= getenv("WATCHDOG_USEC");
522 r
= safe_atou64(s
, &u
);
530 p
= getenv("WATCHDOG_PID");
534 r
= parse_pid(p
, &pid
);
538 /* Is this for us? */
539 if (getpid() != pid
) {
551 if (unset_environment
&& s
)
552 unsetenv("WATCHDOG_USEC");
553 if (unset_environment
&& p
)
554 unsetenv("WATCHDOG_PID");