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  }