// systemctlUnitFileStatus checks whether or not the given unit file has the // given status: static | enabled | disabled func systemctlUnitFileStatus(parameters []string) (exitCode int, exitMessage string) { // getUnitFilesWithStatuses returns a pair of string slices that hold // the name of unit files with their current statuses. getUnitFilesWithStatuses := func() (units []string, statuses []string) { cmd := exec.Command("systemctl", "--no-pager", "list-unit-files") units = wrkutils.CommandColumnNoHeader(0, cmd) cmd = exec.Command("systemctl", "--no-pager", "list-unit-files") statuses = wrkutils.CommandColumnNoHeader(1, cmd) // last two are empty line and junk statistics we don't care about msg := fmt.Sprint(cmd.Args) + " didn't output enough lines" wrkutils.IndexError(msg, 2, units) wrkutils.IndexError(msg, 2, statuses) return units[:len(units)-2], statuses[:len(statuses)-2] } unit := parameters[0] status := parameters[1] units, statuses := getUnitFilesWithStatuses() var actualStatus string // TODO check if unit could be found at all for i, un := range units { if un == unit { actualStatus = statuses[i] if actualStatus == status { return 0, "" } } } msg := "Unit didn't have status" return wrkutils.GenericError(msg, status, []string{actualStatus}) }
// 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" wrkutils.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 := wrkutils.CommandOutput(cmd) slc := tabular.ProbabalisticSplit(outstr) ids := tabular.GetColumnNoHeader(0, slc) // TODO use columnbyheader here wrkutils.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 }
// systemctlSock is an abstraction of systemctlSockPath and systemctlSockUnit, // it reads from `systemctl list-sockets` and sees if the value is in the // appropriate column. func systemctlSock(value string, column string) (exitCode int, exitMessage string) { outstr := wrkutils.CommandOutput(exec.Command("systemctl", "list-sockets")) lines := tabular.Lines(outstr) msg := "systemctl list-sockers didn't output enough rows" wrkutils.IndexError(msg, len(lines)-4, lines) unlines := tabular.Unlines(lines[:len(lines)-4]) table := tabular.SeparateOnAlignment(unlines) values := tabular.GetColumnByHeader(column, table) if tabular.StrIn(value, values) { return 0, "" } return wrkutils.GenericError("Socket not found", value, values) }
// temp parses the output of lm_sensors and determines if Core 0 (all cores) are // over a certain threshold as specified in the JSON. func temp(parameters []string) (exitCode int, exitMessage string) { // TODO: check for negative, outrageously high temperatures // allCoreTemps returns the temperature of each core allCoreTemps := func() (temps []int) { cmd := exec.Command("sensors") out, err := cmd.CombinedOutput() outstr := string(out) wrkutils.ExecError(cmd, outstr, err) restr := `Core\s\d+:\s+[\+\-](?P<temp>\d+)\.*\d*°C` re := regexp.MustCompile(restr) for _, line := range regexp.MustCompile(`\n+`).Split(outstr, -1) { if re.MatchString(line) { // submatch captures only the integer part of the temperature matchDict := wrkutils.SubmatchMap(re, line) if _, ok := matchDict["temp"]; !ok { log.WithFields(log.Fields{ "regexp": re.String(), "matchDict": matchDict, "output": outstr, }).Fatal("Couldn't find any temperatures in `sensors` output") } tempInt64, err := strconv.ParseInt(matchDict["temp"], 10, 64) if err != nil { log.WithFields(log.Fields{ "regexp": re.String(), "matchDict": matchDict, "output": outstr, "error": err.Error(), }).Fatal("Couldn't parse integer from `sensors` output") } temps = append(temps, int(tempInt64)) } } return temps } // getCoreTemp returns an integer temperature for a certain core getCoreTemp := func(core int) (temp int) { temps := allCoreTemps() wrkutils.IndexError("No such core available", core, temps) return temps[core] } max := wrkutils.ParseMyInt(parameters[0]) temp := getCoreTemp(0) if temp < max { return 0, "" } msg := "Core temp exceeds defined maximum" return wrkutils.GenericError(msg, max, []string{fmt.Sprint(temp)}) }
// getTimers returns of all the timers under the UNIT column of // `systemctl list-timers` func getTimers(all bool) []string { cmd := exec.Command("systemctl", "list-timers") if all { cmd = exec.Command("systemctl", "list-timers", "--all") } out, err := cmd.CombinedOutput() outstr := string(out) wrkutils.ExecError(cmd, outstr, err) // last three lines are junk lines := tabular.Lines(outstr) msg := fmt.Sprint(cmd.Args) + " didn't output enough lines" wrkutils.IndexError(msg, 3, lines) table := tabular.SeparateOnAlignment(tabular.Unlines(lines[:len(lines)-3])) column := tabular.GetColumnByHeader("UNIT", table) return column }
// pacmanIgnore checks to see whether a given package is in /etc/pacman.conf's // IgnorePkg setting func pacmanIgnore(parameters []string) (exitCode int, exitMessage string) { pkg := parameters[0] path := "/etc/pacman.conf" data := wrkutils.FileToString(path) re := regexp.MustCompile(`[^#]IgnorePkg\s+=\s+.+`) find := re.FindString(data) var packages []string if find != "" { spl := strings.Split(find, " ") wrkutils.IndexError("Not enough lines in "+path, 2, spl) packages = spl[2:] // first two are "IgnorePkg" and "=" if tabular.StrIn(pkg, packages) { return 0, "" } } msg := "Couldn't find package in IgnorePkg" return wrkutils.GenericError(msg, pkg, packages) }
// gatewayInterface checks that the default gateway is using a specified interface func gatewayInterface(parameters []string) (exitCode int, exitMessage string) { // getGatewayInterface returns the interface that the default gateway is // operating on getGatewayInterface := func() (iface string) { ips := routingTableColumn("Gateway") names := routingTableColumn("Iface") for i, ip := range ips { if ip != "0.0.0.0" { msg := "Fewer names in kernel routing table than IPs" wrkutils.IndexError(msg, i, names) return names[i] // interface name } } return "" } name := parameters[0] iface := getGatewayInterface() if name == iface { return 0, "" } msg := "Default gateway does not operate on interface" return wrkutils.GenericError(msg, name, []string{iface}) }