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
|
||||
--user
|
||||
--cgroup
|
||||
--time
|
||||
--fork
|
||||
--kill-child
|
||||
--keep-caps
|
||||
|
@ -38,6 +39,8 @@ _unshare_module()
|
|||
--version
|
||||
--root
|
||||
--wd
|
||||
--monotonic
|
||||
--boottime
|
||||
--setuid
|
||||
--setgid"
|
||||
COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
# ifndef CLONE_NEWPID
|
||||
# define CLONE_NEWPID 0x20000000
|
||||
# endif
|
||||
# ifndef CLONE_NEWTIME
|
||||
# define CLONE_NEWTIME 0x00000080
|
||||
# endif
|
||||
|
||||
# if !defined(HAVE_UNSHARE) || !defined(HAVE_SETNS)
|
||||
# include <sys/syscall.h>
|
||||
|
|
|
@ -100,6 +100,13 @@ and the discussion of the
|
|||
.B CLONE_NEWUSER
|
||||
flag in
|
||||
.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
|
||||
.TP
|
||||
.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
|
||||
by bind mount.
|
||||
.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"
|
||||
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.
|
||||
|
@ -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
|
||||
supplementary groups.
|
||||
.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"
|
||||
Display version information and exit.
|
||||
.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.
|
||||
Without it, the children of \fIprogram\fR would have orphaned and
|
||||
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
|
||||
.BR clone (2),
|
||||
|
|
|
@ -65,6 +65,7 @@ static struct namespace_file {
|
|||
{ .type = CLONE_NEWNET, .name = "ns/net" },
|
||||
{ .type = CLONE_NEWPID, .name = "ns/pid" },
|
||||
{ .type = CLONE_NEWNS, .name = "ns/mnt" },
|
||||
{ .type = CLONE_NEWTIME, .name = "ns/time" },
|
||||
{ .name = NULL }
|
||||
};
|
||||
|
||||
|
@ -213,6 +214,23 @@ static ino_t get_mnt_ino(pid_t pid)
|
|||
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])
|
||||
{
|
||||
char ch;
|
||||
|
@ -267,6 +285,7 @@ static void __attribute__((__noreturn__)) usage(void)
|
|||
fputs(_(" -p, --pid[=<file>] unshare pid namespace\n"), out);
|
||||
fputs(_(" -U, --user[=<file>] unshare user 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(_(" -f, --fork fork before launching <program>\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(_(" --keep-caps retain capabilities granted in user namespaces\n"), out);
|
||||
fputs(USAGE_SEPARATOR, 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(_(" -S, --setuid <uid> set uid in entered namespace\n"), out);
|
||||
fputs(_(" -G, --setgid <gid> set gid in entered namespace\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(_(" -S, --setuid <uid> set uid 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);
|
||||
printf(USAGE_HELP_OPTIONS(27));
|
||||
|
@ -300,6 +321,8 @@ int main(int argc, char *argv[])
|
|||
OPT_SETGROUPS,
|
||||
OPT_KILLCHILD,
|
||||
OPT_KEEPCAPS,
|
||||
OPT_MONOTONIC,
|
||||
OPT_BOOTTIME,
|
||||
};
|
||||
static const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
|
@ -312,6 +335,7 @@ int main(int argc, char *argv[])
|
|||
{ "pid", optional_argument, NULL, 'p' },
|
||||
{ "user", optional_argument, NULL, 'U' },
|
||||
{ "cgroup", optional_argument, NULL, 'C' },
|
||||
{ "time", optional_argument, NULL, 't' },
|
||||
|
||||
{ "fork", no_argument, NULL, 'f' },
|
||||
{ "kill-child", optional_argument, NULL, OPT_KILLCHILD },
|
||||
|
@ -325,6 +349,8 @@ int main(int argc, char *argv[])
|
|||
{ "setgid", required_argument, NULL, 'G' },
|
||||
{ "root", required_argument, NULL, 'R' },
|
||||
{ "wd", required_argument, NULL, 'w' },
|
||||
{ "monotonic", required_argument, NULL, OPT_MONOTONIC },
|
||||
{ "boottime", required_argument, NULL, OPT_BOOTTIME },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
|
@ -343,13 +369,17 @@ int main(int argc, char *argv[])
|
|||
uid_t uid = 0, real_euid = geteuid();
|
||||
gid_t gid = 0, real_egid = getegid();
|
||||
int keepcaps = 0;
|
||||
time_t monotonic = 0;
|
||||
time_t boottime = 0;
|
||||
int force_monotonic = 0;
|
||||
int force_boottime = 0;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
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) {
|
||||
case 'f':
|
||||
forkit = 1;
|
||||
|
@ -389,6 +419,11 @@ int main(int argc, char *argv[])
|
|||
if (optarg)
|
||||
set_ns_target(CLONE_NEWCGROUP, optarg);
|
||||
break;
|
||||
case 't':
|
||||
unshare_flags |= CLONE_NEWTIME;
|
||||
if (optarg)
|
||||
set_ns_target(CLONE_NEWTIME, optarg);
|
||||
break;
|
||||
case OPT_MOUNTPROC:
|
||||
unshare_flags |= CLONE_NEWNS;
|
||||
procmnt = optarg ? optarg : "/proc";
|
||||
|
@ -443,6 +478,14 @@ int main(int argc, char *argv[])
|
|||
case 'w':
|
||||
newdir = optarg;
|
||||
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':
|
||||
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))
|
||||
bind_ns_files_from_child(&pid, fds);
|
||||
|
||||
|
@ -486,6 +533,12 @@ int main(int argc, char *argv[])
|
|||
bind_ns_files(getpid());
|
||||
}
|
||||
|
||||
if (force_boottime)
|
||||
settime(boottime, CLOCK_BOOTTIME);
|
||||
|
||||
if (force_monotonic)
|
||||
settime(monotonic, CLOCK_MONOTONIC);
|
||||
|
||||
if (forkit) {
|
||||
pid = fork();
|
||||
|
||||
|
|
Loading…
Reference in New Issue