github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/builder/dockerfile/internals_linux.go (about)

     1  package dockerfile // import "github.com/docker/docker/builder/dockerfile"
     2  
     3  import (
     4  	"path/filepath"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/docker/docker/pkg/idtools"
     9  	"github.com/docker/docker/pkg/symlink"
    10  	lcUser "github.com/opencontainers/runc/libcontainer/user"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
    15  	var userStr, grpStr string
    16  	parts := strings.Split(chown, ":")
    17  	if len(parts) > 2 {
    18  		return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
    19  	}
    20  	if len(parts) == 1 {
    21  		// if no group specified, use the user spec as group as well
    22  		userStr, grpStr = parts[0], parts[0]
    23  	} else {
    24  		userStr, grpStr = parts[0], parts[1]
    25  	}
    26  
    27  	passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
    28  	if err != nil {
    29  		return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
    30  	}
    31  	groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
    32  	if err != nil {
    33  		return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
    34  	}
    35  	uid, err := lookupUser(userStr, passwdPath)
    36  	if err != nil {
    37  		return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
    38  	}
    39  	gid, err := lookupGroup(grpStr, groupPath)
    40  	if err != nil {
    41  		return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
    42  	}
    43  
    44  	// convert as necessary because of user namespaces
    45  	chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
    46  	if err != nil {
    47  		return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
    48  	}
    49  	return chownPair, nil
    50  }
    51  
    52  func lookupUser(userStr, filepath string) (int, error) {
    53  	// if the string is actually a uid integer, parse to int and return
    54  	// as we don't need to translate with the help of files
    55  	uid, err := strconv.Atoi(userStr)
    56  	if err == nil {
    57  		return uid, nil
    58  	}
    59  	users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
    60  		return u.Name == userStr
    61  	})
    62  	if err != nil {
    63  		return 0, err
    64  	}
    65  	if len(users) == 0 {
    66  		return 0, errors.New("no such user: " + userStr)
    67  	}
    68  	return users[0].Uid, nil
    69  }
    70  
    71  func lookupGroup(groupStr, filepath string) (int, error) {
    72  	// if the string is actually a gid integer, parse to int and return
    73  	// as we don't need to translate with the help of files
    74  	gid, err := strconv.Atoi(groupStr)
    75  	if err == nil {
    76  		return gid, nil
    77  	}
    78  	groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
    79  		return g.Name == groupStr
    80  	})
    81  	if err != nil {
    82  		return 0, err
    83  	}
    84  	if len(groups) == 0 {
    85  		return 0, errors.New("no such group: " + groupStr)
    86  	}
    87  	return groups[0].Gid, nil
    88  }