2019-09-30 10:53:48 -04:00
|
|
|
// Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
|
|
|
|
|
// iSulad-lxcfs-toolkit is licensed under the Mulan PSL v1.
|
|
|
|
|
// You can use this software according to the terms and conditions of the Mulan PSL v1.
|
|
|
|
|
// You may obtain a copy of Mulan PSL v1 at:
|
|
|
|
|
// http://license.coscl.org.cn/MulanPSL
|
|
|
|
|
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
|
|
|
|
// PURPOSE.
|
|
|
|
|
// See the Mulan PSL v1 for more details.
|
|
|
|
|
// Description: mount/umount in container namespace
|
|
|
|
|
// Author: zhangsong
|
|
|
|
|
// Create: 2019-05-31
|
|
|
|
|
|
|
|
|
|
package libmount
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
2019-12-13 15:30:17 +08:00
|
|
|
"isulad-lxcfs-toolkit/libmount/nsexec"
|
2019-09-30 10:53:48 -04:00
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
|
|
"github.com/docker/docker/pkg/reexec"
|
|
|
|
|
)
|
|
|
|
|
|
2019-12-25 16:01:46 +08:00
|
|
|
var (
|
|
|
|
|
lxcfsPath = "/var/lib/lxc/lxcfs/cgroup"
|
|
|
|
|
)
|
|
|
|
|
|
2019-09-30 10:53:48 -04:00
|
|
|
func init() {
|
|
|
|
|
reexec.Register(nsexec.NsEnterReexecName, WorkInContainer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setupPipe(name string) (*os.File, error) {
|
|
|
|
|
v := os.Getenv(name)
|
|
|
|
|
|
|
|
|
|
fd, err := strconv.Atoi(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("unable to convert %s=%s to int", name, v)
|
|
|
|
|
}
|
|
|
|
|
return os.NewFile(uintptr(fd), "pipe"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setupWorkType(name string) (int, error) {
|
|
|
|
|
v := os.Getenv(name)
|
|
|
|
|
|
|
|
|
|
worktype, err := strconv.Atoi(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return -1, fmt.Errorf("unable to convert %s=%s to int", name, v)
|
|
|
|
|
}
|
|
|
|
|
return worktype, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WorkInContainer will handle command in new namespace(container).
|
|
|
|
|
func WorkInContainer() {
|
|
|
|
|
var err error
|
|
|
|
|
var worktype int
|
|
|
|
|
var pipe *os.File
|
|
|
|
|
pipe, err = setupPipe(nsexec.InitPipe)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%v", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// when pipe setup, should always send back the errors.
|
|
|
|
|
defer func() {
|
|
|
|
|
var msg nsexec.ErrMsg
|
|
|
|
|
if err != nil {
|
|
|
|
|
msg.Error = fmt.Sprintf("%s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if err := nsexec.WriteJSON(pipe, msg); err != nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
worktype, err = setupWorkType(nsexec.WorkType)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle work here:
|
|
|
|
|
switch worktype {
|
|
|
|
|
case nsexec.MountMsg:
|
|
|
|
|
err = doMount(pipe)
|
|
|
|
|
case nsexec.UmountMsg:
|
|
|
|
|
err = doUmount(pipe)
|
|
|
|
|
default:
|
|
|
|
|
err = fmt.Errorf("unkown worktype=(%d)", worktype)
|
|
|
|
|
}
|
|
|
|
|
// do not need to check err here because we have check in defer
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func doMount(pipe *os.File) error {
|
|
|
|
|
var mount nsexec.Mount
|
|
|
|
|
if err := json.NewDecoder(pipe).Decode(&mount); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2019-12-25 16:01:46 +08:00
|
|
|
|
|
|
|
|
// remount lxcfs cgroup path readonly
|
|
|
|
|
if err := syscall.Mount(mount.Rootfs+lxcfsPath, mount.Rootfs+lxcfsPath, "none", syscall.MS_BIND, ""); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err := syscall.Mount(mount.Rootfs+lxcfsPath, mount.Rootfs+lxcfsPath, "none", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2019-09-30 10:53:48 -04:00
|
|
|
for i := 0; i < len(mount.SrcPaths) && i < len(mount.DestPaths); i++ {
|
|
|
|
|
if err := syscall.Mount(mount.SrcPaths[i], mount.DestPaths[i], "none", syscall.MS_BIND, ""); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func doUmount(pipe *os.File) error {
|
|
|
|
|
var umount nsexec.Umount
|
|
|
|
|
if err := json.NewDecoder(pipe).Decode(&umount); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < len(umount.Paths); i++ {
|
|
|
|
|
if err := syscall.Unmount(umount.Paths[i], syscall.MNT_DETACH); err != nil {
|
|
|
|
|
if !strings.Contains(err.Error(), "invalid argument") {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-25 16:01:46 +08:00
|
|
|
if err := syscall.Unmount(lxcfsPath, 0); err != nil {
|
|
|
|
|
if !strings.Contains(err.Error(), "invalid argument") {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-30 10:53:48 -04:00
|
|
|
return nil
|
|
|
|
|
}
|