github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/container/kvm/run_linux.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 //go:build linux 5 6 package kvm 7 8 import ( 9 "os" 10 "os/exec" 11 "os/user" 12 "strconv" 13 "syscall" 14 15 "github.com/juju/errors" 16 ) 17 18 // Run the command as user libvirt-qemu and return the combined output. 19 // If dir is non-empty, use it as the working directory. 20 func runAsLibvirt(dir, command string, args ...string) (string, error) { 21 uid, gid, err := getUserUIDGID(libvirtUser) 22 if err != nil { 23 return "", errors.Trace(err) 24 } 25 26 cmd := exec.Command(command, args...) 27 if dir != "" { 28 cmd.Dir = dir 29 } 30 31 if dir == "" { 32 dir, _ = os.Getwd() 33 } 34 logger.Debugf("running: %s %v from %s", command, args, dir) 35 logger.Debugf("running as uid: %d, gid: %d\n", uid, gid) 36 37 cmd.SysProcAttr = &syscall.SysProcAttr{} 38 cmd.SysProcAttr.Credential = &syscall.Credential{ 39 Uid: uint32(uid), 40 Gid: uint32(gid), 41 } 42 43 out, err := cmd.CombinedOutput() 44 output := string(out) 45 logger.Debugf("output: %v", output) 46 47 return output, err 48 49 } 50 51 // getUserUIDGID returns integer vals for uid and gid for the user. It returns 52 // -1 when there's an error so no one accidentally thinks 0 is the appropriate 53 // uid/gid when there's an error. 54 func getUserUIDGID(_ string) (int, int, error) { 55 u, err := user.Lookup(libvirtUser) 56 if err != nil { 57 return -1, -1, errors.Trace(err) 58 } 59 uid, err := strconv.ParseUint(u.Uid, 10, 32) 60 if err != nil { 61 return -1, -1, errors.Trace(err) 62 } 63 gid, err := strconv.ParseUint(u.Gid, 10, 32) 64 if err != nil { 65 return -1, -1, errors.Trace(err) 66 } 67 return int(uid), int(gid), nil 68 }