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 "path-util.h"
40 #include "socket-util.h"
44 static void unsetenv_all(bool unset_environment
) {
46 if (!unset_environment
)
49 unsetenv("LISTEN_PID");
50 unsetenv("LISTEN_FDS");
51 unsetenv("LISTEN_FDNAMES");
54 _public_
int sd_listen_fds(int unset_environment
) {
60 e
= getenv("LISTEN_PID");
66 r
= parse_pid(e
, &pid
);
71 if (getpid() != pid
) {
76 e
= getenv("LISTEN_FDS");
86 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ (int) n
; fd
++) {
87 r
= fd_cloexec(fd
, true);
95 unsetenv_all(unset_environment
);
99 _public_
int sd_listen_fds_with_names(int unset_environment
, char ***names
) {
100 _cleanup_strv_free_
char **l
= NULL
;
102 int n_names
= 0, n_fds
;
107 return sd_listen_fds(unset_environment
);
109 e
= getenv("LISTEN_FDNAMES");
111 n_names
= strv_split_extract(&l
, e
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
113 unsetenv_all(unset_environment
);
121 n_fds
= sd_listen_fds(unset_environment
);
126 if (n_names
!= n_fds
)
129 r
= strv_extend_n(&l
, "unknown", n_fds
);
140 _public_
int sd_is_fifo(int fd
, const char *path
) {
143 assert_return(fd
>= 0, -EBADF
);
145 if (fstat(fd
, &st_fd
) < 0)
148 if (!S_ISFIFO(st_fd
.st_mode
))
154 if (stat(path
, &st_path
) < 0) {
156 if (errno
== ENOENT
|| errno
== ENOTDIR
)
163 st_path
.st_dev
== st_fd
.st_dev
&&
164 st_path
.st_ino
== st_fd
.st_ino
;
170 _public_
int sd_is_special(int fd
, const char *path
) {
173 assert_return(fd
>= 0, -EBADF
);
175 if (fstat(fd
, &st_fd
) < 0)
178 if (!S_ISREG(st_fd
.st_mode
) && !S_ISCHR(st_fd
.st_mode
))
184 if (stat(path
, &st_path
) < 0) {
186 if (errno
== ENOENT
|| errno
== ENOTDIR
)
192 if (S_ISREG(st_fd
.st_mode
) && S_ISREG(st_path
.st_mode
))
194 st_path
.st_dev
== st_fd
.st_dev
&&
195 st_path
.st_ino
== st_fd
.st_ino
;
196 else if (S_ISCHR(st_fd
.st_mode
) && S_ISCHR(st_path
.st_mode
))
197 return st_path
.st_rdev
== st_fd
.st_rdev
;
205 static int sd_is_socket_internal(int fd
, int type
, int listening
) {
208 assert_return(fd
>= 0, -EBADF
);
209 assert_return(type
>= 0, -EINVAL
);
211 if (fstat(fd
, &st_fd
) < 0)
214 if (!S_ISSOCK(st_fd
.st_mode
))
219 socklen_t l
= sizeof(other_type
);
221 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &other_type
, &l
) < 0)
224 if (l
!= sizeof(other_type
))
227 if (other_type
!= type
)
231 if (listening
>= 0) {
233 socklen_t l
= sizeof(accepting
);
235 if (getsockopt(fd
, SOL_SOCKET
, SO_ACCEPTCONN
, &accepting
, &l
) < 0)
238 if (l
!= sizeof(accepting
))
241 if (!accepting
!= !listening
)
248 _public_
int sd_is_socket(int fd
, int family
, int type
, int listening
) {
251 assert_return(fd
>= 0, -EBADF
);
252 assert_return(family
>= 0, -EINVAL
);
254 r
= sd_is_socket_internal(fd
, type
, listening
);
259 union sockaddr_union sockaddr
= {};
260 socklen_t l
= sizeof(sockaddr
);
262 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
265 if (l
< sizeof(sa_family_t
))
268 return sockaddr
.sa
.sa_family
== family
;
274 _public_
int sd_is_socket_inet(int fd
, int family
, int type
, int listening
, uint16_t port
) {
275 union sockaddr_union sockaddr
= {};
276 socklen_t l
= sizeof(sockaddr
);
279 assert_return(fd
>= 0, -EBADF
);
280 assert_return(IN_SET(family
, 0, AF_INET
, AF_INET6
), -EINVAL
);
282 r
= sd_is_socket_internal(fd
, type
, listening
);
286 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
289 if (l
< sizeof(sa_family_t
))
292 if (sockaddr
.sa
.sa_family
!= AF_INET
&&
293 sockaddr
.sa
.sa_family
!= AF_INET6
)
297 if (sockaddr
.sa
.sa_family
!= family
)
301 if (sockaddr
.sa
.sa_family
== AF_INET
) {
302 if (l
< sizeof(struct sockaddr_in
))
305 return htons(port
) == sockaddr
.in
.sin_port
;
307 if (l
< sizeof(struct sockaddr_in6
))
310 return htons(port
) == sockaddr
.in6
.sin6_port
;
317 _public_
int sd_is_socket_unix(int fd
, int type
, int listening
, const char *path
, size_t length
) {
318 union sockaddr_union sockaddr
= {};
319 socklen_t l
= sizeof(sockaddr
);
322 assert_return(fd
>= 0, -EBADF
);
324 r
= sd_is_socket_internal(fd
, type
, listening
);
328 if (getsockname(fd
, &sockaddr
.sa
, &l
) < 0)
331 if (l
< sizeof(sa_family_t
))
334 if (sockaddr
.sa
.sa_family
!= AF_UNIX
)
339 length
= strlen(path
);
343 return l
== offsetof(struct sockaddr_un
, sun_path
);
346 /* Normal path socket */
348 (l
>= offsetof(struct sockaddr_un
, sun_path
) + length
+ 1) &&
349 memcmp(path
, sockaddr
.un
.sun_path
, length
+1) == 0;
351 /* Abstract namespace socket */
353 (l
== offsetof(struct sockaddr_un
, sun_path
) + length
) &&
354 memcmp(path
, sockaddr
.un
.sun_path
, length
) == 0;
360 _public_
int sd_is_mq(int fd
, const char *path
) {
363 /* Check that the fd is valid */
364 assert_return(fcntl(fd
, F_GETFD
) >= 0, -errno
);
366 if (mq_getattr(fd
, &attr
) < 0) {
368 /* A non-mq fd (or an invalid one, but we ruled that out above) */
374 char fpath
[PATH_MAX
];
377 assert_return(path_is_absolute(path
), -EINVAL
);
379 if (fstat(fd
, &a
) < 0)
382 strncpy(stpcpy(fpath
, "/dev/mqueue"), path
, sizeof(fpath
) - 12);
383 fpath
[sizeof(fpath
)-1] = 0;
385 if (stat(fpath
, &b
) < 0)
388 if (a
.st_dev
!= b
.st_dev
||
389 a
.st_ino
!= b
.st_ino
)
396 _public_
int sd_pid_notify_with_fds(pid_t pid
, int unset_environment
, const char *state
, const int *fds
, unsigned n_fds
) {
397 union sockaddr_union sockaddr
= {
398 .sa
.sa_family
= AF_UNIX
,
400 struct iovec iovec
= {
401 .iov_base
= (char*) state
,
403 struct msghdr msghdr
= {
406 .msg_name
= &sockaddr
,
408 _cleanup_close_
int fd
= -1;
409 struct cmsghdr
*cmsg
= NULL
;
419 if (n_fds
> 0 && !fds
) {
424 e
= getenv("NOTIFY_SOCKET");
428 /* Must be an abstract socket, or an absolute path */
429 if ((e
[0] != '@' && e
[0] != '/') || e
[1] == 0) {
434 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
440 iovec
.iov_len
= strlen(state
);
442 strncpy(sockaddr
.un
.sun_path
, e
, sizeof(sockaddr
.un
.sun_path
));
443 if (sockaddr
.un
.sun_path
[0] == '@')
444 sockaddr
.un
.sun_path
[0] = 0;
446 msghdr
.msg_namelen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(e
);
447 if (msghdr
.msg_namelen
> sizeof(struct sockaddr_un
))
448 msghdr
.msg_namelen
= sizeof(struct sockaddr_un
);
450 have_pid
= pid
!= 0 && pid
!= getpid();
452 if (n_fds
> 0 || have_pid
) {
453 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
454 msghdr
.msg_controllen
=
455 (n_fds
> 0 ? CMSG_SPACE(sizeof(int) * n_fds
) : 0) +
456 (have_pid
? CMSG_SPACE(sizeof(struct ucred
)) : 0);
458 msghdr
.msg_control
= alloca0(msghdr
.msg_controllen
);
460 cmsg
= CMSG_FIRSTHDR(&msghdr
);
462 cmsg
->cmsg_level
= SOL_SOCKET
;
463 cmsg
->cmsg_type
= SCM_RIGHTS
;
464 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * n_fds
);
466 memcpy(CMSG_DATA(cmsg
), fds
, sizeof(int) * n_fds
);
469 assert_se(cmsg
= CMSG_NXTHDR(&msghdr
, cmsg
));
475 cmsg
->cmsg_level
= SOL_SOCKET
;
476 cmsg
->cmsg_type
= SCM_CREDENTIALS
;
477 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct ucred
));
479 ucred
= (struct ucred
*) CMSG_DATA(cmsg
);
481 ucred
->uid
= getuid();
482 ucred
->gid
= getgid();
486 /* First try with fake ucred data, as requested */
487 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
492 /* If that failed, try with our own ucred instead */
494 msghdr
.msg_controllen
-= CMSG_SPACE(sizeof(struct ucred
));
495 if (msghdr
.msg_controllen
== 0)
496 msghdr
.msg_control
= NULL
;
498 if (sendmsg(fd
, &msghdr
, MSG_NOSIGNAL
) >= 0) {
507 if (unset_environment
)
508 unsetenv("NOTIFY_SOCKET");
513 _public_
int sd_pid_notify(pid_t pid
, int unset_environment
, const char *state
) {
514 return sd_pid_notify_with_fds(pid
, unset_environment
, state
, NULL
, 0);
517 _public_
int sd_notify(int unset_environment
, const char *state
) {
518 return sd_pid_notify_with_fds(0, unset_environment
, state
, NULL
, 0);
521 _public_
int sd_pid_notifyf(pid_t pid
, int unset_environment
, const char *format
, ...) {
522 _cleanup_free_
char *p
= NULL
;
528 va_start(ap
, format
);
529 r
= vasprintf(&p
, format
, ap
);
536 return sd_pid_notify(pid
, unset_environment
, p
);
539 _public_
int sd_notifyf(int unset_environment
, const char *format
, ...) {
540 _cleanup_free_
char *p
= NULL
;
546 va_start(ap
, format
);
547 r
= vasprintf(&p
, format
, ap
);
554 return sd_pid_notify(0, unset_environment
, p
);
557 _public_
int sd_booted(void) {
558 /* We test whether the runtime unit file directory has been
559 * created. This takes place in mount-setup.c, so is
560 * guaranteed to happen very early during boot. */
562 return laccess("/run/systemd/system/", F_OK
) >= 0;
565 _public_
int sd_watchdog_enabled(int unset_environment
, uint64_t *usec
) {
566 const char *s
, *p
= ""; /* p is set to dummy value to do unsetting */
570 s
= getenv("WATCHDOG_USEC");
574 r
= safe_atou64(s
, &u
);
582 p
= getenv("WATCHDOG_PID");
586 r
= parse_pid(p
, &pid
);
590 /* Is this for us? */
591 if (getpid() != pid
) {
603 if (unset_environment
&& s
)
604 unsetenv("WATCHDOG_USEC");
605 if (unset_environment
&& p
)
606 unsetenv("WATCHDOG_PID");