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/>.
25 #include <netinet/in.h>
31 #include <sys/socket.h>
36 #include "sd-daemon.h"
39 #include "parse-util.h"
40 #include "path-util.h"
41 #include "socket-util.h"
45 static void unsetenv_all(bool unset_environment
) {
47 if (!unset_environment
)
50 unsetenv("LISTEN_PID");
51 unsetenv("LISTEN_FDS");
52 unsetenv("LISTEN_FDNAMES");
55 _public_
int sd_listen_fds(int unset_environment
) {
61 e
= getenv("LISTEN_PID");
67 r
= parse_pid(e
, &pid
);
72 if (getpid() != pid
) {
77 e
= getenv("LISTEN_FDS");
87 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ (int) n
; fd
++) {
88 r
= fd_cloexec(fd
, true);
96 unsetenv_all(unset_environment
);
100 _public_
int sd_listen_fds_with_names(int unset_environment
, char ***names
) {
101 _cleanup_strv_free_
char **l
= NULL
;
103 int n_names
= 0, n_fds
;
108 return sd_listen_fds(unset_environment
);
110 e
= getenv("LISTEN_FDNAMES");
112 n_names
= strv_split_extract(&l
, e
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
114 unsetenv_all(unset_environment
);
122 n_fds
= sd_listen_fds(unset_environment
);
127 if (n_names
!= n_fds
)
130 r
= strv_extend_n(&l
, "unknown", n_fds
);
141 _public_
int sd_is_fifo(int fd
, const char *path
) {
144 assert_return(fd
>= 0, -EBADF
);
146 if (fstat(fd
, &st_fd
) < 0)
149 if (!S_ISFIFO(st_fd
.st_mode
))
155 if (stat(path
, &st_path
) < 0) {
157 if (errno
== ENOENT
|| errno
== ENOTDIR
)
164 st_path
.st_dev
== st_fd
.st_dev
&&
165 st_path
.st_ino
== st_fd
.st_ino
;
171 _public_
int sd_is_special(int fd
, const char *path
) {
174 assert_return(fd
>= 0, -EBADF
);
176 if (fstat(fd
, &st_fd
) < 0)
179 if (!S_ISREG(st_fd
.st_mode
) && !S_ISCHR(st_fd
.st_mode
))
185 if (stat(path
, &st_path
) < 0) {
187 if (errno
== ENOENT
|| errno
== ENOTDIR
)
193 if (S_ISREG(st_fd
.st_mode
) && S_ISREG(st_path
.st_mode
))
195 st_path
.st_dev
== st_fd
.st_dev
&&
196 st_path
.st_ino
== st_fd
.st_ino
;
197 else if (S_ISCHR(st_fd
.st_mode
) && S_ISCHR(st_path
.st_mode
))
198 return st_path
.st_rdev
== st_fd
.st_rdev
;
206 static int sd_is_socket_internal(int fd
, int type
, int listening
) {
209 assert_return(fd
>= 0, -EBADF
);
210 assert_return(type
>= 0, -EINVAL
);
212 if (fstat(fd
, &st_fd
) < 0)
215 if (!S_ISSOCK(st_fd
.st_mode
))
220 socklen_t l
= sizeof(other_type
);
222 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &other_type
, &l
) < 0)
225 if (l
!= sizeof(other_type
))
228 if (other_type
!= type
)
232 if (listening
>= 0) {
234 socklen_t l
= sizeof(accepting
);
236 if (getsockopt(fd
, SOL_SOCKET
, SO_ACCEPTCONN
, &accepting
, &l
) < 0)
239 if (l
!= sizeof(accepting
))
242 if (!accepting
!= !listening
)
249 _public_
int sd_is_socket(int fd
, int family
, int type
, int listening
) {
252 assert_return(fd
>= 0, -EBADF
);
253 assert_return(family
>= 0, -EINVAL
);
255 r
= sd_is_socket_internal(fd
, type
, listening
);
260 union sockaddr_union sockaddr
= {};
261 socklen_t l
= sizeof(sockaddr
);
263 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
266 if (l
< sizeof(sa_family_t
))
269 return sockaddr
.sa
.sa_family
== family
;
275 _public_
int sd_is_socket_inet(int fd
, int family
, int type
, int listening
, uint16_t port
) {
276 union sockaddr_union sockaddr
= {};
277 socklen_t l
= sizeof(sockaddr
);
280 assert_return(fd
>= 0, -EBADF
);
281 assert_return(IN_SET(family
, 0, AF_INET
, AF_INET6
), -EINVAL
);
283 r
= sd_is_socket_internal(fd
, type
, listening
);
287 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
290 if (l
< sizeof(sa_family_t
))
293 if (sockaddr
.sa
.sa_family
!= AF_INET
&&
294 sockaddr
.sa
.sa_family
!= AF_INET6
)
298 if (sockaddr
.sa
.sa_family
!= family
)
302 if (sockaddr
.sa
.sa_family
== AF_INET
) {
303 if (l
< sizeof(struct sockaddr_in
))
306 return htons(port
) == sockaddr
.in
.sin_port
;
308 if (l
< sizeof(struct sockaddr_in6
))
311 return htons(port
) == sockaddr
.in6
.sin6_port
;
318 _public_
int sd_is_socket_unix(int fd
, int type
, int listening
, const char *path
, size_t length
) {
319 union sockaddr_union sockaddr
= {};
320 socklen_t l
= sizeof(sockaddr
);
323 assert_return(fd
>= 0, -EBADF
);
325 r
= sd_is_socket_internal(fd
, type
, listening
);
329 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
332 if (l
< sizeof(sa_family_t
))
335 if (sockaddr
.sa
.sa_family
!= AF_UNIX
)
340 length
= strlen(path
);
344 return l
== offsetof(struct sockaddr_un
, sun_path
);
347 /* Normal path socket */
349 (l
>= offsetof(struct sockaddr_un
, sun_path
) + length
+ 1) &&
350 memcmp(path
, sockaddr
.un
.sun_path
, length
+1) == 0;
352 /* Abstract namespace socket */
354 (l
== offsetof(struct sockaddr_un
, sun_path
) + length
) &&
355 memcmp(path
, sockaddr
.un
.sun_path
, length
) == 0;
361 _public_
int sd_is_mq(int fd
, const char *path
) {
364 /* Check that the fd is valid */
365 assert_return(fcntl(fd
, F_GETFD
) >= 0, -errno
);
367 if (mq_getattr(fd
, &attr
) < 0) {
369 /* A non-mq fd (or an invalid one, but we ruled that out above) */
375 char fpath
[PATH_MAX
];
378 assert_return(path_is_absolute(path
), -EINVAL
);
380 if (fstat(fd
, &a
) < 0)
383 strncpy(stpcpy(fpath
, "/dev/mqueue"), path
, sizeof(fpath
) - 12);
384 fpath
[sizeof(fpath
)-1] = 0;
386 if (stat(fpath
, &b
) < 0)
389 if (a
.st_dev
!= b
.st_dev
||
390 a
.st_ino
!= b
.st_ino
)
397 _public_
int sd_pid_notify_with_fds(pid_t pid
, int unset_environment
, const char *state
, const int *fds
, unsigned n_fds
) {
398 union sockaddr_union sockaddr
= {
399 .sa
.sa_family
= AF_UNIX
,
401 struct iovec iovec
= {
402 .iov_base
= (char*) state
,
404 struct msghdr msghdr
= {
407 .msg_name
= &sockaddr
,
409 _cleanup_close_
int fd
= -1;
410 struct cmsghdr
*cmsg
= NULL
;
420 if (n_fds
> 0 && !fds
) {
425 e
= getenv("NOTIFY_SOCKET");
429 /* Must be an abstract socket, or an absolute path */
430 if ((e
[0] != '@' && e
[0] != '/') || e
[1] == 0) {
435 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
441 iovec
.iov_len
= strlen(state
);
443 strncpy(sockaddr
.un
.sun_path
, e
, sizeof(sockaddr
.un
.sun_path
));
444 if (sockaddr
.un
.sun_path
[0] == '@')
445 sockaddr
.un
.sun_path
[0] = 0;
447 msghdr
.msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(e
);
448 if (msghdr
.msg_namelen
> sizeof(struct sockaddr_un
))
449 msghdr
.msg_namelen
= sizeof(struct sockaddr_un
);
451 have_pid
= pid
!= 0 && pid
!= getpid();
453 if (n_fds
> 0 || have_pid
) {
454 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
455 msghdr
.msg_controllen
=
456 (n_fds
> 0 ? CMSG_SPACE(sizeof(int) * n_fds
) : 0) +
457 (have_pid
? CMSG_SPACE(sizeof(struct ucred
)) : 0);
459 msghdr
.msg_control
= alloca0(msghdr
.msg_controllen
);
461 cmsg
= CMSG_FIRSTHDR(&msghdr
);
463 cmsg
->cmsg_level
= SOL_SOCKET
;
464 cmsg
->cmsg_type
= SCM_RIGHTS
;
465 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * n_fds
);
467 memcpy(CMSG_DATA(cmsg
), fds
, sizeof(int) * n_fds
);
470 assert_se(cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
));
476 cmsg
->cmsg_level
= SOL_SOCKET
;
477 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
478 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
480 ucred
= (struct ucred
*) CMSG_DATA(cmsg
);
482 ucred
->uid
= getuid();
483 ucred
->gid
= getgid();
487 /* First try with fake ucred data, as requested */
488 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
493 /* If that failed, try with our own ucred instead */
495 msghdr
.msg_controllen
-= CMSG_SPACE(sizeof(struct ucred
));
496 if (msghdr
.msg_controllen
== 0)
497 msghdr
.msg_control
= NULL
;
499 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
508 if (unset_environment
)
509 unsetenv("NOTIFY_SOCKET");
514 _public_
int sd_pid_notify(pid_t pid
, int unset_environment
, const char *state
) {
515 return sd_pid_notify_with_fds(pid
, unset_environment
, state
, NULL
, 0);
518 _public_
int sd_notify(int unset_environment
, const char *state
) {
519 return sd_pid_notify_with_fds(0, unset_environment
, state
, NULL
, 0);
522 _public_
int sd_pid_notifyf(pid_t pid
, int unset_environment
, const char *format
, ...) {
523 _cleanup_free_
char *p
= NULL
;
529 va_start(ap
, format
);
530 r
= vasprintf(&p
, format
, ap
);
537 return sd_pid_notify(pid
, unset_environment
, p
);
540 _public_
int sd_notifyf(int unset_environment
, const char *format
, ...) {
541 _cleanup_free_
char *p
= NULL
;
547 va_start(ap
, format
);
548 r
= vasprintf(&p
, format
, ap
);
555 return sd_pid_notify(0, unset_environment
, p
);
558 _public_
int sd_booted(void) {
559 /* We test whether the runtime unit file directory has been
560 * created. This takes place in mount-setup.c, so is
561 * guaranteed to happen very early during boot. */
563 return laccess("/run/systemd/system/", F_OK
) >= 0;
566 _public_
int sd_watchdog_enabled(int unset_environment
, uint64_t *usec
) {
567 const char *s
, *p
= ""; /* p is set to dummy value to do unsetting */
571 s
= getenv("WATCHDOG_USEC");
575 r
= safe_atou64(s
, &u
);
583 p
= getenv("WATCHDOG_PID");
587 r
= parse_pid(p
, &pid
);
591 /* Is this for us? */
592 if (getpid() != pid
) {
604 if (unset_environment
&& s
)
605 unsetenv("WATCHDOG_USEC");
606 if (unset_environment
&& p
)
607 unsetenv("WATCHDOG_PID");