func getUIDandGID()

in internal/util/util.go [99:150]


func getUIDandGID(username string) (uid int, gid int, err error) {
	var uidstr, gidstr string

	// Preference is user.Lookup(), if it works
	u, lookupErr := user.Lookup(username)
	if lookupErr == nil {
		// user.Lookup() was successful, use the returned UID/GID
		uidstr = u.Uid
		gidstr = u.Gid
	} else {
		// user.Lookup() has failed, second try by checking the DS cache
		out, cmdErr := ExecuteCommand(context.Background(), []string{"dscacheutil", "-q", "user", "-a", "name", username}, "", []string{}, nil)
		if cmdErr != nil {
			// dscacheutil has failed with an error
			return 0, 0, fmt.Errorf("dscacheutil: %w", cmdErr)
		}

		if len(out.Stdout) == 0 {
			// dscacheutil returns nothing if user is not found
			return 0, 0, fmt.Errorf("dscacheutil read user %q: %w", username, cmdErr)
		} else {
			// dscacheutil found user, extract the user info by keys
			dscacheUserInfo := extractDSCacheUtilKeyValues([]byte(out.Stdout), []string{"gid", "uid"})
			if len(dscacheUserInfo) == 0 {
				return 0, 0, fmt.Errorf("dscacheutil read user %q: %w", username, cmdErr)
			}
			if gid, ok := dscacheUserInfo["gid"]; ok {
				gidstr = gid
			}
			if uid, ok := dscacheUserInfo["uid"]; ok {
				uidstr = uid
			}
		}
	}

	// make sure we actually resolved a user before carrying on
	if uidstr == "" || gidstr == "" {
		return 0, 0, fmt.Errorf("user %q: no user info", username)
	}

	// Parse read UID and GID to integers
	uid, err = strconv.Atoi(uidstr)
	if err != nil {
		return 0, 0, fmt.Errorf("parse %q uid: %w", username, err)
	}
	gid, err = strconv.Atoi(gidstr)
	if err != nil {
		return 0, 0, fmt.Errorf("parse %q gid: %w", username, err)
	}

	return uid, gid, nil
}