github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/builder/dockerfile/internals_linux.go (about) 1 package dockerfile // import "github.com/demonoid81/moby/builder/dockerfile" 2 3 import ( 4 "path/filepath" 5 "strconv" 6 "strings" 7 8 "github.com/demonoid81/moby/pkg/idtools" 9 "github.com/demonoid81/moby/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 }