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) }
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 }