2
* lxc: linux Container library
4
* (C) Copyright IBM Corp. 2007, 2008
7
* Daniel Lezcano <dlezcano at fr.ibm.com>
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Lesser General Public
11
* License as published by the Free Software Foundation; either
12
* version 2.1 of the License, or (at your option) any later version.
14
* This library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Lesser General Public License for more details.
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with this library; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33
#include <sys/types.h>
39
#include "namespace.h"
43
lxc_log_define(lxc_unshare_ui, lxc);
47
fprintf(stderr, "%s <options> command [command_arguments]\n", basename(cmd));
48
fprintf(stderr, "Options are:\n");
49
fprintf(stderr, "\t -s flags: ORed list of flags to unshare:\n" \
50
"\t MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n");
51
fprintf(stderr, "\t -u <id> : new id to be set if -s USER is specified\n");
55
static uid_t lookup_user(const char *optarg)
57
int bufflen = sysconf(_SC_GETPW_R_SIZE_MAX);
59
char name[sysconf(_SC_LOGIN_NAME_MAX)];
64
if (!optarg || (optarg[0] == '\0'))
67
if (sscanf(optarg, "%u", &uid) < 1) {
68
/* not a uid -- perhaps a username */
69
if (sscanf(optarg, "%s", name) < 1)
72
if (getpwnam_r(name, &pwent, buff, bufflen, &pent) || !pent) {
73
ERROR("invalid username %s", name);
78
if (getpwuid_r(uid, &pwent, buff, bufflen, &pent) || !pent) {
79
ERROR("invalid uid %d", uid);
87
static char *namespaces_list[] = {
88
"MOUNT", "PID", "UTSNAME", "IPC",
91
static int cloneflags_list[] = {
92
CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
93
CLONE_NEWUSER, CLONE_NEWNET
96
static int lxc_namespace_2_cloneflag(char *namespace)
99
len = sizeof(namespaces_list)/sizeof(namespaces_list[0]);
100
for (i = 0; i < len; i++)
101
if (!strcmp(namespaces_list[i], namespace))
102
return cloneflags_list[i];
104
ERROR("invalid namespace name %s", namespace);
108
static int lxc_fill_namespace_flags(char *flaglist, int *flags)
110
char *token, *saveptr = NULL;
114
ERROR("need at least one namespace to unshare");
118
token = strtok_r(flaglist, "|", &saveptr);
121
aflag = lxc_namespace_2_cloneflag(token);
127
token = strtok_r(NULL, "|", &saveptr);
139
static int do_start(void *arg)
141
struct start_arg *start_arg = arg;
142
char **args = *start_arg->args;
143
int flags = *start_arg->flags;
144
uid_t uid = *start_arg->uid;
146
if (flags & CLONE_NEWUSER && setuid(uid)) {
147
ERROR("failed to set uid %d: %s", uid, strerror(errno));
151
execvp(args[0], args);
153
ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
157
int main(int argc, char *argv[])
162
char *namespaces = NULL;
165
uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
168
struct start_arg start_arg = {
174
while ((opt = getopt(argc, argv, "s:u:")) != -1) {
180
uid = lookup_user(optarg);
186
if (argv[optind] == NULL) {
187
ERROR("a command to execute in the new namespace is required");
191
args = &argv[optind];
193
ret = lxc_caps_init();
197
ret = lxc_fill_namespace_flags(namespaces, &flags);
201
if (!(flags & CLONE_NEWUSER) && uid != -1) {
202
ERROR("-u <uid> needs -s USER option");
206
pid = lxc_clone(do_start, &start_arg, flags);
208
ERROR("failed to clone");
212
if (waitpid(pid, &status, 0) < 0) {
213
ERROR("failed to wait for '%d'", pid);
217
if (lxc_ns_is_mounted()) {
218
if (asprintf(&pid_name, "%d", pid) == -1) {
219
ERROR("pid_name: failed to allocate memory");
222
lxc_cgroup_destroy(pid_name);
226
return lxc_error_set_and_log(pid, status);