Example #1
0
func buildImageFromRaw(imageSClient *srpc.Client, filter *filter.Filter,
	imageFile *os.File, partitionTable *mbr.Mbr,
	h *hasher) (*filesystem.FileSystem, error) {
	var index uint
	var offsetOfLargest, sizeOfLargest uint64
	numPartitions := partitionTable.GetNumPartitions()
	for index = 0; index < numPartitions; index++ {
		offset := partitionTable.GetPartitionOffset(index)
		size := partitionTable.GetPartitionSize(index)
		if size > sizeOfLargest {
			offsetOfLargest = offset
			sizeOfLargest = size
		}
	}
	if sizeOfLargest < 1 {
		return nil, errors.New("unable to find largest partition")
	}
	if err := wsyscall.UnshareMountNamespace(); err != nil {
		if os.IsPermission(err) {
			// Try again with sudo(8).
			args := make([]string, 0, len(os.Args)+1)
			if sudoPath, err := exec.LookPath("sudo"); err != nil {
				return nil, err
			} else {
				args = append(args, sudoPath)
			}
			if myPath, err := exec.LookPath(os.Args[0]); err != nil {
				return nil, err
			} else {
				args = append(args, myPath)
			}
			args = append(args, fmt.Sprintf("-certDirectory=%s",
				setupclient.GetCertDirectory()))
			args = append(args, os.Args[1:]...)
			if err := syscall.Exec(args[0], args, os.Environ()); err != nil {
				return nil, errors.New("unable to Exec: " + err.Error())
			}
		}
		return nil, errors.New(
			"error unsharing mount namespace: " + err.Error())
	}
	cmd := exec.Command("mount", "-o",
		fmt.Sprintf("loop,offset=%d", offsetOfLargest), imageFile.Name(),
		"/mnt")
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		return nil, err
	}
	return buildImageWithHasher(imageSClient, filter, "/mnt", h)
}
Example #2
0
func unshareAndBind(workingRootDir string) bool {
	if *unshare {
		// Re-exec myself using the unshare syscall while on a locked thread.
		// This hack is required because syscall.Unshare() operates on only one
		// thread in the process, and Go switches execution between threads
		// randomly. Thus, the namespace can be suddenly switched for running
		// code. This is an aspect of Go that was not well thought out.
		runtime.LockOSThread()
		if err := wsyscall.UnshareMountNamespace(); err != nil {
			fmt.Fprintf(os.Stderr, "Unable to unshare mount namesace: %s\n",
				err)
			return false
		}
		// Ensure the process is slightly niced. Since the Linux implementation
		// of setpriority(2) only applies to a thread, not the whole process
		// (contrary to the POSIX specification), do this in the pinned OS
		// thread so that the whole process (after exec) will be niced.
		syscall.Setpriority(syscall.PRIO_PROCESS, 0, 1)
		args := append(os.Args, "-unshare=false")
		if err := syscall.Exec(args[0], args, os.Environ()); err != nil {
			fmt.Fprintf(os.Stderr, "Unable to Exec:%s: %s\n", args[0], err)
			return false
		}
	}
	syscall.Unmount(workingRootDir, 0)
	err := wsyscall.Mount(*rootDir, workingRootDir, "", wsyscall.MS_BIND, "")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to bind mount %s to %s: %s\n",
			*rootDir, workingRootDir, err)
		return false
	}
	// Clean up -unshare=false so that a subsequent re-exec starts from scratch.
	args := make([]string, 0, len(os.Args)-1)
	for _, arg := range os.Args {
		if arg != "-unshare=false" {
			args = append(args, arg)
		}
	}
	os.Args = args
	return true
}