github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/id/groups.go (about)

     1  // Copyright 2017-2018 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build !plan9
     6  // +build !plan9
     7  
     8  package main
     9  
    10  import (
    11  	"bufio"
    12  	"fmt"
    13  	"os"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  // Groups manages a group database, typically loaded from /etc/group
    19  type Groups struct {
    20  	gidToGroup map[int]string
    21  	groupToGID map[string]int
    22  	userToGIDs map[string][]int
    23  	gidToUsers map[int][]string
    24  }
    25  
    26  // GetGID returns the GID of a group
    27  func (g *Groups) GetGID(name string) (int, error) {
    28  	if v, ok := g.groupToGID[name]; ok {
    29  		return v, nil
    30  	}
    31  	return -1, fmt.Errorf("unknown group name: %s", name)
    32  }
    33  
    34  // GetGroup gets the group of a GID
    35  func (g *Groups) GetGroup(gid int) (string, error) {
    36  	if v, ok := g.gidToGroup[gid]; ok {
    37  		return v, nil
    38  	}
    39  	return "", fmt.Errorf("unknown gid: %d", gid)
    40  }
    41  
    42  // UserGetGIDs returns a slice of GIDs for a username
    43  func (g *Groups) UserGetGIDs(username string) []int {
    44  	if v, ok := g.userToGIDs[username]; ok {
    45  		return v
    46  	}
    47  	return nil
    48  }
    49  
    50  // NewGroups reads the GroupFile for groups.
    51  // It assumes the format "name:passwd:number:groupList".
    52  func NewGroups(file string) (g *Groups, e error) {
    53  	g = &Groups{}
    54  
    55  	g.gidToGroup = make(map[int]string)
    56  	g.groupToGID = make(map[string]int)
    57  	g.gidToUsers = make(map[int][]string)
    58  	g.userToGIDs = make(map[string][]int)
    59  
    60  	groupFile, err := os.Open(file)
    61  	if err != nil {
    62  		return g, err
    63  	}
    64  
    65  	var groupInfo []string
    66  
    67  	groupScanner := bufio.NewScanner(groupFile)
    68  
    69  	for groupScanner.Scan() {
    70  		txt := groupScanner.Text()
    71  		if len(txt) == 0 || txt[0] == '#' { // skip empty lines and comments
    72  			continue
    73  		}
    74  		groupInfo = strings.Split(txt, ":")
    75  		groupNum, err := strconv.Atoi(groupInfo[2])
    76  		if err != nil {
    77  			return nil, err
    78  		}
    79  
    80  		g.gidToGroup[groupNum] = groupInfo[0]
    81  		g.groupToGID[groupInfo[0]] = groupNum
    82  
    83  		users := strings.Split(groupInfo[3], ",")
    84  		for _, u := range users {
    85  			g.userToGIDs[u] = append(g.userToGIDs[u], groupNum)
    86  			g.gidToUsers[groupNum] = append(g.gidToUsers[groupNum], u)
    87  		}
    88  	}
    89  
    90  	return
    91  }