Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
183ebf0a
Commit
183ebf0a
authored
Aug 02, 2017
by
Serge Hallyn
Committed by
GitHub
Aug 02, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1725 from brauner/2017-08-01/handle_pre_mounted_dev
conf: NOTICE() on mounts on container's /dev
parents
ebc52433
307eba8a
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
384 additions
and
256 deletions
+384
-256
userns.conf.in
config/templates/userns.conf.in
+0
-8
conf.c
src/lxc/conf.c
+287
-188
criu.c
src/lxc/criu.c
+7
-3
utils.c
src/lxc/utils.c
+58
-36
utils.h
src/lxc/utils.h
+8
-1
lxc-test-utils.c
src/tests/lxc-test-utils.c
+24
-20
No files found.
config/templates/userns.conf.in
View file @
183ebf0a
...
@@ -4,11 +4,3 @@ lxc.cgroup.devices.allow =
...
@@ -4,11 +4,3 @@ lxc.cgroup.devices.allow =
# We can't move bind-mounts, so don't use /dev/lxc/
# We can't move bind-mounts, so don't use /dev/lxc/
lxc.tty.dir =
lxc.tty.dir =
# Extra bind-mounts for userns
lxc.mount.entry = /dev/full dev/full none bind,create=file 0 0
lxc.mount.entry = /dev/null dev/null none bind,create=file 0 0
lxc.mount.entry = /dev/random dev/random none bind,create=file 0 0
lxc.mount.entry = /dev/tty dev/tty none bind,create=file 0 0
lxc.mount.entry = /dev/urandom dev/urandom none bind,create=file 0 0
lxc.mount.entry = /dev/zero dev/zero none bind,create=file 0 0
src/lxc/conf.c
View file @
183ebf0a
...
@@ -234,8 +234,9 @@ static int memfd_create(const char *name, unsigned int flags) {
...
@@ -234,8 +234,9 @@ static int memfd_create(const char *name, unsigned int flags) {
extern
int
memfd_create
(
const
char
*
name
,
unsigned
int
flags
);
extern
int
memfd_create
(
const
char
*
name
,
unsigned
int
flags
);
#endif
#endif
char
*
lxchook_names
[
NUM_LXC_HOOKS
]
=
{
char
*
lxchook_names
[
NUM_LXC_HOOKS
]
=
{
"pre-start"
,
"pre-mount"
,
"mount"
,
"pre-start"
,
"pre-mount"
,
"mount"
,
"autodev"
,
"start"
,
"stop"
,
"post-stop"
,
"clone"
,
"destroy"
};
"autodev"
,
"start"
,
"stop"
,
"post-stop"
,
"clone"
,
"destroy"
};
typedef
int
(
*
instantiate_cb
)(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
typedef
int
(
*
instantiate_cb
)(
struct
lxc_handler
*
,
struct
lxc_netdev
*
);
...
@@ -1034,58 +1035,56 @@ fail:
...
@@ -1034,58 +1035,56 @@ fail:
return
-
1
;
return
-
1
;
}
}
/*
/* Just create a path for /dev under $lxcpath/$name and in rootfs If we hit an
* Just create a path for /dev under $lxcpath/$name and in rootfs
* error, log it but don't fail yet.
* If we hit an error, log it but don't fail yet.
*/
*/
static
int
mount_autodev
(
const
char
*
name
,
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
lxcpath
)
static
int
mount_autodev
(
const
char
*
name
,
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
lxcpath
)
{
{
int
ret
;
int
ret
;
size_t
clen
;
size_t
clen
;
char
*
path
;
char
*
path
;
INFO
(
"
Mounting container /dev
"
);
INFO
(
"
Preparing
\"
/dev
\"
"
);
/* $(rootfs->mount) + "/dev/pts" + '\0' */
/* $(rootfs->mount) + "/dev/pts" + '\0' */
clen
=
(
rootfs
->
path
?
strlen
(
rootfs
->
mount
)
:
0
)
+
9
;
clen
=
(
rootfs
->
path
?
strlen
(
rootfs
->
mount
)
:
0
)
+
9
;
path
=
alloca
(
clen
);
path
=
alloca
(
clen
);
ret
=
snprintf
(
path
,
clen
,
"%s/dev"
,
rootfs
->
path
?
rootfs
->
mount
:
""
);
ret
=
snprintf
(
path
,
clen
,
"%s/dev"
,
rootfs
->
path
?
rootfs
->
mount
:
""
);
if
(
ret
<
0
||
ret
>=
clen
)
if
(
ret
<
0
||
(
size_t
)
ret
>=
clen
)
return
-
1
;
return
-
1
;
if
(
!
dir_exists
(
path
))
{
if
(
!
dir_exists
(
path
))
{
WARN
(
"
No /dev in container."
);
WARN
(
"
\"
/dev
\"
directory does not exist. Proceeding without "
WARN
(
"Proceeding without autodev set
up"
);
"autodev being set
up"
);
return
0
;
return
0
;
}
}
ret
=
safe_mount
(
"none"
,
path
,
"tmpfs"
,
0
,
"size=500000,mode=755"
,
ret
=
safe_mount
(
"none"
,
path
,
"tmpfs"
,
0
,
"size=500000,mode=755"
,
rootfs
->
path
?
rootfs
->
mount
:
NULL
);
rootfs
->
path
?
rootfs
->
mount
:
NULL
);
if
(
ret
!=
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Failed
mounting tmpfs onto %s
\n
"
,
path
);
SYSERROR
(
"Failed
to mount tmpfs on
\"
%s
\"
"
,
path
);
return
-
1
;
return
-
1
;
}
}
INFO
(
"Mounted tmpfs on
\"
%s
\"
"
,
path
);
INFO
(
"Mounted tmpfs onto %s"
,
path
);
ret
=
snprintf
(
path
,
clen
,
"%s/dev/pts"
,
rootfs
->
path
?
rootfs
->
mount
:
""
);
ret
=
snprintf
(
path
,
clen
,
"%s/dev/pts"
,
rootfs
->
path
?
rootfs
->
mount
:
""
);
if
(
ret
<
0
||
ret
>=
clen
)
if
(
ret
<
0
||
(
size_t
)
ret
>=
clen
)
return
-
1
;
return
-
1
;
/*
/* If we are running on a devtmpfs mapping, dev/pts may already exist.
* If we are running on a devtmpfs mapping, dev/pts may already exist.
* If not, then create it and exit if that fails...
* If not, then create it and exit if that fails...
*/
*/
if
(
!
dir_exists
(
path
))
{
if
(
!
dir_exists
(
path
))
{
ret
=
mkdir
(
path
,
S_IRWXU
|
S_IRGRP
|
S_IXGRP
|
S_IROTH
|
S_IXOTH
);
ret
=
mkdir
(
path
,
S_IRWXU
|
S_IRGRP
|
S_IXGRP
|
S_IROTH
|
S_IXOTH
);
if
(
ret
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to create
/dev/pts in container"
);
SYSERROR
(
"Failed to create
directory
\"
%s
\"
"
,
path
);
return
-
1
;
return
-
1
;
}
}
}
}
INFO
(
"
Mounted container /dev
"
);
INFO
(
"
Prepared
\"
/dev
\"
"
);
return
0
;
return
0
;
}
}
...
@@ -1097,12 +1096,12 @@ struct lxc_devs {
...
@@ -1097,12 +1096,12 @@ struct lxc_devs {
};
};
static
const
struct
lxc_devs
lxc_devs
[]
=
{
static
const
struct
lxc_devs
lxc_devs
[]
=
{
{
"null"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
3
},
{
"null"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
3
},
{
"zero"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
5
},
{
"zero"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
5
},
{
"full"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
7
},
{
"full"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
7
},
{
"urandom"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
9
},
{
"urandom"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
9
},
{
"random"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
8
},
{
"random"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
1
,
8
},
{
"tty"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
5
,
0
},
{
"tty"
,
S_IFCHR
|
S_IRWXU
|
S_IRWXG
|
S_IRWXO
,
5
,
0
},
};
};
static
int
lxc_fill_autodev
(
const
struct
lxc_rootfs
*
rootfs
)
static
int
lxc_fill_autodev
(
const
struct
lxc_rootfs
*
rootfs
)
...
@@ -1112,29 +1111,30 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
...
@@ -1112,29 +1111,30 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
int
i
;
int
i
;
mode_t
cmask
;
mode_t
cmask
;
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/dev"
,
rootfs
->
path
?
rootfs
->
mount
:
""
);
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/dev"
,
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
{
rootfs
->
path
?
rootfs
->
mount
:
""
);
ERROR
(
"Error calculating container /dev location"
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
return
-
1
;
return
-
1
;
}
/* ignore, just don't try to fill in */
/* ignore, just don't try to fill in */
if
(
!
dir_exists
(
path
))
if
(
!
dir_exists
(
path
))
return
0
;
return
0
;
INFO
(
"populating container /dev"
);
INFO
(
"Populating
\"
/dev
\"
"
);
cmask
=
umask
(
S_IXUSR
|
S_IXGRP
|
S_IXOTH
);
cmask
=
umask
(
S_IXUSR
|
S_IXGRP
|
S_IXOTH
);
for
(
i
=
0
;
i
<
sizeof
(
lxc_devs
)
/
sizeof
(
lxc_devs
[
0
]);
i
++
)
{
for
(
i
=
0
;
i
<
sizeof
(
lxc_devs
)
/
sizeof
(
lxc_devs
[
0
]);
i
++
)
{
const
struct
lxc_devs
*
d
=
&
lxc_devs
[
i
];
const
struct
lxc_devs
*
d
=
&
lxc_devs
[
i
];
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/dev/%s"
,
rootfs
->
path
?
rootfs
->
mount
:
""
,
d
->
name
);
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/dev/%s"
,
rootfs
->
path
?
rootfs
->
mount
:
""
,
d
->
name
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
return
-
1
;
return
-
1
;
ret
=
mknod
(
path
,
d
->
mode
,
makedev
(
d
->
maj
,
d
->
min
));
ret
=
mknod
(
path
,
d
->
mode
,
makedev
(
d
->
maj
,
d
->
min
));
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
char
hostpath
[
MAXPATHLEN
];
FILE
*
pathfile
;
FILE
*
pathfile
;
char
hostpath
[
MAXPATHLEN
];
if
(
errno
==
EEXIST
)
{
if
(
errno
==
EEXIST
)
{
DEBUG
(
"
\"
%s
\"
device already existed"
,
path
);
DEBUG
(
"
\"
%s
\"
device already existed"
,
path
);
...
@@ -1147,24 +1147,31 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
...
@@ -1147,24 +1147,31 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
ret
=
snprintf
(
hostpath
,
MAXPATHLEN
,
"/dev/%s"
,
d
->
name
);
ret
=
snprintf
(
hostpath
,
MAXPATHLEN
,
"/dev/%s"
,
d
->
name
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
return
-
1
;
return
-
1
;
pathfile
=
fopen
(
path
,
"wb"
);
pathfile
=
fopen
(
path
,
"wb"
);
if
(
!
pathfile
)
{
if
(
!
pathfile
)
{
SYSERROR
(
"Failed to create
device mount target '%s'
"
,
path
);
SYSERROR
(
"Failed to create
file
\"
%s
\"
"
,
path
);
return
-
1
;
return
-
1
;
}
}
fclose
(
pathfile
);
fclose
(
pathfile
);
if
(
safe_mount
(
hostpath
,
path
,
0
,
MS_BIND
,
NULL
,
rootfs
->
path
?
rootfs
->
mount
:
NULL
)
!=
0
)
{
SYSERROR
(
"Failed bind mounting device %s from host into container"
,
d
->
name
);
ret
=
safe_mount
(
hostpath
,
path
,
0
,
MS_BIND
,
NULL
,
rootfs
->
path
?
rootfs
->
mount
:
NULL
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to bind mount
\"
%s
\"
from "
"host into container"
,
d
->
name
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"bind mounted
\"
%s
\"
onto
\"
%s
\"
"
,
hostpath
,
path
);
DEBUG
(
"Bind mounted
\"
%s
\"
onto
\"
%s
\"
"
,
hostpath
,
path
);
}
else
{
}
else
{
DEBUG
(
"
c
reated device node
\"
%s
\"
"
,
path
);
DEBUG
(
"
C
reated device node
\"
%s
\"
"
,
path
);
}
}
}
}
umask
(
cmask
);
umask
(
cmask
);
INFO
(
"
populated container /dev
"
);
INFO
(
"
Populated
\"
/dev
\"
"
);
return
0
;
return
0
;
}
}
...
@@ -1726,174 +1733,201 @@ static char *get_field(char *src, int nfields)
...
@@ -1726,174 +1733,201 @@ static char *get_field(char *src, int nfields)
static
int
mount_entry
(
const
char
*
fsname
,
const
char
*
target
,
static
int
mount_entry
(
const
char
*
fsname
,
const
char
*
target
,
const
char
*
fstype
,
unsigned
long
mountflags
,
const
char
*
fstype
,
unsigned
long
mountflags
,
const
char
*
data
,
int
optional
,
int
dev
,
const
char
*
rootfs
)
const
char
*
data
,
int
optional
,
int
dev
,
const
char
*
rootfs
)
{
{
int
ret
;
#ifdef HAVE_STATVFS
#ifdef HAVE_STATVFS
struct
statvfs
sb
;
struct
statvfs
sb
;
#endif
#endif
if
(
safe_mount
(
fsname
,
target
,
fstype
,
mountflags
&
~
MS_REMOUNT
,
data
,
rootfs
))
{
ret
=
safe_mount
(
fsname
,
target
,
fstype
,
mountflags
&
~
MS_REMOUNT
,
data
,
rootfs
);
if
(
ret
<
0
)
{
if
(
optional
)
{
if
(
optional
)
{
INFO
(
"
failed to mount '%s' on '%s' (optional): %s"
,
fsname
,
INFO
(
"
Failed to mount
\"
%s
\"
on
\"
%s
\"
(optional): %s"
,
target
,
strerror
(
errno
));
fsname
,
target
,
strerror
(
errno
));
return
0
;
return
0
;
}
}
else
{
SYSERROR
(
"failed to mount '%s' on '%s'"
,
fsname
,
target
);
SYSERROR
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
"
,
fsname
,
target
);
return
-
1
;
return
-
1
;
}
}
}
if
((
mountflags
&
MS_REMOUNT
)
||
(
mountflags
&
MS_BIND
))
{
if
((
mountflags
&
MS_REMOUNT
)
||
(
mountflags
&
MS_BIND
))
{
DEBUG
(
"remounting %s on %s to respect bind or remount options"
,
fsname
?
fsname
:
"(none)"
,
target
?
target
:
"(none)"
);
unsigned
long
rqd_flags
=
0
;
unsigned
long
rqd_flags
=
0
;
DEBUG
(
"Remounting
\"
%s
\"
on
\"
%s
\"
to respect bind or remount "
"options"
,
fsname
?
fsname
:
"(none)"
,
target
?
target
:
"(none)"
);
if
(
mountflags
&
MS_RDONLY
)
if
(
mountflags
&
MS_RDONLY
)
rqd_flags
|=
MS_RDONLY
;
rqd_flags
|=
MS_RDONLY
;
#ifdef HAVE_STATVFS
#ifdef HAVE_STATVFS
if
(
statvfs
(
fsname
,
&
sb
)
==
0
)
{
if
(
statvfs
(
fsname
,
&
sb
)
==
0
)
{
unsigned
long
required_flags
=
rqd_flags
;
unsigned
long
required_flags
=
rqd_flags
;
if
(
sb
.
f_flag
&
MS_NOSUID
)
if
(
sb
.
f_flag
&
MS_NOSUID
)
required_flags
|=
MS_NOSUID
;
required_flags
|=
MS_NOSUID
;
if
(
sb
.
f_flag
&
MS_NODEV
&&
!
dev
)
if
(
sb
.
f_flag
&
MS_NODEV
&&
!
dev
)
required_flags
|=
MS_NODEV
;
required_flags
|=
MS_NODEV
;
if
(
sb
.
f_flag
&
MS_RDONLY
)
if
(
sb
.
f_flag
&
MS_RDONLY
)
required_flags
|=
MS_RDONLY
;
required_flags
|=
MS_RDONLY
;
if
(
sb
.
f_flag
&
MS_NOEXEC
)
if
(
sb
.
f_flag
&
MS_NOEXEC
)
required_flags
|=
MS_NOEXEC
;
required_flags
|=
MS_NOEXEC
;
DEBUG
(
"(at remount) flags for %s was %lu, required extra flags are %lu"
,
fsname
,
sb
.
f_flag
,
required_flags
);
/*
DEBUG
(
"Flags for
\"
%s
\"
were %lu, required extra flags "
* If this was a bind mount request, and required_flags
"are %lu"
,
fsname
,
sb
.
f_flag
,
required_flags
);
/* If this was a bind mount request, and required_flags
* does not have any flags which are not already in
* does not have any flags which are not already in
* mountflags, then skip the remount
* mountflags, then skip the remount
.
*/
*/
if
(
!
(
mountflags
&
MS_REMOUNT
))
{
if
(
!
(
mountflags
&
MS_REMOUNT
))
{
if
(
!
(
required_flags
&
~
mountflags
)
&&
rqd_flags
==
0
)
{
if
(
!
(
required_flags
&
~
mountflags
)
&&
DEBUG
(
"mountflags already was %lu, skipping remount"
,
rqd_flags
==
0
)
{
mountflags
);
DEBUG
(
"Mountflags already were %lu, "
"skipping remount"
,
mountflags
);
goto
skipremount
;
goto
skipremount
;
}
}
}
}
mountflags
|=
required_flags
;
mountflags
|=
required_flags
;
}
}
#endif
#endif
if
(
mount
(
fsname
,
target
,
fstype
,
ret
=
mount
(
fsname
,
target
,
fstype
,
mountflags
|
MS_REMOUNT
,
data
);
mountflags
|
MS_REMOUNT
,
data
)
<
0
)
{
if
(
ret
<
0
)
{
if
(
optional
)
{
if
(
optional
)
{
INFO
(
"failed to mount '%s' on '%s' (optional): %s"
,
INFO
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
"
fsname
,
target
,
strerror
(
errno
));
"(optional): %s"
,
fsname
,
target
,
strerror
(
errno
));
return
0
;
return
0
;
}
}
else
{
SYSERROR
(
"failed to mount '%s' on '%s'"
,
SYSERROR
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
"
,
fsname
,
target
);
fsname
,
target
);
return
-
1
;
return
-
1
;
}
}
}
}
}
#ifdef HAVE_STATVFS
#ifdef HAVE_STATVFS
skipremount:
skipremount:
#endif
#endif
DEBUG
(
"mounted '%s' on '%s', type '%s'"
,
fsname
,
target
,
fstype
);
DEBUG
(
"Mounted
\"
%s
\"
on
\"
%s
\"
with filesystem type
\"
%s
\"
"
,
fsname
,
target
,
fstype
);
return
0
;
return
0
;
}
}
/*
/* Remove "optional", "create=dir", and "create=file" from mntopt */
* Remove 'optional', 'create=dir', and 'create=file' from mntopt
*/
static
void
cull_mntent_opt
(
struct
mntent
*
mntent
)
static
void
cull_mntent_opt
(
struct
mntent
*
mntent
)
{
{
int
i
;
int
i
;
char
*
p
,
*
p2
;
char
*
list
[]
=
{
"create=dir"
,
"create=file"
,
"optional"
,
NULL
};
char
*
list
[]
=
{
"create=dir"
,
"create=file"
,
for
(
i
=
0
;
list
[
i
];
i
++
)
{
"optional"
,
char
*
p
,
*
p2
;
NULL
};
p
=
strstr
(
mntent
->
mnt_opts
,
list
[
i
]);
for
(
i
=
0
;
list
[
i
];
i
++
)
{
if
(
!
p
)
if
(
!
(
p
=
strstr
(
mntent
->
mnt_opts
,
list
[
i
])))
continue
;
continue
;
p2
=
strchr
(
p
,
','
);
p2
=
strchr
(
p
,
','
);
if
(
!
p2
)
{
if
(
!
p2
)
{
/* no more mntopts, so just chop it here */
/* no more mntopts, so just chop it here */
*
p
=
'\0'
;
*
p
=
'\0'
;
continue
;
continue
;
}
}
memmove
(
p
,
p2
+
1
,
strlen
(
p2
+
1
)
+
1
);
memmove
(
p
,
p2
+
1
,
strlen
(
p2
+
1
)
+
1
);
}
}
}
}
static
int
mount_entry_create_dir_file
(
const
struct
mntent
*
mntent
,
static
int
mount_entry_create_dir_file
(
const
struct
mntent
*
mntent
,
const
char
*
path
,
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
path
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
{
{
char
*
pathdirname
=
NULL
;
int
ret
=
0
;
int
ret
=
0
;
FILE
*
pathfile
=
NULL
;
if
(
strncmp
(
mntent
->
mnt_type
,
"overlay"
,
7
)
==
0
)
{
if
(
!
strncmp
(
mntent
->
mnt_type
,
"overlay"
,
7
))
if
(
ovl_mkdir
(
mntent
,
rootfs
,
lxc_name
,
lxc_path
)
<
0
)
ret
=
ovl_mkdir
(
mntent
,
rootfs
,
lxc_name
,
lxc_path
);
return
-
1
;
else
if
(
!
strncmp
(
mntent
->
mnt_type
,
"aufs"
,
4
))
}
else
if
(
strncmp
(
mntent
->
mnt_type
,
"aufs"
,
4
)
==
0
)
{
ret
=
aufs_mkdir
(
mntent
,
rootfs
,
lxc_name
,
lxc_path
);
if
(
aufs_mkdir
(
mntent
,
rootfs
,
lxc_name
,
lxc_path
)
<
0
)
if
(
ret
<
0
)
return
-
1
;
return
-
1
;
}
if
(
hasmntopt
(
mntent
,
"create=dir"
))
{
if
(
hasmntopt
(
mntent
,
"create=dir"
))
{
if
(
mkdir_p
(
path
,
0755
)
<
0
)
{
ret
=
mkdir_p
(
path
,
0755
);
WARN
(
"Failed to create mount target '%s'"
,
path
);
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
ret
=
-
1
;
SYSERROR
(
"Failed to create directory
\"
%s
\"
"
,
path
);
return
-
1
;
}
}
}
}
if
(
hasmntopt
(
mntent
,
"create=file"
)
&&
access
(
path
,
F_OK
))
{
if
(
hasmntopt
(
mntent
,
"create=file"
)
&&
access
(
path
,
F_OK
))
{
pathdirname
=
strdup
(
path
);
int
fd
;
pathdirname
=
dirname
(
pathdirname
);
char
*
p1
,
*
p2
;
if
(
mkdir_p
(
pathdirname
,
0755
)
<
0
)
{
WARN
(
"Failed to create target directory"
);
p1
=
strdup
(
path
);
}
if
(
!
p1
)
pathfile
=
fopen
(
path
,
"wb"
);
return
-
1
;
if
(
!
pathfile
)
{
WARN
(
"Failed to create mount target '%s'"
,
path
);
p2
=
dirname
(
p1
);
ret
=
-
1
;
}
else
{
ret
=
mkdir_p
(
p2
,
0755
);
fclose
(
pathfile
);
free
(
p1
);
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
SYSERROR
(
"Failed to create directory
\"
%s
\"
"
,
path
);
return
-
1
;
}
}
fd
=
open
(
path
,
O_CREAT
,
0644
);
if
(
fd
<
0
)
return
-
1
;
close
(
fd
);
}
}
free
(
pathdirname
);
return
ret
;
return
0
;
}
}
/* rootfs, lxc_name, and lxc_path can be NULL when the container is created
/* rootfs, lxc_name, and lxc_path can be NULL when the container is created
* without a rootfs. */
* without a rootfs. */
static
inline
int
mount_entry_on_generic
(
struct
mntent
*
mntent
,
static
inline
int
mount_entry_on_generic
(
struct
mntent
*
mntent
,
const
char
*
path
,
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
path
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
{
{
int
ret
;
unsigned
long
mntflags
;
unsigned
long
mntflags
;
char
*
mntdata
;
char
*
mntdata
;
int
ret
;
bool
dev
,
optional
;
bool
optional
=
hasmntopt
(
mntent
,
"optional"
)
!=
NULL
;
bool
dev
=
hasmntopt
(
mntent
,
"dev"
)
!=
NULL
;
char
*
rootfs_path
=
NULL
;
char
*
rootfs_path
=
NULL
;
optional
=
hasmntopt
(
mntent
,
"optional"
)
!=
NULL
;
dev
=
hasmntopt
(
mntent
,
"dev"
)
!=
NULL
;
if
(
rootfs
&&
rootfs
->
path
)
if
(
rootfs
&&
rootfs
->
path
)
rootfs_path
=
rootfs
->
mount
;
rootfs_path
=
rootfs
->
mount
;
ret
=
mount_entry_create_dir_file
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
ret
=
mount_entry_create_dir_file
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
if
(
ret
<
0
)
if
(
ret
<
0
)
{
return
optional
?
0
:
-
1
;
if
(
optional
)
return
0
;
return
-
1
;
}
cull_mntent_opt
(
mntent
);
cull_mntent_opt
(
mntent
);
if
(
parse_mntopts
(
mntent
->
mnt_opts
,
&
mntflags
,
&
mntdata
)
<
0
)
{
ret
=
parse_mntopts
(
mntent
->
mnt_opts
,
&
mntflags
,
&
mntdata
);
free
(
mntdata
);
if
(
ret
<
0
)
return
-
1
;
return
-
1
;
}
ret
=
mount_entry
(
mntent
->
mnt_fsname
,
path
,
mntent
->
mnt_type
,
mntflags
,
ret
=
mount_entry
(
mntent
->
mnt_fsname
,
path
,
mntent
->
mnt_type
,
mntflags
,
mntdata
,
optional
,
dev
,
rootfs_path
);
mntdata
,
optional
,
dev
,
rootfs_path
);
...
@@ -1904,20 +1938,18 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
...
@@ -1904,20 +1938,18 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
static
inline
int
mount_entry_on_systemfs
(
struct
mntent
*
mntent
)
static
inline
int
mount_entry_on_systemfs
(
struct
mntent
*
mntent
)
{
{
char
path
[
MAXPATHLEN
];
int
ret
;
int
ret
;
char
path
[
MAXPATHLEN
];
/* For containers created without a rootfs all mounts are treated as
/* For containers created without a rootfs all mounts are treated as
* absolute paths starting at / on the host. */
* absolute paths starting at / on the host.
*/
if
(
mntent
->
mnt_dir
[
0
]
!=
'/'
)
if
(
mntent
->
mnt_dir
[
0
]
!=
'/'
)
ret
=
snprintf
(
path
,
sizeof
(
path
),
"/%s"
,
mntent
->
mnt_dir
);
ret
=
snprintf
(
path
,
sizeof
(
path
),
"/%s"
,
mntent
->
mnt_dir
);
else
else
ret
=
snprintf
(
path
,
sizeof
(
path
),
"%s"
,
mntent
->
mnt_dir
);
ret
=
snprintf
(
path
,
sizeof
(
path
),
"%s"
,
mntent
->
mnt_dir
);
if
(
ret
<
0
||
ret
>=
sizeof
(
path
))
if
(
ret
<
0
||
ret
>=
sizeof
(
path
))
{
ERROR
(
"path name too long"
);
return
-
1
;
return
-
1
;
}
return
mount_entry_on_generic
(
mntent
,
path
,
NULL
,
NULL
,
NULL
);
return
mount_entry_on_generic
(
mntent
,
path
,
NULL
,
NULL
,
NULL
);
}
}
...
@@ -1927,21 +1959,21 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
...
@@ -1927,21 +1959,21 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
const
char
*
lxc_name
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
char
*
lxc_path
)
{
{
int
offset
;
char
*
aux
;
char
*
aux
;
char
path
[
MAXPATHLEN
];
int
r
,
ret
=
0
,
offset
;
const
char
*
lxcpath
;
const
char
*
lxcpath
;
char
path
[
MAXPATHLEN
];
int
ret
=
0
;
lxcpath
=
lxc_global_config_value
(
"lxc.lxcpath"
);
lxcpath
=
lxc_global_config_value
(
"lxc.lxcpath"
);
if
(
!
lxcpath
)
{
if
(
!
lxcpath
)
ERROR
(
"Out of memory"
);
return
-
1
;
return
-
1
;
}
/* if rootfs->path is a blockdev path, allow container fstab to
/* If rootfs->path is a blockdev path, allow container fstab to use
* use $lxcpath/CN/rootfs as the target prefix */
* <lxcpath>/<name>/rootfs" as the target prefix.
r
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/%s/rootfs"
,
lxcpath
,
lxc_name
);
*/
if
(
r
<
0
||
r
>=
MAXPATHLEN
)
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/%s/rootfs"
,
lxcpath
,
lxc_name
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
goto
skipvarlib
;
goto
skipvarlib
;
aux
=
strstr
(
mntent
->
mnt_dir
,
path
);
aux
=
strstr
(
mntent
->
mnt_dir
,
path
);
...
@@ -1953,19 +1985,15 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
...
@@ -1953,19 +1985,15 @@ static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
skipvarlib:
skipvarlib:
aux
=
strstr
(
mntent
->
mnt_dir
,
rootfs
->
path
);
aux
=
strstr
(
mntent
->
mnt_dir
,
rootfs
->
path
);
if
(
!
aux
)
{
if
(
!
aux
)
{
WARN
(
"
ignoring mount point '%s'
"
,
mntent
->
mnt_dir
);
WARN
(
"
Ignoring mount point
\"
%s
\"
"
,
mntent
->
mnt_dir
);
return
ret
;
return
ret
;
}
}
offset
=
strlen
(
rootfs
->
path
);
offset
=
strlen
(
rootfs
->
path
);
skipabs:
skipabs:
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/%s"
,
rootfs
->
mount
,
aux
+
offset
);
r
=
snprintf
(
path
,
MAXPATHLEN
,
"%s/%s"
,
rootfs
->
mount
,
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
aux
+
offset
);
if
(
r
<
0
||
r
>=
MAXPATHLEN
)
{
WARN
(
"pathnme too long for '%s'"
,
mntent
->
mnt_dir
);
return
-
1
;
return
-
1
;
}
return
mount_entry_on_generic
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
return
mount_entry_on_generic
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
}
}
...
@@ -1988,57 +2016,123 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent,
...
@@ -1988,57 +2016,123 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent,
return
mount_entry_on_generic
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
return
mount_entry_on_generic
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
}
}
static
int
mount_file_entries
(
const
struct
lxc_rootfs
*
rootfs
,
FILE
*
file
,
/* This logs a NOTICE() when a user specifies mounts that would conflict with
const
char
*
lxc_name
,
const
char
*
lxc_path
)
* devices liblxc sets up automatically.
*/
static
void
log_notice_on_conflict
(
const
struct
lxc_conf
*
conf
,
const
char
*
src
,
const
char
*
dest
)
{
char
*
clean_mnt_fsname
,
*
clean_mnt_dir
,
*
tmp
;
bool
needs_warning
=
false
;
clean_mnt_fsname
=
lxc_deslashify
(
src
);
if
(
!
clean_mnt_fsname
)
return
;
clean_mnt_dir
=
lxc_deslashify
(
dest
);
if
(
!
clean_mnt_dir
)
{
free
(
clean_mnt_fsname
);
return
;
}
tmp
=
clean_mnt_dir
;
if
(
*
tmp
==
'/'
)
tmp
++
;
if
(
strncmp
(
src
,
"/dev"
,
4
)
||
strncmp
(
tmp
,
"dev"
,
3
))
{
free
(
clean_mnt_dir
);
free
(
clean_mnt_fsname
);
return
;
}
if
(
!
conf
->
autodev
&&
!
conf
->
pts
&&
!
conf
->
tty
&&
(
!
conf
->
console
.
path
||
!
strcmp
(
conf
->
console
.
path
,
"none"
)))
{
free
(
clean_mnt_dir
);
free
(
clean_mnt_fsname
);
return
;
}
if
(
!
strcmp
(
tmp
,
"dev"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/pts"
)
&&
(
conf
->
autodev
>
0
||
conf
->
pts
>
0
))
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/ptmx"
)
&&
(
conf
->
autodev
>
0
||
conf
->
pts
>
0
))
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/pts/ptmx"
)
&&
(
conf
->
autodev
>
0
||
conf
->
pts
>
0
))
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/null"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/zero"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/full"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/urandom"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/random"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/tty"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strncmp
(
tmp
,
"dev/tty"
,
7
)
&&
(
conf
->
autodev
>
0
||
conf
->
tty
>
0
))
needs_warning
=
true
;
if
(
needs_warning
)
NOTICE
(
"Requesting to mount
\"
%s
\"
on
\"
%s
\"
while requesting "
"automatic device setup under
\"
/dev
\"
"
,
clean_mnt_fsname
,
clean_mnt_dir
);
free
(
clean_mnt_dir
);
free
(
clean_mnt_fsname
);
}
static
int
mount_file_entries
(
const
struct
lxc_conf
*
conf
,
const
struct
lxc_rootfs
*
rootfs
,
FILE
*
file
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
{
{
struct
mntent
mntent
;
struct
mntent
mntent
;
char
buf
[
4096
];
char
buf
[
4096
];
int
ret
=
-
1
;
int
ret
=
-
1
;
while
(
getmntent_r
(
file
,
&
mntent
,
buf
,
sizeof
(
buf
)))
{
while
(
getmntent_r
(
file
,
&
mntent
,
buf
,
sizeof
(
buf
)))
{
log_notice_on_conflict
(
conf
,
mntent
.
mnt_fsname
,
mntent
.
mnt_dir
);
if
(
!
rootfs
->
path
)
{
if
(
!
rootfs
->
path
)
if
(
mount_entry_on_systemfs
(
&
mntent
))
ret
=
mount_entry_on_systemfs
(
&
mntent
);
goto
out
;
else
if
(
mntent
.
mnt_dir
[
0
]
!=
'/'
)
continue
;
ret
=
mount_entry_on_relative_rootfs
(
&
mntent
,
rootfs
,
}
lxc_name
,
lxc_path
);
else
/* We have a separate root, mounts are relative to it */
ret
=
mount_entry_on_absolute_rootfs
(
&
mntent
,
rootfs
,
if
(
mntent
.
mnt_dir
[
0
]
!=
'/'
)
{
lxc_name
,
lxc_path
);
if
(
mount_entry_on_relative_rootfs
(
&
mntent
,
rootfs
,
lxc_name
,
lxc_path
))
if
(
ret
<
0
)
goto
out
;
return
-
1
;
continue
;
}
if
(
mount_entry_on_absolute_rootfs
(
&
mntent
,
rootfs
,
lxc_name
,
lxc_path
))
goto
out
;
}
}
ret
=
0
;
ret
=
0
;
INFO
(
"mount points have been setup"
);
INFO
(
"Set up mount entries"
);
out:
return
ret
;
return
ret
;
}
}
static
int
setup_mount
(
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
fstab
,
static
int
setup_mount
(
const
struct
lxc_conf
*
conf
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
fstab
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
{
{
FILE
*
f
ile
;
FILE
*
f
;
int
ret
;
int
ret
;
if
(
!
fstab
)
if
(
!
fstab
)
return
0
;
return
0
;
f
ile
=
setmntent
(
fstab
,
"r"
);
f
=
setmntent
(
fstab
,
"r"
);
if
(
!
f
ile
)
{
if
(
!
f
)
{
SYSERROR
(
"
failed to use '%s'
"
,
fstab
);
SYSERROR
(
"
Failed to open
\"
%s
\"
"
,
fstab
);
return
-
1
;
return
-
1
;
}
}
ret
=
mount_file_entries
(
rootfs
,
file
,
lxc_name
,
lxc_path
);
ret
=
mount_file_entries
(
conf
,
rootfs
,
f
,
lxc_name
,
lxc_path
);
if
(
ret
<
0
)
ERROR
(
"Failed to set up mount entries"
);
endmntent
(
f
ile
);
endmntent
(
f
);
return
ret
;
return
ret
;
}
}
...
@@ -2047,55 +2141,59 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount)
...
@@ -2047,55 +2141,59 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount)
int
ret
;
int
ret
;
char
*
mount_entry
;
char
*
mount_entry
;
struct
lxc_list
*
iterator
;
struct
lxc_list
*
iterator
;
FILE
*
f
ile
;
FILE
*
f
;
int
fd
=
-
1
;
int
fd
=
-
1
;
fd
=
memfd_create
(
"lxc_mount_file"
,
MFD_CLOEXEC
);
fd
=
memfd_create
(
"lxc_mount_file"
,
MFD_CLOEXEC
);
if
(
fd
<
0
)
{
if
(
fd
<
0
)
{
if
(
errno
!=
ENOSYS
)
if
(
errno
!=
ENOSYS
)
return
NULL
;
return
NULL
;
file
=
tmpfile
();
f
=
tmpfile
();
TRACE
(
"Created temporary mount file"
);
}
else
{
}
else
{
file
=
fdopen
(
fd
,
"r+"
);
f
=
fdopen
(
fd
,
"r+"
);
TRACE
(
"Created anonymous mount file"
);
}
}
if
(
!
f
ile
)
{
if
(
!
f
)
{
int
saved_errno
=
errno
;
SYSERROR
(
"Could not create mount file"
)
;
if
(
fd
!=
-
1
)
if
(
fd
!=
-
1
)
close
(
fd
);
close
(
fd
);
ERROR
(
"Could not create mount entry file: %s."
,
strerror
(
saved_errno
));
return
NULL
;
return
NULL
;
}
}
lxc_list_for_each
(
iterator
,
mount
)
{
lxc_list_for_each
(
iterator
,
mount
)
{
mount_entry
=
iterator
->
elem
;
mount_entry
=
iterator
->
elem
;
ret
=
fprintf
(
f
ile
,
"%s
\n
"
,
mount_entry
);
ret
=
fprintf
(
f
,
"%s
\n
"
,
mount_entry
);
if
(
ret
<
strlen
(
mount_entry
))
if
(
ret
<
strlen
(
mount_entry
))
WARN
(
"Could not write mount entry to
anonymous mount file.
"
);
WARN
(
"Could not write mount entry to
mount file
"
);
}
}
if
(
fseek
(
file
,
0
,
SEEK_SET
)
<
0
)
{
ret
=
fseek
(
f
,
0
,
SEEK_SET
);
fclose
(
file
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to seek mount file"
);
fclose
(
f
);
return
NULL
;
return
NULL
;
}
}
return
f
ile
;
return
f
;
}
}
static
int
setup_mount_entries
(
const
struct
lxc_rootfs
*
rootfs
,
static
int
setup_mount_entries
(
const
struct
lxc_conf
*
conf
,
const
struct
lxc_rootfs
*
rootfs
,
struct
lxc_list
*
mount
,
const
char
*
lxc_name
,
struct
lxc_list
*
mount
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
char
*
lxc_path
)
{
{
FILE
*
f
ile
;
FILE
*
f
;
int
ret
;
int
ret
;
f
ile
=
make_anonymous_mount_file
(
mount
);
f
=
make_anonymous_mount_file
(
mount
);
if
(
!
f
ile
)
if
(
!
f
)
return
-
1
;
return
-
1
;
ret
=
mount_file_entries
(
rootfs
,
file
,
lxc_name
,
lxc_path
);
ret
=
mount_file_entries
(
conf
,
rootfs
,
f
,
lxc_name
,
lxc_path
);
fclose
(
f
ile
);
fclose
(
f
);
return
ret
;
return
ret
;
}
}
...
@@ -4137,12 +4235,12 @@ int lxc_setup(struct lxc_handler *handler)
...
@@ -4137,12 +4235,12 @@ int lxc_setup(struct lxc_handler *handler)
return
-
1
;
return
-
1
;
}
}
if
(
setup_mount
(
&
lxc_conf
->
rootfs
,
lxc_conf
->
fstab
,
name
,
lxcpath
))
{
if
(
setup_mount
(
lxc_conf
,
&
lxc_conf
->
rootfs
,
lxc_conf
->
fstab
,
name
,
lxcpath
))
{
ERROR
(
"failed to setup the mounts for '%s'"
,
name
);
ERROR
(
"failed to setup the mounts for '%s'"
,
name
);
return
-
1
;
return
-
1
;
}
}
if
(
!
lxc_list_empty
(
&
lxc_conf
->
mount_list
)
&&
setup_mount_entries
(
&
lxc_conf
->
rootfs
,
&
lxc_conf
->
mount_list
,
name
,
lxcpath
))
{
if
(
!
lxc_list_empty
(
&
lxc_conf
->
mount_list
)
&&
setup_mount_entries
(
lxc_conf
,
&
lxc_conf
->
rootfs
,
&
lxc_conf
->
mount_list
,
name
,
lxcpath
))
{
ERROR
(
"failed to setup the mount entries for '%s'"
,
name
);
ERROR
(
"failed to setup the mount entries for '%s'"
,
name
);
return
-
1
;
return
-
1
;
}
}
...
@@ -4173,6 +4271,7 @@ int lxc_setup(struct lxc_handler *handler)
...
@@ -4173,6 +4271,7 @@ int lxc_setup(struct lxc_handler *handler)
ERROR
(
"failed to run autodev hooks for container '%s'."
,
name
);
ERROR
(
"failed to run autodev hooks for container '%s'."
,
name
);
return
-
1
;
return
-
1
;
}
}
if
(
lxc_fill_autodev
(
&
lxc_conf
->
rootfs
))
{
if
(
lxc_fill_autodev
(
&
lxc_conf
->
rootfs
))
{
ERROR
(
"failed to populate /dev in the container"
);
ERROR
(
"failed to populate /dev in the container"
);
return
-
1
;
return
-
1
;
...
...
src/lxc/criu.c
View file @
183ebf0a
...
@@ -263,7 +263,7 @@ static void exec_criu(struct criu_opts *opts)
...
@@ -263,7 +263,7 @@ static void exec_criu(struct criu_opts *opts)
for
(
i
=
0
;
i
<
cgroup_num_hierarchies
();
i
++
)
{
for
(
i
=
0
;
i
<
cgroup_num_hierarchies
();
i
++
)
{
char
**
controllers
=
NULL
,
*
fullname
;
char
**
controllers
=
NULL
,
*
fullname
;
char
*
path
;
char
*
path
,
*
tmp
;
if
(
!
cgroup_get_hierarchies
(
i
,
&
controllers
))
{
if
(
!
cgroup_get_hierarchies
(
i
,
&
controllers
))
{
ERROR
(
"failed to get hierarchy %d"
,
i
);
ERROR
(
"failed to get hierarchy %d"
,
i
);
...
@@ -296,11 +296,15 @@ static void exec_criu(struct criu_opts *opts)
...
@@ -296,11 +296,15 @@ static void exec_criu(struct criu_opts *opts)
}
}
}
}
if
(
!
lxc_deslashify
(
&
path
))
{
tmp
=
lxc_deslashify
(
path
);
ERROR
(
"failed to deslashify %s"
,
path
);
if
(
!
tmp
)
{
ERROR
(
"Failed to remove extraneous slashes from
\"
%s
\"
"
,
path
);
free
(
path
);
free
(
path
);
goto
err
;
goto
err
;
}
}
free
(
path
);
path
=
tmp
;
fullname
=
lxc_string_join
(
","
,
(
const
char
**
)
controllers
,
false
);
fullname
=
lxc_string_join
(
","
,
(
const
char
**
)
controllers
,
false
);
if
(
!
fullname
)
{
if
(
!
fullname
)
{
...
...
src/lxc/utils.c
View file @
183ebf0a
...
@@ -42,7 +42,6 @@
...
@@ -42,7 +42,6 @@
#include <sys/prctl.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/wait.h>
#include <sys/wait.h>
#include "log.h"
#include "log.h"
...
@@ -183,22 +182,24 @@ static int _recursive_rmdir(char *dirname, dev_t pdev,
...
@@ -183,22 +182,24 @@ static int _recursive_rmdir(char *dirname, dev_t pdev,
return
failed
?
-
1
:
0
;
return
failed
?
-
1
:
0
;
}
}
/* we have two different magic values for overlayfs, yay */
/* We have two different magic values for overlayfs, yay. */
#ifndef OVERLAYFS_SUPER_MAGIC
#define OVERLAYFS_SUPER_MAGIC 0x794c764f
#define OVERLAYFS_SUPER_MAGIC 0x794c764f
#endif
#ifndef OVERLAY_SUPER_MAGIC
#define OVERLAY_SUPER_MAGIC 0x794c7630
#define OVERLAY_SUPER_MAGIC 0x794c7630
/*
#endif
* In overlayfs, st_dev is unreliable. so on overlayfs we don't do
* the lxc_rmdir_onedev()
/* In overlayfs, st_dev is unreliable. So on overlayfs we don't do the
* lxc_rmdir_onedev()
*/
*/
static
bool
is_native_overlayfs
(
const
char
*
path
)
static
bool
is_native_overlayfs
(
const
char
*
path
)
{
{
struct
statfs
sb
;
if
(
has_fs_type
(
path
,
OVERLAY_SUPER_MAGIC
)
||
has_fs_type
(
path
,
OVERLAYFS_SUPER_MAGIC
))
if
(
statfs
(
path
,
&
sb
)
<
0
)
return
false
;
if
(
sb
.
f_type
==
OVERLAYFS_SUPER_MAGIC
||
sb
.
f_type
==
OVERLAY_SUPER_MAGIC
)
return
true
;
return
true
;
return
false
;
return
false
;
}
}
...
@@ -728,47 +729,46 @@ char **lxc_normalize_path(const char *path)
...
@@ -728,47 +729,46 @@ char **lxc_normalize_path(const char *path)
return
components
;
return
components
;
}
}
bool
lxc_deslashify
(
char
*
*
path
)
char
*
lxc_deslashify
(
const
char
*
path
)
{
{
bool
ret
=
false
;
char
*
dup
,
*
p
;
char
*
p
;
char
**
parts
=
NULL
;
char
**
parts
=
NULL
;
size_t
n
,
len
;
size_t
n
,
len
;
parts
=
lxc_normalize_path
(
*
path
);
dup
=
strdup
(
path
);
if
(
!
parts
)
if
(
!
dup
)
return
false
;
return
NULL
;
parts
=
lxc_normalize_path
(
dup
);
if
(
!
parts
)
{
free
(
dup
);
return
NULL
;
}
/* We'll end up here if path == "///" or path == "". */
/* We'll end up here if path == "///" or path == "". */
if
(
!*
parts
)
{
if
(
!*
parts
)
{
len
=
strlen
(
*
path
);
len
=
strlen
(
dup
);
if
(
!
len
)
{
if
(
!
len
)
{
ret
=
true
;
lxc_free_array
((
void
**
)
parts
,
free
)
;
goto
out
;
return
dup
;
}
}
n
=
strcspn
(
*
path
,
"/"
);
n
=
strcspn
(
dup
,
"/"
);
if
(
n
==
len
)
{
if
(
n
==
len
)
{
free
(
dup
);
lxc_free_array
((
void
**
)
parts
,
free
);
p
=
strdup
(
"/"
);
p
=
strdup
(
"/"
);
if
(
!
p
)
if
(
!
p
)
goto
out
;
return
NULL
;
free
(
*
path
);
*
path
=
p
;
return
p
;
ret
=
true
;
goto
out
;
}
}
}
}
p
=
lxc_string_join
(
"/"
,
(
const
char
**
)
parts
,
**
path
==
'/'
);
p
=
lxc_string_join
(
"/"
,
(
const
char
**
)
parts
,
*
dup
==
'/'
);
if
(
!
p
)
free
(
dup
);
goto
out
;
free
(
*
path
);
*
path
=
p
;
ret
=
true
;
out
:
lxc_free_array
((
void
**
)
parts
,
free
);
lxc_free_array
((
void
**
)
parts
,
free
);
return
ret
;
return
p
;
}
}
char
*
lxc_append_paths
(
const
char
*
first
,
const
char
*
second
)
char
*
lxc_append_paths
(
const
char
*
first
,
const
char
*
second
)
...
@@ -2384,3 +2384,25 @@ void *must_realloc(void *orig, size_t sz)
...
@@ -2384,3 +2384,25 @@ void *must_realloc(void *orig, size_t sz)
return
ret
;
return
ret
;
}
}
bool
is_fs_type
(
const
struct
statfs
*
fs
,
fs_type_magic
magic_val
)
{
return
(
fs
->
f_type
==
(
fs_type_magic
)
magic_val
);
}
bool
has_fs_type
(
const
char
*
path
,
fs_type_magic
magic_val
)
{
bool
has_type
;
int
ret
;
struct
statfs
sb
;
ret
=
statfs
(
path
,
&
sb
);
if
(
ret
<
0
)
return
false
;
has_type
=
is_fs_type
(
&
sb
,
magic_val
);
if
(
!
has_type
&&
magic_val
==
RAMFS_MAGIC
)
WARN
(
"When the ramfs it a tmpfs statfs() might report tmpfs"
);
return
has_type
;
}
src/lxc/utils.h
View file @
183ebf0a
...
@@ -34,8 +34,10 @@
...
@@ -34,8 +34,10 @@
#include <stdbool.h>
#include <stdbool.h>
#include <unistd.h>
#include <unistd.h>
#include <linux/loop.h>
#include <linux/loop.h>
#include <linux/magic.h>
#include <sys/syscall.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include "initutils.h"
#include "initutils.h"
...
@@ -273,7 +275,7 @@ extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_pr
...
@@ -273,7 +275,7 @@ extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_pr
*/
*/
extern
char
**
lxc_normalize_path
(
const
char
*
path
);
extern
char
**
lxc_normalize_path
(
const
char
*
path
);
/* remove multiple slashes from the path, e.g. ///foo//bar -> /foo/bar */
/* remove multiple slashes from the path, e.g. ///foo//bar -> /foo/bar */
extern
bool
lxc_deslashify
(
char
*
*
path
);
extern
char
*
lxc_deslashify
(
const
char
*
path
);
extern
char
*
lxc_append_paths
(
const
char
*
first
,
const
char
*
second
);
extern
char
*
lxc_append_paths
(
const
char
*
first
,
const
char
*
second
);
/* Note: the following two functions use strtok(), so they will never
/* Note: the following two functions use strtok(), so they will never
* consider an empty element, even if two delimiters are next to
* consider an empty element, even if two delimiters are next to
...
@@ -386,4 +388,9 @@ char *must_copy_string(const char *entry);
...
@@ -386,4 +388,9 @@ char *must_copy_string(const char *entry);
/* Re-alllocate a pointer, do not fail */
/* Re-alllocate a pointer, do not fail */
void
*
must_realloc
(
void
*
orig
,
size_t
sz
);
void
*
must_realloc
(
void
*
orig
,
size_t
sz
);
/* __typeof__ should be safe to use with all compilers. */
typedef
__typeof__
(((
struct
statfs
*
)
NULL
)
->
f_type
)
fs_type_magic
;
bool
has_fs_type
(
const
char
*
path
,
fs_type_magic
magic_val
);
bool
is_fs_type
(
const
struct
statfs
*
fs
,
fs_type_magic
magic_val
);
#endif
/* __LXC_UTILS_H */
#endif
/* __LXC_UTILS_H */
src/tests/lxc-test-utils.c
View file @
183ebf0a
...
@@ -41,33 +41,37 @@
...
@@ -41,33 +41,37 @@
void
test_lxc_deslashify
(
void
)
void
test_lxc_deslashify
(
void
)
{
{
char
*
s
=
strdup
(
"/A///B//C/D/E/"
);
char
*
s
=
"/A///B//C/D/E/"
;
if
(
!
s
)
char
*
t
;
t
=
lxc_deslashify
(
s
);
if
(
!
t
)
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
lxc_test_assert_abort
(
lxc_deslashify
(
&
s
));
lxc_test_assert_abort
(
strcmp
(
t
,
"/A/B/C/D/E"
)
==
0
);
lxc_test_assert_abort
(
strcmp
(
s
,
"/A/B/C/D/E"
)
==
0
);
free
(
t
);
free
(
s
);
s
=
strdup
(
"/A"
);
s
=
"/A"
;
if
(
!
s
)
t
=
lxc_deslashify
(
s
);
if
(
!
t
)
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
lxc_test_assert_abort
(
lxc_deslashify
(
&
s
));
lxc_test_assert_abort
(
strcmp
(
t
,
"/A"
)
==
0
);
lxc_test_assert_abort
(
strcmp
(
s
,
"/A"
)
==
0
);
free
(
t
);
free
(
s
);
s
=
strdup
(
""
);
s
=
""
;
if
(
!
s
)
t
=
lxc_deslashify
(
s
);
if
(
!
t
)
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
lxc_test_assert_abort
(
lxc_deslashify
(
&
s
));
lxc_test_assert_abort
(
strcmp
(
t
,
""
)
==
0
);
lxc_test_assert_abort
(
strcmp
(
s
,
""
)
==
0
);
free
(
t
);
free
(
s
);
s
=
"//"
;
s
=
strdup
(
"//"
);
t
=
lxc_deslashify
(
s
);
if
(
!
s
)
if
(
!
t
)
exit
(
EXIT_FAILURE
);
exit
(
EXIT_FAILURE
);
lxc_test_assert_abort
(
lxc_deslashify
(
&
s
));
lxc_test_assert_abort
(
strcmp
(
t
,
"/"
)
==
0
);
lxc_test_assert_abort
(
strcmp
(
s
,
"/"
)
==
0
);
free
(
t
);
free
(
s
);
}
}
/* /proc/int_as_str/ns/mnt\0 = (5 + 21 + 7 + 1) */
/* /proc/int_as_str/ns/mnt\0 = (5 + 21 + 7 + 1) */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment