// UnitFileStatuses returns a list of all unit files with their current status, // as shown by `systemctl list-unit-files`. func UnitFileStatuses() (units, statuses []string, err error) { cmd := exec.Command("systemctl", "--no-pager", "list-unit-files") out, err := cmd.CombinedOutput() if err != nil { err2 := errors.New(err.Error() + ": output: " + string(out)) return units, statuses, err2 } table := tabular.ProbabalisticSplit(string(out)) units = tabular.GetColumnNoHeader(0, table) // last two are empty line and junk statistics we don't care about if len(units) <= 3 { msg := fmt.Sprint(cmd.Args) + " didn't output enough lines" return units, statuses, errors.New(msg) } cmd = exec.Command("systemctl", "--no-pager", "list-unit-files") table = tabular.ProbabalisticSplit(string(out)) statuses = tabular.GetColumnNoHeader(1, table) // last two are empty line and junk statistics we don't care about if len(statuses) <= 3 { msg := fmt.Sprint(cmd.Args) + " didn't output enough lines" return units, statuses, errors.New(msg) } return units[:len(units)-2], statuses[:len(statuses)-2], nil }
// getYumRepos constructs Repos from the yum.conf file at path. Gives non-zero // Names, Fullnames, and URLs. func getYumRepos() (repos []repo) { // safeAccess allows access w/o fear of a panic into a slice of strings safeAccess := func(slc []string, index int) string { // catch runtime panic defer func() { if err := recover(); err != nil { msg := "safeAccess: Please report this error" errutil.IndexError(msg, index, slc) } }() // invoke inside defer if len(slc) > index { return slc[index] } return "" } // get and parse output of `yum repolist` cmd := exec.Command("yum", "repolist") outstr := chkutil.CommandOutput(cmd) // handle empty case if strings.Contains(outstr, "repolist: 0") { return repos } slc := tabular.ProbabalisticSplit(outstr) ids := tabular.GetColumnNoHeader(0, slc) // TODO use columnbyheader here errutil.IndexError("getYumRepos", 2, ids) ids = ids[:len(ids)-2] names := tabular.GetColumnNoHeader(1, slc) // TODO and here statuses := tabular.GetColumnNoHeader(2, slc) // TODO and here if len(ids) != len(names) || len(names) != len(statuses) { log.WithFields(log.Fields{ "names": len(names), "ids": len(ids), "statuses": len(statuses), }).Warn("Could not fetch complete metadata for every repo.") } // Construct repos for i := range ids { name := safeAccess(names, i) id := safeAccess(ids, i) status := safeAccess(statuses, i) repo := repo{Name: name, ID: id, Status: status} repos = append(repos, repo) } return repos }
// CommandColumnNoHeader returns a specified column of the output of a command, // without that column's header. Useful for parsing the output of shell commands, // which many of the Checks require. func CommandColumnNoHeader(col int, cmd *exec.Cmd) []string { out := CommandOutput(cmd) return tabular.GetColumnNoHeader(col, tabular.StringToSlice(out)) }
// port parses /proc/net/tcp to determine if a given port is in an open state // and returns an error if it is not. func port(parameters []string) (exitCode int, exitMessage string) { // getHexPorts gets all open ports as hex strings from /proc/net/tcp getHexPorts := func() (ports []string) { path := "/proc/net/tcp" data := wrkutils.FileToString(path) table := tabular.ProbabalisticSplit(data) // TODO by header isn't working //localAddresses := tabular.GetColumnByHeader("local_address", table) localAddresses := tabular.GetColumnNoHeader(1, table) portRe := regexp.MustCompile(`([0-9A-F]{8}):([0-9A-F]{4})`) for _, address := range localAddresses { port := portRe.FindString(address) if port != "" { if len(port) < 10 { log.WithFields(log.Fields{ "port": port, "length": len(port), }).Fatal("Couldn't parse port number in " + path) } portString := string(port[9:]) ports = append(ports, portString) } } return ports } // strHexToDecimal converts from string containing hex number to int strHexToDecimal := func(hex string) int { portInt, err := strconv.ParseInt(hex, 16, 64) if err != nil { log.WithFields(log.Fields{ "number": hex, "error": err.Error(), }).Fatal("Couldn't parse hex number") } return int(portInt) } // getOpenPorts gets a list of open/listening ports as integers getOpenPorts := func() (ports []int) { for _, port := range getHexPorts() { ports = append(ports, strHexToDecimal(port)) } return ports } // TODO check if it is in a valid range port := wrkutils.ParseMyInt(parameters[0]) open := getOpenPorts() for _, p := range open { if p == port { return 0, "" } } // convert ports to string to send to wrkutils.GenericError var strPorts []string for _, port := range open { strPorts = append(strPorts, fmt.Sprint(port)) } return wrkutils.GenericError("Port not open", fmt.Sprint(port), strPorts) }