2010-02-03 13:03:47 +01:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2010 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
2012-04-12 00:20:58 +02:00
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2010-02-03 13:03:47 +01:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2012-04-12 00:20:58 +02:00
|
|
|
Lesser General Public License for more details.
|
2010-02-03 13:03:47 +01:00
|
|
|
|
2012-04-12 00:20:58 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2010-02-03 13:03:47 +01:00
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
2015-11-30 21:43:37 +01:00
|
|
|
#include <alloca.h>
|
2009-11-18 00:42:52 +01:00
|
|
|
#include <errno.h>
|
2015-09-19 00:53:58 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sched.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2011-10-07 21:06:39 +02:00
|
|
|
#include <sys/mman.h>
|
2015-09-19 00:53:58 +02:00
|
|
|
#include <sys/prctl.h>
|
2015-11-30 21:43:37 +01:00
|
|
|
#include <sys/statfs.h>
|
|
|
|
#include <sys/sysmacros.h>
|
2015-09-19 00:53:58 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2015-02-11 18:50:38 +01:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "build.h"
|
2016-06-08 18:56:20 +02:00
|
|
|
#include "cgroup-util.h"
|
2015-09-19 00:53:58 +02:00
|
|
|
#include "def.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "dirent-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-09-19 00:53:58 +02:00
|
|
|
#include "fileio.h"
|
2016-11-07 16:14:59 +01:00
|
|
|
#include "format-util.h"
|
2015-09-19 00:53:58 +02:00
|
|
|
#include "hashmap.h"
|
|
|
|
#include "hostname-util.h"
|
2010-02-12 02:01:14 +01:00
|
|
|
#include "log.h"
|
2015-09-19 00:53:58 +02:00
|
|
|
#include "macro.h"
|
|
|
|
#include "missing.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2012-05-07 21:36:12 +02:00
|
|
|
#include "path-util.h"
|
2015-04-10 19:10:00 +02:00
|
|
|
#include "process-util.h"
|
2015-11-30 21:43:37 +01:00
|
|
|
#include "set.h"
|
2015-12-01 23:22:03 +01:00
|
|
|
#include "signal-util.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "stat-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2015-09-19 00:53:58 +02:00
|
|
|
#include "strv.h"
|
2015-12-01 23:22:03 +01:00
|
|
|
#include "time-util.h"
|
2016-04-07 16:15:26 +02:00
|
|
|
#include "umask-util.h"
|
2015-10-25 22:32:30 +01:00
|
|
|
#include "user-util.h"
|
2015-10-23 18:52:53 +02:00
|
|
|
#include "util.h"
|
Systemd is causing mislabeled devices to be created and then attempting to read them.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 07/28/2010 05:57 AM, Kay Sievers wrote:
> On Wed, Jul 28, 2010 at 11:43, Lennart Poettering
> <lennart@poettering.net> wrote:
>> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote:
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1
>>> comm="systemd" name="autofs" dev=devtmpfs ino=9482
>>> scontext=system_u:system_r:init_t:s0
>>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file
>>>
>>> Lennart, we talked about this earlier. I think this is caused by the
>>> modprobe calls to create /dev/autofs. Since udev is not created at the
>>> point that init loads the kernel modules, the devices get created with
>>> the wrong label. Once udev starts the labels get fixed.
>>>
>>> I can allow init_t to read device_t chr_files.
>>
>> Hmm, I think a cleaner fix would be to make systemd relabel this device
>> properly before accessing it? Given that this is only one device this
>> should not be a problem for us to maintain, I think? How would the
>> fixing of the label work? Would we have to spawn restorecon for this, or
>> can we actually do this in C without too much work?
>
> I guess we can just do what udev is doing, and call setfilecon(), with
> a context of an earlier matchpathcon().
>
> Kay
> _______________________________________________
> systemd-devel mailing list
> systemd-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Here is the updated patch with a fix for the labeling of /dev/autofs
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf
gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk
=pC2e
2010-07-28 15:39:54 +02:00
|
|
|
|
2015-03-14 03:10:19 +01:00
|
|
|
/* Put this test here for a lack of better place */
|
|
|
|
assert_cc(EAGAIN == EWOULDBLOCK);
|
|
|
|
|
2011-06-30 04:16:10 +02:00
|
|
|
int saved_argc = 0;
|
|
|
|
char **saved_argv = NULL;
|
2016-06-13 16:28:42 +02:00
|
|
|
static int saved_in_initrd = -1;
|
2012-09-24 14:43:07 +02:00
|
|
|
|
2011-03-18 03:03:41 +01:00
|
|
|
size_t page_size(void) {
|
2013-12-16 01:24:14 +01:00
|
|
|
static thread_local size_t pgsz = 0;
|
2011-03-18 03:03:41 +01:00
|
|
|
long r;
|
|
|
|
|
2011-10-07 21:06:39 +02:00
|
|
|
if (_likely_(pgsz > 0))
|
2011-03-18 03:03:41 +01:00
|
|
|
return pgsz;
|
|
|
|
|
2012-09-14 10:06:42 +02:00
|
|
|
r = sysconf(_SC_PAGESIZE);
|
|
|
|
assert(r > 0);
|
2011-03-18 03:03:41 +01:00
|
|
|
|
|
|
|
pgsz = (size_t) r;
|
|
|
|
return pgsz;
|
|
|
|
}
|
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
static int do_execute(char **directories, usec_t timeout, char *argv[]) {
|
2015-01-08 23:30:07 +01:00
|
|
|
_cleanup_hashmap_free_free_ Hashmap *pids = NULL;
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
_cleanup_set_free_free_ Set *seen = NULL;
|
|
|
|
char **directory;
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
/* We fork this all off from a child process so that we can
|
|
|
|
* somewhat cleanly make use of SIGALRM to set a time limit */
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-05-31 23:55:55 +02:00
|
|
|
(void) reset_all_signal_handlers();
|
|
|
|
(void) reset_signal_mask();
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
pids = hashmap_new(NULL);
|
|
|
|
if (!pids)
|
|
|
|
return log_oom();
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
seen = set_new(&string_hash_ops);
|
|
|
|
if (!seen)
|
|
|
|
return log_oom();
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
STRV_FOREACH(directory, directories) {
|
|
|
|
_cleanup_closedir_ DIR *d;
|
|
|
|
struct dirent *de;
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
d = opendir(*directory);
|
|
|
|
if (!d) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
continue;
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
|
|
|
|
}
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
FOREACH_DIRENT(de, d, break) {
|
|
|
|
_cleanup_free_ char *path = NULL;
|
|
|
|
pid_t pid;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!dirent_is_file(de))
|
|
|
|
continue;
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
if (set_contains(seen, de->d_name)) {
|
|
|
|
log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = set_put_strdup(seen, de->d_name);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
2016-10-23 17:43:27 +02:00
|
|
|
path = strjoin(*directory, "/", de->d_name);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
if (!path)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
if (null_or_empty_path(path)) {
|
|
|
|
log_debug("%s is empty (a mask).", path);
|
|
|
|
continue;
|
2015-03-15 01:14:39 +01:00
|
|
|
}
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
|
|
log_error_errno(errno, "Failed to fork: %m");
|
|
|
|
continue;
|
|
|
|
} else if (pid == 0) {
|
|
|
|
char *_argv[2];
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
if (!argv) {
|
|
|
|
_argv[0] = path;
|
|
|
|
_argv[1] = NULL;
|
|
|
|
argv = _argv;
|
|
|
|
} else
|
|
|
|
argv[0] = path;
|
|
|
|
|
|
|
|
execv(path, argv);
|
|
|
|
return log_error_errno(errno, "Failed to execute %s: %m", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
log_debug("Spawned %s as " PID_FMT ".", path, pid);
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-11-17 00:00:32 +01:00
|
|
|
r = hashmap_put(pids, PID_TO_PTR(pid), path);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
path = NULL;
|
|
|
|
}
|
2015-01-08 23:30:07 +01:00
|
|
|
}
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
/* Abort execution of this process after the timout. We simply
|
|
|
|
* rely on SIGALRM as default action terminating the process,
|
|
|
|
* and turn on alarm(). */
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
if (timeout != USEC_INFINITY)
|
|
|
|
alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
while (!hashmap_isempty(pids)) {
|
|
|
|
_cleanup_free_ char *path = NULL;
|
|
|
|
pid_t pid;
|
2014-03-06 02:19:06 +01:00
|
|
|
|
2015-11-17 00:00:32 +01:00
|
|
|
pid = PTR_TO_PID(hashmap_first_key(pids));
|
2015-01-08 23:30:07 +01:00
|
|
|
assert(pid > 0);
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-11-17 00:00:32 +01:00
|
|
|
path = hashmap_remove(pids, PID_TO_PTR(pid));
|
2015-01-08 23:30:07 +01:00
|
|
|
assert(path);
|
2014-03-06 02:19:06 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
wait_for_terminate_and_warn(path, pid, true);
|
|
|
|
}
|
2014-03-06 02:19:06 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2014-03-06 02:19:06 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
|
2015-01-08 23:30:07 +01:00
|
|
|
pid_t executor_pid;
|
|
|
|
int r;
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
char *name;
|
|
|
|
char **dirs = (char**) directories;
|
|
|
|
|
|
|
|
assert(!strv_isempty(dirs));
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
name = basename(dirs[0]);
|
|
|
|
assert(!isempty(name));
|
2014-03-06 02:19:06 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
/* Executes all binaries in the directories in parallel and waits
|
|
|
|
* for them to finish. Optionally a timeout is applied. If a file
|
|
|
|
* with the same name exists in more than one directory, the
|
|
|
|
* earliest one wins. */
|
2011-02-15 00:30:11 +01:00
|
|
|
|
2015-01-08 23:30:07 +01:00
|
|
|
executor_pid = fork();
|
|
|
|
if (executor_pid < 0) {
|
|
|
|
log_error_errno(errno, "Failed to fork: %m");
|
|
|
|
return;
|
|
|
|
|
|
|
|
} else if (executor_pid == 0) {
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
r = do_execute(dirs, timeout, argv);
|
2015-01-08 23:30:07 +01:00
|
|
|
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
2014-03-06 02:19:06 +01:00
|
|
|
}
|
2011-02-15 00:30:11 +01:00
|
|
|
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
wait_for_terminate_and_warn(name, executor_pid, true);
|
2011-02-15 00:30:11 +01:00
|
|
|
}
|
|
|
|
|
2015-03-16 18:29:26 +01:00
|
|
|
bool plymouth_running(void) {
|
|
|
|
return access("/run/plymouth/pid", F_OK) >= 0;
|
|
|
|
}
|
|
|
|
|
2011-06-27 22:44:12 +02:00
|
|
|
bool display_is_local(const char *display) {
|
|
|
|
assert(display);
|
|
|
|
|
|
|
|
return
|
|
|
|
display[0] == ':' &&
|
|
|
|
display[1] >= '0' &&
|
|
|
|
display[1] <= '9';
|
|
|
|
}
|
|
|
|
|
|
|
|
int socket_from_display(const char *display, char **path) {
|
|
|
|
size_t k;
|
|
|
|
char *f, *c;
|
|
|
|
|
|
|
|
assert(display);
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
if (!display_is_local(display))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
k = strspn(display+1, "0123456789");
|
|
|
|
|
2014-03-15 19:40:07 +01:00
|
|
|
f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
|
2011-06-27 22:44:12 +02:00
|
|
|
if (!f)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
c = stpcpy(f, "/tmp/.X11-unix/X");
|
|
|
|
memcpy(c, display+1, k);
|
|
|
|
c[k] = 0;
|
|
|
|
|
|
|
|
*path = f;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-21 00:28:30 +02:00
|
|
|
int block_get_whole_disk(dev_t d, dev_t *ret) {
|
|
|
|
char *p, *s;
|
|
|
|
int r;
|
|
|
|
unsigned n, m;
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
/* If it has a queue this is good enough for us */
|
|
|
|
if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = access(p, F_OK);
|
|
|
|
free(p);
|
|
|
|
|
|
|
|
if (r >= 0) {
|
|
|
|
*ret = d;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If it is a partition find the originating device */
|
|
|
|
if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = access(p, F_OK);
|
|
|
|
free(p);
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
/* Get parent dev_t */
|
|
|
|
if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = read_one_line_file(p, &s);
|
|
|
|
free(p);
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sscanf(s, "%u:%u", &m, &n);
|
|
|
|
free(s);
|
|
|
|
|
|
|
|
if (r != 2)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Only return this if it is really good enough for us. */
|
|
|
|
if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = access(p, F_OK);
|
|
|
|
free(p);
|
|
|
|
|
|
|
|
if (r >= 0) {
|
|
|
|
*ret = makedev(m, n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2011-08-22 14:58:50 +02:00
|
|
|
bool kexec_loaded(void) {
|
|
|
|
bool loaded = false;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
|
|
|
|
if (s[0] == '1')
|
|
|
|
loaded = true;
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
return loaded;
|
|
|
|
}
|
2011-09-28 04:25:13 +02:00
|
|
|
|
2011-10-07 21:06:39 +02:00
|
|
|
int prot_from_flags(int flags) {
|
|
|
|
|
|
|
|
switch (flags & O_ACCMODE) {
|
|
|
|
|
|
|
|
case O_RDONLY:
|
|
|
|
return PROT_READ;
|
|
|
|
|
|
|
|
case O_WRONLY:
|
|
|
|
return PROT_WRITE;
|
|
|
|
|
|
|
|
case O_RDWR:
|
|
|
|
return PROT_READ|PROT_WRITE;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2011-10-12 04:42:38 +02:00
|
|
|
}
|
2011-10-12 04:29:11 +02:00
|
|
|
|
2012-04-11 22:37:13 +02:00
|
|
|
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
|
2012-04-11 18:50:16 +02:00
|
|
|
bool stdout_is_tty, stderr_is_tty;
|
2014-08-27 21:42:20 +02:00
|
|
|
pid_t parent_pid, agent_pid;
|
|
|
|
sigset_t ss, saved_ss;
|
2012-04-11 18:50:16 +02:00
|
|
|
unsigned n, i;
|
|
|
|
va_list ap;
|
|
|
|
char **l;
|
|
|
|
|
|
|
|
assert(pid);
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
/* Spawns a temporary TTY agent, making sure it goes away when
|
|
|
|
* we go away */
|
|
|
|
|
2014-08-27 21:42:20 +02:00
|
|
|
parent_pid = getpid();
|
|
|
|
|
|
|
|
/* First we temporarily block all signals, so that the new
|
|
|
|
* child has them blocked initially. This way, we can be sure
|
|
|
|
* that SIGTERMs are not lost we might send to the agent. */
|
|
|
|
assert_se(sigfillset(&ss) >= 0);
|
|
|
|
assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
|
|
|
|
|
2012-04-11 18:50:16 +02:00
|
|
|
agent_pid = fork();
|
2014-08-27 21:42:20 +02:00
|
|
|
if (agent_pid < 0) {
|
|
|
|
assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
|
2012-04-11 18:50:16 +02:00
|
|
|
return -errno;
|
2014-08-27 21:42:20 +02:00
|
|
|
}
|
2012-04-11 18:50:16 +02:00
|
|
|
|
|
|
|
if (agent_pid != 0) {
|
2014-08-27 21:42:20 +02:00
|
|
|
assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
|
2012-04-11 18:50:16 +02:00
|
|
|
*pid = agent_pid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In the child:
|
|
|
|
*
|
|
|
|
* Make sure the agent goes away when the parent dies */
|
|
|
|
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
|
2014-08-27 21:42:20 +02:00
|
|
|
/* Make sure we actually can kill the agent, if we need to, in
|
|
|
|
* case somebody invoked us from a shell script that trapped
|
|
|
|
* SIGTERM or so... */
|
2015-05-31 23:55:55 +02:00
|
|
|
(void) reset_all_signal_handlers();
|
|
|
|
(void) reset_signal_mask();
|
2014-08-27 21:42:20 +02:00
|
|
|
|
2012-04-11 18:50:16 +02:00
|
|
|
/* Check whether our parent died before we were able
|
2014-08-27 21:42:20 +02:00
|
|
|
* to set the death signal and unblock the signals */
|
2012-04-11 18:50:16 +02:00
|
|
|
if (getppid() != parent_pid)
|
|
|
|
_exit(EXIT_SUCCESS);
|
|
|
|
|
|
|
|
/* Don't leak fds to the agent */
|
2012-04-11 22:37:13 +02:00
|
|
|
close_all_fds(except, n_except);
|
2012-04-11 18:50:16 +02:00
|
|
|
|
|
|
|
stdout_is_tty = isatty(STDOUT_FILENO);
|
|
|
|
stderr_is_tty = isatty(STDERR_FILENO);
|
|
|
|
|
|
|
|
if (!stdout_is_tty || !stderr_is_tty) {
|
2014-08-27 21:42:20 +02:00
|
|
|
int fd;
|
|
|
|
|
2012-04-11 18:50:16 +02:00
|
|
|
/* Detach from stdout/stderr. and reopen
|
|
|
|
* /dev/tty for them. This is important to
|
|
|
|
* ensure that when systemctl is started via
|
|
|
|
* popen() or a similar call that expects to
|
|
|
|
* read EOF we actually do generate EOF and
|
|
|
|
* not delay this indefinitely by because we
|
|
|
|
* keep an unused copy of stdin around. */
|
|
|
|
fd = open("/dev/tty", O_WRONLY);
|
|
|
|
if (fd < 0) {
|
2014-11-28 19:29:59 +01:00
|
|
|
log_error_errno(errno, "Failed to open /dev/tty: %m");
|
2012-04-11 18:50:16 +02:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2016-04-09 03:08:29 +02:00
|
|
|
if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
|
|
|
|
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-11 18:50:16 +02:00
|
|
|
|
2016-04-09 03:08:29 +02:00
|
|
|
if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
|
|
|
|
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-11 18:50:16 +02:00
|
|
|
|
2016-04-09 03:08:29 +02:00
|
|
|
if (fd > STDERR_FILENO)
|
2012-04-11 18:50:16 +02:00
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Count arguments */
|
|
|
|
va_start(ap, path);
|
|
|
|
for (n = 0; va_arg(ap, char*); n++)
|
|
|
|
;
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
/* Allocate strv */
|
|
|
|
l = alloca(sizeof(char *) * (n + 1));
|
|
|
|
|
|
|
|
/* Fill in arguments */
|
|
|
|
va_start(ap, path);
|
|
|
|
for (i = 0; i <= n; i++)
|
|
|
|
l[i] = va_arg(ap, char*);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
execv(path, l);
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
2012-04-12 03:38:52 +02:00
|
|
|
|
2012-05-16 14:22:40 +02:00
|
|
|
bool in_initrd(void) {
|
2012-07-10 18:46:26 +02:00
|
|
|
struct statfs s;
|
2012-05-21 20:00:58 +02:00
|
|
|
|
2016-06-13 16:28:42 +02:00
|
|
|
if (saved_in_initrd >= 0)
|
|
|
|
return saved_in_initrd;
|
2012-07-10 18:46:26 +02:00
|
|
|
|
|
|
|
/* We make two checks here:
|
|
|
|
*
|
|
|
|
* 1. the flag file /etc/initrd-release must exist
|
|
|
|
* 2. the root file system must be a memory file system
|
|
|
|
*
|
|
|
|
* The second check is extra paranoia, since misdetecting an
|
2016-10-02 19:37:21 +02:00
|
|
|
* initrd can have bad consequences due the initrd
|
2012-07-10 18:46:26 +02:00
|
|
|
* emptying when transititioning to the main systemd.
|
|
|
|
*/
|
|
|
|
|
2016-06-13 16:28:42 +02:00
|
|
|
saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
|
|
|
|
statfs("/", &s) >= 0 &&
|
|
|
|
is_temporary_fs(&s);
|
2012-05-16 14:22:40 +02:00
|
|
|
|
2016-06-13 16:28:42 +02:00
|
|
|
return saved_in_initrd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void in_initrd_force(bool value) {
|
|
|
|
saved_in_initrd = value;
|
2012-05-16 14:22:40 +02:00
|
|
|
}
|
2012-05-30 15:01:51 +02:00
|
|
|
|
2012-10-22 14:31:46 +02:00
|
|
|
/* hey glibc, APIs with callbacks without a user pointer are so useless */
|
|
|
|
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
2012-10-25 21:40:01 +02:00
|
|
|
int (*compar) (const void *, const void *, void *), void *arg) {
|
2012-10-22 14:31:46 +02:00
|
|
|
size_t l, u, idx;
|
|
|
|
const void *p;
|
|
|
|
int comparison;
|
|
|
|
|
|
|
|
l = 0;
|
|
|
|
u = nmemb;
|
|
|
|
while (l < u) {
|
|
|
|
idx = (l + u) / 2;
|
|
|
|
p = (void *)(((const char *) base) + (idx * size));
|
|
|
|
comparison = compar(key, p, arg);
|
|
|
|
if (comparison < 0)
|
|
|
|
u = idx;
|
|
|
|
else if (comparison > 0)
|
|
|
|
l = idx + 1;
|
|
|
|
else
|
|
|
|
return (void *)p;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-11-02 17:27:15 +01:00
|
|
|
|
2012-12-25 16:29:51 +01:00
|
|
|
int on_ac_power(void) {
|
|
|
|
bool found_offline = false, found_online = false;
|
|
|
|
_cleanup_closedir_ DIR *d = NULL;
|
2016-12-09 10:04:30 +01:00
|
|
|
struct dirent *de;
|
2012-12-25 16:29:51 +01:00
|
|
|
|
|
|
|
d = opendir("/sys/class/power_supply");
|
|
|
|
if (!d)
|
2015-03-04 01:07:28 +01:00
|
|
|
return errno == ENOENT ? true : -errno;
|
2012-12-25 16:29:51 +01:00
|
|
|
|
2016-12-09 10:04:30 +01:00
|
|
|
FOREACH_DIRENT(de, d, return -errno) {
|
2012-12-25 16:29:51 +01:00
|
|
|
_cleanup_close_ int fd = -1, device = -1;
|
|
|
|
char contents[6];
|
|
|
|
ssize_t n;
|
|
|
|
|
|
|
|
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
|
|
if (device < 0) {
|
|
|
|
if (errno == ENOENT || errno == ENOTDIR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
|
|
if (fd < 0) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = read(fd, contents, sizeof(contents));
|
|
|
|
if (n < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
if (n != 6 || memcmp(contents, "Mains\n", 6))
|
|
|
|
continue;
|
|
|
|
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(fd);
|
2012-12-25 16:29:51 +01:00
|
|
|
fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
|
|
if (fd < 0) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = read(fd, contents, sizeof(contents));
|
|
|
|
if (n < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
if (n != 2 || contents[1] != '\n')
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
if (contents[0] == '1') {
|
|
|
|
found_online = true;
|
|
|
|
break;
|
|
|
|
} else if (contents[0] == '0')
|
|
|
|
found_offline = true;
|
|
|
|
else
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return found_online || !found_offline;
|
|
|
|
}
|
2013-02-11 23:48:36 +01:00
|
|
|
|
2013-12-13 22:02:47 +01:00
|
|
|
int container_get_leader(const char *machine, pid_t *pid) {
|
|
|
|
_cleanup_free_ char *s = NULL, *class = NULL;
|
|
|
|
const char *p;
|
|
|
|
pid_t leader;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(machine);
|
|
|
|
assert(pid);
|
|
|
|
|
2015-08-23 14:33:50 +02:00
|
|
|
if (!machine_name_is_valid(machine))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-02-03 02:05:59 +01:00
|
|
|
p = strjoina("/run/systemd/machines/", machine);
|
2013-12-13 22:02:47 +01:00
|
|
|
r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
return -EHOSTDOWN;
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (!s)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
if (!streq_ptr(class, "container"))
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
r = parse_pid(s, &leader);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (leader <= 1)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
*pid = leader;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
namespace helpers: Allow entering a UID namespace
To be able to use `systemd-run` or `machinectl login` on a container
that is in a private user namespace, the sub-process must have entered
the user namespace before connecting to the container's D-Bus, otherwise
the UID and GID in the peer credentials are garbage.
So we extend namespace_open and namespace_enter to support UID namespaces,
and we enter the UID namespace in bus_container_connect_{socket,kernel}.
namespace_open will degrade to a no-op if user namespaces are not enabled
in the kernel.
Special handling is required for the setns call in namespace_enter with
a user namespace, since transitioning to your own namespace is forbidden,
as it would result in re-entering your user namespace as root.
Arguably it may be valid to check this at the call site, rather than
inside namespace_enter, but it is less code to do it inside, and if the
intention of calling namespace_enter is to *be* in the target namespace,
rather than to transition to the target namespace, it is a reasonable
approach.
The check for whether the user namespace is the same must happen before
entering namespaces, as we may not be able to access /proc during the
intermediate transition stage.
We can't instead attempt to enter the user namespace and then ignore
the failure from it being the same namespace, since the error code is
not distinct, and we can't compare namespaces while mid-transition.
2015-08-17 10:52:13 +02:00
|
|
|
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
|
|
|
|
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
|
2014-05-21 10:44:45 +02:00
|
|
|
int rfd = -1;
|
2013-12-13 22:02:47 +01:00
|
|
|
|
|
|
|
assert(pid >= 0);
|
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (mntns_fd) {
|
|
|
|
const char *mntns;
|
2013-12-17 01:03:09 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
mntns = procfs_file_alloca(pid, "ns/mnt");
|
|
|
|
mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
|
|
|
if (mntnsfd < 0)
|
|
|
|
return -errno;
|
|
|
|
}
|
2013-12-13 22:02:47 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (pidns_fd) {
|
|
|
|
const char *pidns;
|
|
|
|
|
|
|
|
pidns = procfs_file_alloca(pid, "ns/pid");
|
|
|
|
pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
|
|
|
if (pidnsfd < 0)
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (netns_fd) {
|
|
|
|
const char *netns;
|
|
|
|
|
|
|
|
netns = procfs_file_alloca(pid, "ns/net");
|
|
|
|
netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
|
|
|
if (netnsfd < 0)
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
namespace helpers: Allow entering a UID namespace
To be able to use `systemd-run` or `machinectl login` on a container
that is in a private user namespace, the sub-process must have entered
the user namespace before connecting to the container's D-Bus, otherwise
the UID and GID in the peer credentials are garbage.
So we extend namespace_open and namespace_enter to support UID namespaces,
and we enter the UID namespace in bus_container_connect_{socket,kernel}.
namespace_open will degrade to a no-op if user namespaces are not enabled
in the kernel.
Special handling is required for the setns call in namespace_enter with
a user namespace, since transitioning to your own namespace is forbidden,
as it would result in re-entering your user namespace as root.
Arguably it may be valid to check this at the call site, rather than
inside namespace_enter, but it is less code to do it inside, and if the
intention of calling namespace_enter is to *be* in the target namespace,
rather than to transition to the target namespace, it is a reasonable
approach.
The check for whether the user namespace is the same must happen before
entering namespaces, as we may not be able to access /proc during the
intermediate transition stage.
We can't instead attempt to enter the user namespace and then ignore
the failure from it being the same namespace, since the error code is
not distinct, and we can't compare namespaces while mid-transition.
2015-08-17 10:52:13 +02:00
|
|
|
if (userns_fd) {
|
|
|
|
const char *userns;
|
|
|
|
|
|
|
|
userns = procfs_file_alloca(pid, "ns/user");
|
|
|
|
usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
|
|
|
if (usernsfd < 0 && errno != ENOENT)
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (root_fd) {
|
|
|
|
const char *root;
|
|
|
|
|
|
|
|
root = procfs_file_alloca(pid, "root");
|
|
|
|
rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
|
|
|
|
if (rfd < 0)
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pidns_fd)
|
|
|
|
*pidns_fd = pidnsfd;
|
2013-12-13 22:02:47 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (mntns_fd)
|
|
|
|
*mntns_fd = mntnsfd;
|
|
|
|
|
|
|
|
if (netns_fd)
|
|
|
|
*netns_fd = netnsfd;
|
|
|
|
|
namespace helpers: Allow entering a UID namespace
To be able to use `systemd-run` or `machinectl login` on a container
that is in a private user namespace, the sub-process must have entered
the user namespace before connecting to the container's D-Bus, otherwise
the UID and GID in the peer credentials are garbage.
So we extend namespace_open and namespace_enter to support UID namespaces,
and we enter the UID namespace in bus_container_connect_{socket,kernel}.
namespace_open will degrade to a no-op if user namespaces are not enabled
in the kernel.
Special handling is required for the setns call in namespace_enter with
a user namespace, since transitioning to your own namespace is forbidden,
as it would result in re-entering your user namespace as root.
Arguably it may be valid to check this at the call site, rather than
inside namespace_enter, but it is less code to do it inside, and if the
intention of calling namespace_enter is to *be* in the target namespace,
rather than to transition to the target namespace, it is a reasonable
approach.
The check for whether the user namespace is the same must happen before
entering namespaces, as we may not be able to access /proc during the
intermediate transition stage.
We can't instead attempt to enter the user namespace and then ignore
the failure from it being the same namespace, since the error code is
not distinct, and we can't compare namespaces while mid-transition.
2015-08-17 10:52:13 +02:00
|
|
|
if (userns_fd)
|
|
|
|
*userns_fd = usernsfd;
|
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (root_fd)
|
|
|
|
*root_fd = rfd;
|
|
|
|
|
namespace helpers: Allow entering a UID namespace
To be able to use `systemd-run` or `machinectl login` on a container
that is in a private user namespace, the sub-process must have entered
the user namespace before connecting to the container's D-Bus, otherwise
the UID and GID in the peer credentials are garbage.
So we extend namespace_open and namespace_enter to support UID namespaces,
and we enter the UID namespace in bus_container_connect_{socket,kernel}.
namespace_open will degrade to a no-op if user namespaces are not enabled
in the kernel.
Special handling is required for the setns call in namespace_enter with
a user namespace, since transitioning to your own namespace is forbidden,
as it would result in re-entering your user namespace as root.
Arguably it may be valid to check this at the call site, rather than
inside namespace_enter, but it is less code to do it inside, and if the
intention of calling namespace_enter is to *be* in the target namespace,
rather than to transition to the target namespace, it is a reasonable
approach.
The check for whether the user namespace is the same must happen before
entering namespaces, as we may not be able to access /proc during the
intermediate transition stage.
We can't instead attempt to enter the user namespace and then ignore
the failure from it being the same namespace, since the error code is
not distinct, and we can't compare namespaces while mid-transition.
2015-08-17 10:52:13 +02:00
|
|
|
pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
|
2013-12-13 22:02:47 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
namespace helpers: Allow entering a UID namespace
To be able to use `systemd-run` or `machinectl login` on a container
that is in a private user namespace, the sub-process must have entered
the user namespace before connecting to the container's D-Bus, otherwise
the UID and GID in the peer credentials are garbage.
So we extend namespace_open and namespace_enter to support UID namespaces,
and we enter the UID namespace in bus_container_connect_{socket,kernel}.
namespace_open will degrade to a no-op if user namespaces are not enabled
in the kernel.
Special handling is required for the setns call in namespace_enter with
a user namespace, since transitioning to your own namespace is forbidden,
as it would result in re-entering your user namespace as root.
Arguably it may be valid to check this at the call site, rather than
inside namespace_enter, but it is less code to do it inside, and if the
intention of calling namespace_enter is to *be* in the target namespace,
rather than to transition to the target namespace, it is a reasonable
approach.
The check for whether the user namespace is the same must happen before
entering namespaces, as we may not be able to access /proc during the
intermediate transition stage.
We can't instead attempt to enter the user namespace and then ignore
the failure from it being the same namespace, since the error code is
not distinct, and we can't compare namespaces while mid-transition.
2015-08-17 10:52:13 +02:00
|
|
|
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
|
|
|
|
if (userns_fd >= 0) {
|
|
|
|
/* Can't setns to your own userns, since then you could
|
|
|
|
* escalate from non-root to root in your own namespace, so
|
|
|
|
* check if namespaces equal before attempting to enter. */
|
|
|
|
_cleanup_free_ char *userns_fd_path = NULL;
|
|
|
|
int r;
|
|
|
|
if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = files_same(userns_fd_path, "/proc/self/ns/user");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r)
|
|
|
|
userns_fd = -1;
|
|
|
|
}
|
2013-12-13 22:02:47 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (pidns_fd >= 0)
|
|
|
|
if (setns(pidns_fd, CLONE_NEWPID) < 0)
|
|
|
|
return -errno;
|
2013-12-17 01:03:09 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (mntns_fd >= 0)
|
|
|
|
if (setns(mntns_fd, CLONE_NEWNS) < 0)
|
|
|
|
return -errno;
|
2013-12-13 22:02:47 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (netns_fd >= 0)
|
|
|
|
if (setns(netns_fd, CLONE_NEWNET) < 0)
|
|
|
|
return -errno;
|
2013-12-13 22:02:47 +01:00
|
|
|
|
namespace helpers: Allow entering a UID namespace
To be able to use `systemd-run` or `machinectl login` on a container
that is in a private user namespace, the sub-process must have entered
the user namespace before connecting to the container's D-Bus, otherwise
the UID and GID in the peer credentials are garbage.
So we extend namespace_open and namespace_enter to support UID namespaces,
and we enter the UID namespace in bus_container_connect_{socket,kernel}.
namespace_open will degrade to a no-op if user namespaces are not enabled
in the kernel.
Special handling is required for the setns call in namespace_enter with
a user namespace, since transitioning to your own namespace is forbidden,
as it would result in re-entering your user namespace as root.
Arguably it may be valid to check this at the call site, rather than
inside namespace_enter, but it is less code to do it inside, and if the
intention of calling namespace_enter is to *be* in the target namespace,
rather than to transition to the target namespace, it is a reasonable
approach.
The check for whether the user namespace is the same must happen before
entering namespaces, as we may not be able to access /proc during the
intermediate transition stage.
We can't instead attempt to enter the user namespace and then ignore
the failure from it being the same namespace, since the error code is
not distinct, and we can't compare namespaces while mid-transition.
2015-08-17 10:52:13 +02:00
|
|
|
if (userns_fd >= 0)
|
|
|
|
if (setns(userns_fd, CLONE_NEWUSER) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
if (root_fd >= 0) {
|
|
|
|
if (fchdir(root_fd) < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
if (chroot(".") < 0)
|
|
|
|
return -errno;
|
|
|
|
}
|
2013-12-13 22:02:47 +01:00
|
|
|
|
2015-05-20 14:41:39 +02:00
|
|
|
return reset_uid_gid();
|
2013-12-13 22:02:47 +01:00
|
|
|
}
|
2013-12-18 04:19:20 +01:00
|
|
|
|
2014-03-04 19:20:21 +01:00
|
|
|
uint64_t physical_memory(void) {
|
2016-06-08 18:56:20 +02:00
|
|
|
_cleanup_free_ char *root = NULL, *value = NULL;
|
|
|
|
uint64_t mem, lim;
|
|
|
|
size_t ps;
|
|
|
|
long sc;
|
2014-03-04 19:20:21 +01:00
|
|
|
|
2016-06-08 18:56:20 +02:00
|
|
|
/* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
|
|
|
|
* memory.
|
|
|
|
*
|
|
|
|
* In order to support containers nicely that have a configured memory limit we'll take the minimum of the
|
|
|
|
* physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
|
|
|
|
|
|
|
|
sc = sysconf(_SC_PHYS_PAGES);
|
|
|
|
assert(sc > 0);
|
|
|
|
|
|
|
|
ps = page_size();
|
|
|
|
mem = (uint64_t) sc * (uint64_t) ps;
|
|
|
|
|
|
|
|
if (cg_get_root_path(&root) < 0)
|
|
|
|
return mem;
|
|
|
|
|
|
|
|
if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value))
|
|
|
|
return mem;
|
|
|
|
|
|
|
|
if (safe_atou64(value, &lim) < 0)
|
|
|
|
return mem;
|
2014-03-04 19:20:21 +01:00
|
|
|
|
2016-06-08 18:56:20 +02:00
|
|
|
/* Make sure the limit is a multiple of our own page size */
|
|
|
|
lim /= ps;
|
|
|
|
lim *= ps;
|
2014-03-04 19:20:21 +01:00
|
|
|
|
2016-06-08 18:56:20 +02:00
|
|
|
return MIN(mem, lim);
|
2014-03-04 19:20:21 +01:00
|
|
|
}
|
2014-03-06 21:14:26 +01:00
|
|
|
|
2016-06-08 20:45:32 +02:00
|
|
|
uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
|
|
|
|
uint64_t p, m, ps, r;
|
|
|
|
|
|
|
|
assert(max > 0);
|
|
|
|
|
|
|
|
/* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
|
|
|
|
* the result is a multiple of the page size (rounds down). */
|
|
|
|
|
|
|
|
ps = page_size();
|
|
|
|
assert(ps > 0);
|
|
|
|
|
|
|
|
p = physical_memory() / ps;
|
|
|
|
assert(p > 0);
|
|
|
|
|
|
|
|
m = p * v;
|
|
|
|
if (m / p != v)
|
|
|
|
return UINT64_MAX;
|
|
|
|
|
|
|
|
m /= max;
|
|
|
|
|
|
|
|
r = m * ps;
|
|
|
|
if (r / ps != m)
|
|
|
|
return UINT64_MAX;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-07-19 15:58:49 +02:00
|
|
|
uint64_t system_tasks_max(void) {
|
|
|
|
|
|
|
|
#if SIZEOF_PID_T == 4
|
|
|
|
#define TASKS_MAX ((uint64_t) (INT32_MAX-1))
|
|
|
|
#elif SIZEOF_PID_T == 2
|
|
|
|
#define TASKS_MAX ((uint64_t) (INT16_MAX-1))
|
|
|
|
#else
|
|
|
|
#error "Unknown pid_t size"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
_cleanup_free_ char *value = NULL, *root = NULL;
|
|
|
|
uint64_t a = TASKS_MAX, b = TASKS_MAX;
|
|
|
|
|
|
|
|
/* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
|
|
|
|
* limit:
|
|
|
|
*
|
|
|
|
* a) the maximum value for the pid_t type
|
|
|
|
* b) the cgroups pids_max attribute for the system
|
|
|
|
* c) the kernel's configure maximum PID value
|
|
|
|
*
|
|
|
|
* And then pick the smallest of the three */
|
|
|
|
|
|
|
|
if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0)
|
|
|
|
(void) safe_atou64(value, &a);
|
|
|
|
|
|
|
|
if (cg_get_root_path(&root) >= 0) {
|
|
|
|
value = mfree(value);
|
|
|
|
|
|
|
|
if (cg_get_attribute("pids", root, "pids.max", &value) >= 0)
|
|
|
|
(void) safe_atou64(value, &b);
|
|
|
|
}
|
|
|
|
|
|
|
|
return MIN3(TASKS_MAX,
|
|
|
|
a <= 0 ? TASKS_MAX : a,
|
|
|
|
b <= 0 ? TASKS_MAX : b);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
|
|
|
|
uint64_t t, m;
|
|
|
|
|
|
|
|
assert(max > 0);
|
|
|
|
|
|
|
|
/* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
|
|
|
|
* relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
|
|
|
|
|
|
|
|
t = system_tasks_max();
|
|
|
|
assert(t > 0);
|
|
|
|
|
|
|
|
m = t * v;
|
|
|
|
if (m / t != v) /* overflow? */
|
|
|
|
return UINT64_MAX;
|
|
|
|
|
|
|
|
return m / max;
|
|
|
|
}
|
|
|
|
|
2016-04-07 16:53:37 +02:00
|
|
|
int update_reboot_parameter_and_warn(const char *param) {
|
|
|
|
int r;
|
2014-03-25 14:15:44 +01:00
|
|
|
|
2016-04-07 16:53:37 +02:00
|
|
|
if (isempty(param)) {
|
|
|
|
if (unlink("/run/systemd/reboot-param") < 0) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-09 04:20:22 +02:00
|
|
|
RUN_WITH_UMASK(0022) {
|
2016-04-07 16:53:37 +02:00
|
|
|
r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
|
2016-04-09 04:20:22 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_warning_errno(r, "Failed to write reboot parameter file: %m");
|
|
|
|
}
|
2014-03-25 14:15:44 +01:00
|
|
|
|
2015-09-30 22:16:17 +02:00
|
|
|
return 0;
|
2014-03-25 14:15:44 +01:00
|
|
|
}
|
2014-06-05 21:35:35 +02:00
|
|
|
|
2015-09-23 03:01:06 +02:00
|
|
|
int version(void) {
|
|
|
|
puts(PACKAGE_STRING "\n"
|
|
|
|
SYSTEMD_FEATURES);
|
|
|
|
return 0;
|
|
|
|
}
|