Merge branch 'time-namespace' of https://github.com/adrianreber/util-linux
* 'time-namespace' of https://github.com/adrianreber/util-linux: unshare: support the time namespace unshare: fix help message indentation
This commit is contained in:
commit
ef0341c9be
|
@ -26,6 +26,7 @@ _unshare_module()
|
||||||
--pid
|
--pid
|
||||||
--user
|
--user
|
||||||
--cgroup
|
--cgroup
|
||||||
|
--time
|
||||||
--fork
|
--fork
|
||||||
--kill-child
|
--kill-child
|
||||||
--keep-caps
|
--keep-caps
|
||||||
|
@ -38,6 +39,8 @@ _unshare_module()
|
||||||
--version
|
--version
|
||||||
--root
|
--root
|
||||||
--wd
|
--wd
|
||||||
|
--monotonic
|
||||||
|
--boottime
|
||||||
--setuid
|
--setuid
|
||||||
--setgid"
|
--setgid"
|
||||||
COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
|
COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
# ifndef CLONE_NEWPID
|
# ifndef CLONE_NEWPID
|
||||||
# define CLONE_NEWPID 0x20000000
|
# define CLONE_NEWPID 0x20000000
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef CLONE_NEWTIME
|
||||||
|
# define CLONE_NEWTIME 0x00000080
|
||||||
|
# endif
|
||||||
|
|
||||||
# if !defined(HAVE_UNSHARE) || !defined(HAVE_SETNS)
|
# if !defined(HAVE_UNSHARE) || !defined(HAVE_SETNS)
|
||||||
# include <sys/syscall.h>
|
# include <sys/syscall.h>
|
||||||
|
|
|
@ -100,6 +100,13 @@ and the discussion of the
|
||||||
.B CLONE_NEWUSER
|
.B CLONE_NEWUSER
|
||||||
flag in
|
flag in
|
||||||
.BR clone (2).
|
.BR clone (2).
|
||||||
|
.TP
|
||||||
|
.B time namespace
|
||||||
|
The process can have a distinct view of
|
||||||
|
.B CLOCK_MONOTONIC
|
||||||
|
and/or
|
||||||
|
.B CLOCK_BOOTTIME
|
||||||
|
which can be changed using \fI/proc/self/timens_offsets\fP.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.BR \-i , " \-\-ipc" [ =\fIfile ]
|
.BR \-i , " \-\-ipc" [ =\fIfile ]
|
||||||
|
@ -134,6 +141,12 @@ namespace is created by a bind mount.
|
||||||
Unshare the cgroup namespace. If \fIfile\fP is specified then persistent namespace is created
|
Unshare the cgroup namespace. If \fIfile\fP is specified then persistent namespace is created
|
||||||
by bind mount.
|
by bind mount.
|
||||||
.TP
|
.TP
|
||||||
|
.BR \-t , " \-\-time"[=\fIfile\fP]
|
||||||
|
Unshare the time namespace. If \fIfile\fP is specified then a persistent
|
||||||
|
namespace is created by a bind mount. The \fB\-\-monotonic\fP and
|
||||||
|
\fB\-\-boottime\fP options can be used to specify the corresponding
|
||||||
|
offset in the time namespace.
|
||||||
|
.TP
|
||||||
.BR \-f , " \-\-fork"
|
.BR \-f , " \-\-fork"
|
||||||
Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than
|
Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than
|
||||||
running it directly. This is useful when creating a new PID namespace.
|
running it directly. This is useful when creating a new PID namespace.
|
||||||
|
@ -208,6 +221,18 @@ Set the user ID which will be used in the entered namespace.
|
||||||
Set the group ID which will be used in the entered namespace and drop
|
Set the group ID which will be used in the entered namespace and drop
|
||||||
supplementary groups.
|
supplementary groups.
|
||||||
.TP
|
.TP
|
||||||
|
.BR "\-\-monotonic \fIoffset"
|
||||||
|
Set the offset of
|
||||||
|
.B CLOCK_MONOTONIC
|
||||||
|
which will be used in the entered time namespace. This option requires
|
||||||
|
unsharing a time namespace with \fB\-\-time\fP.
|
||||||
|
.TP
|
||||||
|
.BR "\-\-boottime \fIoffset"
|
||||||
|
Set the offset of
|
||||||
|
.B CLOCK_BOOTTIME
|
||||||
|
which will be used in the entered time namespace. This option requires
|
||||||
|
unsharing a time namespace with \fB\-\-time\fP.
|
||||||
|
.TP
|
||||||
.BR \-V , " \-\-version"
|
.BR \-V , " \-\-version"
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
.TP
|
.TP
|
||||||
|
@ -269,6 +294,10 @@ Reliable killing of subprocesses of the \fIprogram\fR.
|
||||||
When \fBunshare\fR gets killed, everything below it gets killed as well.
|
When \fBunshare\fR gets killed, everything below it gets killed as well.
|
||||||
Without it, the children of \fIprogram\fR would have orphaned and
|
Without it, the children of \fIprogram\fR would have orphaned and
|
||||||
been re-parented to PID 1.
|
been re-parented to PID 1.
|
||||||
|
.TP
|
||||||
|
.B # unshare \-\-fork \-\-time \-\-boottime 100000000 uptime
|
||||||
|
.TQ
|
||||||
|
10:58:48 up 1158 days, 6:05, 1 user, load average: 0.00, 0.00, 0.00
|
||||||
|
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR clone (2),
|
.BR clone (2),
|
||||||
|
|
|
@ -65,6 +65,7 @@ static struct namespace_file {
|
||||||
{ .type = CLONE_NEWNET, .name = "ns/net" },
|
{ .type = CLONE_NEWNET, .name = "ns/net" },
|
||||||
{ .type = CLONE_NEWPID, .name = "ns/pid" },
|
{ .type = CLONE_NEWPID, .name = "ns/pid" },
|
||||||
{ .type = CLONE_NEWNS, .name = "ns/mnt" },
|
{ .type = CLONE_NEWNS, .name = "ns/mnt" },
|
||||||
|
{ .type = CLONE_NEWTIME, .name = "ns/time" },
|
||||||
{ .name = NULL }
|
{ .name = NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -213,6 +214,23 @@ static ino_t get_mnt_ino(pid_t pid)
|
||||||
return st.st_ino;
|
return st.st_ino;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void settime(time_t offset, clockid_t clk_id)
|
||||||
|
{
|
||||||
|
char buf[sizeof(stringify_value(ULONG_MAX)) * 3];
|
||||||
|
int fd, len;
|
||||||
|
|
||||||
|
len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset);
|
||||||
|
|
||||||
|
fd = open("/proc/self/timens_offsets", O_WRONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
err(EXIT_FAILURE, _("failed to open /proc/self/timens_offsets"));
|
||||||
|
|
||||||
|
if (write(fd, buf, len) != len)
|
||||||
|
err(EXIT_FAILURE, _("failed to write to /proc/self/timens_offsets"));
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
static void bind_ns_files_from_child(pid_t *child, int fds[2])
|
static void bind_ns_files_from_child(pid_t *child, int fds[2])
|
||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
|
@ -267,6 +285,7 @@ static void __attribute__((__noreturn__)) usage(void)
|
||||||
fputs(_(" -p, --pid[=<file>] unshare pid namespace\n"), out);
|
fputs(_(" -p, --pid[=<file>] unshare pid namespace\n"), out);
|
||||||
fputs(_(" -U, --user[=<file>] unshare user namespace\n"), out);
|
fputs(_(" -U, --user[=<file>] unshare user namespace\n"), out);
|
||||||
fputs(_(" -C, --cgroup[=<file>] unshare cgroup namespace\n"), out);
|
fputs(_(" -C, --cgroup[=<file>] unshare cgroup namespace\n"), out);
|
||||||
|
fputs(_(" -t, --time[=<file>] unshare time namespace\n"), out);
|
||||||
fputs(USAGE_SEPARATOR, out);
|
fputs(USAGE_SEPARATOR, out);
|
||||||
fputs(_(" -f, --fork fork before launching <program>\n"), out);
|
fputs(_(" -f, --fork fork before launching <program>\n"), out);
|
||||||
fputs(_(" -r, --map-root-user map current user to root (implies --user)\n"), out);
|
fputs(_(" -r, --map-root-user map current user to root (implies --user)\n"), out);
|
||||||
|
@ -280,10 +299,12 @@ static void __attribute__((__noreturn__)) usage(void)
|
||||||
fputs(_(" --setgroups allow|deny control the setgroups syscall in user namespaces\n"), out);
|
fputs(_(" --setgroups allow|deny control the setgroups syscall in user namespaces\n"), out);
|
||||||
fputs(_(" --keep-caps retain capabilities granted in user namespaces\n"), out);
|
fputs(_(" --keep-caps retain capabilities granted in user namespaces\n"), out);
|
||||||
fputs(USAGE_SEPARATOR, out);
|
fputs(USAGE_SEPARATOR, out);
|
||||||
fputs(_(" -R, --root=<dir> run the command with root directory set to <dir>\n"), out);
|
fputs(_(" -R, --root=<dir> run the command with root directory set to <dir>\n"), out);
|
||||||
fputs(_(" -w, --wd=<dir> change working directory to <dir>\n"), out);
|
fputs(_(" -w, --wd=<dir> change working directory to <dir>\n"), out);
|
||||||
fputs(_(" -S, --setuid <uid> set uid in entered namespace\n"), out);
|
fputs(_(" -S, --setuid <uid> set uid in entered namespace\n"), out);
|
||||||
fputs(_(" -G, --setgid <gid> set gid in entered namespace\n"), out);
|
fputs(_(" -G, --setgid <gid> set gid in entered namespace\n"), out);
|
||||||
|
fputs(_(" --monotonic <offset> set clock monotonic offset (seconds) in time namespaces\n"), out);
|
||||||
|
fputs(_(" --boottime <offset> set clock boottime offset (seconds) in time namespaces\n"), out);
|
||||||
|
|
||||||
fputs(USAGE_SEPARATOR, out);
|
fputs(USAGE_SEPARATOR, out);
|
||||||
printf(USAGE_HELP_OPTIONS(27));
|
printf(USAGE_HELP_OPTIONS(27));
|
||||||
|
@ -300,6 +321,8 @@ int main(int argc, char *argv[])
|
||||||
OPT_SETGROUPS,
|
OPT_SETGROUPS,
|
||||||
OPT_KILLCHILD,
|
OPT_KILLCHILD,
|
||||||
OPT_KEEPCAPS,
|
OPT_KEEPCAPS,
|
||||||
|
OPT_MONOTONIC,
|
||||||
|
OPT_BOOTTIME,
|
||||||
};
|
};
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
@ -312,6 +335,7 @@ int main(int argc, char *argv[])
|
||||||
{ "pid", optional_argument, NULL, 'p' },
|
{ "pid", optional_argument, NULL, 'p' },
|
||||||
{ "user", optional_argument, NULL, 'U' },
|
{ "user", optional_argument, NULL, 'U' },
|
||||||
{ "cgroup", optional_argument, NULL, 'C' },
|
{ "cgroup", optional_argument, NULL, 'C' },
|
||||||
|
{ "time", optional_argument, NULL, 't' },
|
||||||
|
|
||||||
{ "fork", no_argument, NULL, 'f' },
|
{ "fork", no_argument, NULL, 'f' },
|
||||||
{ "kill-child", optional_argument, NULL, OPT_KILLCHILD },
|
{ "kill-child", optional_argument, NULL, OPT_KILLCHILD },
|
||||||
|
@ -325,6 +349,8 @@ int main(int argc, char *argv[])
|
||||||
{ "setgid", required_argument, NULL, 'G' },
|
{ "setgid", required_argument, NULL, 'G' },
|
||||||
{ "root", required_argument, NULL, 'R' },
|
{ "root", required_argument, NULL, 'R' },
|
||||||
{ "wd", required_argument, NULL, 'w' },
|
{ "wd", required_argument, NULL, 'w' },
|
||||||
|
{ "monotonic", required_argument, NULL, OPT_MONOTONIC },
|
||||||
|
{ "boottime", required_argument, NULL, OPT_BOOTTIME },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -343,13 +369,17 @@ int main(int argc, char *argv[])
|
||||||
uid_t uid = 0, real_euid = geteuid();
|
uid_t uid = 0, real_euid = geteuid();
|
||||||
gid_t gid = 0, real_egid = getegid();
|
gid_t gid = 0, real_egid = getegid();
|
||||||
int keepcaps = 0;
|
int keepcaps = 0;
|
||||||
|
time_t monotonic = 0;
|
||||||
|
time_t boottime = 0;
|
||||||
|
int force_monotonic = 0;
|
||||||
|
int force_boottime = 0;
|
||||||
|
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||||
textdomain(PACKAGE);
|
textdomain(PACKAGE);
|
||||||
close_stdout_atexit();
|
close_stdout_atexit();
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "+fhVmuinpCUrR:w:S:G:c", longopts, NULL)) != -1) {
|
while ((c = getopt_long(argc, argv, "+fhVmuinpCtUrR:w:S:G:c", longopts, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'f':
|
case 'f':
|
||||||
forkit = 1;
|
forkit = 1;
|
||||||
|
@ -389,6 +419,11 @@ int main(int argc, char *argv[])
|
||||||
if (optarg)
|
if (optarg)
|
||||||
set_ns_target(CLONE_NEWCGROUP, optarg);
|
set_ns_target(CLONE_NEWCGROUP, optarg);
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
unshare_flags |= CLONE_NEWTIME;
|
||||||
|
if (optarg)
|
||||||
|
set_ns_target(CLONE_NEWTIME, optarg);
|
||||||
|
break;
|
||||||
case OPT_MOUNTPROC:
|
case OPT_MOUNTPROC:
|
||||||
unshare_flags |= CLONE_NEWNS;
|
unshare_flags |= CLONE_NEWNS;
|
||||||
procmnt = optarg ? optarg : "/proc";
|
procmnt = optarg ? optarg : "/proc";
|
||||||
|
@ -443,6 +478,14 @@ int main(int argc, char *argv[])
|
||||||
case 'w':
|
case 'w':
|
||||||
newdir = optarg;
|
newdir = optarg;
|
||||||
break;
|
break;
|
||||||
|
case OPT_MONOTONIC:
|
||||||
|
monotonic = strtoul_or_err(optarg, _("failed to parse monotonic offset"));
|
||||||
|
force_monotonic = 1;
|
||||||
|
break;
|
||||||
|
case OPT_BOOTTIME:
|
||||||
|
boottime = strtoul_or_err(optarg, _("failed to parse boottime offset"));
|
||||||
|
force_boottime = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
usage();
|
usage();
|
||||||
|
@ -453,6 +496,10 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((force_monotonic || force_boottime) && !(unshare_flags & CLONE_NEWTIME))
|
||||||
|
errx(EXIT_FAILURE, _("options --monotonic and --boottime require "
|
||||||
|
"unsharing of a time namespace (-t)"));
|
||||||
|
|
||||||
if (npersists && (unshare_flags & CLONE_NEWNS))
|
if (npersists && (unshare_flags & CLONE_NEWNS))
|
||||||
bind_ns_files_from_child(&pid, fds);
|
bind_ns_files_from_child(&pid, fds);
|
||||||
|
|
||||||
|
@ -486,6 +533,12 @@ int main(int argc, char *argv[])
|
||||||
bind_ns_files(getpid());
|
bind_ns_files(getpid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (force_boottime)
|
||||||
|
settime(boottime, CLOCK_BOOTTIME);
|
||||||
|
|
||||||
|
if (force_monotonic)
|
||||||
|
settime(monotonic, CLOCK_MONOTONIC);
|
||||||
|
|
||||||
if (forkit) {
|
if (forkit) {
|
||||||
pid = fork();
|
pid = fork();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue