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"
38 #include "path-util.h"
39 #include "socket-util.h"
43 static void unsetenv_all(bool unset_environment
) {
45 if (!unset_environment
)
48 unsetenv("LISTEN_PID");
49 unsetenv("LISTEN_FDS");
50 unsetenv("LISTEN_FDNAMES");
53 _public_
int sd_listen_fds(int unset_environment
) {
59 e
= getenv("LISTEN_PID");
65 r
= parse_pid(e
, &pid
);
70 if (getpid() != pid
) {
75 e
= getenv("LISTEN_FDS");
85 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ (int) n
; fd
++) {
86 r
= fd_cloexec(fd
, true);
94 unsetenv_all(unset_environment
);
98 _public_
int sd_listen_fds_with_names(int unset_environment
, char ***names
) {
99 _cleanup_strv_free_
char **l
= NULL
;
101 int n_names
= 0, n_fds
;
106 return sd_listen_fds(unset_environment
);
108 e
= getenv("LISTEN_FDNAMES");
110 n_names
= strv_split_extract(&l
, e
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
112 unsetenv_all(unset_environment
);
120 n_fds
= sd_listen_fds(unset_environment
);
125 if (n_names
!= n_fds
)
128 r
= strv_extend_n(&l
, "unknown", n_fds
);
139 _public_
int sd_is_fifo(int fd
, const char *path
) {
142 assert_return(fd
>= 0, -EBADF
);
144 if (fstat(fd
, &st_fd
) < 0)
147 if (!S_ISFIFO(st_fd
.st_mode
))
153 if (stat(path
, &st_path
) < 0) {
155 if (errno
== ENOENT
|| errno
== ENOTDIR
)
162 st_path
.st_dev
== st_fd
.st_dev
&&
163 st_path
.st_ino
== st_fd
.st_ino
;
169 _public_
int sd_is_special(int fd
, const char *path
) {
172 assert_return(fd
>= 0, -EBADF
);
174 if (fstat(fd
, &st_fd
) < 0)
177 if (!S_ISREG(st_fd
.st_mode
) && !S_ISCHR(st_fd
.st_mode
))
183 if (stat(path
, &st_path
) < 0) {
185 if (errno
== ENOENT
|| errno
== ENOTDIR
)
191 if (S_ISREG(st_fd
.st_mode
) && S_ISREG(st_path
.st_mode
))
193 st_path
.st_dev
== st_fd
.st_dev
&&
194 st_path
.st_ino
== st_fd
.st_ino
;
195 else if (S_ISCHR(st_fd
.st_mode
) && S_ISCHR(st_path
.st_mode
))
196 return st_path
.st_rdev
== st_fd
.st_rdev
;
204 static int sd_is_socket_internal(int fd
, int type
, int listening
) {
207 assert_return(fd
>= 0, -EBADF
);
208 assert_return(type
>= 0, -EINVAL
);
210 if (fstat(fd
, &st_fd
) < 0)
213 if (!S_ISSOCK(st_fd
.st_mode
))
218 socklen_t l
= sizeof(other_type
);
220 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &other_type
, &l
) < 0)
223 if (l
!= sizeof(other_type
))
226 if (other_type
!= type
)
230 if (listening
>= 0) {
232 socklen_t l
= sizeof(accepting
);
234 if (getsockopt(fd
, SOL_SOCKET
, SO_ACCEPTCONN
, &accepting
, &l
) < 0)
237 if (l
!= sizeof(accepting
))
240 if (!accepting
!= !listening
)
247 _public_
int sd_is_socket(int fd
, int family
, int type
, int listening
) {
250 assert_return(fd
>= 0, -EBADF
);
251 assert_return(family
>= 0, -EINVAL
);
253 r
= sd_is_socket_internal(fd
, type
, listening
);
258 union sockaddr_union sockaddr
= {};
259 socklen_t l
= sizeof(sockaddr
);
261 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
264 if (l
< sizeof(sa_family_t
))
267 return sockaddr
.sa
.sa_family
== family
;
273 _public_
int sd_is_socket_inet(int fd
, int family
, int type
, int listening
, uint16_t port
) {
274 union sockaddr_union sockaddr
= {};
275 socklen_t l
= sizeof(sockaddr
);
278 assert_return(fd
>= 0, -EBADF
);
279 assert_return(IN_SET(family
, 0, AF_INET
, AF_INET6
), -EINVAL
);
281 r
= sd_is_socket_internal(fd
, type
, listening
);
285 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
288 if (l
< sizeof(sa_family_t
))
291 if (sockaddr
.sa
.sa_family
!= AF_INET
&&
292 sockaddr
.sa
.sa_family
!= AF_INET6
)
296 if (sockaddr
.sa
.sa_family
!= family
)
300 if (sockaddr
.sa
.sa_family
== AF_INET
) {
301 if (l
< sizeof(struct sockaddr_in
))
304 return htons(port
) == sockaddr
.in
.sin_port
;
306 if (l
< sizeof(struct sockaddr_in6
))
309 return htons(port
) == sockaddr
.in6
.sin6_port
;
316 _public_
int sd_is_socket_unix(int fd
, int type
, int listening
, const char *path
, size_t length
) {
317 union sockaddr_union sockaddr
= {};
318 socklen_t l
= sizeof(sockaddr
);
321 assert_return(fd
>= 0, -EBADF
);
323 r
= sd_is_socket_internal(fd
, type
, listening
);
327 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
330 if (l
< sizeof(sa_family_t
))
333 if (sockaddr
.sa
.sa_family
!= AF_UNIX
)
338 length
= strlen(path
);
342 return l
== offsetof(struct sockaddr_un
, sun_path
);
345 /* Normal path socket */
347 (l
>= offsetof(struct sockaddr_un
, sun_path
) + length
+ 1) &&
348 memcmp(path
, sockaddr
.un
.sun_path
, length
+1) == 0;
350 /* Abstract namespace socket */
352 (l
== offsetof(struct sockaddr_un
, sun_path
) + length
) &&
353 memcmp(path
, sockaddr
.un
.sun_path
, length
) == 0;
359 _public_
int sd_is_mq(int fd
, const char *path
) {
362 /* Check that the fd is valid */
363 assert_return(fcntl(fd
, F_GETFD
) >= 0, -errno
);
365 if (mq_getattr(fd
, &attr
) < 0) {
367 /* A non-mq fd (or an invalid one, but we ruled that out above) */
373 char fpath
[PATH_MAX
];
376 assert_return(path_is_absolute(path
), -EINVAL
);
378 if (fstat(fd
, &a
) < 0)
381 strncpy(stpcpy(fpath
, "/dev/mqueue"), path
, sizeof(fpath
) - 12);
382 fpath
[sizeof(fpath
)-1] = 0;
384 if (stat(fpath
, &b
) < 0)
387 if (a
.st_dev
!= b
.st_dev
||
388 a
.st_ino
!= b
.st_ino
)
395 _public_
int sd_pid_notify_with_fds(pid_t pid
, int unset_environment
, const char *state
, const int *fds
, unsigned n_fds
) {
396 union sockaddr_union sockaddr
= {
397 .sa
.sa_family
= AF_UNIX
,
399 struct iovec iovec
= {
400 .iov_base
= (char*) state
,
402 struct msghdr msghdr
= {
405 .msg_name
= &sockaddr
,
407 _cleanup_close_
int fd
= -1;
408 struct cmsghdr
*cmsg
= NULL
;
418 if (n_fds
> 0 && !fds
) {
423 e
= getenv("NOTIFY_SOCKET");
427 /* Must be an abstract socket, or an absolute path */
428 if ((e
[0] != '@' && e
[0] != '/') || e
[1] == 0) {
433 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
439 iovec
.iov_len
= strlen(state
);
441 strncpy(sockaddr
.un
.sun_path
, e
, sizeof(sockaddr
.un
.sun_path
));
442 if (sockaddr
.un
.sun_path
[0] == '@')
443 sockaddr
.un
.sun_path
[0] = 0;
445 msghdr
.msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(e
);
446 if (msghdr
.msg_namelen
> sizeof(struct sockaddr_un
))
447 msghdr
.msg_namelen
= sizeof(struct sockaddr_un
);
449 have_pid
= pid
!= 0 && pid
!= getpid();
451 if (n_fds
> 0 || have_pid
) {
452 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
453 msghdr
.msg_controllen
=
454 (n_fds
> 0 ? CMSG_SPACE(sizeof(int) * n_fds
) : 0) +
455 (have_pid
? CMSG_SPACE(sizeof(struct ucred
)) : 0);
457 msghdr
.msg_control
= alloca0(msghdr
.msg_controllen
);
459 cmsg
= CMSG_FIRSTHDR(&msghdr
);
461 cmsg
->cmsg_level
= SOL_SOCKET
;
462 cmsg
->cmsg_type
= SCM_RIGHTS
;
463 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * n_fds
);
465 memcpy(CMSG_DATA(cmsg
), fds
, sizeof(int) * n_fds
);
468 assert_se(cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
));
474 cmsg
->cmsg_level
= SOL_SOCKET
;
475 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
476 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
478 ucred
= (struct ucred
*) CMSG_DATA(cmsg
);
480 ucred
->uid
= getuid();
481 ucred
->gid
= getgid();
485 /* First try with fake ucred data, as requested */
486 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
491 /* If that failed, try with our own ucred instead */
493 msghdr
.msg_controllen
-= CMSG_SPACE(sizeof(struct ucred
));
494 if (msghdr
.msg_controllen
== 0)
495 msghdr
.msg_control
= NULL
;
497 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
506 if (unset_environment
)
507 unsetenv("NOTIFY_SOCKET");
512 _public_
int sd_pid_notify(pid_t pid
, int unset_environment
, const char *state
) {
513 return sd_pid_notify_with_fds(pid
, unset_environment
, state
, NULL
, 0);
516 _public_
int sd_notify(int unset_environment
, const char *state
) {
517 return sd_pid_notify_with_fds(0, unset_environment
, state
, NULL
, 0);
520 _public_
int sd_pid_notifyf(pid_t pid
, int unset_environment
, const char *format
, ...) {
521 _cleanup_free_
char *p
= NULL
;
527 va_start(ap
, format
);
528 r
= vasprintf(&p
, format
, ap
);
535 return sd_pid_notify(pid
, unset_environment
, p
);
538 _public_
int sd_notifyf(int unset_environment
, const char *format
, ...) {
539 _cleanup_free_
char *p
= NULL
;
545 va_start(ap
, format
);
546 r
= vasprintf(&p
, format
, ap
);
553 return sd_pid_notify(0, unset_environment
, p
);
556 _public_
int sd_booted(void) {
557 /* We test whether the runtime unit file directory has been
558 * created. This takes place in mount-setup.c, so is
559 * guaranteed to happen very early during boot. */
561 return laccess("/run/systemd/system/", F_OK
) >= 0;
564 _public_
int sd_watchdog_enabled(int unset_environment
, uint64_t *usec
) {
565 const char *s
, *p
= ""; /* p is set to dummy value to do unsetting */
569 s
= getenv("WATCHDOG_USEC");
573 r
= safe_atou64(s
, &u
);
581 p
= getenv("WATCHDOG_PID");
585 r
= parse_pid(p
, &pid
);
589 /* Is this for us? */
590 if (getpid() != pid
) {
602 if (unset_environment
&& s
)
603 unsetenv("WATCHDOG_USEC");
604 if (unset_environment
&& p
)
605 unsetenv("WATCHDOG_PID");