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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include <sys/resource.h>
32 #include <linux/sched.h>
33 #include <sys/types.h>
37 #include <sys/ioctl.h>
39 #include <linux/tiocl.h>
42 #include <sys/inotify.h>
46 #include <sys/prctl.h>
47 #include <sys/utsname.h>
49 #include <netinet/ip.h>
53 #include <sys/capability.h>
55 #include <linux/rtc.h>
67 #include "exit-status.h"
71 char **saved_argv
= NULL
;
73 size_t page_size(void) {
74 static __thread
size_t pgsz
= 0;
77 if (_likely_(pgsz
> 0))
80 assert_se((r
= sysconf(_SC_PAGESIZE
)) > 0);
87 bool streq_ptr(const char *a
, const char *b
) {
89 /* Like streq(), but tries to make sense of NULL pointers */
100 usec_t
now(clockid_t clock_id
) {
103 assert_se(clock_gettime(clock_id
, &ts
) == 0);
105 return timespec_load(&ts
);
108 dual_timestamp
* dual_timestamp_get(dual_timestamp
*ts
) {
111 ts
->realtime
= now(CLOCK_REALTIME
);
112 ts
->monotonic
= now(CLOCK_MONOTONIC
);
117 dual_timestamp
* dual_timestamp_from_realtime(dual_timestamp
*ts
, usec_t u
) {
126 delta
= (int64_t) now(CLOCK_REALTIME
) - (int64_t) u
;
128 ts
->monotonic
= now(CLOCK_MONOTONIC
);
130 if ((int64_t) ts
->monotonic
> delta
)
131 ts
->monotonic
-= delta
;
139 usec_t
timespec_load(const struct timespec
*ts
) {
143 (usec_t
) ts
->tv_sec
* USEC_PER_SEC
+
144 (usec_t
) ts
->tv_nsec
/ NSEC_PER_USEC
;
147 struct timespec
*timespec_store(struct timespec
*ts
, usec_t u
) {
150 ts
->tv_sec
= (time_t) (u
/ USEC_PER_SEC
);
151 ts
->tv_nsec
= (long int) ((u
% USEC_PER_SEC
) * NSEC_PER_USEC
);
156 usec_t
timeval_load(const struct timeval
*tv
) {
160 (usec_t
) tv
->tv_sec
* USEC_PER_SEC
+
161 (usec_t
) tv
->tv_usec
;
164 struct timeval
*timeval_store(struct timeval
*tv
, usec_t u
) {
167 tv
->tv_sec
= (time_t) (u
/ USEC_PER_SEC
);
168 tv
->tv_usec
= (suseconds_t
) (u
% USEC_PER_SEC
);
173 bool endswith(const char *s
, const char *postfix
) {
180 pl
= strlen(postfix
);
188 return memcmp(s
+ sl
- pl
, postfix
, pl
) == 0;
191 bool startswith(const char *s
, const char *prefix
) {
206 return memcmp(s
, prefix
, pl
) == 0;
209 bool startswith_no_case(const char *s
, const char *prefix
) {
225 for(i
= 0; i
< pl
; ++i
) {
226 if (tolower(s
[i
]) != tolower(prefix
[i
]))
233 bool first_word(const char *s
, const char *word
) {
248 if (memcmp(s
, word
, wl
) != 0)
252 strchr(WHITESPACE
, s
[wl
]);
255 int close_nointr(int fd
) {
270 void close_nointr_nofail(int fd
) {
271 int saved_errno
= errno
;
273 /* like close_nointr() but cannot fail, and guarantees errno
276 assert_se(close_nointr(fd
) == 0);
281 void close_many(const int fds
[], unsigned n_fd
) {
284 for (i
= 0; i
< n_fd
; i
++)
285 close_nointr_nofail(fds
[i
]);
288 int parse_boolean(const char *v
) {
291 if (streq(v
, "1") || v
[0] == 'y' || v
[0] == 'Y' || v
[0] == 't' || v
[0] == 'T' || !strcasecmp(v
, "on"))
293 else if (streq(v
, "0") || v
[0] == 'n' || v
[0] == 'N' || v
[0] == 'f' || v
[0] == 'F' || !strcasecmp(v
, "off"))
299 int parse_pid(const char *s
, pid_t
* ret_pid
) {
300 unsigned long ul
= 0;
307 if ((r
= safe_atolu(s
, &ul
)) < 0)
312 if ((unsigned long) pid
!= ul
)
322 int parse_uid(const char *s
, uid_t
* ret_uid
) {
323 unsigned long ul
= 0;
330 if ((r
= safe_atolu(s
, &ul
)) < 0)
335 if ((unsigned long) uid
!= ul
)
342 int safe_atou(const char *s
, unsigned *ret_u
) {
350 l
= strtoul(s
, &x
, 0);
352 if (!x
|| *x
|| errno
)
353 return errno
? -errno
: -EINVAL
;
355 if ((unsigned long) (unsigned) l
!= l
)
358 *ret_u
= (unsigned) l
;
362 int safe_atoi(const char *s
, int *ret_i
) {
370 l
= strtol(s
, &x
, 0);
372 if (!x
|| *x
|| errno
)
373 return errno
? -errno
: -EINVAL
;
375 if ((long) (int) l
!= l
)
382 int safe_atollu(const char *s
, long long unsigned *ret_llu
) {
384 unsigned long long l
;
390 l
= strtoull(s
, &x
, 0);
392 if (!x
|| *x
|| errno
)
393 return errno
? -errno
: -EINVAL
;
399 int safe_atolli(const char *s
, long long int *ret_lli
) {
407 l
= strtoll(s
, &x
, 0);
409 if (!x
|| *x
|| errno
)
410 return errno
? -errno
: -EINVAL
;
416 /* Split a string into words. */
417 char *split(const char *c
, size_t *l
, const char *separator
, char **state
) {
420 current
= *state
? *state
: (char*) c
;
422 if (!*current
|| *c
== 0)
425 current
+= strspn(current
, separator
);
426 *l
= strcspn(current
, separator
);
429 return (char*) current
;
432 /* Split a string into words, but consider strings enclosed in '' and
433 * "" as words even if they include spaces. */
434 char *split_quoted(const char *c
, size_t *l
, char **state
) {
436 bool escaped
= false;
438 current
= *state
? *state
: (char*) c
;
440 if (!*current
|| *c
== 0)
443 current
+= strspn(current
, WHITESPACE
);
445 if (*current
== '\'') {
448 for (e
= current
; *e
; e
++) {
458 *state
= *e
== 0 ? e
: e
+1;
459 } else if (*current
== '\"') {
462 for (e
= current
; *e
; e
++) {
472 *state
= *e
== 0 ? e
: e
+1;
474 for (e
= current
; *e
; e
++) {
479 else if (strchr(WHITESPACE
, *e
))
486 return (char*) current
;
489 char **split_path_and_make_absolute(const char *p
) {
493 if (!(l
= strv_split(p
, ":")))
496 if (!strv_path_make_absolute_cwd(l
)) {
504 int get_parent_of_pid(pid_t pid
, pid_t
*_ppid
) {
507 char fn
[PATH_MAX
], line
[LINE_MAX
], *p
;
513 assert_se(snprintf(fn
, sizeof(fn
)-1, "/proc/%lu/stat", (unsigned long) pid
) < (int) (sizeof(fn
)-1));
516 if (!(f
= fopen(fn
, "re")))
519 if (!(fgets(line
, sizeof(line
), f
))) {
520 r
= feof(f
) ? -EIO
: -errno
;
527 /* Let's skip the pid and comm fields. The latter is enclosed
528 * in () but does not escape any () in its value, so let's
529 * skip over it manually */
531 if (!(p
= strrchr(line
, ')')))
542 if ((long unsigned) (pid_t
) ppid
!= ppid
)
545 *_ppid
= (pid_t
) ppid
;
550 int get_starttime_of_pid(pid_t pid
, unsigned long long *st
) {
553 char fn
[PATH_MAX
], line
[LINE_MAX
], *p
;
558 assert_se(snprintf(fn
, sizeof(fn
)-1, "/proc/%lu/stat", (unsigned long) pid
) < (int) (sizeof(fn
)-1));
561 if (!(f
= fopen(fn
, "re")))
564 if (!(fgets(line
, sizeof(line
), f
))) {
565 r
= feof(f
) ? -EIO
: -errno
;
572 /* Let's skip the pid and comm fields. The latter is enclosed
573 * in () but does not escape any () in its value, so let's
574 * skip over it manually */
576 if (!(p
= strrchr(line
, ')')))
597 "%*d " /* priority */
599 "%*d " /* num_threads */
600 "%*d " /* itrealvalue */
601 "%llu " /* starttime */,
608 int write_one_line_file(const char *fn
, const char *line
) {
615 if (!(f
= fopen(fn
, "we")))
619 if (fputs(line
, f
) < 0) {
624 if (!endswith(line
, "\n"))
642 int fchmod_umask(int fd
, mode_t m
) {
647 r
= fchmod(fd
, m
& (~u
)) < 0 ? -errno
: 0;
653 int write_one_line_file_atomic(const char *fn
, const char *line
) {
661 r
= fopen_temporary(fn
, &f
, &p
);
665 fchmod_umask(fileno(f
), 0644);
668 if (fputs(line
, f
) < 0) {
673 if (!endswith(line
, "\n"))
684 if (rename(p
, fn
) < 0)
700 int read_one_line_file(const char *fn
, char **line
) {
703 char t
[LINE_MAX
], *c
;
712 if (!fgets(t
, sizeof(t
), f
)) {
738 int read_full_file(const char *fn
, char **contents
, size_t *size
) {
745 if (!(f
= fopen(fn
, "re")))
748 if (fstat(fileno(f
), &st
) < 0) {
754 if (st
.st_size
> 4*1024*1024) {
759 n
= st
.st_size
> 0 ? st
.st_size
: LINE_MAX
;
766 if (!(t
= realloc(buf
, n
+1))) {
772 k
= fread(buf
+ l
, 1, n
- l
, f
);
787 if (n
> 4*1024*1024) {
811 const char *separator
, ...) {
814 char *contents
= NULL
, *p
;
819 if ((r
= read_full_file(fname
, &contents
, NULL
)) < 0)
824 const char *key
= NULL
;
826 p
+= strspn(p
, separator
);
827 p
+= strspn(p
, WHITESPACE
);
832 if (!strchr(COMMENTS
, *p
)) {
836 va_start(ap
, separator
);
837 while ((key
= va_arg(ap
, char *))) {
841 value
= va_arg(ap
, char **);
844 if (strncmp(p
, key
, n
) != 0 ||
849 n
= strcspn(p
, separator
);
852 strchr(QUOTES
, p
[0]) &&
854 v
= strndup(p
+1, n
-2);
865 /* return empty value strings as NULL */
882 p
+= strcspn(p
, separator
);
901 if (!(f
= fopen(fname
, "re")))
905 char l
[LINE_MAX
], *p
, *u
;
908 if (!fgets(l
, sizeof(l
), f
)) {
921 if (strchr(COMMENTS
, *p
))
924 if (!(u
= normalize_env_assignment(p
))) {
925 log_error("Out of memory");
930 t
= strv_append(m
, u
);
934 log_error("Out of memory");
957 int write_env_file(const char *fname
, char **l
) {
962 r
= fopen_temporary(fname
, &f
, &p
);
966 fchmod_umask(fileno(f
), 0644);
982 if (rename(p
, fname
) < 0)
997 char *truncate_nl(char *s
) {
1000 s
[strcspn(s
, NEWLINE
)] = 0;
1004 int get_process_comm(pid_t pid
, char **name
) {
1010 r
= read_one_line_file("/proc/self/comm", name
);
1013 if (asprintf(&p
, "/proc/%lu/comm", (unsigned long) pid
) < 0)
1016 r
= read_one_line_file(p
, name
);
1023 int get_process_cmdline(pid_t pid
, size_t max_length
, bool comm_fallback
, char **line
) {
1030 assert(max_length
> 0);
1034 f
= fopen("/proc/self/cmdline", "re");
1037 if (asprintf(&p
, "/proc/%lu/cmdline", (unsigned long) pid
) < 0)
1047 r
= new(char, max_length
);
1055 while ((c
= getc(f
)) != EOF
) {
1077 size_t n
= MIN(left
-1, 3U);
1078 memcpy(k
, "...", n
);
1085 /* Kernel threads have no argv[] */
1095 h
= get_process_comm(pid
, &t
);
1099 r
= join("[", t
, "]", NULL
);
1110 int is_kernel_thread(pid_t pid
) {
1120 if (asprintf(&p
, "/proc/%lu/cmdline", (unsigned long) pid
) < 0)
1129 count
= fread(&c
, 1, 1, f
);
1133 /* Kernel threads have an empty cmdline */
1136 return eof
? 1 : -errno
;
1141 int get_process_exe(pid_t pid
, char **name
) {
1147 r
= readlink_malloc("/proc/self/exe", name
);
1150 if (asprintf(&p
, "/proc/%lu/exe", (unsigned long) pid
) < 0)
1153 r
= readlink_malloc(p
, name
);
1160 int get_process_uid(pid_t pid
, uid_t
*uid
) {
1170 if (asprintf(&p
, "/proc/%lu/status", (unsigned long) pid
) < 0)
1180 char line
[LINE_MAX
], *l
;
1182 if (!fgets(line
, sizeof(line
), f
)) {
1192 if (startswith(l
, "Uid:")) {
1194 l
+= strspn(l
, WHITESPACE
);
1196 l
[strcspn(l
, WHITESPACE
)] = 0;
1198 r
= parse_uid(l
, uid
);
1211 char *strnappend(const char *s
, const char *suffix
, size_t b
) {
1219 return strndup(suffix
, b
);
1229 if (!(r
= new(char, a
+b
+1)))
1233 memcpy(r
+a
, suffix
, b
);
1239 char *strappend(const char *s
, const char *suffix
) {
1240 return strnappend(s
, suffix
, suffix
? strlen(suffix
) : 0);
1243 int readlink_malloc(const char *p
, char **r
) {
1253 if (!(c
= new(char, l
)))
1256 if ((n
= readlink(p
, c
, l
-1)) < 0) {
1262 if ((size_t) n
< l
-1) {
1273 int readlink_and_make_absolute(const char *p
, char **r
) {
1280 if ((j
= readlink_malloc(p
, &target
)) < 0)
1283 k
= file_in_same_dir(p
, target
);
1293 int readlink_and_canonicalize(const char *p
, char **r
) {
1300 j
= readlink_and_make_absolute(p
, &t
);
1304 s
= canonicalize_file_name(t
);
1311 path_kill_slashes(*r
);
1316 int parent_of_path(const char *path
, char **_r
) {
1317 const char *e
, *a
= NULL
, *b
= NULL
, *p
;
1327 for (e
= path
; *e
; e
++) {
1329 if (!slash
&& *e
== '/') {
1333 } else if (slash
&& *e
!= '/')
1348 r
= strndup(path
, p
-path
);
1358 char *file_name_from_path(const char *p
) {
1363 if ((r
= strrchr(p
, '/')))
1369 bool path_is_absolute(const char *p
) {
1375 bool is_path(const char *p
) {
1377 return !!strchr(p
, '/');
1380 char *path_make_absolute(const char *p
, const char *prefix
) {
1383 /* Makes every item in the list an absolute path by prepending
1384 * the prefix, if specified and necessary */
1386 if (path_is_absolute(p
) || !prefix
)
1389 return join(prefix
, "/", p
, NULL
);
1392 char *path_make_absolute_cwd(const char *p
) {
1397 /* Similar to path_make_absolute(), but prefixes with the
1398 * current working directory. */
1400 if (path_is_absolute(p
))
1403 if (!(cwd
= get_current_dir_name()))
1406 r
= path_make_absolute(p
, cwd
);
1412 char **strv_path_make_absolute_cwd(char **l
) {
1415 /* Goes through every item in the string list and makes it
1416 * absolute. This works in place and won't rollback any
1417 * changes on failure. */
1419 STRV_FOREACH(s
, l
) {
1422 if (!(t
= path_make_absolute_cwd(*s
)))
1432 char **strv_path_canonicalize(char **l
) {
1435 bool enomem
= false;
1437 if (strv_isempty(l
))
1440 /* Goes through every item in the string list and canonicalize
1441 * the path. This works in place and won't rollback any
1442 * changes on failure. */
1444 STRV_FOREACH(s
, l
) {
1447 t
= path_make_absolute_cwd(*s
);
1456 u
= canonicalize_file_name(t
);
1460 if (errno
== ENOMEM
|| !errno
)
1477 char **strv_path_remove_empty(char **l
) {
1483 for (f
= t
= l
; *f
; f
++) {
1485 if (dir_is_empty(*f
) > 0) {
1497 int reset_all_signal_handlers(void) {
1500 for (sig
= 1; sig
< _NSIG
; sig
++) {
1501 struct sigaction sa
;
1503 if (sig
== SIGKILL
|| sig
== SIGSTOP
)
1507 sa
.sa_handler
= SIG_DFL
;
1508 sa
.sa_flags
= SA_RESTART
;
1510 /* On Linux the first two RT signals are reserved by
1511 * glibc, and sigaction() will return EINVAL for them. */
1512 if ((sigaction(sig
, &sa
, NULL
) < 0))
1513 if (errno
!= EINVAL
)
1520 char *strstrip(char *s
) {
1523 /* Drops trailing whitespace. Modifies the string in
1524 * place. Returns pointer to first non-space character */
1526 s
+= strspn(s
, WHITESPACE
);
1528 for (e
= strchr(s
, 0); e
> s
; e
--)
1529 if (!strchr(WHITESPACE
, e
[-1]))
1537 char *delete_chars(char *s
, const char *bad
) {
1540 /* Drops all whitespace, regardless where in the string */
1542 for (f
= s
, t
= s
; *f
; f
++) {
1543 if (strchr(bad
, *f
))
1554 bool in_charset(const char *s
, const char* charset
) {
1560 for (i
= s
; *i
; i
++)
1561 if (!strchr(charset
, *i
))
1567 char *file_in_same_dir(const char *path
, const char *filename
) {
1574 /* This removes the last component of path and appends
1575 * filename, unless the latter is absolute anyway or the
1578 if (path_is_absolute(filename
))
1579 return strdup(filename
);
1581 if (!(e
= strrchr(path
, '/')))
1582 return strdup(filename
);
1584 k
= strlen(filename
);
1585 if (!(r
= new(char, e
-path
+1+k
+1)))
1588 memcpy(r
, path
, e
-path
+1);
1589 memcpy(r
+(e
-path
)+1, filename
, k
+1);
1594 int safe_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
) {
1597 if (label_mkdir(path
, mode
) >= 0)
1598 if (chmod_and_chown(path
, mode
, uid
, gid
) < 0)
1601 if (lstat(path
, &st
) < 0)
1604 if ((st
.st_mode
& 0777) != mode
||
1607 !S_ISDIR(st
.st_mode
)) {
1616 int mkdir_parents(const char *path
, mode_t mode
) {
1621 /* Creates every parent directory in the path except the last
1624 p
= path
+ strspn(path
, "/");
1629 e
= p
+ strcspn(p
, "/");
1630 p
= e
+ strspn(e
, "/");
1632 /* Is this the last component? If so, then we're
1637 if (!(t
= strndup(path
, e
- path
)))
1640 r
= label_mkdir(t
, mode
);
1643 if (r
< 0 && errno
!= EEXIST
)
1648 int mkdir_p(const char *path
, mode_t mode
) {
1653 if ((r
= mkdir_parents(path
, mode
)) < 0)
1656 if (label_mkdir(path
, mode
) < 0 && errno
!= EEXIST
)
1662 int rmdir_parents(const char *path
, const char *stop
) {
1671 /* Skip trailing slashes */
1672 while (l
> 0 && path
[l
-1] == '/')
1678 /* Skip last component */
1679 while (l
> 0 && path
[l
-1] != '/')
1682 /* Skip trailing slashes */
1683 while (l
> 0 && path
[l
-1] == '/')
1689 if (!(t
= strndup(path
, l
)))
1692 if (path_startswith(stop
, t
)) {
1701 if (errno
!= ENOENT
)
1709 char hexchar(int x
) {
1710 static const char table
[16] = "0123456789abcdef";
1712 return table
[x
& 15];
1715 int unhexchar(char c
) {
1717 if (c
>= '0' && c
<= '9')
1720 if (c
>= 'a' && c
<= 'f')
1721 return c
- 'a' + 10;
1723 if (c
>= 'A' && c
<= 'F')
1724 return c
- 'A' + 10;
1729 char octchar(int x
) {
1730 return '0' + (x
& 7);
1733 int unoctchar(char c
) {
1735 if (c
>= '0' && c
<= '7')
1741 char decchar(int x
) {
1742 return '0' + (x
% 10);
1745 int undecchar(char c
) {
1747 if (c
>= '0' && c
<= '9')
1753 char *cescape(const char *s
) {
1759 /* Does C style string escaping. */
1761 if (!(r
= new(char, strlen(s
)*4 + 1)))
1764 for (f
= s
, t
= r
; *f
; f
++)
1810 /* For special chars we prefer octal over
1811 * hexadecimal encoding, simply because glib's
1812 * g_strescape() does the same */
1813 if ((*f
< ' ') || (*f
>= 127)) {
1815 *(t
++) = octchar((unsigned char) *f
>> 6);
1816 *(t
++) = octchar((unsigned char) *f
>> 3);
1817 *(t
++) = octchar((unsigned char) *f
);
1828 char *cunescape_length(const char *s
, size_t length
) {
1834 /* Undoes C style string escaping */
1836 if (!(r
= new(char, length
+1)))
1839 for (f
= s
, t
= r
; f
< s
+ length
; f
++) {
1882 /* This is an extension of the XDG syntax files */
1887 /* hexadecimal encoding */
1890 if ((a
= unhexchar(f
[1])) < 0 ||
1891 (b
= unhexchar(f
[2])) < 0) {
1892 /* Invalid escape code, let's take it literal then */
1896 *(t
++) = (char) ((a
<< 4) | b
);
1911 /* octal encoding */
1914 if ((a
= unoctchar(f
[0])) < 0 ||
1915 (b
= unoctchar(f
[1])) < 0 ||
1916 (c
= unoctchar(f
[2])) < 0) {
1917 /* Invalid escape code, let's take it literal then */
1921 *(t
++) = (char) ((a
<< 6) | (b
<< 3) | c
);
1929 /* premature end of string.*/
1934 /* Invalid escape code, let's take it literal then */
1946 char *cunescape(const char *s
) {
1947 return cunescape_length(s
, strlen(s
));
1950 char *xescape(const char *s
, const char *bad
) {
1954 /* Escapes all chars in bad, in addition to \ and all special
1955 * chars, in \xFF style escaping. May be reversed with
1958 if (!(r
= new(char, strlen(s
)*4+1)))
1961 for (f
= s
, t
= r
; *f
; f
++) {
1963 if ((*f
< ' ') || (*f
>= 127) ||
1964 (*f
== '\\') || strchr(bad
, *f
)) {
1967 *(t
++) = hexchar(*f
>> 4);
1968 *(t
++) = hexchar(*f
);
1978 char *bus_path_escape(const char *s
) {
1984 /* Escapes all chars that D-Bus' object path cannot deal
1985 * with. Can be reverse with bus_path_unescape() */
1987 if (!(r
= new(char, strlen(s
)*3+1)))
1990 for (f
= s
, t
= r
; *f
; f
++) {
1992 if (!(*f
>= 'A' && *f
<= 'Z') &&
1993 !(*f
>= 'a' && *f
<= 'z') &&
1994 !(*f
>= '0' && *f
<= '9')) {
1996 *(t
++) = hexchar(*f
>> 4);
1997 *(t
++) = hexchar(*f
);
2007 char *bus_path_unescape(const char *f
) {
2012 if (!(r
= strdup(f
)))
2015 for (t
= r
; *f
; f
++) {
2020 if ((a
= unhexchar(f
[1])) < 0 ||
2021 (b
= unhexchar(f
[2])) < 0) {
2022 /* Invalid escape code, let's take it literal then */
2025 *(t
++) = (char) ((a
<< 4) | b
);
2037 char *path_kill_slashes(char *path
) {
2041 /* Removes redundant inner and trailing slashes. Modifies the
2042 * passed string in-place.
2044 * ///foo///bar/ becomes /foo/bar
2047 for (f
= path
, t
= path
; *f
; f
++) {
2062 /* Special rule, if we are talking of the root directory, a
2063 trailing slash is good */
2065 if (t
== path
&& slash
)
2072 bool path_startswith(const char *path
, const char *prefix
) {
2076 if ((path
[0] == '/') != (prefix
[0] == '/'))
2082 path
+= strspn(path
, "/");
2083 prefix
+= strspn(prefix
, "/");
2091 a
= strcspn(path
, "/");
2092 b
= strcspn(prefix
, "/");
2097 if (memcmp(path
, prefix
, a
) != 0)
2105 bool path_equal(const char *a
, const char *b
) {
2109 if ((a
[0] == '/') != (b
[0] == '/'))
2115 a
+= strspn(a
, "/");
2116 b
+= strspn(b
, "/");
2118 if (*a
== 0 && *b
== 0)
2121 if (*a
== 0 || *b
== 0)
2124 j
= strcspn(a
, "/");
2125 k
= strcspn(b
, "/");
2130 if (memcmp(a
, b
, j
) != 0)
2138 char *ascii_strlower(char *t
) {
2143 for (p
= t
; *p
; p
++)
2144 if (*p
>= 'A' && *p
<= 'Z')
2145 *p
= *p
- 'A' + 'a';
2150 bool ignore_file(const char *filename
) {
2154 filename
[0] == '.' ||
2155 streq(filename
, "lost+found") ||
2156 streq(filename
, "aquota.user") ||
2157 streq(filename
, "aquota.group") ||
2158 endswith(filename
, "~") ||
2159 endswith(filename
, ".rpmnew") ||
2160 endswith(filename
, ".rpmsave") ||
2161 endswith(filename
, ".rpmorig") ||
2162 endswith(filename
, ".dpkg-old") ||
2163 endswith(filename
, ".dpkg-new") ||
2164 endswith(filename
, ".swp");
2167 int fd_nonblock(int fd
, bool nonblock
) {
2172 if ((flags
= fcntl(fd
, F_GETFL
, 0)) < 0)
2176 flags
|= O_NONBLOCK
;
2178 flags
&= ~O_NONBLOCK
;
2180 if (fcntl(fd
, F_SETFL
, flags
) < 0)
2186 int fd_cloexec(int fd
, bool cloexec
) {
2191 if ((flags
= fcntl(fd
, F_GETFD
, 0)) < 0)
2195 flags
|= FD_CLOEXEC
;
2197 flags
&= ~FD_CLOEXEC
;
2199 if (fcntl(fd
, F_SETFD
, flags
) < 0)
2205 int close_all_fds(const int except
[], unsigned n_except
) {
2210 if (!(d
= opendir("/proc/self/fd")))
2213 while ((de
= readdir(d
))) {
2216 if (ignore_file(de
->d_name
))
2219 if (safe_atoi(de
->d_name
, &fd
) < 0)
2220 /* Let's better ignore this, just in case */
2234 for (i
= 0; i
< n_except
; i
++)
2235 if (except
[i
] == fd
) {
2244 if (close_nointr(fd
) < 0) {
2245 /* Valgrind has its own FD and doesn't want to have it closed */
2246 if (errno
!= EBADF
&& r
== 0)
2255 bool chars_intersect(const char *a
, const char *b
) {
2258 /* Returns true if any of the chars in a are in b. */
2259 for (p
= a
; *p
; p
++)
2266 char *format_timestamp(char *buf
, size_t l
, usec_t t
) {
2276 sec
= (time_t) (t
/ USEC_PER_SEC
);
2278 if (strftime(buf
, l
, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec
, &tm
)) <= 0)
2284 char *format_timestamp_pretty(char *buf
, size_t l
, usec_t t
) {
2287 n
= now(CLOCK_REALTIME
);
2289 if (t
<= 0 || t
> n
|| t
+ USEC_PER_DAY
*7 <= t
)
2294 if (d
>= USEC_PER_YEAR
)
2295 snprintf(buf
, l
, "%llu years and %llu months ago",
2296 (unsigned long long) (d
/ USEC_PER_YEAR
),
2297 (unsigned long long) ((d
% USEC_PER_YEAR
) / USEC_PER_MONTH
));
2298 else if (d
>= USEC_PER_MONTH
)
2299 snprintf(buf
, l
, "%llu months and %llu days ago",
2300 (unsigned long long) (d
/ USEC_PER_MONTH
),
2301 (unsigned long long) ((d
% USEC_PER_MONTH
) / USEC_PER_DAY
));
2302 else if (d
>= USEC_PER_WEEK
)
2303 snprintf(buf
, l
, "%llu weeks and %llu days ago",
2304 (unsigned long long) (d
/ USEC_PER_WEEK
),
2305 (unsigned long long) ((d
% USEC_PER_WEEK
) / USEC_PER_DAY
));
2306 else if (d
>= 2*USEC_PER_DAY
)
2307 snprintf(buf
, l
, "%llu days ago", (unsigned long long) (d
/ USEC_PER_DAY
));
2308 else if (d
>= 25*USEC_PER_HOUR
)
2309 snprintf(buf
, l
, "1 day and %lluh ago",
2310 (unsigned long long) ((d
- USEC_PER_DAY
) / USEC_PER_HOUR
));
2311 else if (d
>= 6*USEC_PER_HOUR
)
2312 snprintf(buf
, l
, "%lluh ago",
2313 (unsigned long long) (d
/ USEC_PER_HOUR
));
2314 else if (d
>= USEC_PER_HOUR
)
2315 snprintf(buf
, l
, "%lluh %llumin ago",
2316 (unsigned long long) (d
/ USEC_PER_HOUR
),
2317 (unsigned long long) ((d
% USEC_PER_HOUR
) / USEC_PER_MINUTE
));
2318 else if (d
>= 5*USEC_PER_MINUTE
)
2319 snprintf(buf
, l
, "%llumin ago",
2320 (unsigned long long) (d
/ USEC_PER_MINUTE
));
2321 else if (d
>= USEC_PER_MINUTE
)
2322 snprintf(buf
, l
, "%llumin %llus ago",
2323 (unsigned long long) (d
/ USEC_PER_MINUTE
),
2324 (unsigned long long) ((d
% USEC_PER_MINUTE
) / USEC_PER_SEC
));
2325 else if (d
>= USEC_PER_SEC
)
2326 snprintf(buf
, l
, "%llus ago",
2327 (unsigned long long) (d
/ USEC_PER_SEC
));
2328 else if (d
>= USEC_PER_MSEC
)
2329 snprintf(buf
, l
, "%llums ago",
2330 (unsigned long long) (d
/ USEC_PER_MSEC
));
2332 snprintf(buf
, l
, "%lluus ago",
2333 (unsigned long long) d
);
2335 snprintf(buf
, l
, "now");
2341 char *format_timespan(char *buf
, size_t l
, usec_t t
) {
2342 static const struct {
2346 { "w", USEC_PER_WEEK
},
2347 { "d", USEC_PER_DAY
},
2348 { "h", USEC_PER_HOUR
},
2349 { "min", USEC_PER_MINUTE
},
2350 { "s", USEC_PER_SEC
},
2351 { "ms", USEC_PER_MSEC
},
2361 if (t
== (usec_t
) -1)
2365 snprintf(p
, l
, "0");
2370 /* The result of this function can be parsed with parse_usec */
2372 for (i
= 0; i
< ELEMENTSOF(table
); i
++) {
2376 if (t
< table
[i
].usec
)
2382 k
= snprintf(p
, l
, "%s%llu%s", p
> buf
? " " : "", (unsigned long long) (t
/ table
[i
].usec
), table
[i
].suffix
);
2383 n
= MIN((size_t) k
, l
);
2396 bool fstype_is_network(const char *fstype
) {
2397 static const char * const table
[] = {
2409 for (i
= 0; i
< ELEMENTSOF(table
); i
++)
2410 if (streq(table
[i
], fstype
))
2419 if ((fd
= open_terminal("/dev/tty0", O_RDWR
|O_NOCTTY
|O_CLOEXEC
)) < 0)
2424 TIOCL_GETKMSGREDIRECT
,
2428 if (ioctl(fd
, TIOCLINUX
, tiocl
) < 0) {
2433 vt
= tiocl
[0] <= 0 ? 1 : tiocl
[0];
2436 if (ioctl(fd
, VT_ACTIVATE
, vt
) < 0)
2440 close_nointr_nofail(fd
);
2444 int read_one_char(FILE *f
, char *ret
, usec_t t
, bool *need_nl
) {
2445 struct termios old_termios
, new_termios
;
2447 char line
[LINE_MAX
];
2452 if (tcgetattr(fileno(f
), &old_termios
) >= 0) {
2453 new_termios
= old_termios
;
2455 new_termios
.c_lflag
&= ~ICANON
;
2456 new_termios
.c_cc
[VMIN
] = 1;
2457 new_termios
.c_cc
[VTIME
] = 0;
2459 if (tcsetattr(fileno(f
), TCSADRAIN
, &new_termios
) >= 0) {
2462 if (t
!= (usec_t
) -1) {
2463 if (fd_wait_for_event(fileno(f
), POLLIN
, t
) <= 0) {
2464 tcsetattr(fileno(f
), TCSADRAIN
, &old_termios
);
2469 k
= fread(&c
, 1, 1, f
);
2471 tcsetattr(fileno(f
), TCSADRAIN
, &old_termios
);
2477 *need_nl
= c
!= '\n';
2484 if (t
!= (usec_t
) -1)
2485 if (fd_wait_for_event(fileno(f
), POLLIN
, t
) <= 0)
2488 if (!fgets(line
, sizeof(line
), f
))
2493 if (strlen(line
) != 1)
2503 int ask(char *ret
, const char *replies
, const char *text
, ...) {
2510 on_tty
= isatty(STDOUT_FILENO
);
2516 bool need_nl
= true;
2519 fputs(ANSI_HIGHLIGHT_ON
, stdout
);
2526 fputs(ANSI_HIGHLIGHT_OFF
, stdout
);
2530 r
= read_one_char(stdin
, &c
, (usec_t
) -1, &need_nl
);
2533 if (r
== -EBADMSG
) {
2534 puts("Bad input, please try again.");
2545 if (strchr(replies
, c
)) {
2550 puts("Read unexpected character, please try again.");
2554 int reset_terminal_fd(int fd
, bool switch_to_text
) {
2555 struct termios termios
;
2558 /* Set terminal to some sane defaults */
2562 /* We leave locked terminal attributes untouched, so that
2563 * Plymouth may set whatever it wants to set, and we don't
2564 * interfere with that. */
2566 /* Disable exclusive mode, just in case */
2567 ioctl(fd
, TIOCNXCL
);
2569 /* Switch to text mode */
2571 ioctl(fd
, KDSETMODE
, KD_TEXT
);
2573 /* Enable console unicode mode */
2574 ioctl(fd
, KDSKBMODE
, K_UNICODE
);
2576 if (tcgetattr(fd
, &termios
) < 0) {
2581 /* We only reset the stuff that matters to the software. How
2582 * hardware is set up we don't touch assuming that somebody
2583 * else will do that for us */
2585 termios
.c_iflag
&= ~(IGNBRK
| BRKINT
| ISTRIP
| INLCR
| IGNCR
| IUCLC
);
2586 termios
.c_iflag
|= ICRNL
| IMAXBEL
| IUTF8
;
2587 termios
.c_oflag
|= ONLCR
;
2588 termios
.c_cflag
|= CREAD
;
2589 termios
.c_lflag
= ISIG
| ICANON
| IEXTEN
| ECHO
| ECHOE
| ECHOK
| ECHOCTL
| ECHOPRT
| ECHOKE
;
2591 termios
.c_cc
[VINTR
] = 03; /* ^C */
2592 termios
.c_cc
[VQUIT
] = 034; /* ^\ */
2593 termios
.c_cc
[VERASE
] = 0177;
2594 termios
.c_cc
[VKILL
] = 025; /* ^X */
2595 termios
.c_cc
[VEOF
] = 04; /* ^D */
2596 termios
.c_cc
[VSTART
] = 021; /* ^Q */
2597 termios
.c_cc
[VSTOP
] = 023; /* ^S */
2598 termios
.c_cc
[VSUSP
] = 032; /* ^Z */
2599 termios
.c_cc
[VLNEXT
] = 026; /* ^V */
2600 termios
.c_cc
[VWERASE
] = 027; /* ^W */
2601 termios
.c_cc
[VREPRINT
] = 022; /* ^R */
2602 termios
.c_cc
[VEOL
] = 0;
2603 termios
.c_cc
[VEOL2
] = 0;
2605 termios
.c_cc
[VTIME
] = 0;
2606 termios
.c_cc
[VMIN
] = 1;
2608 if (tcsetattr(fd
, TCSANOW
, &termios
) < 0)
2612 /* Just in case, flush all crap out */
2613 tcflush(fd
, TCIOFLUSH
);
2618 int reset_terminal(const char *name
) {
2621 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
2625 r
= reset_terminal_fd(fd
, true);
2626 close_nointr_nofail(fd
);
2631 int open_terminal(const char *name
, int mode
) {
2636 * If a TTY is in the process of being closed opening it might
2637 * cause EIO. This is horribly awful, but unlikely to be
2638 * changed in the kernel. Hence we work around this problem by
2639 * retrying a couple of times.
2641 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
2645 if ((fd
= open(name
, mode
)) >= 0)
2654 usleep(50 * USEC_PER_MSEC
);
2661 if ((r
= isatty(fd
)) < 0) {
2662 close_nointr_nofail(fd
);
2667 close_nointr_nofail(fd
);
2674 int flush_fd(int fd
) {
2675 struct pollfd pollfd
;
2679 pollfd
.events
= POLLIN
;
2686 if ((r
= poll(&pollfd
, 1, 0)) < 0) {
2697 if ((l
= read(fd
, buf
, sizeof(buf
))) < 0) {
2702 if (errno
== EAGAIN
)
2713 int acquire_terminal(const char *name
, bool fail
, bool force
, bool ignore_tiocstty_eperm
) {
2714 int fd
= -1, notify
= -1, r
, wd
= -1;
2718 /* We use inotify to be notified when the tty is closed. We
2719 * create the watch before checking if we can actually acquire
2720 * it, so that we don't lose any event.
2722 * Note: strictly speaking this actually watches for the
2723 * device being closed, it does *not* really watch whether a
2724 * tty loses its controlling process. However, unless some
2725 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
2726 * its tty otherwise this will not become a problem. As long
2727 * as the administrator makes sure not configure any service
2728 * on the same tty as an untrusted user this should not be a
2729 * problem. (Which he probably should not do anyway.) */
2731 if (!fail
&& !force
) {
2732 if ((notify
= inotify_init1(IN_CLOEXEC
)) < 0) {
2737 if ((wd
= inotify_add_watch(notify
, name
, IN_CLOSE
)) < 0) {
2745 if ((r
= flush_fd(notify
)) < 0)
2748 /* We pass here O_NOCTTY only so that we can check the return
2749 * value TIOCSCTTY and have a reliable way to figure out if we
2750 * successfully became the controlling process of the tty */
2751 if ((fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
)) < 0)
2754 /* First, try to get the tty */
2755 r
= ioctl(fd
, TIOCSCTTY
, force
);
2757 /* Sometimes it makes sense to ignore TIOCSCTTY
2758 * returning EPERM, i.e. when very likely we already
2759 * are have this controlling terminal. */
2760 if (r
< 0 && errno
== EPERM
&& ignore_tiocstty_eperm
)
2763 if (r
< 0 && (force
|| fail
|| errno
!= EPERM
)) {
2773 assert(notify
>= 0);
2776 uint8_t inotify_buffer
[sizeof(struct inotify_event
) + FILENAME_MAX
];
2778 struct inotify_event
*e
;
2780 if ((l
= read(notify
, inotify_buffer
, sizeof(inotify_buffer
))) < 0) {
2789 e
= (struct inotify_event
*) inotify_buffer
;
2794 if (e
->wd
!= wd
|| !(e
->mask
& IN_CLOSE
)) {
2799 step
= sizeof(struct inotify_event
) + e
->len
;
2800 assert(step
<= (size_t) l
);
2802 e
= (struct inotify_event
*) ((uint8_t*) e
+ step
);
2809 /* We close the tty fd here since if the old session
2810 * ended our handle will be dead. It's important that
2811 * we do this after sleeping, so that we don't enter
2812 * an endless loop. */
2813 close_nointr_nofail(fd
);
2817 close_nointr_nofail(notify
);
2819 r
= reset_terminal_fd(fd
, true);
2821 log_warning("Failed to reset terminal: %s", strerror(-r
));
2827 close_nointr_nofail(fd
);
2830 close_nointr_nofail(notify
);
2835 int release_terminal(void) {
2837 struct sigaction sa_old
, sa_new
;
2839 if ((fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_NDELAY
|O_CLOEXEC
)) < 0)
2842 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
2843 * by our own TIOCNOTTY */
2846 sa_new
.sa_handler
= SIG_IGN
;
2847 sa_new
.sa_flags
= SA_RESTART
;
2848 assert_se(sigaction(SIGHUP
, &sa_new
, &sa_old
) == 0);
2850 if (ioctl(fd
, TIOCNOTTY
) < 0)
2853 assert_se(sigaction(SIGHUP
, &sa_old
, NULL
) == 0);
2855 close_nointr_nofail(fd
);
2859 int sigaction_many(const struct sigaction
*sa
, ...) {
2864 while ((sig
= va_arg(ap
, int)) > 0)
2865 if (sigaction(sig
, sa
, NULL
) < 0)
2872 int ignore_signals(int sig
, ...) {
2873 struct sigaction sa
;
2878 sa
.sa_handler
= SIG_IGN
;
2879 sa
.sa_flags
= SA_RESTART
;
2881 if (sigaction(sig
, &sa
, NULL
) < 0)
2885 while ((sig
= va_arg(ap
, int)) > 0)
2886 if (sigaction(sig
, &sa
, NULL
) < 0)
2893 int default_signals(int sig
, ...) {
2894 struct sigaction sa
;
2899 sa
.sa_handler
= SIG_DFL
;
2900 sa
.sa_flags
= SA_RESTART
;
2902 if (sigaction(sig
, &sa
, NULL
) < 0)
2906 while ((sig
= va_arg(ap
, int)) > 0)
2907 if (sigaction(sig
, &sa
, NULL
) < 0)
2914 int close_pipe(int p
[]) {
2920 a
= close_nointr(p
[0]);
2925 b
= close_nointr(p
[1]);
2929 return a
< 0 ? a
: b
;
2932 ssize_t
loop_read(int fd
, void *buf
, size_t nbytes
, bool do_poll
) {
2941 while (nbytes
> 0) {
2944 if ((k
= read(fd
, p
, nbytes
)) <= 0) {
2946 if (k
< 0 && errno
== EINTR
)
2949 if (k
< 0 && errno
== EAGAIN
&& do_poll
) {
2950 struct pollfd pollfd
;
2954 pollfd
.events
= POLLIN
;
2956 if (poll(&pollfd
, 1, -1) < 0) {
2960 return n
> 0 ? n
: -errno
;
2963 if (pollfd
.revents
!= POLLIN
)
2964 return n
> 0 ? n
: -EIO
;
2969 return n
> 0 ? n
: (k
< 0 ? -errno
: 0);
2980 ssize_t
loop_write(int fd
, const void *buf
, size_t nbytes
, bool do_poll
) {
2989 while (nbytes
> 0) {
2992 k
= write(fd
, p
, nbytes
);
2995 if (k
< 0 && errno
== EINTR
)
2998 if (k
< 0 && errno
== EAGAIN
&& do_poll
) {
2999 struct pollfd pollfd
;
3003 pollfd
.events
= POLLOUT
;
3005 if (poll(&pollfd
, 1, -1) < 0) {
3009 return n
> 0 ? n
: -errno
;
3012 if (pollfd
.revents
!= POLLOUT
)
3013 return n
> 0 ? n
: -EIO
;
3018 return n
> 0 ? n
: (k
< 0 ? -errno
: 0);
3029 int path_is_mount_point(const char *t
, bool allow_symlink
) {
3040 if (errno
== ENOENT
)
3046 r
= parent_of_path(t
, &parent
);
3050 r
= lstat(parent
, &b
);
3056 return a
.st_dev
!= b
.st_dev
;
3059 int parse_usec(const char *t
, usec_t
*usec
) {
3060 static const struct {
3064 { "sec", USEC_PER_SEC
},
3065 { "s", USEC_PER_SEC
},
3066 { "min", USEC_PER_MINUTE
},
3067 { "hr", USEC_PER_HOUR
},
3068 { "h", USEC_PER_HOUR
},
3069 { "d", USEC_PER_DAY
},
3070 { "w", USEC_PER_WEEK
},
3071 { "msec", USEC_PER_MSEC
},
3072 { "ms", USEC_PER_MSEC
},
3073 { "m", USEC_PER_MINUTE
},
3076 { "", USEC_PER_SEC
},
3092 l
= strtoll(p
, &e
, 10);
3103 e
+= strspn(e
, WHITESPACE
);
3105 for (i
= 0; i
< ELEMENTSOF(table
); i
++)
3106 if (startswith(e
, table
[i
].suffix
)) {
3107 r
+= (usec_t
) l
* table
[i
].usec
;
3108 p
= e
+ strlen(table
[i
].suffix
);
3112 if (i
>= ELEMENTSOF(table
))
3122 int parse_bytes(const char *t
, off_t
*bytes
) {
3123 static const struct {
3129 { "M", 1024ULL*1024ULL },
3130 { "G", 1024ULL*1024ULL*1024ULL },
3131 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
3132 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
3133 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
3150 l
= strtoll(p
, &e
, 10);
3161 e
+= strspn(e
, WHITESPACE
);
3163 for (i
= 0; i
< ELEMENTSOF(table
); i
++)
3164 if (startswith(e
, table
[i
].suffix
)) {
3165 r
+= (off_t
) l
* table
[i
].factor
;
3166 p
= e
+ strlen(table
[i
].suffix
);
3170 if (i
>= ELEMENTSOF(table
))
3180 int make_stdio(int fd
) {
3185 r
= dup2(fd
, STDIN_FILENO
);
3186 s
= dup2(fd
, STDOUT_FILENO
);
3187 t
= dup2(fd
, STDERR_FILENO
);
3190 close_nointr_nofail(fd
);
3192 if (r
< 0 || s
< 0 || t
< 0)
3195 fd_cloexec(STDIN_FILENO
, false);
3196 fd_cloexec(STDOUT_FILENO
, false);
3197 fd_cloexec(STDERR_FILENO
, false);
3202 int make_null_stdio(void) {
3205 if ((null_fd
= open("/dev/null", O_RDWR
|O_NOCTTY
)) < 0)
3208 return make_stdio(null_fd
);
3211 bool is_device_path(const char *path
) {
3213 /* Returns true on paths that refer to a device, either in
3214 * sysfs or in /dev */
3217 path_startswith(path
, "/dev/") ||
3218 path_startswith(path
, "/sys/");
3221 int dir_is_empty(const char *path
) {
3224 struct dirent buf
, *de
;
3226 if (!(d
= opendir(path
)))
3230 if ((r
= readdir_r(d
, &buf
, &de
)) > 0) {
3240 if (!ignore_file(de
->d_name
)) {
3250 unsigned long long random_ull(void) {
3255 if ((fd
= open("/dev/urandom", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
)) < 0)
3258 r
= loop_read(fd
, &ull
, sizeof(ull
), true);
3259 close_nointr_nofail(fd
);
3261 if (r
!= sizeof(ull
))
3267 return random() * RAND_MAX
+ random();
3270 void rename_process(const char name
[8]) {
3273 /* This is a like a poor man's setproctitle(). It changes the
3274 * comm field, argv[0], and also the glibc's internally used
3275 * name of the process. For the first one a limit of 16 chars
3276 * applies, to the second one usually one of 10 (i.e. length
3277 * of "/sbin/init"), to the third one one of 7 (i.e. length of
3278 * "systemd"). If you pass a longer string it will be
3281 prctl(PR_SET_NAME
, name
);
3283 if (program_invocation_name
)
3284 strncpy(program_invocation_name
, name
, strlen(program_invocation_name
));
3286 if (saved_argc
> 0) {
3290 strncpy(saved_argv
[0], name
, strlen(saved_argv
[0]));
3292 for (i
= 1; i
< saved_argc
; i
++) {
3296 memset(saved_argv
[i
], 0, strlen(saved_argv
[i
]));
3301 void sigset_add_many(sigset_t
*ss
, ...) {
3308 while ((sig
= va_arg(ap
, int)) > 0)
3309 assert_se(sigaddset(ss
, sig
) == 0);
3313 char* gethostname_malloc(void) {
3316 assert_se(uname(&u
) >= 0);
3319 return strdup(u
.nodename
);
3321 return strdup(u
.sysname
);
3324 char* getlogname_malloc(void) {
3328 struct passwd pwbuf
, *pw
= NULL
;
3331 if (isatty(STDIN_FILENO
) && fstat(STDIN_FILENO
, &st
) >= 0)
3336 /* Shortcut things to avoid NSS lookups */
3338 return strdup("root");
3340 if ((bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
)) <= 0)
3343 if (!(buf
= malloc(bufsize
)))
3346 if (getpwuid_r(uid
, &pwbuf
, buf
, bufsize
, &pw
) == 0 && pw
) {
3347 name
= strdup(pw
->pw_name
);
3354 if (asprintf(&name
, "%lu", (unsigned long) uid
) < 0)
3360 int getttyname_malloc(int fd
, char **r
) {
3361 char path
[PATH_MAX
], *c
;
3366 if ((k
= ttyname_r(fd
, path
, sizeof(path
))) != 0)
3371 if (!(c
= strdup(startswith(path
, "/dev/") ? path
+ 5 : path
)))
3378 int getttyname_harder(int fd
, char **r
) {
3382 if ((k
= getttyname_malloc(fd
, &s
)) < 0)
3385 if (streq(s
, "tty")) {
3387 return get_ctty(0, NULL
, r
);
3394 int get_ctty_devnr(pid_t pid
, dev_t
*d
) {
3396 char line
[LINE_MAX
], *p
, *fn
;
3397 unsigned long ttynr
;
3400 if (asprintf(&fn
, "/proc/%lu/stat", (unsigned long) (pid
<= 0 ? getpid() : pid
)) < 0)
3403 f
= fopen(fn
, "re");
3408 if (!fgets(line
, sizeof(line
), f
)) {
3409 k
= feof(f
) ? -EIO
: -errno
;
3416 p
= strrchr(line
, ')');
3426 "%*d " /* session */
3435 int get_ctty(pid_t pid
, dev_t
*_devnr
, char **r
) {
3437 char fn
[PATH_MAX
], *s
, *b
, *p
;
3442 k
= get_ctty_devnr(pid
, &devnr
);
3446 snprintf(fn
, sizeof(fn
), "/dev/char/%u:%u", major(devnr
), minor(devnr
));
3449 if ((k
= readlink_malloc(fn
, &s
)) < 0) {
3454 /* This is an ugly hack */
3455 if (major(devnr
) == 136) {
3456 if (asprintf(&b
, "pts/%lu", (unsigned long) minor(devnr
)) < 0)
3466 /* Probably something like the ptys which have no
3467 * symlink in /dev/char. Let's return something
3468 * vaguely useful. */
3470 if (!(b
= strdup(fn
+ 5)))
3480 if (startswith(s
, "/dev/"))
3482 else if (startswith(s
, "../"))
3500 static int rm_rf_children(int fd
, bool only_dirs
, bool honour_sticky
) {
3506 /* This returns the first error we run into, but nevertheless
3509 if (!(d
= fdopendir(fd
))) {
3510 close_nointr_nofail(fd
);
3512 return errno
== ENOENT
? 0 : -errno
;
3516 struct dirent buf
, *de
;
3517 bool is_dir
, keep_around
= false;
3520 if ((r
= readdir_r(d
, &buf
, &de
)) != 0) {
3529 if (streq(de
->d_name
, ".") || streq(de
->d_name
, ".."))
3532 if (de
->d_type
== DT_UNKNOWN
) {
3535 if (fstatat(fd
, de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
3536 if (ret
== 0 && errno
!= ENOENT
)
3543 (st
.st_uid
== 0 || st
.st_uid
== getuid()) &&
3544 (st
.st_mode
& S_ISVTX
);
3546 is_dir
= S_ISDIR(st
.st_mode
);
3549 if (honour_sticky
) {
3552 if (fstatat(fd
, de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
3553 if (ret
== 0 && errno
!= ENOENT
)
3559 (st
.st_uid
== 0 || st
.st_uid
== getuid()) &&
3560 (st
.st_mode
& S_ISVTX
);
3563 is_dir
= de
->d_type
== DT_DIR
;
3569 if ((subdir_fd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
)) < 0) {
3570 if (ret
== 0 && errno
!= ENOENT
)
3575 if ((r
= rm_rf_children(subdir_fd
, only_dirs
, honour_sticky
)) < 0) {
3581 if (unlinkat(fd
, de
->d_name
, AT_REMOVEDIR
) < 0) {
3582 if (ret
== 0 && errno
!= ENOENT
)
3586 } else if (!only_dirs
&& !keep_around
) {
3588 if (unlinkat(fd
, de
->d_name
, 0) < 0) {
3589 if (ret
== 0 && errno
!= ENOENT
)
3600 int rm_rf(const char *path
, bool only_dirs
, bool delete_root
, bool honour_sticky
) {
3606 if ((fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
)) < 0) {
3608 if (errno
!= ENOTDIR
)
3611 if (delete_root
&& !only_dirs
)
3612 if (unlink(path
) < 0)
3618 r
= rm_rf_children(fd
, only_dirs
, honour_sticky
);
3622 if (honour_sticky
&& file_is_priv_sticky(path
) > 0)
3625 if (rmdir(path
) < 0 && errno
!= ENOENT
) {
3634 int chmod_and_chown(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
) {
3637 /* Under the assumption that we are running privileged we
3638 * first change the access mode and only then hand out
3639 * ownership to avoid a window where access is too open. */
3641 if (mode
!= (mode_t
) -1)
3642 if (chmod(path
, mode
) < 0)
3645 if (uid
!= (uid_t
) -1 || gid
!= (gid_t
) -1)
3646 if (chown(path
, uid
, gid
) < 0)
3652 int fchmod_and_fchown(int fd
, mode_t mode
, uid_t uid
, gid_t gid
) {
3655 /* Under the assumption that we are running privileged we
3656 * first change the access mode and only then hand out
3657 * ownership to avoid a window where access is too open. */
3659 if (fchmod(fd
, mode
) < 0)
3662 if (fchown(fd
, uid
, gid
) < 0)
3668 cpu_set_t
* cpu_set_malloc(unsigned *ncpus
) {
3672 /* Allocates the cpuset in the right size */
3675 if (!(r
= CPU_ALLOC(n
)))
3678 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n
), r
) >= 0) {
3679 CPU_ZERO_S(CPU_ALLOC_SIZE(n
), r
);
3689 if (errno
!= EINVAL
)
3696 void status_vprintf(const char *status
, bool ellipse
, const char *format
, va_list ap
) {
3697 char *s
= NULL
, *spaces
= NULL
, *e
;
3699 size_t emax
, sl
, left
;
3700 struct iovec iovec
[5];
3705 /* This independent of logging, as status messages are
3706 * optional and go exclusively to the console. */
3708 if (vasprintf(&s
, format
, ap
) < 0)
3711 fd
= open_terminal("/dev/console", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
3721 sl
= 2 + 6 + 1; /* " [" status "]" */
3722 emax
= (size_t) c
> sl
? c
- sl
- 1 : 0;
3726 e
= ellipsize(s
, emax
, 75);
3734 IOVEC_SET_STRING(iovec
[n
++], s
);
3738 left
= emax
> sl
? emax
- sl
: 0;
3740 spaces
= malloc(left
);
3742 memset(spaces
, ' ', left
);
3743 iovec
[n
].iov_base
= spaces
;
3744 iovec
[n
].iov_len
= left
;
3751 IOVEC_SET_STRING(iovec
[n
++], " [");
3752 IOVEC_SET_STRING(iovec
[n
++], status
);
3753 IOVEC_SET_STRING(iovec
[n
++], "]\n");
3755 IOVEC_SET_STRING(iovec
[n
++], "\n");
3757 writev(fd
, iovec
, n
);
3764 close_nointr_nofail(fd
);
3767 void status_printf(const char *status
, bool ellipse
, const char *format
, ...) {
3772 va_start(ap
, format
);
3773 status_vprintf(status
, ellipse
, format
, ap
);
3777 void status_welcome(void) {
3778 char *pretty_name
= NULL
, *ansi_color
= NULL
;
3779 const char *const_pretty
= NULL
, *const_color
= NULL
;
3782 if ((r
= parse_env_file("/etc/os-release", NEWLINE
,
3783 "PRETTY_NAME", &pretty_name
,
3784 "ANSI_COLOR", &ansi_color
,
3788 log_warning("Failed to read /etc/os-release: %s", strerror(-r
));
3791 if (!pretty_name
&& !const_pretty
)
3792 const_pretty
= "Linux";
3794 if (!ansi_color
&& !const_color
)
3799 "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
3800 const_color
? const_color
: ansi_color
,
3801 const_pretty
? const_pretty
: pretty_name
);
3807 char *replace_env(const char *format
, char **env
) {
3814 const char *e
, *word
= format
;
3819 for (e
= format
; *e
; e
++) {
3830 if (!(k
= strnappend(r
, word
, e
-word
-1)))
3839 } else if (*e
== '$') {
3840 if (!(k
= strnappend(r
, word
, e
-word
)))
3856 if (!(t
= strv_env_get_with_length(env
, word
+2, e
-word
-2)))
3859 if (!(k
= strappend(r
, t
)))
3872 if (!(k
= strnappend(r
, word
, e
-word
)))
3883 char **replace_env_argv(char **argv
, char **env
) {
3885 unsigned k
= 0, l
= 0;
3887 l
= strv_length(argv
);
3889 if (!(r
= new(char*, l
+1)))
3892 STRV_FOREACH(i
, argv
) {
3894 /* If $FOO appears as single word, replace it by the split up variable */
3895 if ((*i
)[0] == '$' && (*i
)[1] != '{') {
3900 if ((e
= strv_env_get(env
, *i
+1))) {
3902 if (!(m
= strv_split_quoted(e
))) {
3913 if (!(w
= realloc(r
, sizeof(char*) * (l
+1)))) {
3922 memcpy(r
+ k
, m
, q
* sizeof(char*));
3930 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
3931 if (!(r
[k
++] = replace_env(*i
, env
))) {
3941 int fd_columns(int fd
) {
3945 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
3954 unsigned columns(void) {
3955 static __thread
int parsed_columns
= 0;
3958 if (_likely_(parsed_columns
> 0))
3959 return parsed_columns
;
3961 e
= getenv("COLUMNS");
3963 parsed_columns
= atoi(e
);
3965 if (parsed_columns
<= 0)
3966 parsed_columns
= fd_columns(STDOUT_FILENO
);
3968 if (parsed_columns
<= 0)
3969 parsed_columns
= 80;
3971 return parsed_columns
;
3974 int fd_lines(int fd
) {
3978 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
3987 unsigned lines(void) {
3988 static __thread
int parsed_lines
= 0;
3991 if (_likely_(parsed_lines
> 0))
3992 return parsed_lines
;
3994 e
= getenv("LINES");
3996 parsed_lines
= atoi(e
);
3998 if (parsed_lines
<= 0)
3999 parsed_lines
= fd_lines(STDOUT_FILENO
);
4001 if (parsed_lines
<= 0)
4004 return parsed_lines
;
4007 int running_in_chroot(void) {
4013 /* Only works as root */
4015 if (stat("/proc/1/root", &a
) < 0)
4018 if (stat("/", &b
) < 0)
4022 a
.st_dev
!= b
.st_dev
||
4023 a
.st_ino
!= b
.st_ino
;
4026 char *ellipsize_mem(const char *s
, size_t old_length
, size_t new_length
, unsigned percent
) {
4031 assert(percent
<= 100);
4032 assert(new_length
>= 3);
4034 if (old_length
<= 3 || old_length
<= new_length
)
4035 return strndup(s
, old_length
);
4037 r
= new0(char, new_length
+1);
4041 x
= (new_length
* percent
) / 100;
4043 if (x
> new_length
- 3)
4051 s
+ old_length
- (new_length
- x
- 3),
4052 new_length
- x
- 3);
4057 char *ellipsize(const char *s
, size_t length
, unsigned percent
) {
4058 return ellipsize_mem(s
, strlen(s
), length
, percent
);
4061 int touch(const char *path
) {
4066 if ((fd
= open(path
, O_WRONLY
|O_CREAT
|O_CLOEXEC
|O_NOCTTY
, 0644)) < 0)
4069 close_nointr_nofail(fd
);
4073 char *unquote(const char *s
, const char* quotes
) {
4081 if (strchr(quotes
, s
[0]) && s
[l
-1] == s
[0])
4082 return strndup(s
+1, l
-2);
4087 char *normalize_env_assignment(const char *s
) {
4088 char *name
, *value
, *p
, *r
;
4093 if (!(r
= strdup(s
)))
4099 if (!(name
= strndup(s
, p
- s
)))
4102 if (!(p
= strdup(p
+1))) {
4107 value
= unquote(strstrip(p
), QUOTES
);
4115 if (asprintf(&r
, "%s=%s", name
, value
) < 0)
4124 int wait_for_terminate(pid_t pid
, siginfo_t
*status
) {
4135 if (waitid(P_PID
, pid
, status
, WEXITED
) < 0) {
4147 int wait_for_terminate_and_warn(const char *name
, pid_t pid
) {
4154 if ((r
= wait_for_terminate(pid
, &status
)) < 0) {
4155 log_warning("Failed to wait for %s: %s", name
, strerror(-r
));
4159 if (status
.si_code
== CLD_EXITED
) {
4160 if (status
.si_status
!= 0) {
4161 log_warning("%s failed with error code %i.", name
, status
.si_status
);
4162 return status
.si_status
;
4165 log_debug("%s succeeded.", name
);
4168 } else if (status
.si_code
== CLD_KILLED
||
4169 status
.si_code
== CLD_DUMPED
) {
4171 log_warning("%s terminated by signal %s.", name
, signal_to_string(status
.si_status
));
4175 log_warning("%s failed due to unknown reason.", name
);
4180 _noreturn_
void freeze(void) {
4182 /* Make sure nobody waits for us on a socket anymore */
4183 close_all_fds(NULL
, 0);
4191 bool null_or_empty(struct stat
*st
) {
4194 if (S_ISREG(st
->st_mode
) && st
->st_size
<= 0)
4197 if (S_ISCHR(st
->st_mode
) || S_ISBLK(st
->st_mode
))
4203 int null_or_empty_path(const char *fn
) {
4208 if (stat(fn
, &st
) < 0)
4211 return null_or_empty(&st
);
4214 DIR *xopendirat(int fd
, const char *name
, int flags
) {
4218 if ((nfd
= openat(fd
, name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|flags
)) < 0)
4221 if (!(d
= fdopendir(nfd
))) {
4222 close_nointr_nofail(nfd
);
4229 int signal_from_string_try_harder(const char *s
) {
4233 if ((signo
= signal_from_string(s
)) <= 0)
4234 if (startswith(s
, "SIG"))
4235 return signal_from_string(s
+3);
4240 void dual_timestamp_serialize(FILE *f
, const char *name
, dual_timestamp
*t
) {
4246 if (!dual_timestamp_is_set(t
))
4249 fprintf(f
, "%s=%llu %llu\n",
4251 (unsigned long long) t
->realtime
,
4252 (unsigned long long) t
->monotonic
);
4255 void dual_timestamp_deserialize(const char *value
, dual_timestamp
*t
) {
4256 unsigned long long a
, b
;
4261 if (sscanf(value
, "%lli %llu", &a
, &b
) != 2)
4262 log_debug("Failed to parse finish timestamp value %s", value
);
4269 char *fstab_node_to_udev_node(const char *p
) {
4273 /* FIXME: to follow udev's logic 100% we need to leave valid
4274 * UTF8 chars unescaped */
4276 if (startswith(p
, "LABEL=")) {
4278 if (!(u
= unquote(p
+6, "\"\'")))
4281 t
= xescape(u
, "/ ");
4287 r
= asprintf(&dn
, "/dev/disk/by-label/%s", t
);
4296 if (startswith(p
, "UUID=")) {
4298 if (!(u
= unquote(p
+5, "\"\'")))
4301 t
= xescape(u
, "/ ");
4307 r
= asprintf(&dn
, "/dev/disk/by-uuid/%s", t
);
4319 void filter_environ(const char *prefix
) {
4326 for (i
= 0, j
= 0; environ
[i
]; i
++) {
4328 if (startswith(environ
[i
], prefix
))
4331 environ
[j
++] = environ
[i
];
4337 bool tty_is_vc(const char *tty
) {
4340 if (startswith(tty
, "/dev/"))
4343 return vtnr_from_tty(tty
) >= 0;
4346 int vtnr_from_tty(const char *tty
) {
4351 if (startswith(tty
, "/dev/"))
4354 if (!startswith(tty
, "tty") )
4357 if (tty
[3] < '0' || tty
[3] > '9')
4360 r
= safe_atoi(tty
+3, &i
);
4364 if (i
< 0 || i
> 63)
4370 bool tty_is_vc_resolve(const char *tty
) {
4371 char *active
= NULL
;
4376 if (startswith(tty
, "/dev/"))
4379 /* Resolve where /dev/console is pointing to */
4380 if (streq(tty
, "console"))
4381 if (read_one_line_file("/sys/class/tty/console/active", &active
) >= 0) {
4382 /* If multiple log outputs are configured the
4383 * last one is what /dev/console points to */
4384 tty
= strrchr(active
, ' ');
4397 const char *default_term_for_tty(const char *tty
) {
4400 return tty_is_vc_resolve(tty
) ? "TERM=linux" : "TERM=vt100";
4403 bool dirent_is_file(const struct dirent
*de
) {
4406 if (ignore_file(de
->d_name
))
4409 if (de
->d_type
!= DT_REG
&&
4410 de
->d_type
!= DT_LNK
&&
4411 de
->d_type
!= DT_UNKNOWN
)
4417 bool dirent_is_file_with_suffix(const struct dirent
*de
, const char *suffix
) {
4420 if (!dirent_is_file(de
))
4423 return endswith(de
->d_name
, suffix
);
4426 void execute_directory(const char *directory
, DIR *d
, char *argv
[]) {
4429 Hashmap
*pids
= NULL
;
4433 /* Executes all binaries in a directory in parallel and waits
4434 * until all they all finished. */
4437 if (!(_d
= opendir(directory
))) {
4439 if (errno
== ENOENT
)
4442 log_error("Failed to enumerate directory %s: %m", directory
);
4449 if (!(pids
= hashmap_new(trivial_hash_func
, trivial_compare_func
))) {
4450 log_error("Failed to allocate set.");
4454 while ((de
= readdir(d
))) {
4459 if (!dirent_is_file(de
))
4462 if (asprintf(&path
, "%s/%s", directory
, de
->d_name
) < 0) {
4463 log_error("Out of memory");
4467 if ((pid
= fork()) < 0) {
4468 log_error("Failed to fork: %m");
4487 log_error("Failed to execute %s: %m", path
);
4488 _exit(EXIT_FAILURE
);
4491 log_debug("Spawned %s as %lu", path
, (unsigned long) pid
);
4493 if ((k
= hashmap_put(pids
, UINT_TO_PTR(pid
), path
)) < 0) {
4494 log_error("Failed to add PID to set: %s", strerror(-k
));
4499 while (!hashmap_isempty(pids
)) {
4500 pid_t pid
= PTR_TO_UINT(hashmap_first_key(pids
));
4505 if (waitid(P_PID
, pid
, &si
, WEXITED
) < 0) {
4510 log_error("waitid() failed: %m");
4514 if ((path
= hashmap_remove(pids
, UINT_TO_PTR(si
.si_pid
)))) {
4515 if (!is_clean_exit(si
.si_code
, si
.si_status
)) {
4516 if (si
.si_code
== CLD_EXITED
)
4517 log_error("%s exited with exit status %i.", path
, si
.si_status
);
4519 log_error("%s terminated by signal %s.", path
, signal_to_string(si
.si_status
));
4521 log_debug("%s exited successfully.", path
);
4532 hashmap_free_free(pids
);
4535 int kill_and_sigcont(pid_t pid
, int sig
) {
4538 r
= kill(pid
, sig
) < 0 ? -errno
: 0;
4546 bool nulstr_contains(const char*nulstr
, const char *needle
) {
4552 NULSTR_FOREACH(i
, nulstr
)
4553 if (streq(i
, needle
))
4559 bool plymouth_running(void) {
4560 return access("/run/plymouth/pid", F_OK
) >= 0;
4563 void parse_syslog_priority(char **p
, int *priority
) {
4564 int a
= 0, b
= 0, c
= 0;
4574 if (!strchr(*p
, '>'))
4577 if ((*p
)[2] == '>') {
4578 c
= undecchar((*p
)[1]);
4580 } else if ((*p
)[3] == '>') {
4581 b
= undecchar((*p
)[1]);
4582 c
= undecchar((*p
)[2]);
4584 } else if ((*p
)[4] == '>') {
4585 a
= undecchar((*p
)[1]);
4586 b
= undecchar((*p
)[2]);
4587 c
= undecchar((*p
)[3]);
4592 if (a
< 0 || b
< 0 || c
< 0)
4595 *priority
= a
*100+b
*10+c
;
4599 void skip_syslog_pid(char **buf
) {
4611 p
+= strspn(p
, "0123456789");
4621 void skip_syslog_date(char **buf
) {
4629 LETTER
, LETTER
, LETTER
,
4631 SPACE_OR_NUMBER
, NUMBER
,
4633 SPACE_OR_NUMBER
, NUMBER
,
4635 SPACE_OR_NUMBER
, NUMBER
,
4637 SPACE_OR_NUMBER
, NUMBER
,
4649 for (i
= 0; i
< ELEMENTSOF(sequence
); i
++, p
++) {
4654 switch (sequence
[i
]) {
4661 case SPACE_OR_NUMBER
:
4668 if (*p
< '0' || *p
> '9')
4674 if (!(*p
>= 'A' && *p
<= 'Z') &&
4675 !(*p
>= 'a' && *p
<= 'z'))
4691 int have_effective_cap(int value
) {
4693 cap_flag_value_t fv
;
4696 if (!(cap
= cap_get_proc()))
4699 if (cap_get_flag(cap
, value
, CAP_EFFECTIVE
, &fv
) < 0)
4708 char* strshorten(char *s
, size_t l
) {
4717 static bool hostname_valid_char(char c
) {
4719 (c
>= 'a' && c
<= 'z') ||
4720 (c
>= 'A' && c
<= 'Z') ||
4721 (c
>= '0' && c
<= '9') ||
4727 bool hostname_is_valid(const char *s
) {
4733 for (p
= s
; *p
; p
++)
4734 if (!hostname_valid_char(*p
))
4737 if (p
-s
> HOST_NAME_MAX
)
4743 char* hostname_cleanup(char *s
) {
4746 for (p
= s
, d
= s
; *p
; p
++)
4747 if ((*p
>= 'a' && *p
<= 'z') ||
4748 (*p
>= 'A' && *p
<= 'Z') ||
4749 (*p
>= '0' && *p
<= '9') ||
4757 strshorten(s
, HOST_NAME_MAX
);
4761 int pipe_eof(int fd
) {
4762 struct pollfd pollfd
;
4767 pollfd
.events
= POLLIN
|POLLHUP
;
4769 r
= poll(&pollfd
, 1, 0);
4776 return pollfd
.revents
& POLLHUP
;
4779 int fd_wait_for_event(int fd
, int event
, usec_t t
) {
4780 struct pollfd pollfd
;
4785 pollfd
.events
= event
;
4787 r
= poll(&pollfd
, 1, t
== (usec_t
) -1 ? -1 : (int) (t
/ USEC_PER_MSEC
));
4794 return pollfd
.revents
;
4797 int fopen_temporary(const char *path
, FILE **_f
, char **_temp_path
) {
4808 t
= new(char, strlen(path
) + 1 + 6 + 1);
4812 fn
= file_name_from_path(path
);
4816 stpcpy(stpcpy(t
+k
+1, fn
), "XXXXXX");
4818 fd
= mkostemp(t
, O_WRONLY
|O_CLOEXEC
);
4824 f
= fdopen(fd
, "we");
4837 int terminal_vhangup_fd(int fd
) {
4840 if (ioctl(fd
, TIOCVHANGUP
) < 0)
4846 int terminal_vhangup(const char *name
) {
4849 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
4853 r
= terminal_vhangup_fd(fd
);
4854 close_nointr_nofail(fd
);
4859 int vt_disallocate(const char *name
) {
4863 /* Deallocate the VT if possible. If not possible
4864 * (i.e. because it is the active one), at least clear it
4865 * entirely (including the scrollback buffer) */
4867 if (!startswith(name
, "/dev/"))
4870 if (!tty_is_vc(name
)) {
4871 /* So this is not a VT. I guess we cannot deallocate
4872 * it then. But let's at least clear the screen */
4874 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
4879 "\033[r" /* clear scrolling region */
4880 "\033[H" /* move home */
4881 "\033[2J", /* clear screen */
4883 close_nointr_nofail(fd
);
4888 if (!startswith(name
, "/dev/tty"))
4891 r
= safe_atou(name
+8, &u
);
4898 /* Try to deallocate */
4899 fd
= open_terminal("/dev/tty0", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
4903 r
= ioctl(fd
, VT_DISALLOCATE
, u
);
4904 close_nointr_nofail(fd
);
4912 /* Couldn't deallocate, so let's clear it fully with
4914 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
4919 "\033[r" /* clear scrolling region */
4920 "\033[H" /* move home */
4921 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
4923 close_nointr_nofail(fd
);
4928 static int files_add(Hashmap
*h
, const char *path
, const char *suffix
) {
4930 struct dirent buffer
, *de
;
4933 dir
= opendir(path
);
4935 if (errno
== ENOENT
)
4944 k
= readdir_r(dir
, &buffer
, &de
);
4953 if (!dirent_is_file_with_suffix(de
, suffix
))
4956 if (asprintf(&p
, "%s/%s", path
, de
->d_name
) < 0) {
4961 f
= canonicalize_file_name(p
);
4963 log_error("Failed to canonicalize file name '%s': %m", p
);
4969 log_debug("found: %s\n", f
);
4970 if (hashmap_put(h
, file_name_from_path(f
), f
) <= 0)
4979 static int base_cmp(const void *a
, const void *b
) {
4980 const char *s1
, *s2
;
4982 s1
= *(char * const *)a
;
4983 s2
= *(char * const *)b
;
4984 return strcmp(file_name_from_path(s1
), file_name_from_path(s2
));
4987 int conf_files_list(char ***strv
, const char *suffix
, const char *dir
, ...) {
4990 char **files
= NULL
;
4996 dirs
= strv_new_ap(dir
, ap
);
5002 if (!strv_path_canonicalize(dirs
)) {
5006 if (!strv_uniq(dirs
)) {
5011 fh
= hashmap_new(string_hash_func
, string_compare_func
);
5017 STRV_FOREACH(p
, dirs
) {
5018 if (files_add(fh
, *p
, suffix
) < 0) {
5019 log_error("Failed to search for files.");
5025 files
= hashmap_get_strv(fh
);
5026 if (files
== NULL
) {
5027 log_error("Failed to compose list of files.");
5032 qsort(files
, hashmap_size(fh
), sizeof(char *), base_cmp
);
5041 int hwclock_is_localtime(void) {
5046 * The third line of adjtime is "UTC" or "LOCAL" or nothing.
5052 f
= fopen("/etc/adjtime", "re");
5054 char line
[LINE_MAX
];
5057 b
= fgets(line
, sizeof(line
), f
) &&
5058 fgets(line
, sizeof(line
), f
) &&
5059 fgets(line
, sizeof(line
), f
);
5068 local
= streq(line
, "LOCAL");
5070 } else if (errno
!= -ENOENT
)
5076 int hwclock_apply_localtime_delta(int *min
) {
5077 const struct timeval
*tv_null
= NULL
;
5083 assert_se(clock_gettime(CLOCK_REALTIME
, &ts
) == 0);
5084 assert_se(tm
= localtime(&ts
.tv_sec
));
5085 minuteswest
= tm
->tm_gmtoff
/ 60;
5087 tz
.tz_minuteswest
= -minuteswest
;
5088 tz
.tz_dsttime
= 0; /* DST_NONE*/
5091 * If the hardware clock does not run in UTC, but in local time:
5092 * The very first time we set the kernel's timezone, it will warp
5093 * the clock so that it runs in UTC instead of local time.
5095 if (settimeofday(tv_null
, &tz
) < 0)
5102 int hwclock_reset_localtime_delta(void) {
5103 const struct timeval
*tv_null
= NULL
;
5106 tz
.tz_minuteswest
= 0;
5107 tz
.tz_dsttime
= 0; /* DST_NONE*/
5109 if (settimeofday(tv_null
, &tz
) < 0)
5115 int rtc_open(int flags
) {
5119 /* First, we try to make use of the /dev/rtc symlink. If that
5120 * doesn't exist, we open the first RTC which has hctosys=1
5121 * set. If we don't find any we just take the first RTC that
5124 fd
= open("/dev/rtc", flags
);
5128 d
= opendir("/sys/class/rtc");
5134 struct dirent buf
, *de
;
5137 r
= readdir_r(d
, &buf
, &de
);
5144 if (ignore_file(de
->d_name
))
5147 p
= join("/sys/class/rtc/", de
->d_name
, "/hctosys", NULL
);
5153 r
= read_one_line_file(p
, &v
);
5159 r
= parse_boolean(v
);
5165 p
= strappend("/dev/", de
->d_name
);
5166 fd
= open(p
, flags
);
5179 fd
= open("/dev/rtc0", flags
);
5186 int hwclock_get_time(struct tm
*tm
) {
5192 fd
= rtc_open(O_RDONLY
|O_CLOEXEC
);
5196 /* This leaves the timezone fields of struct tm
5198 if (ioctl(fd
, RTC_RD_TIME
, tm
) < 0)
5201 /* We don't now daylight saving, so we reset this in order not
5202 * to confused mktime(). */
5205 close_nointr_nofail(fd
);
5210 int hwclock_set_time(const struct tm
*tm
) {
5216 fd
= rtc_open(O_RDONLY
|O_CLOEXEC
);
5220 if (ioctl(fd
, RTC_SET_TIME
, tm
) < 0)
5223 close_nointr_nofail(fd
);
5228 int copy_file(const char *from
, const char *to
) {
5234 fdf
= open(from
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
5238 fdt
= open(to
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
|O_NOCTTY
, 0644);
5240 close_nointr_nofail(fdf
);
5248 n
= read(fdf
, buf
, sizeof(buf
));
5252 close_nointr_nofail(fdf
);
5263 k
= loop_write(fdt
, buf
, n
, false);
5265 r
= k
< 0 ? k
: (errno
? -errno
: -EIO
);
5267 close_nointr_nofail(fdf
);
5275 close_nointr_nofail(fdf
);
5276 r
= close_nointr(fdt
);
5286 int symlink_or_copy(const char *from
, const char *to
) {
5287 char *pf
= NULL
, *pt
= NULL
;
5294 if (parent_of_path(from
, &pf
) < 0 ||
5295 parent_of_path(to
, &pt
) < 0) {
5300 if (stat(pf
, &a
) < 0 ||
5306 if (a
.st_dev
!= b
.st_dev
) {
5310 return copy_file(from
, to
);
5313 if (symlink(from
, to
) < 0) {
5327 int symlink_or_copy_atomic(const char *from
, const char *to
) {
5331 unsigned long long ull
;
5338 t
= new(char, strlen(to
) + 1 + 16 + 1);
5342 fn
= file_name_from_path(to
);
5346 x
= stpcpy(t
+k
+1, fn
);
5349 for (i
= 0; i
< 16; i
++) {
5350 *(x
++) = hexchar(ull
& 0xF);
5356 r
= symlink_or_copy(from
, t
);
5363 if (rename(t
, to
) < 0) {
5374 int audit_session_from_pid(pid_t pid
, uint32_t *id
) {
5381 if (have_effective_cap(CAP_AUDIT_CONTROL
) <= 0)
5385 r
= read_one_line_file("/proc/self/sessionid", &s
);
5389 if (asprintf(&p
, "/proc/%lu/sessionid", (unsigned long) pid
) < 0)
5392 r
= read_one_line_file(p
, &s
);
5399 r
= safe_atou32(s
, &u
);
5405 if (u
== (uint32_t) -1 || u
<= 0)
5412 int audit_loginuid_from_pid(pid_t pid
, uid_t
*uid
) {
5419 /* Only use audit login uid if we are executed with sufficient
5420 * capabilities so that pam_loginuid could do its job. If we
5421 * are lacking the CAP_AUDIT_CONTROL capabality we most likely
5422 * are being run in a container and /proc/self/loginuid is
5423 * useless since it probably contains a uid of the host
5426 if (have_effective_cap(CAP_AUDIT_CONTROL
) <= 0)
5430 r
= read_one_line_file("/proc/self/loginuid", &s
);
5434 if (asprintf(&p
, "/proc/%lu/loginuid", (unsigned long) pid
) < 0)
5437 r
= read_one_line_file(p
, &s
);
5444 r
= parse_uid(s
, &u
);
5450 if (u
== (uid_t
) -1)
5457 bool display_is_local(const char *display
) {
5461 display
[0] == ':' &&
5462 display
[1] >= '0' &&
5466 int socket_from_display(const char *display
, char **path
) {
5473 if (!display_is_local(display
))
5476 k
= strspn(display
+1, "0123456789");
5478 f
= new(char, sizeof("/tmp/.X11-unix/X") + k
);
5482 c
= stpcpy(f
, "/tmp/.X11-unix/X");
5483 memcpy(c
, display
+1, k
);
5491 int get_user_creds(const char **username
, uid_t
*uid
, gid_t
*gid
, const char **home
) {
5498 /* We enforce some special rules for uid=0: in order to avoid
5499 * NSS lookups for root we hardcode its data. */
5501 if (streq(*username
, "root") || streq(*username
, "0")) {
5515 if (parse_uid(*username
, &u
) >= 0) {
5519 /* If there are multiple users with the same id, make
5520 * sure to leave $USER to the configured value instead
5521 * of the first occurrence in the database. However if
5522 * the uid was configured by a numeric uid, then let's
5523 * pick the real username from /etc/passwd. */
5525 *username
= p
->pw_name
;
5528 p
= getpwnam(*username
);
5532 return errno
!= 0 ? -errno
: -ESRCH
;
5546 int get_group_creds(const char **groupname
, gid_t
*gid
) {
5552 /* We enforce some special rules for gid=0: in order to avoid
5553 * NSS lookups for root we hardcode its data. */
5555 if (streq(*groupname
, "root") || streq(*groupname
, "0")) {
5556 *groupname
= "root";
5564 if (parse_gid(*groupname
, &id
) >= 0) {
5569 *groupname
= g
->gr_name
;
5572 g
= getgrnam(*groupname
);
5576 return errno
!= 0 ? -errno
: -ESRCH
;
5584 int glob_exists(const char *path
) {
5592 k
= glob(path
, GLOB_NOSORT
|GLOB_BRACE
, NULL
, &g
);
5594 if (k
== GLOB_NOMATCH
)
5596 else if (k
== GLOB_NOSPACE
)
5599 r
= !strv_isempty(g
.gl_pathv
);
5601 r
= errno
? -errno
: -EIO
;
5608 int dirent_ensure_type(DIR *d
, struct dirent
*de
) {
5614 if (de
->d_type
!= DT_UNKNOWN
)
5617 if (fstatat(dirfd(d
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0)
5621 S_ISREG(st
.st_mode
) ? DT_REG
:
5622 S_ISDIR(st
.st_mode
) ? DT_DIR
:
5623 S_ISLNK(st
.st_mode
) ? DT_LNK
:
5624 S_ISFIFO(st
.st_mode
) ? DT_FIFO
:
5625 S_ISSOCK(st
.st_mode
) ? DT_SOCK
:
5626 S_ISCHR(st
.st_mode
) ? DT_CHR
:
5627 S_ISBLK(st
.st_mode
) ? DT_BLK
:
5633 int in_search_path(const char *path
, char **search
) {
5637 r
= parent_of_path(path
, &parent
);
5643 STRV_FOREACH(i
, search
) {
5644 if (path_equal(parent
, *i
)) {
5655 int get_files_in_directory(const char *path
, char ***list
) {
5663 /* Returns all files in a directory in *list, and the number
5664 * of files as return value. If list is NULL returns only the
5672 struct dirent buffer
, *de
;
5675 k
= readdir_r(d
, &buffer
, &de
);
5684 dirent_ensure_type(d
, de
);
5686 if (!dirent_is_file(de
))
5690 if ((unsigned) r
>= n
) {
5694 t
= realloc(l
, sizeof(char*) * n
);
5703 assert((unsigned) r
< n
);
5705 l
[r
] = strdup(de
->d_name
);
5729 char *join(const char *x
, ...) {
5742 t
= va_arg(ap
, const char *);
5765 t
= va_arg(ap
, const char *);
5779 bool is_main_thread(void) {
5780 static __thread
int cached
= 0;
5782 if (_unlikely_(cached
== 0))
5783 cached
= getpid() == gettid() ? 1 : -1;
5788 int block_get_whole_disk(dev_t d
, dev_t
*ret
) {
5795 /* If it has a queue this is good enough for us */
5796 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", major(d
), minor(d
)) < 0)
5799 r
= access(p
, F_OK
);
5807 /* If it is a partition find the originating device */
5808 if (asprintf(&p
, "/sys/dev/block/%u:%u/partition", major(d
), minor(d
)) < 0)
5811 r
= access(p
, F_OK
);
5817 /* Get parent dev_t */
5818 if (asprintf(&p
, "/sys/dev/block/%u:%u/../dev", major(d
), minor(d
)) < 0)
5821 r
= read_one_line_file(p
, &s
);
5827 r
= sscanf(s
, "%u:%u", &m
, &n
);
5833 /* Only return this if it is really good enough for us. */
5834 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", m
, n
) < 0)
5837 r
= access(p
, F_OK
);
5841 *ret
= makedev(m
, n
);
5848 int file_is_priv_sticky(const char *p
) {
5853 if (lstat(p
, &st
) < 0)
5857 (st
.st_uid
== 0 || st
.st_uid
== getuid()) &&
5858 (st
.st_mode
& S_ISVTX
);
5861 static const char *const ioprio_class_table
[] = {
5862 [IOPRIO_CLASS_NONE
] = "none",
5863 [IOPRIO_CLASS_RT
] = "realtime",
5864 [IOPRIO_CLASS_BE
] = "best-effort",
5865 [IOPRIO_CLASS_IDLE
] = "idle"
5868 DEFINE_STRING_TABLE_LOOKUP(ioprio_class
, int);
5870 static const char *const sigchld_code_table
[] = {
5871 [CLD_EXITED
] = "exited",
5872 [CLD_KILLED
] = "killed",
5873 [CLD_DUMPED
] = "dumped",
5874 [CLD_TRAPPED
] = "trapped",
5875 [CLD_STOPPED
] = "stopped",
5876 [CLD_CONTINUED
] = "continued",
5879 DEFINE_STRING_TABLE_LOOKUP(sigchld_code
, int);
5881 static const char *const log_facility_unshifted_table
[LOG_NFACILITIES
] = {
5882 [LOG_FAC(LOG_KERN
)] = "kern",
5883 [LOG_FAC(LOG_USER
)] = "user",
5884 [LOG_FAC(LOG_MAIL
)] = "mail",
5885 [LOG_FAC(LOG_DAEMON
)] = "daemon",
5886 [LOG_FAC(LOG_AUTH
)] = "auth",
5887 [LOG_FAC(LOG_SYSLOG
)] = "syslog",
5888 [LOG_FAC(LOG_LPR
)] = "lpr",
5889 [LOG_FAC(LOG_NEWS
)] = "news",
5890 [LOG_FAC(LOG_UUCP
)] = "uucp",
5891 [LOG_FAC(LOG_CRON
)] = "cron",
5892 [LOG_FAC(LOG_AUTHPRIV
)] = "authpriv",
5893 [LOG_FAC(LOG_FTP
)] = "ftp",
5894 [LOG_FAC(LOG_LOCAL0
)] = "local0",
5895 [LOG_FAC(LOG_LOCAL1
)] = "local1",
5896 [LOG_FAC(LOG_LOCAL2
)] = "local2",
5897 [LOG_FAC(LOG_LOCAL3
)] = "local3",
5898 [LOG_FAC(LOG_LOCAL4
)] = "local4",
5899 [LOG_FAC(LOG_LOCAL5
)] = "local5",
5900 [LOG_FAC(LOG_LOCAL6
)] = "local6",
5901 [LOG_FAC(LOG_LOCAL7
)] = "local7"
5904 DEFINE_STRING_TABLE_LOOKUP(log_facility_unshifted
, int);
5906 static const char *const log_level_table
[] = {
5907 [LOG_EMERG
] = "emerg",
5908 [LOG_ALERT
] = "alert",
5909 [LOG_CRIT
] = "crit",
5911 [LOG_WARNING
] = "warning",
5912 [LOG_NOTICE
] = "notice",
5913 [LOG_INFO
] = "info",
5914 [LOG_DEBUG
] = "debug"
5917 DEFINE_STRING_TABLE_LOOKUP(log_level
, int);
5919 static const char* const sched_policy_table
[] = {
5920 [SCHED_OTHER
] = "other",
5921 [SCHED_BATCH
] = "batch",
5922 [SCHED_IDLE
] = "idle",
5923 [SCHED_FIFO
] = "fifo",
5927 DEFINE_STRING_TABLE_LOOKUP(sched_policy
, int);
5929 static const char* const rlimit_table
[] = {
5930 [RLIMIT_CPU
] = "LimitCPU",
5931 [RLIMIT_FSIZE
] = "LimitFSIZE",
5932 [RLIMIT_DATA
] = "LimitDATA",
5933 [RLIMIT_STACK
] = "LimitSTACK",
5934 [RLIMIT_CORE
] = "LimitCORE",
5935 [RLIMIT_RSS
] = "LimitRSS",
5936 [RLIMIT_NOFILE
] = "LimitNOFILE",
5937 [RLIMIT_AS
] = "LimitAS",
5938 [RLIMIT_NPROC
] = "LimitNPROC",
5939 [RLIMIT_MEMLOCK
] = "LimitMEMLOCK",
5940 [RLIMIT_LOCKS
] = "LimitLOCKS",
5941 [RLIMIT_SIGPENDING
] = "LimitSIGPENDING",
5942 [RLIMIT_MSGQUEUE
] = "LimitMSGQUEUE",
5943 [RLIMIT_NICE
] = "LimitNICE",
5944 [RLIMIT_RTPRIO
] = "LimitRTPRIO",
5945 [RLIMIT_RTTIME
] = "LimitRTTIME"
5948 DEFINE_STRING_TABLE_LOOKUP(rlimit
, int);
5950 static const char* const ip_tos_table
[] = {
5951 [IPTOS_LOWDELAY
] = "low-delay",
5952 [IPTOS_THROUGHPUT
] = "throughput",
5953 [IPTOS_RELIABILITY
] = "reliability",
5954 [IPTOS_LOWCOST
] = "low-cost",
5957 DEFINE_STRING_TABLE_LOOKUP(ip_tos
, int);
5959 static const char *const __signal_table
[] = {
5976 [SIGSTKFLT
] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
5987 [SIGVTALRM
] = "VTALRM",
5989 [SIGWINCH
] = "WINCH",
5995 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal
, int);
5997 const char *signal_to_string(int signo
) {
5998 static __thread
char buf
[12];
6001 name
= __signal_to_string(signo
);
6005 if (signo
>= SIGRTMIN
&& signo
<= SIGRTMAX
)
6006 snprintf(buf
, sizeof(buf
) - 1, "RTMIN+%d", signo
- SIGRTMIN
);
6008 snprintf(buf
, sizeof(buf
) - 1, "%d", signo
);
6013 int signal_from_string(const char *s
) {
6018 signo
=__signal_from_string(s
);
6022 if (startswith(s
, "RTMIN+")) {
6026 if (safe_atou(s
, &u
) >= 0) {
6027 signo
= (int) u
+ offset
;
6028 if (signo
> 0 && signo
< _NSIG
)
6034 bool kexec_loaded(void) {
6035 bool loaded
= false;
6038 if (read_one_line_file("/sys/kernel/kexec_loaded", &s
) >= 0) {
6046 int strdup_or_null(const char *a
, char **b
) {
6064 int prot_from_flags(int flags
) {
6066 switch (flags
& O_ACCMODE
) {
6075 return PROT_READ
|PROT_WRITE
;
6082 unsigned long cap_last_cap(void) {
6083 static __thread
unsigned long saved
;
6084 static __thread
bool valid
= false;
6090 p
= (unsigned long) CAP_LAST_CAP
;
6092 if (prctl(PR_CAPBSET_READ
, p
) < 0) {
6094 /* Hmm, look downwards, until we find one that
6096 for (p
--; p
> 0; p
--)
6097 if (prctl(PR_CAPBSET_READ
, p
) >= 0)
6102 /* Hmm, look upwards, until we find one that doesn't
6105 if (prctl(PR_CAPBSET_READ
, p
+1) < 0)
6115 char *format_bytes(char *buf
, size_t l
, off_t t
) {
6118 static const struct {
6122 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
6123 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
6124 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
6125 { "G", 1024ULL*1024ULL*1024ULL },
6126 { "M", 1024ULL*1024ULL },
6130 for (i
= 0; i
< ELEMENTSOF(table
); i
++) {
6132 if (t
>= table
[i
].factor
) {
6135 (unsigned long long) (t
/ table
[i
].factor
),
6136 (unsigned long long) (((t
*10ULL) / table
[i
].factor
) % 10ULL),
6143 snprintf(buf
, l
, "%lluB", (unsigned long long) t
);
6151 void* memdup(const void *p
, size_t l
) {
6164 int fd_inc_sndbuf(int fd
, size_t n
) {
6166 socklen_t l
= sizeof(value
);
6168 r
= getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &value
, &l
);
6170 l
== sizeof(value
) &&
6171 (size_t) value
>= n
*2)
6175 r
= setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &value
, sizeof(value
));
6182 int fd_inc_rcvbuf(int fd
, size_t n
) {
6184 socklen_t l
= sizeof(value
);
6186 r
= getsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &value
, &l
);
6188 l
== sizeof(value
) &&
6189 (size_t) value
>= n
*2)
6193 r
= setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &value
, sizeof(value
));