chiark / gitweb /
logind: update empty and "infinity" handling for [User]TasksMax (#3835)
[elogind.git] / src / basic / util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <alloca.h>
21 //#include <dirent.h>
22 //#include <errno.h>
23 //#include <fcntl.h>
24 #include <sched.h>
25 //#include <signal.h>
26 //#include <stdarg.h>
27 //#include <stdio.h>
28 #include <stdlib.h>
29 //#include <string.h>
30 //#include <sys/mman.h>
31 #include <sys/prctl.h>
32 #include <sys/statfs.h>
33 #include <sys/sysmacros.h>
34 //#include <sys/types.h>
35 //#include <unistd.h>
36
37 #include "alloc-util.h"
38 #include "build.h"
39 #include "cgroup-util.h"
40 //#include "def.h"
41 #include "dirent-util.h"
42 #include "fd-util.h"
43 #include "fileio.h"
44 //#include "formats-util.h"
45 #include "hashmap.h"
46 #include "hostname-util.h"
47 //#include "log.h"
48 #include "macro.h"
49 //#include "missing.h"
50 #include "parse-util.h"
51 //#include "path-util.h"
52 #include "process-util.h"
53 #include "set.h"
54 #include "signal-util.h"
55 #include "stat-util.h"
56 #include "string-util.h"
57 #include "strv.h"
58 #include "time-util.h"
59 #include "umask-util.h"
60 #include "user-util.h"
61 #include "util.h"
62
63 /* Put this test here for a lack of better place */
64 assert_cc(EAGAIN == EWOULDBLOCK);
65
66 int saved_argc = 0;
67 char **saved_argv = NULL;
68 static int saved_in_initrd = -1;
69
70 size_t page_size(void) {
71         static thread_local size_t pgsz = 0;
72         long r;
73
74         if (_likely_(pgsz > 0))
75                 return pgsz;
76
77         r = sysconf(_SC_PAGESIZE);
78         assert(r > 0);
79
80         pgsz = (size_t) r;
81         return pgsz;
82 }
83
84 static int do_execute(char **directories, usec_t timeout, char *argv[]) {
85         _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
86         _cleanup_set_free_free_ Set *seen = NULL;
87         char **directory;
88
89         /* We fork this all off from a child process so that we can
90          * somewhat cleanly make use of SIGALRM to set a time limit */
91
92         (void) reset_all_signal_handlers();
93         (void) reset_signal_mask();
94
95         assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
96
97         pids = hashmap_new(NULL);
98         if (!pids)
99                 return log_oom();
100
101         seen = set_new(&string_hash_ops);
102         if (!seen)
103                 return log_oom();
104
105         STRV_FOREACH(directory, directories) {
106                 _cleanup_closedir_ DIR *d;
107                 struct dirent *de;
108
109                 d = opendir(*directory);
110                 if (!d) {
111                         if (errno == ENOENT)
112                                 continue;
113
114                         return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
115                 }
116
117                 FOREACH_DIRENT(de, d, break) {
118                         _cleanup_free_ char *path = NULL;
119                         pid_t pid;
120                         int r;
121
122                         if (!dirent_is_file(de))
123                                 continue;
124
125                         if (set_contains(seen, de->d_name)) {
126                                 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
127                                 continue;
128                         }
129
130                         r = set_put_strdup(seen, de->d_name);
131                         if (r < 0)
132                                 return log_oom();
133
134                         path = strjoin(*directory, "/", de->d_name, NULL);
135                         if (!path)
136                                 return log_oom();
137
138                         if (null_or_empty_path(path)) {
139                                 log_debug("%s is empty (a mask).", path);
140                                 continue;
141                         }
142
143                         pid = fork();
144                         if (pid < 0) {
145                                 log_error_errno(errno, "Failed to fork: %m");
146                                 continue;
147                         } else if (pid == 0) {
148                                 char *_argv[2];
149
150                                 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
151
152                                 if (!argv) {
153                                         _argv[0] = path;
154                                         _argv[1] = NULL;
155                                         argv = _argv;
156                                 } else
157                                         argv[0] = path;
158
159                                 execv(path, argv);
160                                 return log_error_errno(errno, "Failed to execute %s: %m", path);
161                         }
162
163                         log_debug("Spawned %s as " PID_FMT ".", path, pid);
164
165                         r = hashmap_put(pids, PID_TO_PTR(pid), path);
166                         if (r < 0)
167                                 return log_oom();
168                         path = NULL;
169                 }
170         }
171
172         /* Abort execution of this process after the timout. We simply
173          * rely on SIGALRM as default action terminating the process,
174          * and turn on alarm(). */
175
176         if (timeout != USEC_INFINITY)
177                 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
178
179         while (!hashmap_isempty(pids)) {
180                 _cleanup_free_ char *path = NULL;
181                 pid_t pid;
182
183                 pid = PTR_TO_PID(hashmap_first_key(pids));
184                 assert(pid > 0);
185
186                 path = hashmap_remove(pids, PID_TO_PTR(pid));
187                 assert(path);
188
189                 wait_for_terminate_and_warn(path, pid, true);
190         }
191
192         return 0;
193 }
194
195 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
196         pid_t executor_pid;
197         int r;
198         char *name;
199         char **dirs = (char**) directories;
200
201         assert(!strv_isempty(dirs));
202
203         name = basename(dirs[0]);
204         assert(!isempty(name));
205
206         /* Executes all binaries in the directories in parallel and waits
207          * for them to finish. Optionally a timeout is applied. If a file
208          * with the same name exists in more than one directory, the
209          * earliest one wins. */
210
211         executor_pid = fork();
212         if (executor_pid < 0) {
213                 log_error_errno(errno, "Failed to fork: %m");
214                 return;
215
216         } else if (executor_pid == 0) {
217                 r = do_execute(dirs, timeout, argv);
218                 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
219         }
220
221         wait_for_terminate_and_warn(name, executor_pid, true);
222 }
223
224 #if 0 /// UNNEEDED by elogind
225 bool plymouth_running(void) {
226         return access("/run/plymouth/pid", F_OK) >= 0;
227 }
228 #endif // 0
229
230 bool display_is_local(const char *display) {
231         assert(display);
232
233         return
234                 display[0] == ':' &&
235                 display[1] >= '0' &&
236                 display[1] <= '9';
237 }
238
239 int socket_from_display(const char *display, char **path) {
240         size_t k;
241         char *f, *c;
242
243         assert(display);
244         assert(path);
245
246         if (!display_is_local(display))
247                 return -EINVAL;
248
249         k = strspn(display+1, "0123456789");
250
251         f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
252         if (!f)
253                 return -ENOMEM;
254
255         c = stpcpy(f, "/tmp/.X11-unix/X");
256         memcpy(c, display+1, k);
257         c[k] = 0;
258
259         *path = f;
260
261         return 0;
262 }
263
264 #if 0 /// UNNEEDED by elogind
265 int block_get_whole_disk(dev_t d, dev_t *ret) {
266         char *p, *s;
267         int r;
268         unsigned n, m;
269
270         assert(ret);
271
272         /* If it has a queue this is good enough for us */
273         if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
274                 return -ENOMEM;
275
276         r = access(p, F_OK);
277         free(p);
278
279         if (r >= 0) {
280                 *ret = d;
281                 return 0;
282         }
283
284         /* If it is a partition find the originating device */
285         if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
286                 return -ENOMEM;
287
288         r = access(p, F_OK);
289         free(p);
290
291         if (r < 0)
292                 return -ENOENT;
293
294         /* Get parent dev_t */
295         if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
296                 return -ENOMEM;
297
298         r = read_one_line_file(p, &s);
299         free(p);
300
301         if (r < 0)
302                 return r;
303
304         r = sscanf(s, "%u:%u", &m, &n);
305         free(s);
306
307         if (r != 2)
308                 return -EINVAL;
309
310         /* Only return this if it is really good enough for us. */
311         if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
312                 return -ENOMEM;
313
314         r = access(p, F_OK);
315         free(p);
316
317         if (r >= 0) {
318                 *ret = makedev(m, n);
319                 return 0;
320         }
321
322         return -ENOENT;
323 }
324
325 bool kexec_loaded(void) {
326        bool loaded = false;
327        char *s;
328
329        if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
330                if (s[0] == '1')
331                        loaded = true;
332                free(s);
333        }
334        return loaded;
335 }
336
337 int prot_from_flags(int flags) {
338
339         switch (flags & O_ACCMODE) {
340
341         case O_RDONLY:
342                 return PROT_READ;
343
344         case O_WRONLY:
345                 return PROT_WRITE;
346
347         case O_RDWR:
348                 return PROT_READ|PROT_WRITE;
349
350         default:
351                 return -EINVAL;
352         }
353 }
354 #endif // 0
355
356 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
357         bool stdout_is_tty, stderr_is_tty;
358         pid_t parent_pid, agent_pid;
359         sigset_t ss, saved_ss;
360         unsigned n, i;
361         va_list ap;
362         char **l;
363
364         assert(pid);
365         assert(path);
366
367         /* Spawns a temporary TTY agent, making sure it goes away when
368          * we go away */
369
370         parent_pid = getpid();
371
372         /* First we temporarily block all signals, so that the new
373          * child has them blocked initially. This way, we can be sure
374          * that SIGTERMs are not lost we might send to the agent. */
375         assert_se(sigfillset(&ss) >= 0);
376         assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
377
378         agent_pid = fork();
379         if (agent_pid < 0) {
380                 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
381                 return -errno;
382         }
383
384         if (agent_pid != 0) {
385                 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
386                 *pid = agent_pid;
387                 return 0;
388         }
389
390         /* In the child:
391          *
392          * Make sure the agent goes away when the parent dies */
393         if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
394                 _exit(EXIT_FAILURE);
395
396         /* Make sure we actually can kill the agent, if we need to, in
397          * case somebody invoked us from a shell script that trapped
398          * SIGTERM or so... */
399         (void) reset_all_signal_handlers();
400         (void) reset_signal_mask();
401
402         /* Check whether our parent died before we were able
403          * to set the death signal and unblock the signals */
404         if (getppid() != parent_pid)
405                 _exit(EXIT_SUCCESS);
406
407         /* Don't leak fds to the agent */
408         close_all_fds(except, n_except);
409
410         stdout_is_tty = isatty(STDOUT_FILENO);
411         stderr_is_tty = isatty(STDERR_FILENO);
412
413         if (!stdout_is_tty || !stderr_is_tty) {
414                 int fd;
415
416                 /* Detach from stdout/stderr. and reopen
417                  * /dev/tty for them. This is important to
418                  * ensure that when systemctl is started via
419                  * popen() or a similar call that expects to
420                  * read EOF we actually do generate EOF and
421                  * not delay this indefinitely by because we
422                  * keep an unused copy of stdin around. */
423                 fd = open("/dev/tty", O_WRONLY);
424                 if (fd < 0) {
425                         log_error_errno(errno, "Failed to open /dev/tty: %m");
426                         _exit(EXIT_FAILURE);
427                 }
428
429                 if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
430                         log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
431                         _exit(EXIT_FAILURE);
432                 }
433
434                 if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
435                         log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
436                         _exit(EXIT_FAILURE);
437                 }
438
439                 if (fd > STDERR_FILENO)
440                         close(fd);
441         }
442
443         /* Count arguments */
444         va_start(ap, path);
445         for (n = 0; va_arg(ap, char*); n++)
446                 ;
447         va_end(ap);
448
449         /* Allocate strv */
450         l = alloca(sizeof(char *) * (n + 1));
451
452         /* Fill in arguments */
453         va_start(ap, path);
454         for (i = 0; i <= n; i++)
455                 l[i] = va_arg(ap, char*);
456         va_end(ap);
457
458         execv(path, l);
459         _exit(EXIT_FAILURE);
460 }
461
462 bool in_initrd(void) {
463         struct statfs s;
464
465         if (saved_in_initrd >= 0)
466                 return saved_in_initrd;
467
468         /* We make two checks here:
469          *
470          * 1. the flag file /etc/initrd-release must exist
471          * 2. the root file system must be a memory file system
472          *
473          * The second check is extra paranoia, since misdetecting an
474          * initrd can have bad bad consequences due the initrd
475          * emptying when transititioning to the main systemd.
476          */
477
478         saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
479                           statfs("/", &s) >= 0 &&
480                           is_temporary_fs(&s);
481
482         return saved_in_initrd;
483 }
484
485 void in_initrd_force(bool value) {
486         saved_in_initrd = value;
487 }
488
489 #if 0 /// UNNEEDED by elogind
490 /* hey glibc, APIs with callbacks without a user pointer are so useless */
491 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
492                  int (*compar) (const void *, const void *, void *), void *arg) {
493         size_t l, u, idx;
494         const void *p;
495         int comparison;
496
497         l = 0;
498         u = nmemb;
499         while (l < u) {
500                 idx = (l + u) / 2;
501                 p = (void *)(((const char *) base) + (idx * size));
502                 comparison = compar(key, p, arg);
503                 if (comparison < 0)
504                         u = idx;
505                 else if (comparison > 0)
506                         l = idx + 1;
507                 else
508                         return (void *)p;
509         }
510         return NULL;
511 }
512
513 int on_ac_power(void) {
514         bool found_offline = false, found_online = false;
515         _cleanup_closedir_ DIR *d = NULL;
516
517         d = opendir("/sys/class/power_supply");
518         if (!d)
519                 return errno == ENOENT ? true : -errno;
520
521         for (;;) {
522                 struct dirent *de;
523                 _cleanup_close_ int fd = -1, device = -1;
524                 char contents[6];
525                 ssize_t n;
526
527                 errno = 0;
528                 de = readdir(d);
529                 if (!de && errno > 0)
530                         return -errno;
531
532                 if (!de)
533                         break;
534
535                 if (hidden_or_backup_file(de->d_name))
536                         continue;
537
538                 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
539                 if (device < 0) {
540                         if (errno == ENOENT || errno == ENOTDIR)
541                                 continue;
542
543                         return -errno;
544                 }
545
546                 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
547                 if (fd < 0) {
548                         if (errno == ENOENT)
549                                 continue;
550
551                         return -errno;
552                 }
553
554                 n = read(fd, contents, sizeof(contents));
555                 if (n < 0)
556                         return -errno;
557
558                 if (n != 6 || memcmp(contents, "Mains\n", 6))
559                         continue;
560
561                 safe_close(fd);
562                 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
563                 if (fd < 0) {
564                         if (errno == ENOENT)
565                                 continue;
566
567                         return -errno;
568                 }
569
570                 n = read(fd, contents, sizeof(contents));
571                 if (n < 0)
572                         return -errno;
573
574                 if (n != 2 || contents[1] != '\n')
575                         return -EIO;
576
577                 if (contents[0] == '1') {
578                         found_online = true;
579                         break;
580                 } else if (contents[0] == '0')
581                         found_offline = true;
582                 else
583                         return -EIO;
584         }
585
586         return found_online || !found_offline;
587 }
588
589 #endif // 0
590 int container_get_leader(const char *machine, pid_t *pid) {
591         _cleanup_free_ char *s = NULL, *class = NULL;
592         const char *p;
593         pid_t leader;
594         int r;
595
596         assert(machine);
597         assert(pid);
598
599         if (!machine_name_is_valid(machine))
600                 return -EINVAL;
601
602         p = strjoina("/run/systemd/machines/", machine);
603         r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
604         if (r == -ENOENT)
605                 return -EHOSTDOWN;
606         if (r < 0)
607                 return r;
608         if (!s)
609                 return -EIO;
610
611         if (!streq_ptr(class, "container"))
612                 return -EIO;
613
614         r = parse_pid(s, &leader);
615         if (r < 0)
616                 return r;
617         if (leader <= 1)
618                 return -EIO;
619
620         *pid = leader;
621         return 0;
622 }
623
624 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
625         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
626         int rfd = -1;
627
628         assert(pid >= 0);
629
630         if (mntns_fd) {
631                 const char *mntns;
632
633                 mntns = procfs_file_alloca(pid, "ns/mnt");
634                 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
635                 if (mntnsfd < 0)
636                         return -errno;
637         }
638
639         if (pidns_fd) {
640                 const char *pidns;
641
642                 pidns = procfs_file_alloca(pid, "ns/pid");
643                 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
644                 if (pidnsfd < 0)
645                         return -errno;
646         }
647
648         if (netns_fd) {
649                 const char *netns;
650
651                 netns = procfs_file_alloca(pid, "ns/net");
652                 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
653                 if (netnsfd < 0)
654                         return -errno;
655         }
656
657         if (userns_fd) {
658                 const char *userns;
659
660                 userns = procfs_file_alloca(pid, "ns/user");
661                 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
662                 if (usernsfd < 0 && errno != ENOENT)
663                         return -errno;
664         }
665
666         if (root_fd) {
667                 const char *root;
668
669                 root = procfs_file_alloca(pid, "root");
670                 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
671                 if (rfd < 0)
672                         return -errno;
673         }
674
675         if (pidns_fd)
676                 *pidns_fd = pidnsfd;
677
678         if (mntns_fd)
679                 *mntns_fd = mntnsfd;
680
681         if (netns_fd)
682                 *netns_fd = netnsfd;
683
684         if (userns_fd)
685                 *userns_fd = usernsfd;
686
687         if (root_fd)
688                 *root_fd = rfd;
689
690         pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
691
692         return 0;
693 }
694
695 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
696         if (userns_fd >= 0) {
697                 /* Can't setns to your own userns, since then you could
698                  * escalate from non-root to root in your own namespace, so
699                  * check if namespaces equal before attempting to enter. */
700                 _cleanup_free_ char *userns_fd_path = NULL;
701                 int r;
702                 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
703                         return -ENOMEM;
704
705                 r = files_same(userns_fd_path, "/proc/self/ns/user");
706                 if (r < 0)
707                         return r;
708                 if (r)
709                         userns_fd = -1;
710         }
711
712         if (pidns_fd >= 0)
713                 if (setns(pidns_fd, CLONE_NEWPID) < 0)
714                         return -errno;
715
716         if (mntns_fd >= 0)
717                 if (setns(mntns_fd, CLONE_NEWNS) < 0)
718                         return -errno;
719
720         if (netns_fd >= 0)
721                 if (setns(netns_fd, CLONE_NEWNET) < 0)
722                         return -errno;
723
724         if (userns_fd >= 0)
725                 if (setns(userns_fd, CLONE_NEWUSER) < 0)
726                         return -errno;
727
728         if (root_fd >= 0) {
729                 if (fchdir(root_fd) < 0)
730                         return -errno;
731
732                 if (chroot(".") < 0)
733                         return -errno;
734         }
735
736         return reset_uid_gid();
737 }
738
739 uint64_t physical_memory(void) {
740         _cleanup_free_ char *root = NULL, *value = NULL;
741         uint64_t mem, lim;
742         size_t ps;
743         long sc;
744
745         /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
746          * memory.
747          *
748          * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
749          * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
750
751         sc = sysconf(_SC_PHYS_PAGES);
752         assert(sc > 0);
753
754         ps = page_size();
755         mem = (uint64_t) sc * (uint64_t) ps;
756
757         if (cg_get_root_path(&root) < 0)
758                 return mem;
759
760         if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value))
761                 return mem;
762
763         if (safe_atou64(value, &lim) < 0)
764                 return mem;
765
766         /* Make sure the limit is a multiple of our own page size */
767         lim /= ps;
768         lim *= ps;
769
770         return MIN(mem, lim);
771 }
772
773 uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
774         uint64_t p, m, ps, r;
775
776         assert(max > 0);
777
778         /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
779          * the result is a multiple of the page size (rounds down). */
780
781         ps = page_size();
782         assert(ps > 0);
783
784         p = physical_memory() / ps;
785         assert(p > 0);
786
787         m = p * v;
788         if (m / p != v)
789                 return UINT64_MAX;
790
791         m /= max;
792
793         r = m * ps;
794         if (r / ps != m)
795                 return UINT64_MAX;
796
797         return r;
798 }
799
800 uint64_t system_tasks_max(void) {
801
802 #if SIZEOF_PID_T == 4
803 #define TASKS_MAX ((uint64_t) (INT32_MAX-1))
804 #elif SIZEOF_PID_T == 2
805 #define TASKS_MAX ((uint64_t) (INT16_MAX-1))
806 #else
807 #error "Unknown pid_t size"
808 #endif
809
810         _cleanup_free_ char *value = NULL, *root = NULL;
811         uint64_t a = TASKS_MAX, b = TASKS_MAX;
812
813         /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
814          * limit:
815          *
816          * a) the maximum value for the pid_t type
817          * b) the cgroups pids_max attribute for the system
818          * c) the kernel's configure maximum PID value
819          *
820          * And then pick the smallest of the three */
821
822         if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0)
823                 (void) safe_atou64(value, &a);
824
825         if (cg_get_root_path(&root) >= 0) {
826                 value = mfree(value);
827
828                 if (cg_get_attribute("pids", root, "pids.max", &value) >= 0)
829                         (void) safe_atou64(value, &b);
830         }
831
832         return MIN3(TASKS_MAX,
833                     a <= 0 ? TASKS_MAX : a,
834                     b <= 0 ? TASKS_MAX : b);
835 }
836
837 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
838         uint64_t t, m;
839
840         assert(max > 0);
841
842         /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
843          * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
844
845         t = system_tasks_max();
846         assert(t > 0);
847
848         m = t * v;
849         if (m / t != v) /* overflow? */
850                 return UINT64_MAX;
851
852         return m / max;
853 }
854
855 #if 0 /// UNNEEDED by elogind
856 int update_reboot_parameter_and_warn(const char *param) {
857         int r;
858
859         if (isempty(param)) {
860                 if (unlink("/run/systemd/reboot-param") < 0) {
861                         if (errno == ENOENT)
862                                 return 0;
863
864                         return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
865                 }
866
867                 return 0;
868         }
869
870         RUN_WITH_UMASK(0022) {
871                 r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
872                 if (r < 0)
873                         return log_warning_errno(r, "Failed to write reboot parameter file: %m");
874         }
875
876         return 0;
877 }
878 #endif // 0
879
880 int version(void) {
881         puts(PACKAGE_STRING "\n"
882              SYSTEMD_FEATURES);
883         return 0;
884 }