package pkg import ( "fmt" "regexp" "strconv" "strings" ) var ( rgxNewDevice = regexp.MustCompile(`\+ dumpe2fs -h\s+(\S+.*)`) ) type ( //Dumpe2fsInfo contains dumpe2fs data for all EXT filesystems Dumpe2fsInfo struct { Info []Dumpe2fsDeviceInfo `json:"Info"` } //Dumpe2fsDeviceInfo comtains data for a single EXT filesystem Dumpe2fsDeviceInfo struct { Device string `json:"device"` MountCount int `json:"mount_count"` MaximumMountCount int `json:"maximum_mount_count"` NextCheckAfter string `json:"next_check_after"` CheckInterval int `json:"check_interval"` UUID string `json:"uuid"` FilesystemState string `json:"filesystem_state"` LastChecked string `json:"last_checked"` } ) //ParseDumpe2fsInfo parses data from dumpe2fs output func ParseDumpe2fsInfo(s string) (d Dumpe2fsInfo, err error) { lines := strings.Split(s, "\n") for i, line := range lines { match := rgxNewDevice.FindStringSubmatch(line) if len(match) == 2 { dev, err := ParseDumpe2fsInfoDevice(lines, i, match[1]) if err != nil { return d, fmt.Errorf("unable to parse dumpe2fs data") } d.Info = append(d.Info, dev) } } return d, nil } //ParseDumpe2fsInfoDevice parses data for a single device once it has been identified by ParseDumpe2fsInfo func ParseDumpe2fsInfoDevice(lines []string, index int, device string) (d Dumpe2fsDeviceInfo, err error) { d.Device = device maxCountFound := false countFound := false nextCheckAfterFound := false checkIntervalFound := false uuidFound := false filesystemStateFound := false lastCheckedFound := false for _, line := range lines[index+1:] { matchMountCount := regexp.MustCompile(`Mount count:\s+(\S+.*)`).FindStringSubmatch(line) if len(matchMountCount) == 2 { countFound = true d.MountCount, _ = strconv.Atoi(matchMountCount[1]) continue } matchMaximumMountCount := regexp.MustCompile(`Maximum mount count:\s+(\S+.*)`).FindStringSubmatch(line) if len(matchMaximumMountCount) == 2 { maxCountFound = true d.MaximumMountCount, _ = strconv.Atoi(matchMaximumMountCount[1]) continue } matchNextCheckAfter := regexp.MustCompile(`Next check after:\s+(\S+.*)`).FindStringSubmatch(line) if len(matchNextCheckAfter) == 2 { nextCheckAfterFound = true d.NextCheckAfter = matchNextCheckAfter[1] continue } matchUUID := regexp.MustCompile(`Filesystem UUID:\s+(\S+)`).FindStringSubmatch(line) if len(matchUUID) == 2 { uuidFound = true d.UUID = matchUUID[1] continue } matchFilesystemState := regexp.MustCompile(`Filesystem state:\s+(\S+)`).FindStringSubmatch(line) if len(matchFilesystemState) == 2 { filesystemStateFound = true d.FilesystemState = matchFilesystemState[1] continue } matchLastChecked := regexp.MustCompile(`Last checked:\s+(\S+.*)`).FindStringSubmatch(line) if len(matchLastChecked) == 2 { lastCheckedFound = true d.LastChecked = matchLastChecked[1] continue } matchCheckInterval := regexp.MustCompile(`Check interval:\s+([0-9]+).*`).FindStringSubmatch(line) if len(matchCheckInterval) == 2 { checkIntervalFound = true i, err := strconv.Atoi(matchCheckInterval[1]) if err != nil { return d, err } d.CheckInterval = i continue } //Break if on a new line match := regexp.MustCompile(`^\s*$`).FindStringSubmatch(line) if len(match) == 1 { break } //Break if on new device match = rgxNewDevice.FindStringSubmatch(line) if len(match) == 2 { break } } if !maxCountFound || !countFound || !checkIntervalFound || !uuidFound || !lastCheckedFound || !filesystemStateFound { return d, fmt.Errorf("unable to parse dumpe2fs device data") } if !nextCheckAfterFound { d.NextCheckAfter = "No Data" } return d, nil }