// 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

}
Example #2
0
// 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
}
Example #3
0
// 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))
}
Example #4
0
// 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)
}