Example #1
0
func setresgid(rgid, egid, sgid int) error {
	eno := C.csetresgid(C.gid_t(rgid), C.gid_t(egid), C.gid_t(sgid))
	if eno != 0 {
		return syscall.Errno(eno)
	}
	return nil
}
Example #2
0
/*
SetUIDGID sets owner of the group control files and the @c tasks file. This function
modifies only libcgroup internal cgroup structure, use
Cgroup.Create() afterwards to create the group with given owners.

@param cgroup
@param tasksUID UID of the owner of group's @c tasks file.
@param tasksGID GID of the owner of group's @c tasks file.
@param controlUID UID of the owner of group's control files (i.e.
parameters).
@param controlGID GID of the owner of group's control files (i.e.
parameters).
*/
func (cg Cgroup) SetUIDGID(tasksUID UID, tasksGID GID,
	controlUID UID, controlGID GID) error {
	return _err(C.cgroup_set_uid_gid(cg.g,
		C.uid_t(tasksUID), C.gid_t(tasksGID),
		C.uid_t(controlUID), C.gid_t(controlGID)))

}
Example #3
0
// Set owner of the group control files and the @c tasks file. This function
// modifies only libcgroup internal cgroup structure, use
// Cgroup.Create() afterwards to create the group with given owners.
// @param cgroup
// @param tasks_uid UID of the owner of group's @c tasks file.
// @param tasks_gid GID of the owner of group's @c tasks file.
// @param control_uid UID of the owner of group's control files (i.e.
// parameters).
// @param control_gid GID of the owner of group's control files (i.e.
// parameters).
func (cg Cgroup) SetUidGid(tasks_uid UID, tasks_gid GID,
	control_uid UID, control_gid GID) error {
	return _err(C.cgroup_set_uid_gid(cg.g,
		C.uid_t(tasks_uid), C.gid_t(tasks_gid),
		C.uid_t(control_uid), C.gid_t(control_gid)))

}
Example #4
0
func GetGroupList(u *user.User) ([]string, error) {
	var members []string
	gid, err := strconv.Atoi(u.Gid)
	if err != nil {
		return nil, err
	}

	nameC := C.CString(u.Username)
	defer C.free(unsafe.Pointer(nameC))
	groupC := C.gid_t(gid)
	ngroupsC := C.int(0)

	C.mygetgrouplist(nameC, groupC, nil, &ngroupsC)
	ngroups := int(ngroupsC)

	groups := C.malloc(C.size_t(int(unsafe.Sizeof(groupC)) * ngroups))
	defer C.free(groups)

	rv := C.mygetgrouplist(nameC, groupC, (*C.gid_t)(groups), &ngroupsC)
	if rv == -1 {
		return nil, fmt.Errorf("user: membership of %s in %s: %s", u.Username, u.Gid, syscall.Errno(rv))
	}

	ngroups = int(ngroupsC)
	for i := 0; i < ngroups; i++ {
		gid := C.group_at(C.int(i), (*C.gid_t)(groups))
		gidS := strconv.Itoa(int(gid))
		group, err := LookupGroupID(gidS)
		if err != nil {
			return nil, err
		}
		members = append(members, group.Name)
	}
	return members, nil
}
Example #5
0
func listGroups(u *User) ([]string, error) {
	ug, err := strconv.Atoi(u.Gid)
	if err != nil {
		return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
	}
	userGID := C.gid_t(ug)
	nameC := C.CString(u.Username)
	defer C.free(unsafe.Pointer(nameC))

	n := C.int(256)
	gidsC := make([]C.gid_t, n)
	rv := getGroupList(nameC, userGID, &gidsC[0], &n)
	if rv == -1 {
		// More than initial buffer, but now n contains the correct size.
		const maxGroups = 2048
		if n > maxGroups {
			return nil, fmt.Errorf("user: list groups for %s: member of more than %d groups", u.Username, maxGroups)
		}
		gidsC = make([]C.gid_t, n)
		rv := getGroupList(nameC, userGID, &gidsC[0], &n)
		if rv == -1 {
			return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username)
		}
	}
	gidsC = gidsC[:n]
	gids := make([]string, 0, n)
	for _, g := range gidsC[:n] {
		gids = append(gids, strconv.Itoa(int(g)))
	}
	return gids, nil
}
Example #6
0
//NewGroup returns a new Group given a gid
//or an error if any occurred
func NewGroup(gid uint32) (*Group, error) {
	var buf = new(*C.char)
	grp, err := C.gidtogrp(C.gid_t(gid), buf)
	defer C.free(unsafe.Pointer(*buf))
	defer C.free(unsafe.Pointer(grp))

	if err != nil {
		return nil, err
	}
	if grp == nil {
		return nil, fmt.Errorf("gid does not exist")
	}
	length := int(C.getMemLength(grp.gr_mem))
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(grp.gr_mem)),
		Len:  length,
		Cap:  length,
	}
	return &Group{
		Name:   C.GoString(grp.gr_name),
		Passwd: C.GoString(grp.gr_passwd),
		Gid:    uint32(grp.gr_gid),
		Mem:    *(*[]string)(unsafe.Pointer(&hdr)),
	}, nil
}
Example #7
0
// Using Reflect
// does not work
func passingGrpBufferWithReflect(dst *C.struct_group, dstbuf *C.char, dstbuflen C.int, errnop *C.int) {
	ourGid := 52
	byteArr := C.GoBytes(unsafe.Pointer(buf), buflen)

	byteBuf := bytes.NewBuffer(byteArr[:0])
	for _, s := range []string{"name", "passwd", "one", "two", "three"} {
		byteBuf.WriteString(s)
		byteBuf.WriteByte(0)
	}

	var p *C.char

	memPtr := []*C.char{
		(*C.char)(unsafe.Pointer(&byteArr[12])),
		(*C.char)(unsafe.Pointer(&byteArr[16])),
		(*C.char)(unsafe.Pointer(&byteArr[20])),
		(*C.char)(nil),
	}

	lenCap := len(memPtr) * int(unsafe.Sizeof(p))
	refSlice := &reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(&memPtr[0])),
		Len:  lenCap, Cap: lenCap}

	memBytes := *(*[]byte)(unsafe.Pointer(refSlice))
	byteBuf.Write(memBytes)

	grp.gr_name = (*C.char)(unsafe.Pointer(&byteArr[0]))
	grp.gr_passwd = (*C.char)(unsafe.Pointer(&byteArr[5]))
	grp.gr_gid = C.gid_t(ourGid)
	grp.gr_mem = (**C.char)(unsafe.Pointer(&byteArr[26]))
}
Example #8
0
func setgid(gid int) error {
	eno := C.csetgid(C.gid_t(gid))
	if eno != 0 {
		return syscall.Errno(eno)
	}
	return nil
}
Example #9
0
func userInGroup(u *user.User, g *Group) (bool, error) {
	if u.Gid == g.Gid {
		return true, nil
	}
	gid, err := strconv.Atoi(g.Gid)
	if err != nil {
		return false, err
	}

	nameC := C.CString(u.Username)
	defer C.free(unsafe.Pointer(nameC))
	groupC := C.gid_t(gid)
	ngroupsC := C.int(0)

	C.mygetgrouplist(nameC, groupC, nil, &ngroupsC)
	ngroups := int(ngroupsC)

	groups := C.malloc(C.size_t(int(unsafe.Sizeof(groupC)) * ngroups))
	defer C.free(groups)

	rv := C.mygetgrouplist(nameC, groupC, (*C.gid_t)(groups), &ngroupsC)
	if rv == -1 {
		return false, fmt.Errorf("user: membership of %s in %s: %s", u.Username, g.Name, syscall.Errno(rv))
	}

	ngroups = int(ngroupsC)
	for i := 0; i < ngroups; i++ {
		gid := C.group_at(C.int(i), (*C.gid_t)(groups))
		if g.Gid == strconv.Itoa(int(gid)) {
			return true, nil
		}
	}
	return false, nil
}
Example #10
0
// Because Go is like... naaaaa, no groups aren't a thing!
// Based on Go's src/os/user/lookup_unix.go
func currentUserAndGroup() (*userAndGroup, error) {
	u, err := user.Current()
	if err != nil {
		return nil, err
	}
	gid, err := strconv.Atoi(u.Gid)
	if err != nil {
		return nil, err
	}

	var grp C.struct_group
	var result *C.struct_group
	buflen := C.sysconf(C._SC_GETPW_R_SIZE_MAX)
	if buflen <= 0 || buflen > 1<<20 {
		return nil, fmt.Errorf("unreasonable _SC_GETGR_R_SIZE_MAX of %d", buflen)
	}
	buf := C.malloc(C.size_t(buflen))
	defer C.free(buf)

	r := C.mygetgrgid_r(C.gid_t(gid), &grp,
		(*C.char)(buf),
		C.size_t(buflen),
		&result)
	if r != 0 {
		return nil, fmt.Errorf("lookup gid %d: %s", gid, syscall.Errno(r))
	}
	if result == nil {
		return nil, fmt.Errorf("lookup gid %d failed", gid)
	}

	return &userAndGroup{
		User:      u,
		Groupname: C.GoString(grp.gr_name),
	}, nil
}
Example #11
0
//
// Chown wraps keyctl_chown(3) to change ownership of the key.
//
// See: http://man7.org/linux/man-pages/man3/keyctl_chown.3.html
//
func Chown(key KeySerial, uid uint, gid uint) error {

	_, err := C.keyctl_chown(C.key_serial_t(key), C.uid_t(uid), C.gid_t(gid))

	if err != nil {
		return err.(syscall.Errno)
	}
	return nil
}
Example #12
0
// Pushes an array of gid_t's into the mmapData buffer.
func (m *mmapData) pushGidSlice(gs []uint32) *C.gid_t {
	ptr := unsafe.Pointer(&m.data[m.offset])
	nextptr := ptr
	for _, g := range gs {
		*(*C.gid_t)(nextptr) = C.gid_t(g)
		m.offset += gidSize
		nextptr = unsafe.Pointer(&m.data[m.offset])
	}
	m.panicIfOverAllocated()
	return (*C.gid_t)(ptr)
}
Example #13
0
func getExtraGIDs(gid int) (gids []int, err error) {
	gidn := C.gid_t(gid)

	f := func(gid C.gid_t) {
		gids = append(gids, int(gid))
	}

	if C.de_get_extra_gids(gidn, C.uintptr_t(uintptr(unsafe.Pointer(&f)))) < 0 {
		return nil, fmt.Errorf("cannot retrieve additional groups list for GID %d", gid)
	}

	return
}
Example #14
0
// RunCommandStatus attachs a shell and runs the command within the container.
// The process will wait for the command to finish and return the result of
// waitpid(), i.e. the process' exit status. An error is returned only when
// invocation of the command completely fails.
func (c *Container) RunCommandStatus(args []string, options AttachOptions) (int, error) {
	if len(args) == 0 {
		return -1, ErrInsufficientNumberOfArguments
	}

	if err := c.makeSure(isRunning); err != nil {
		return -1, err
	}

	c.mu.Lock()
	defer c.mu.Unlock()

	cargs := makeNullTerminatedArgs(args)
	if cargs == nil {
		return -1, ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cargs, len(args))

	cenv := makeNullTerminatedArgs(options.Env)
	if cenv == nil {
		return -1, ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenv, len(options.Env))

	cenvToKeep := makeNullTerminatedArgs(options.EnvToKeep)
	if cenvToKeep == nil {
		return -1, ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenvToKeep, len(options.EnvToKeep))

	cwd := C.CString(options.Cwd)
	defer C.free(unsafe.Pointer(cwd))

	ret := int(C.go_lxc_attach_run_wait(
		c.container,
		C.bool(options.ClearEnv),
		C.int(options.Namespaces),
		C.long(options.Arch),
		C.uid_t(options.UID),
		C.gid_t(options.GID),
		C.int(options.StdinFd),
		C.int(options.StdoutFd),
		C.int(options.StderrFd),
		cwd,
		cenv,
		cenvToKeep,
		cargs,
	))

	return ret, nil
}
Example #15
0
func lookup(gid int, groupname string, lookupByName bool) (*Group, error) {
	var grp C.struct_group
	var result *C.struct_group
	var bufsize C.long

	bufsize = C.sysconf(C._SC_GETGR_R_SIZE_MAX)
	if bufsize == -1 {
		bufsize = 1024
	}
	buf := C.malloc(C.size_t(bufsize))
	defer C.free(buf)

	var rv C.int
	if lookupByName {
		CGroup := C.CString(groupname)
		defer C.free(unsafe.Pointer(CGroup))
		rv = C.getgrnam_r(CGroup, &grp, (*C.char)(buf),
			C.size_t(bufsize), &result)
		if rv != 0 {
			return nil,
				fmt.Errorf("group: lookup group name %s: %s",
					groupname, syscall.Errno(rv))
		}
		if result == nil {
			return nil, UnknownGroupError(groupname)
		}
	} else {
		rv = C.getgrgid_r(C.gid_t(gid), &grp, (*C.char)(buf),
			C.size_t(bufsize), &result)
		if rv != 0 {
			return nil, fmt.Errorf("group: lookup gid %d: %s",
				gid, syscall.Errno(rv))
		}
		if result == nil {
			return nil, UnknownGroupIdError(gid)
		}
	}

	g := &Group{
		Gid:     int(grp.gr_gid),
		Name:    C.GoString(grp.gr_name),
		Members: convert(grp.gr_mem),
	}

	return g, nil
}
func (a *InoAttr) toCStat(o *C.struct_stat, timeout *C.double) {
	o.st_ino = C.__darwin_ino64_t(a.Ino)
	o.st_mode = C.mode_t(a.Mode)
	o.st_nlink = C.nlink_t(a.Nlink)
	o.st_size = C.off_t(a.Size)
	if a.Uid != nil {
		o.st_uid = C.uid_t(*a.Uid)
	}
	if a.Gid != nil {
		o.st_gid = C.gid_t(*a.Gid)
	}
	toCTime(&o.st_ctimespec, a.Ctim)
	toCTime(&o.st_mtimespec, a.Mtim)
	toCTime(&o.st_atimespec, a.Atim)
	if timeout != nil {
		(*timeout) = C.double(a.Timeout)
	}
}
Example #17
0
// AttachShell attaches a shell to the container.
// It clears all environment variables before attaching.
func (c *Container) AttachShell(options AttachOptions) error {
	if err := c.makeSure(isRunning); err != nil {
		return err
	}

	c.mu.Lock()
	defer c.mu.Unlock()

	cenv := makeNullTerminatedArgs(options.Env)
	if cenv == nil {
		return ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenv, len(options.Env))

	cenvToKeep := makeNullTerminatedArgs(options.EnvToKeep)
	if cenvToKeep == nil {
		return ErrAllocationFailed
	}
	defer freeNullTerminatedArgs(cenvToKeep, len(options.EnvToKeep))

	cwd := C.CString(options.Cwd)
	defer C.free(unsafe.Pointer(cwd))

	ret := int(C.go_lxc_attach(c.container,
		C.bool(options.ClearEnv),
		C.int(options.Namespaces),
		C.long(options.Arch),
		C.uid_t(options.UID),
		C.gid_t(options.GID),
		C.int(options.StdinFd),
		C.int(options.StdoutFd),
		C.int(options.StderrFd),
		cwd,
		cenv,
		cenvToKeep,
	))
	if ret < 0 {
		return ErrAttachFailed
	}
	return nil
}
Example #18
0
func changeUser(username string) error {
	uid, gid, err := user.IDs(username)
	if err != nil {
		return util.Errorf("Could not retrieve uid/gid for %q: %s", username, err)
	}

	userCstring := C.CString(username)
	defer C.free(unsafe.Pointer(userCstring))

	ret, err := C.initgroups(userCstring, C.int(gid))
	if ret != 0 && err != nil {
		return util.Errorf("Could not initgroups for %q (primary gid %v): %s", username, gid, err)
	}
	ret, err = C.setgid(C.gid_t(gid))
	if ret != 0 && err != nil {
		return util.Errorf("Could not setgid %v: %s", gid, err)
	}
	ret, err = C.setuid(C.uid_t(uid))
	if ret != 0 && err != nil {
		return util.Errorf("Could not setuid %v: %s", uid, err)
	}
	return nil
}
Example #19
0
// Run is a simple wrapper around Start() then Wait() with a common err return.
func (c *Cmd) Start() (err error) {
	// If the process has already started then we can not continue here.
	if c.Process != nil {
		return fmt.Errorf("goclone: already started.")
	}

	// Check that UserMap and GroupMap are not defined if NewUserNameSpace
	// is not true.
	switch {
	case c.NewUserNameSpace:
	case c.UserMap != nil:
		return fmt.Errorf("goclone: UserMap set but NewUserNameSpace is false.")
	case c.GroupMap != nil:
		return fmt.Errorf(
			"goclone: GroupMap set but NewUserNameSpace is false.")
	}

	// Check to see if user name spaces are being used when the support
	// for them does not exist in the kernel.
	switch {
	case C.goclone_user_namespace_enabled == 1:
	case c.NewUserNameSpace:
		fallthrough
	case c.UserNameSpace != "":
		return fmt.Errorf("goclone: The kernel lacks user namespace support.")
	}

	// This function will walk through all of the file descriptors closing them
	// and returning the error passed in (or an error generated during the
	// Close() call if necessary.
	fail := func(err error) error {
		err = closeDescriptors(c.closeAfterStart, err)
		err = closeDescriptors(c.closeAfterWait, err)
		return err
	}

	// Setup the file descriptors needed to actually perform the syscall
	// level clone.
	stdin, err := c.reader(c.Stdin)
	if err != nil {
		return fail(err)
	}
	stdout, err := c.writer(c.Stdout)
	if err != nil {
		return fail(err)
	}

	// As a special case we have to check that stdout and stderr are not the
	// same object. If they are then we should use the same file descriptor
	// object rather than duplicating a whole new one.
	var stderr *os.File
	if c.Stdout == c.Stderr {
		stderr = stdout
	} else {
		stderr, err = c.writer(c.Stderr)
		if err != nil {
			return fail(err)
		}
	}

	// Make the native object type that is necessary in order to pass the
	// data into the cgo side of the world. We do this via a mmaped chunk
	// of memory so that we don't have to fiddle with malloc or any form
	// of shared memory allocations. Mmap works purely in pages so everything
	// needs to be sized to fit within pages of memory.
	//
	// The format for this allocation looks like this:
	// [ C.goclone_cmd ] - This will be several pages, rounded up to the
	//                     next page size.
	// [ buffer ] - This is necessary to ensure that we operate on sizes
	//              one page at a time.
	// [ page ] - This is a single page that will be memprotected in order to
	//            prevent the stack in the C side from growing large enough
	//            to cause memory corruption.
	// [ stack ] - This is a chunk of memory used as the stack for the cloned
	//             process.
	// [ page ] - This is another protected page.
	//
	// If double forking this will also be added to the allocation:
	// [ stack 2 ] - The stack for the short lived middle process.
	// [ page ] - Another protected page.

	// Start by calculating how much data needs to be available in the mmap
	// allocation.
	dataSize := rawDataSize(c)

	// Adjust the dataSize value to be a multiple of pageSize.
	dataSize = ((dataSize - 1) | (pageSize - 1)) + 1

	// Now calculate the total size of the allocation.
	size := dataSize + pageSize + stackSize + pageSize
	if c.DoubleFork {
		size += stackSize + pageSize
	}

	// Allocate the space and ensure it gets freed when the routine exits.
	m, err := mmapDataAlloc(size)
	if err != nil {
		return fail(err)
	}
	defer func() {
		err2 := m.free()
		if err == nil && err2 != nil {
			err = err2
		}
	}()

	// This boolean value is set if the credentials should be set at some
	// point. Its off by default unless a user defined the Credentials field
	// in the SysProcAttr field.
	setCredentials := false
	uid := uint32(0)
	gid := uint32(0)
	groups := []uint32(nil)
	if c.SysProcAttr != nil && c.SysProcAttr.Credential != nil {
		setCredentials = true
		uid = c.SysProcAttr.Credential.Uid
		gid = c.SysProcAttr.Credential.Gid
		groups = c.SysProcAttr.Credential.Groups
	}

	// If the c.SysProcAttr value is set then save the signal.
	deathSignal := syscall.SIGCHLD
	if c.SysProcAttr != nil && c.SysProcAttr.Pdeathsig != 0 {
		deathSignal = c.SysProcAttr.Pdeathsig
	}

	// The chroot directory is set from c.SysProcAttr if defined.
	chrootDir := ""
	if c.SysProcAttr != nil {
		chrootDir = c.SysProcAttr.Chroot
	}

	// Make an array of file descriptors that will be used to setup the
	// file descriptors in the child process.
	files := make([]int, len(c.ExtraFiles)+3)
	files[0] = int(stdin.Fd())
	files[1] = int(stdout.Fd())
	files[2] = int(stderr.Fd())
	for i, fd := range c.ExtraFiles {
		if fd != nil {
			files[i+3] = int(fd.Fd())
		} else {
			files[i+3] = -1
		}
	}

	// Populate the various data elements in the allocation.
	cmd := m.pushGocloneCmd()
	// Exec settings.
	cmd.path = m.pushString(c.Path)
	cmd.args = m.pushStringSlice(c.Args)
	cmd.env = m.pushStringSlice(c.Env)
	cmd.dir = m.pushString(c.Dir)
	cmd.chroot_dir = m.pushString(chrootDir)

	// Set hostname only for new UTS namespace
	if c.NewUTSNameSpace {
		cmd.hostname = m.pushString(c.Hostname)
	} else {
		cmd.hostname = m.pushString("")
	}

	// file descriptors.
	cmd.files = m.pushIntSlice(files)
	cmd.files_len = C.int(len(files))

	// Credentials
	cmd.set_credentials = C.bool(setCredentials)
	cmd.uid = C.uid_t(uid)
	cmd.gid = C.gid_t(gid)
	cmd.groups = m.pushGidSlice(groups)
	cmd.groups_len = C.int(len(groups))

	// Cgroups tasks files.
	cmd.cgroups_tasks_files = m.pushStringSlice(c.CgroupsTasksFiles)

	// Namespaces
	cmd.ipc_namespace = m.pushString(c.IPCNameSpace)
	cmd.mount_namespace = m.pushString(c.MountNameSpace)
	cmd.network_namespace = m.pushString(c.NetworkNameSpace)
	cmd.user_namespace = m.pushString(c.UserNameSpace)
	cmd.uts_namespace = m.pushString(c.UTSNameSpace)
	cmd.pid_namespace = m.pushString(c.PIDNameSpace)
	cmd.new_ipc_namespace = C.bool(c.NewIPCNameSpace)
	cmd.new_network_namespace = C.bool(c.NewNetworkNameSpace)
	cmd.new_pid_namespace = C.bool(c.NewPIDNameSpace)
	cmd.new_mount_namespace = C.bool(c.NewMountNameSpace)
	cmd.new_user_namespace = C.bool(c.NewUserNameSpace)
	cmd.new_uts_namespace = C.bool(c.NewUTSNameSpace)

	// See if we should mount a new /proc from the underlying process.
	if os.Getuid() == 0 && c.NewPIDNameSpace {
		cmd.mount_new_proc = C.bool(true)
	} else {
		cmd.mount_new_proc = C.bool(false)
	}

	// Various simple settings.
	cmd.double_fork = C.bool(c.DoubleFork)
	cmd.death_signal = C.int(deathSignal)

	// Allocate the stacks.
	if err = m.mprotect(); err != nil {
		return
	}
	cmd.stack = m.stack()
	if err = m.mprotect(); err != nil {
		return
	}

	// If double forking, allocate another stack and protect the page after it.
	if c.DoubleFork {
		cmd.df_stack = m.stack()
		if err = m.mprotect(); err != nil {
			return
		}
	}

	// Next we need to create a goclone_parent_data for use by the parent when
	// helpign with the child.
	var data C.goclone_parent_data

	// Setup the uid_map. This will be written to /proc/child/uid_map if
	// defined.
	var uid_map bytes.Buffer
	if c.UserMap == nil {
		data.uid_map = nil
		data.uid_map_length = 0
	} else {
		for i := range c.UserMap {
			elm := &c.UserMap[i]
			fmt.Fprintf(&uid_map, "%d %d %d\n", elm.Inside, elm.Outside, elm.Length)
		}
		data.uid_map = (*C.char)(unsafe.Pointer(&(uid_map.Bytes()[0])))
		data.uid_map_length = (C.int)(uid_map.Len())
	}

	// Setup the gid_map. This will be written to /proc/child/gid_map if
	// defined.
	var gid_map bytes.Buffer
	if c.UserMap == nil {
		data.gid_map = nil
		data.gid_map_length = 0
	} else {
		for i := range c.UserMap {
			elm := &c.UserMap[i]
			fmt.Fprintf(&gid_map, "%d %d %d\n", elm.Inside, elm.Outside, elm.Length)
		}
		b := gid_map.Bytes()
		data.gid_map = (*C.char)(unsafe.Pointer(&b[0]))
		data.gid_map_length = (C.int)(gid_map.Len())
	}

	// Call the C function.
	pid, err := C.goclone(cmd, &data)

	// Close any file descriptors that are no longer needed.
	err = closeDescriptors(c.closeAfterStart, err)

	// Make the Process structure. This functions foot print returns an error
	// but on linux an error can never be returned.
	c.Process, _ = os.FindProcess(int(pid))

	// Start all of the copy goroutines.
	for _, f := range c.copyRoutines {
		c.errWG.Add(1)
		go f()
	}
	c.copyRoutines = nil

	return
}
Example #20
0
import "C"

import (
	"syscall"
	"unsafe"
)

var (
	// The size of a pointer in bytes in the system.
	ptrSize = int(unsafe.Sizeof(unsafe.Pointer(nil)))

	// The size of a C integer in bytes on the system.
	intSize = int(unsafe.Sizeof(C.int(0)))

	// The size of a gid_t type in bytes on the system.
	gidSize = int(unsafe.Sizeof(C.gid_t(0)))

	// The size of system pages on the system.
	pageSize = syscall.Getpagesize()

	// The size that should be allocated for stacks.
	stackSize = pageSize * 8
)

// This function call will calculate exactly how much space is expected to be
// used by the data elements of the c array. The returned size here will
// not be page size shifted.
func rawDataSize(c *Cmd) int {
	// First calculate the size of the C.goclone_cmd, then add each of the
	// strings, or arrays to the size so we know how much space to allocate.
	dataSize := int(unsafe.Sizeof(C.goclone_cmd{}))