diff --git a/CHANGELOG b/CHANGELOG index e42e2302..c8491521 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ jc changelog +20220915 v1.22.0 +- Add /proc file parsers +- Fix `id` command parser to allow usernames and groupnames with spaces + 20220829 v1.21.2 - Fix IP Address string parser for older python versions that don't cleanly accept decimal input format - IPv6 fix (e.g. python 3.6) diff --git a/README.md b/README.md index c6fa2030..24bd24c0 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ values are converted, and, in some cases, additional semantic context fields are added. To access the raw, pre-processed JSON, use the `-r` cli option or the `raw=True` -function parameter in `parse()`. +function parameter in `parse()` when using `jc` as a python library. Schemas for each parser can be found at the documentation link beside each [**Parser**](#parsers) below. @@ -133,14 +133,18 @@ on Github. `jc` accepts piped input from `STDIN` and outputs a JSON representation of the previous command's output to `STDOUT`. ```bash -COMMAND | jc PARSER [OPTIONS] +COMMAND | jc [OPTIONS] PARSER +cat FILE | jc [OPTIONS] PARSER +echo STRING | jc [OPTIONS] PARSER ``` Alternatively, the "magic" syntax can be used by prepending `jc` to the command -to be converted. Options can be passed to `jc` immediately before the command is -given. (Note: command aliases and shell builtins are not supported) +to be converted or in front of the absolute path for Proc files. Options can be +passed to `jc` immediately before the command or Proc file path is given. +(Note: command aliases and shell builtins are not supported) ```bash jc [OPTIONS] COMMAND +jc [OPTIONS] /proc/ ``` The JSON output can be compact (default) or pretty formatted with the `-p` @@ -225,6 +229,7 @@ option. | ` --pip-show` | `pip show` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/pip_show) | | ` --plist` | PLIST file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/plist) | | ` --postconf` | `postconf -M` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/postconf) | +| ` --proc` | `/proc/` file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/proc) | | ` --ps` | `ps` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ps) | | ` --route` | `route` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/route) | | ` --rpm-qi` | `rpm -qi` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/rpm_qi) | @@ -278,7 +283,7 @@ option. | `-a` | `--about` | About `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | | `-C` | `--force-color` | Force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | | `-d` | `--debug` | Debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h` | `--help` | Help. Use `jc -h --parser_name` for parser documentation | +| `-h` | `--help` | Help. Use `jc -h --parser_name` for parser documentation. Use twice to show hidden parsers (e.g. `-hh`) | | `-m` | `--monochrome` | Monochrome output | | `-M` | `--meta-out` | Add metadata to output including timestamp, parser name, magic command, magic command exit code, etc. | | | `-p` | `--pretty` | Pretty format the JSON output | @@ -537,12 +542,12 @@ that case you can suppress the warning message with the `-q` cli option or the macOS: ```bash -cat lsof.out | jc --lsof -q +cat lsof.out | jc -q --lsof ``` or Windows: ```bash -type lsof.out | jc --lsof -q +type lsof.out | jc -q --lsof ``` Tested on: @@ -586,7 +591,7 @@ documentation. ### arp ```bash -arp | jc --arp -p # or: jc -p arp +arp | jc -p --arp # or: jc -p arp ``` ```json [ @@ -625,7 +630,7 @@ cat homes.csv ... ``` ```bash -cat homes.csv | jc --csv -p +cat homes.csv | jc -p --csv ``` ```json [ @@ -666,7 +671,7 @@ cat homes.csv | jc --csv -p ``` ### /etc/hosts file ```bash -cat /etc/hosts | jc --hosts -p +cat /etc/hosts | jc -p --hosts ``` ```json [ @@ -693,7 +698,7 @@ cat /etc/hosts | jc --hosts -p ``` ### ifconfig ```bash -ifconfig | jc --ifconfig -p # or: jc -p ifconfig +ifconfig | jc -p --ifconfig # or: jc -p ifconfig ``` ```json [ @@ -751,7 +756,7 @@ Port = 50022 ForwardX11 = no ``` ```bash -cat example.ini | jc --ini -p +cat example.ini | jc -p --ini ``` ```json { @@ -773,7 +778,7 @@ cat example.ini | jc --ini -p ``` ### ls ```bash -$ ls -l /usr/bin | jc --ls -p # or: jc -p ls -l /usr/bin +$ ls -l /usr/bin | jc -p --ls # or: jc -p ls -l /usr/bin ``` ```json [ @@ -809,7 +814,7 @@ $ ls -l /usr/bin | jc --ls -p # or: jc -p ls -l /usr/bin ``` ### netstat ```bash -netstat -apee | jc --netstat -p # or: jc -p netstat -apee +netstat -apee | jc -p --netstat # or: jc -p netstat -apee ``` ```json [ @@ -897,7 +902,7 @@ netstat -apee | jc --netstat -p # or: jc -p netstat -apee ``` ### /etc/passwd file ```bash -cat /etc/passwd | jc --passwd -p +cat /etc/passwd | jc -p --passwd ``` ```json [ @@ -923,7 +928,7 @@ cat /etc/passwd | jc --passwd -p ``` ### ping ```bash -ping 8.8.8.8 -c 3 | jc --ping -p # or: jc -p ping 8.8.8.8 -c 3 +ping 8.8.8.8 -c 3 | jc -p --ping # or: jc -p ping 8.8.8.8 -c 3 ``` ```json { @@ -976,7 +981,7 @@ ping 8.8.8.8 -c 3 | jc --ping -p # or: jc -p ping 8.8.8.8 -c 3 ``` ### ps ```bash -ps axu | jc --ps -p # or: jc -p ps axu +ps axu | jc -p --ps # or: jc -p ps axu ``` ```json [ @@ -1023,7 +1028,7 @@ ps axu | jc --ps -p # or: jc -p ps axu ``` ### traceroute ```bash -traceroute -m 2 8.8.8.8 | jc --traceroute -p +traceroute -m 2 8.8.8.8 | jc -p --traceroute # or: jc -p traceroute -m 2 8.8.8.8 ``` ```json @@ -1088,7 +1093,7 @@ traceroute -m 2 8.8.8.8 | jc --traceroute -p ``` ### uptime ```bash -uptime | jc --uptime -p # or: jc -p uptime +uptime | jc -p --uptime # or: jc -p uptime ``` ```json { @@ -1133,7 +1138,7 @@ cat cd_catalog.xml ... ``` ```bash -cat cd_catalog.xml | jc --xml -p +cat cd_catalog.xml | jc -p --xml ``` ```json { @@ -1185,7 +1190,7 @@ spec: mode: ISTIO_MUTUAL ``` ```bash -cat istio.yaml | jc --yaml -p +cat istio.yaml | jc -p --yaml ``` ```json [ diff --git a/completions/jc_bash_completion.sh b/completions/jc_bash_completion.sh index 3fa432e0..941ffc92 100644 --- a/completions/jc_bash_completion.sh +++ b/completions/jc_bash_completion.sh @@ -4,7 +4,7 @@ _jc() jc_about_options jc_about_mod_options jc_help_options jc_special_options jc_commands=(acpi airport arp blkid chage cksum crontab date df dig dmidecode dpkg du env file finger free git gpg hciconfig id ifconfig iostat iptables iw jobs last lastb ls lsblk lsmod lsof lsusb md5 md5sum mdadm mount mpstat netstat nmcli ntpq pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss stat sum sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 ufw uname update-alternatives upower uptime vdir vmstat w wc who xrandr zipinfo) - jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cef --cef-s --chage --cksum --crontab --crontab-u --csv --csv-s --date --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --finger --free --fstab --git-log --git-log-s --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iso-datetime --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --passwd --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --ps --route --rpm-qi --rsync --rsync-s --sfdisk --shadow --ss --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) + jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cef --cef-s --chage --cksum --crontab --crontab-u --csv --csv-s --date --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --finger --free --fstab --git-log --git-log-s --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iso-datetime --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --passwd --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --ps --route --rpm-qi --rsync --rsync-s --sfdisk --shadow --ss --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) jc_options=(--force-color -C --debug -d --monochrome -m --meta-out -M --pretty -p --quiet -q --raw -r --unbuffer -u --yaml-out -y) jc_about_options=(--about -a) jc_about_mod_options=(--pretty -p --yaml-out -y --monochrome -m --force-color -C) diff --git a/completions/jc_zsh_completion.sh b/completions/jc_zsh_completion.sh index ec87a73b..13cddabf 100644 --- a/completions/jc_zsh_completion.sh +++ b/completions/jc_zsh_completion.sh @@ -95,7 +95,7 @@ _jc() { 'xrandr:run "xrandr" command with magic syntax.' 'zipinfo:run "zipinfo" command with magic syntax.' ) - jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cef --cef-s --chage --cksum --crontab --crontab-u --csv --csv-s --date --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --finger --free --fstab --git-log --git-log-s --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iso-datetime --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --passwd --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --ps --route --rpm-qi --rsync --rsync-s --sfdisk --shadow --ss --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) + jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cef --cef-s --chage --cksum --crontab --crontab-u --csv --csv-s --date --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --finger --free --fstab --git-log --git-log-s --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iso-datetime --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --passwd --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --ps --route --rpm-qi --rsync --rsync-s --sfdisk --shadow --ss --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo) jc_parsers_describe=( '--acpi:`acpi` command parser' '--airport:`airport -I` command parser' @@ -172,6 +172,7 @@ _jc() { '--pip-show:`pip show` command parser' '--plist:PLIST file parser' '--postconf:`postconf -M` command parser' + '--proc:`/proc/` file parser' '--ps:`ps` command parser' '--route:`route` command parser' '--rpm-qi:`rpm -qi` command parser' diff --git a/docs/lib.md b/docs/lib.md index 25c571bc..a264df2f 100644 --- a/docs/lib.md +++ b/docs/lib.md @@ -162,7 +162,8 @@ Parameters: ### all\_parser\_info ```python -def all_parser_info(documentation: bool = False) -> List[Dict] +def all_parser_info(documentation: bool = False, + show_hidden: bool = False) -> List[Dict] ``` Returns a list of dictionaries that includes metadata for all parser @@ -171,6 +172,8 @@ modules. Parameters: documentation: (boolean) include parser docstrings if True + show_hidden: (boolean) also show parsers marked as hidden + in their info metadata. diff --git a/docs/parsers/id.md b/docs/parsers/id.md index eaf32554..0bac2060 100644 --- a/docs/parsers/id.md +++ b/docs/parsers/id.md @@ -128,4 +128,4 @@ Returns: ### Parser Information Compatibility: linux, darwin, aix, freebsd -Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com) +Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/lsof.md b/docs/parsers/lsof.md index 6a0f7945..2fbdc0af 100644 --- a/docs/parsers/lsof.md +++ b/docs/parsers/lsof.md @@ -140,6 +140,6 @@ Returns: List of Dictionaries. Raw or processed structured data. ### Parser Information -Compatibility: linux +Compatibility: linux, darwin, aix, freebsd Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc.md b/docs/parsers/proc.md new file mode 100644 index 00000000..d51a25d9 --- /dev/null +++ b/docs/parsers/proc.md @@ -0,0 +1,142 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc + +jc - JSON Convert Proc file output parser + +This parser automatically identifies the Proc file and calls the +corresponding parser to peform the parsing. + +Magic syntax for converting `/proc` files is also supported by running +`jc /proc/`. Any `jc` options must be specified before the +`/proc` path. + +specific Proc file parsers can also be called directly, if desired and have +a naming convention of `proc-` (cli) or `proc_` (module). + +Usage (cli): + + $ cat /proc/meminfo | jc --proc + +or + + $ jc /proc/meminfo + +or + + $ cat /proc/meminfo | jc --proc-memifno + +Usage (module): + + import jc + result = jc.parse('proc', proc_file) + +Schema: + +See the specific Proc parser for the schema: + + $ jc --help --proc- + +For example: + + $ jc --help --proc-meminfo + +Specific Proc file parser names can be found with `jc -hh` or `jc -a`. + +Schemas can also be found online at: + + https://kellyjonbrazil.github.io/jc/docs/parsers/proc_ + +For example: + + https://kellyjonbrazil.github.io/jc/docs/parsers/proc_meminfo + +Examples: + + $ cat /proc/modules | jc --proc -p + [ + { + "module": "binfmt_misc", + "size": 24576, + "used": 1, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": 16384, + "used": 0, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": 36864, + "used": 1, + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] + + $ proc_modules | jc --proc_modules -p -r + [ + { + "module": "binfmt_misc", + "size": "24576", + "used": "1", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": "16384", + "used": "0", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": "36864", + "used": "1", + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_buddyinfo.md b/docs/parsers/proc_buddyinfo.md new file mode 100644 index 00000000..7bed14e5 --- /dev/null +++ b/docs/parsers/proc_buddyinfo.md @@ -0,0 +1,128 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_buddyinfo + +jc - JSON Convert `/proc/buddyinfo` file parser + +Usage (cli): + + $ cat /proc/buddyinfo | jc --proc + +or + + $ jc /proc/buddyinfo + +or + + $ cat /proc/buddyinfo | jc --proc-buddyinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_buddyinfo_file) + +or + + import jc + result = jc.parse('proc_buddyinfo', proc_buddyinfo_file) + +Schema: + +All values are integers. + + [ + { + "node": integer, + "zone": string, + "free_chunks": [ + integer # [0] + ] + } + ] + + [0] array index correlates to the Order number. + E.g. free_chunks[0] is the value for Order 0 + + +Examples: + + $ cat /proc/buddyinfo | jc --proc -p + [ + { + "node": 0, + "zone": "DMA", + "free_chunks": [ + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 3 + ] + }, + { + "node": 0, + "zone": "DMA32", + "free_chunks": [ + 78, + 114, + 82, + 52, + 38, + 25, + 13, + 9, + 3, + 4, + 629 + ] + }, + { + "node": 0, + "zone": "Normal", + "free_chunks": [ + 0, + 22, + 8, + 10, + 1, + 1, + 2, + 11, + 13, + 0, + 0 + ] + } + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_consoles.md b/docs/parsers/proc_consoles.md new file mode 100644 index 00000000..db00dced --- /dev/null +++ b/docs/parsers/proc_consoles.md @@ -0,0 +1,111 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_consoles + +jc - JSON Convert `/proc/consoles` file parser + +Usage (cli): + + $ cat /proc/consoles | jc --proc + +or + + $ jc /proc/consoles + +or + + $ cat /proc/consoles | jc --proc-consoles + +Usage (module): + + import jc + result = jc.parse('proc', proc_consoles_file) + +or + + import jc + result = jc.parse('proc_consoles', proc_consoles_file) + +Schema: + + [ + { + "device": string, + "operations": string, + "operations_list": [ + string # [0] + ], + "flags": string, + "flags_list": [ + string # [1] + ], + "major": integer, + "minor": integer + } + ] + + [0] Values: read, write, unblank + [1] Values: enabled, preferred, primary boot, prink buffer, + braille device, safe when CPU offline + +Examples: + + $ cat /proc/consoles | jc --proc -p + [ + { + "device": "tty0", + "operations": "-WU", + "operations_list": [ + "write", + "unblank" + ], + "flags": "ECp", + "flags_list": [ + "enabled", + "preferred", + "printk buffer" + ], + "major": 4, + "minor": 7 + }, + { + "device": "ttyS0", + "operations": "-W-", + "operations_list": [ + "write" + ], + "flags": "Ep", + "flags_list": [ + "enabled", + "printk buffer" + ], + "major": 4, + "minor": 64 + } + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_cpuinfo.md b/docs/parsers/proc_cpuinfo.md new file mode 100644 index 00000000..574c919f --- /dev/null +++ b/docs/parsers/proc_cpuinfo.md @@ -0,0 +1,247 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_cpuinfo + +jc - JSON Convert `/proc/cpuinfo` file parser + +Usage (cli): + + $ cat /proc/cpuinfo | jc --proc + +or + + $ jc /proc/cpuinfo + +or + + $ cat /proc/cpuinfo | jc --proc-cpuinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_cpuinfo_file) + +or + + import jc + result = jc.parse('proc_cpuinfo', proc_cpuinfo_file) + +Schema: + +Integer, float, and boolean ("yes"/"no") conversions are attempted. Blank +strings are converted to `null`. + +"Well-known" keys like `cache size`, `address types`, `bugs`, and `flags` +are processed into sensible data types. (see below) + +If this is not desired, then use the `--raw` (CLI) or `raw=True` (Module) +option. + + [ + { + "processor": integer, + "address sizes": string, + "address_size_physical": integer, # in bits + "address_size_virtual": integer, # in bits + "cache size": string, + "cache_size_num": integer, + "cache_size_unit": string, + "flags": [ + string + ], + "bugs": [ + string + ], + "bogomips": float, + : string/int/float/boolean/null + } + ] + +Examples: + + $ cat /proc/cpuinfo | jc --proc -p + [ + { + "processor": 0, + "vendor_id": "GenuineIntel", + "cpu family": 6, + "model": 142, + "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz", + "stepping": 10, + "cpu MHz": 2400.0, + "cache size": "6144 KB", + "physical id": 0, + "siblings": 1, + "core id": 0, + "cpu cores": 1, + "apicid": 0, + "initial apicid": 0, + "fpu": true, + "fpu_exception": true, + "cpuid level": 22, + "wp": true, + "bogomips": 4800.0, + "clflush size": 64, + "cache_alignment": 64, + "address sizes": "45 bits physical, 48 bits virtual", + "power management": null, + "address_size_physical": 45, + "address_size_virtual": 48, + "cache_size_num": 6144, + "cache_size_unit": "KB", + "flags": [ + "fpu", + "vme", + "de", + "pse", + "tsc", + "msr", + "pae", + "mce", + "cx8", + "apic", + "sep", + "mtrr", + "pge", + "mca", + "cmov", + "pat", + "pse36", + "clflush", + "mmx", + "fxsr", + "sse", + "sse2", + "ss", + "syscall", + "nx", + "pdpe1gb", + "rdtscp", + "lm", + "constant_tsc", + "arch_perfmon", + "nopl", + "xtopology", + "tsc_reliable", + "nonstop_tsc", + "cpuid", + "pni", + "pclmulqdq", + "ssse3", + "fma", + "cx16", + "pcid", + "sse4_1", + "sse4_2", + "x2apic", + "movbe", + "popcnt", + "tsc_deadline_timer", + "aes", + "xsave", + "avx", + "f16c", + "rdrand", + "hypervisor", + "lahf_lm", + "abm", + "3dnowprefetch", + "cpuid_fault", + "invpcid_single", + "pti", + "ssbd", + "ibrs", + "ibpb", + "stibp", + "fsgsbase", + "tsc_adjust", + "bmi1", + "avx2", + "smep", + "bmi2", + "invpcid", + "rdseed", + "adx", + "smap", + "clflushopt", + "xsaveopt", + "xsavec", + "xgetbv1", + "xsaves", + "arat", + "md_clear", + "flush_l1d", + "arch_capabilities" + ], + "bugs": [ + "cpu_meltdown", + "spectre_v1", + "spectre_v2", + "spec_store_bypass", + "l1tf", + "mds", + "swapgs", + "itlb_multihit", + "srbds" + ] + }, + ... + ] + + $ cat /proc/cpuinfo | jc --proc_cpuinfo -p -r + [ + { + "processor": "0", + "vendor_id": "GenuineIntel", + "cpu family": "6", + "model": "142", + "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz", + "stepping": "10", + "cpu MHz": "2400.000", + "cache size": "6144 KB", + "physical id": "0", + "siblings": "1", + "core id": "0", + "cpu cores": "1", + "apicid": "0", + "initial apicid": "0", + "fpu": "yes", + "fpu_exception": "yes", + "cpuid level": "22", + "wp": "yes", + "flags": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge ...", + "bugs": "cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass ...", + "bogomips": "4800.00", + "clflush size": "64", + "cache_alignment": "64", + "address sizes": "45 bits physical, 48 bits virtual", + "power management": "" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_crypto.md b/docs/parsers/proc_crypto.md new file mode 100644 index 00000000..25e9adc0 --- /dev/null +++ b/docs/parsers/proc_crypto.md @@ -0,0 +1,143 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_crypto + +jc - JSON Convert `/proc/crypto` file parser + +Usage (cli): + + $ cat /proc/crypto | jc --proc + +or + + $ jc /proc/crypto + +or + + $ cat /proc/crypto | jc --proc-crypto + +Usage (module): + + import jc + result = jc.parse('proc', proc_crypto_file) + +or + + import jc + result = jc.parse('proc_crypto', proc_crypto_file) + +Schema: + +"Well-known" keys like `priority` and `refcnt` are converted to integers. +Also, keynames ending in "size" are converted to integers. + +If this is not desired, then use the `--raw` (CLI) or `raw=True` (Module) +option. + + [ + { + "name": string, + "driver": string, + "module": string, + "priority": integer, + "refcnt": integer, + "selftest": string, + "internal": string, + "type": string, + "*size": integer + } + ] + +Examples: + + $ cat /proc/crypto | jc --proc -p + [ + { + "name": "ecdh", + "driver": "ecdh-generic", + "module": "ecdh_generic", + "priority": 100, + "refcnt": 1, + "selftest": "passed", + "internal": "no", + "type": "kpp" + }, + { + "name": "blake2b-512", + "driver": "blake2b-512-generic", + "module": "blake2b_generic", + "priority": 100, + "refcnt": 1, + "selftest": "passed", + "internal": "no", + "type": "shash", + "blocksize": 128, + "digestsize": 64 + }, + ... + ] + + $ cat /proc/crypto | jc --proc_crypto -p -r + [ + { + "name": "ecdh", + "driver": "ecdh-generic", + "module": "ecdh_generic", + "priority": "100", + "refcnt": "1", + "selftest": "passed", + "internal": "no", + "type": "kpp" + }, + { + "name": "blake2b-512", + "driver": "blake2b-512-generic", + "module": "blake2b_generic", + "priority": "100", + "refcnt": "1", + "selftest": "passed", + "internal": "no", + "type": "shash", + "blocksize": "128", + "digestsize": "64" + }, + { + "name": "blake2b-384", + "driver": "blake2b-384-generic", + "module": "blake2b_generic", + "priority": "100", + "refcnt": "1", + "selftest": "passed", + "internal": "no", + "type": "shash", + "blocksize": "128", + "digestsize": "48" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_devices.md b/docs/parsers/proc_devices.md new file mode 100644 index 00000000..c5b82a06 --- /dev/null +++ b/docs/parsers/proc_devices.md @@ -0,0 +1,103 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_devices + +jc - JSON Convert `/proc/devices` file parser + +Usage (cli): + + $ cat /proc/devices | jc --proc + +or + + $ jc /proc/devices + +or + + $ cat /proc/devices | jc --proc-devices + +Usage (module): + + import jc + result = jc.parse('proc', proc_devices_file) + +or + + import jc + result = jc.parse('proc_devices', proc_devices_file) + +Schema: + +Since devices can be members of multiple groups, the value for each device +is a list. + + { + "character": { + "": [ + string + ] + }, + "block": { + "": [ + string + ] + } + } + +Examples: + + $ cat /proc/devices | jc --proc -p + { + "character": { + "1": [ + "mem" + ], + "4": [ + "/dev/vc/0", + "tty", + "ttyS" + ], + "5": [ + "/dev/tty", + "/dev/console", + "/dev/ptmx", + "ttyprintk" + ], + "block": { + "7": [ + "loop" + ], + "8": [ + "sd" + ], + "9": [ + "md" + ] + } + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_diskstats.md b/docs/parsers/proc_diskstats.md new file mode 100644 index 00000000..43accf9e --- /dev/null +++ b/docs/parsers/proc_diskstats.md @@ -0,0 +1,202 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_diskstats + +jc - JSON Convert `/proc/diskstats` file parser + +Usage (cli): + + $ cat /proc/diskstats | jc --proc + +or + + $ jc /proc/diskstats + +or + + $ cat /proc/diskstats | jc --proc-diskstats + +Usage (module): + + import jc + result = jc.parse('proc', proc_diskstats_file) + +or + + import jc + result = jc.parse('proc_diskstats', proc_diskstats_file) + +Schema: + + [ + { + "maj": integer, + "min": integer, + "device": string, + "reads_completed": integer, + "reads_merged": integer, + "sectors_read": integer, + "read_time_ms": integer, + "writes_completed": integer, + "writes_merged": integer, + "sectors_written": integer, + "write_time_ms": integer, + "io_in_progress": integer, + "io_time_ms": integer, + "weighted_io_time_ms": integer, + "discards_completed_successfully": integer, + "discards_merged": integer, + "sectors_discarded": integer, + "discarding_time_ms": integer, + "flush_requests_completed_successfully": integer, + "flushing_time_ms": integer + } + ] + +Examples: + + $ cat /proc/diskstats | jc --proc -p + [ + { + "maj": 7, + "min": 0, + "device": "loop0", + "reads_completed": 48, + "reads_merged": 0, + "sectors_read": 718, + "read_time_ms": 19, + "writes_completed": 0, + "writes_merged": 0, + "sectors_written": 0, + "write_time_ms": 0, + "io_in_progress": 0, + "io_time_ms": 36, + "weighted_io_time_ms": 19, + "discards_completed_successfully": 0, + "discards_merged": 0, + "sectors_discarded": 0, + "discarding_time_ms": 0, + "flush_requests_completed_successfully": 0, + "flushing_time_ms": 0 + }, + { + "maj": 7, + "min": 1, + "device": "loop1", + "reads_completed": 41, + "reads_merged": 0, + "sectors_read": 688, + "read_time_ms": 17, + "writes_completed": 0, + "writes_merged": 0, + "sectors_written": 0, + "write_time_ms": 0, + "io_in_progress": 0, + "io_time_ms": 28, + "weighted_io_time_ms": 17, + "discards_completed_successfully": 0, + "discards_merged": 0, + "sectors_discarded": 0, + "discarding_time_ms": 0, + "flush_requests_completed_successfully": 0, + "flushing_time_ms": 0 + }, + ... + ] + + $ cat /proc/diskstats | jc --proc_diskstats -p -r + [ + { + "maj": "7", + "min": "0", + "device": "loop0", + "reads_completed": "48", + "reads_merged": "0", + "sectors_read": "718", + "read_time_ms": "19", + "writes_completed": "0", + "writes_merged": "0", + "sectors_written": "0", + "write_time_ms": "0", + "io_in_progress": "0", + "io_time_ms": "36", + "weighted_io_time_ms": "19", + "discards_completed_successfully": "0", + "discards_merged": "0", + "sectors_discarded": "0", + "discarding_time_ms": "0", + "flush_requests_completed_successfully": "0", + "flushing_time_ms": "0" + }, + { + "maj": "7", + "min": "1", + "device": "loop1", + "reads_completed": "41", + "reads_merged": "0", + "sectors_read": "688", + "read_time_ms": "17", + "writes_completed": "0", + "writes_merged": "0", + "sectors_written": "0", + "write_time_ms": "0", + "io_in_progress": "0", + "io_time_ms": "28", + "weighted_io_time_ms": "17", + "discards_completed_successfully": "0", + "discards_merged": "0", + "sectors_discarded": "0", + "discarding_time_ms": "0", + "flush_requests_completed_successfully": "0", + "flushing_time_ms": "0" + }, + { + "maj": "7", + "min": "2", + "device": "loop2", + "reads_completed": "119", + "reads_merged": "0", + "sectors_read": "2956", + "read_time_ms": "18", + "writes_completed": "0", + "writes_merged": "0", + "sectors_written": "0", + "write_time_ms": "0", + "io_in_progress": "0", + "io_time_ms": "56", + "weighted_io_time_ms": "18", + "discards_completed_successfully": "0", + "discards_merged": "0", + "sectors_discarded": "0", + "discarding_time_ms": "0", + "flush_requests_completed_successfully": "0", + "flushing_time_ms": "0" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_driver_rtc.md b/docs/parsers/proc_driver_rtc.md new file mode 100644 index 00000000..05ea5972 --- /dev/null +++ b/docs/parsers/proc_driver_rtc.md @@ -0,0 +1,126 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_driver\_rtc + +jc - JSON Convert `/proc/driver_rtc` file parser + +Usage (cli): + + $ cat /proc/driver_rtc | jc --proc + +or + + $ jc /proc/driver_rtc + +or + + $ cat /proc/driver_rtc | jc --proc-driver-rtc + +Usage (module): + + import jc + result = jc.parse('proc', proc_driver_rtc_file) + +or + + import jc + result = jc.parse('proc_driver_rtc', proc_driver_rtc_file) + +Schema: + +"yes" and "no" values are converted to `true`/`false`. Integer conversions +are attempted. If you do not want this behavior, then use `--raw` (cli) or +`raw=True` (module). + + { + "rtc_time": string, + "rtc_date": string, + "alrm_time": string, + "alrm_date": string, + "alarm_IRQ": boolean, + "alrm_pending": boolean, + "update IRQ enabled": boolean, + "periodic IRQ enabled": boolean, + "periodic IRQ frequency": integer, + "max user IRQ frequency": integer, + "24hr": boolean, + "periodic_IRQ": boolean, + "update_IRQ": boolean, + "HPET_emulated": boolean, + "BCD": boolean, + "DST_enable": boolean, + "periodic_freq": integer, + "batt_status": string + } + +Examples: + + $ cat /proc/driver_rtc | jc --proc -p + { + "rtc_time": "16:09:21", + "rtc_date": "2022-09-03", + "alrm_time": "00:00:00", + "alrm_date": "2022-09-03", + "alarm_IRQ": false, + "alrm_pending": false, + "update IRQ enabled": false, + "periodic IRQ enabled": false, + "periodic IRQ frequency": 1024, + "max user IRQ frequency": 64, + "24hr": true, + "periodic_IRQ": false, + "update_IRQ": false, + "HPET_emulated": true, + "BCD": true, + "DST_enable": false, + "periodic_freq": 1024, + "batt_status": "okay" + } + + $ cat /proc/driver_rtc | jc --proc -p -r + { + "rtc_time": "16:09:21", + "rtc_date": "2022-09-03", + "alrm_time": "00:00:00", + "alrm_date": "2022-09-03", + "alarm_IRQ": "no", + "alrm_pending": "no", + "update IRQ enabled": "no", + "periodic IRQ enabled": "no", + "periodic IRQ frequency": "1024", + "max user IRQ frequency": "64", + "24hr": "yes", + "periodic_IRQ": "no", + "update_IRQ": "no", + "HPET_emulated": "yes", + "BCD": "yes", + "DST_enable": "no", + "periodic_freq": "1024", + "batt_status": "okay" + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_filesystems.md b/docs/parsers/proc_filesystems.md new file mode 100644 index 00000000..b4b8b443 --- /dev/null +++ b/docs/parsers/proc_filesystems.md @@ -0,0 +1,81 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_filesystems + +jc - JSON Convert `/proc/filesystems` file parser + +Usage (cli): + + $ cat /proc/filesystems | jc --proc + +or + + $ jc /proc/filesystems + +or + + $ cat /proc/filesystems | jc --proc-filesystems + +Usage (module): + + import jc + result = jc.parse('proc', proc_filesystems_file) + +or + + import jc + result = jc.parse('proc_filesystems', proc_filesystems_file) + +Schema: + + [ + { + "filesystem": string, + "nodev": boolean + } + ] + +Examples: + + $ cat /proc/filesystems | jc --proc -p + [ + { + "filesystem": "sysfs", + "nodev": true + }, + { + "filesystem": "tmpfs", + "nodev": true + }, + { + "filesystem": "bdev", + "nodev": true + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_interrupts.md b/docs/parsers/proc_interrupts.md new file mode 100644 index 00000000..f0f8c123 --- /dev/null +++ b/docs/parsers/proc_interrupts.md @@ -0,0 +1,133 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_interrupts + +jc - JSON Convert `/proc/interrupts` file parser + +Usage (cli): + + $ cat /proc/interrupts | jc --proc + +or + + $ jc /proc/interrupts + +or + + $ cat /proc/interrupts | jc --proc-interrupts + +Usage (module): + + import jc + result = jc.parse('proc', proc_interrupts_file) + +or + + import jc + result = jc.parse('proc_interrupts', proc_interrupts_file) + +Schema: + + [ + { + "irq": string, + "cpu_num": integer, + "interrupts": [ + integer + ], + "type": string, + "device": [ + string + ] + } + ] + +Examples: + + $ cat /proc/interrupts | jc --proc -p + [ + { + "irq": "0", + "cpu_num": 2, + "interrupts": [ + 18, + 0 + ], + "type": "IO-APIC", + "device": [ + "2-edge", + "timer" + ] + }, + { + "irq": "1", + "cpu_num": 2, + "interrupts": [ + 0, + 73 + ], + "type": "IO-APIC", + "device": [ + "1-edge", + "i8042" + ] + }, + ... + ] + + $ cat /proc/interrupts | jc --proc_interrupts -p -r + [ + { + "irq": "0", + "cpu_num": 2, + "interrupts": [ + "18", + "0" + ], + "type": "IO-APIC", + "device": [ + "2-edge", + "timer" + ] + }, + { + "irq": "1", + "cpu_num": 2, + "interrupts": [ + "0", + "73" + ], + "type": "IO-APIC", + "device": [ + "1-edge", + "i8042" + ] + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_iomem.md b/docs/parsers/proc_iomem.md new file mode 100644 index 00000000..4bd0ce2f --- /dev/null +++ b/docs/parsers/proc_iomem.md @@ -0,0 +1,85 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_iomem + +jc - JSON Convert `/proc/iomem` file parser + +Usage (cli): + + $ cat /proc/iomem | jc --proc + +or + + $ jc /proc/iomem + +or + + $ cat /proc/iomem | jc --proc-iomem + +Usage (module): + + import jc + result = jc.parse('proc', proc_iomem_file) + +or + + import jc + result = jc.parse('proc_iomem', proc_iomem_file) + +Schema: + + [ + { + "start": string, + "end": string, + "device": string + } + ] + +Examples: + + $ cat /proc/iomem | jc --proc -p + [ + { + "start": "00000000", + "end": "00000fff", + "device": "Reserved" + }, + { + "start": "00001000", + "end": "0009e7ff", + "device": "System RAM" + }, + { + "start": "0009e800", + "end": "0009ffff", + "device": "Reserved" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_ioports.md b/docs/parsers/proc_ioports.md new file mode 100644 index 00000000..9606509c --- /dev/null +++ b/docs/parsers/proc_ioports.md @@ -0,0 +1,85 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_ioports + +jc - JSON Convert `/proc/ioports` file parser + +Usage (cli): + + $ cat /proc/ioports | jc --proc + +or + + $ jc /proc/ioports + +or + + $ cat /proc/ioports | jc --proc-ioports + +Usage (module): + + import jc + result = jc.parse('proc', proc_ioports_file) + +or + + import jc + result = jc.parse('proc_ioports', proc_ioports_file) + +Schema: + + [ + { + "start": string, + "end": string, + "device": string + } + ] + +Examples: + + $ cat /proc/ioports | jc --proc -p + [ + { + "start": "0000", + "end": "0cf7", + "device": "PCI Bus 0000:00" + }, + { + "start": "0000", + "end": "001f", + "device": "dma1" + }, + { + "start": "0020", + "end": "0021", + "device": "PNP0001:00" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_loadavg.md b/docs/parsers/proc_loadavg.md new file mode 100644 index 00000000..05168398 --- /dev/null +++ b/docs/parsers/proc_loadavg.md @@ -0,0 +1,88 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_loadavg + +jc - JSON Convert `/proc/loadavg` file parser + +Usage (cli): + + $ cat /proc/loadavg | jc --proc + +or + + $ jc /proc/loadavg + +or + + $ cat /proc/loadavg | jc --proc-loadavg + +Usage (module): + + import jc + result = jc.parse('proc', proc_loadavg_file) + +or + + import jc + result = jc.parse('proc_loadavg', proc_loadavg_file) + +Schema: + +All values are integers. + + { + "load_1m": float, + "load_5m": float, + "load_15m": float, + "running": integer, + "available": integer, + "last_pid": integer + } + +Examples: + + $ cat /proc/loadavg | jc --proc -p + { + "load_1m": 0.0, + "load_5m": 0.01, + "load_15m": 0.03, + "running": 2, + "available": 111, + "last_pid": 2039 + } + + $ cat /proc/loadavg | jc --proc -p -r + { + "load_1m": "0.00", + "load_5m": "0.01", + "load_15m": "0.03", + "running": "2", + "available": "111", + "last_pid": "2039" + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_locks.md b/docs/parsers/proc_locks.md new file mode 100644 index 00000000..a611bb62 --- /dev/null +++ b/docs/parsers/proc_locks.md @@ -0,0 +1,130 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_locks + +jc - JSON Convert `/proc/locks` file parser + +Usage (cli): + + $ cat /proc/locks | jc --proc + +or + + $ jc /proc/locks + +or + + $ cat /proc/locks | jc --proc-locks + +Usage (module): + + import jc + result = jc.parse('proc', proc_locks_file) + +or + + import jc + result = jc.parse('proc_locks', proc_locks_file) + +Schema: + + [ + { + "id": integer, + "class": string, + "type": string, + "access": string, + "pid": integer, + "maj": string, + "min": string, + "inode": integer, + "start": string, + "end": string + } + ] + +Examples: + + $ cat /proc/locks | jc --proc -p + [ + { + "id": 1, + "class": "POSIX", + "type": "ADVISORY", + "access": "WRITE", + "pid": 877, + "maj": "00", + "min": "19", + "inode": 812, + "start": "0", + "end": "EOF" + }, + { + "id": 2, + "class": "FLOCK", + "type": "ADVISORY", + "access": "WRITE", + "pid": 854, + "maj": "00", + "min": "19", + "inode": 805, + "start": "0", + "end": "EOF" + }, + ... + ] + + $ cat /proc/locks | jc --proc_locks -p -r + [ + { + "id": "1", + "class": "POSIX", + "type": "ADVISORY", + "access": "WRITE", + "pid": "877", + "maj": "00", + "min": "19", + "inode": "812", + "start": "0", + "end": "EOF" + }, + { + "id": "2", + "class": "FLOCK", + "type": "ADVISORY", + "access": "WRITE", + "pid": "854", + "maj": "00", + "min": "19", + "inode": "805", + "start": "0", + "end": "EOF" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_meminfo.md b/docs/parsers/proc_meminfo.md new file mode 100644 index 00000000..45328325 --- /dev/null +++ b/docs/parsers/proc_meminfo.md @@ -0,0 +1,118 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_meminfo + +jc - JSON Convert `/proc/meminfo` file parser + +Usage (cli): + + $ cat /proc/meminfo | jc --proc + +or + + $ jc /proc/meminfo + +or + + $ cat /proc/meminfo | jc --proc-meminfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_meminfo_file) + +or + + import jc + result = jc.parse('proc_meminfo', proc_meminfo_file) + +Schema: + +All values are integers. + + { + integer + } + +Examples: + + $ cat /proc/meminfo | jc --proc -p + { + "MemTotal": 3997272, + "MemFree": 2760316, + "MemAvailable": 3386876, + "Buffers": 40452, + "Cached": 684856, + "SwapCached": 0, + "Active": 475816, + "Inactive": 322064, + "Active(anon)": 70216, + "Inactive(anon)": 148, + "Active(file)": 405600, + "Inactive(file)": 321916, + "Unevictable": 19476, + "Mlocked": 19476, + "SwapTotal": 3996668, + "SwapFree": 3996668, + "Dirty": 152, + "Writeback": 0, + "AnonPages": 92064, + "Mapped": 79464, + "Shmem": 1568, + "KReclaimable": 188216, + "Slab": 288096, + "SReclaimable": 188216, + "SUnreclaim": 99880, + "KernelStack": 5872, + "PageTables": 1812, + "NFS_Unstable": 0, + "Bounce": 0, + "WritebackTmp": 0, + "CommitLimit": 5995304, + "Committed_AS": 445240, + "VmallocTotal": 34359738367, + "VmallocUsed": 21932, + "VmallocChunk": 0, + "Percpu": 107520, + "HardwareCorrupted": 0, + "AnonHugePages": 0, + "ShmemHugePages": 0, + "ShmemPmdMapped": 0, + "FileHugePages": 0, + "FilePmdMapped": 0, + "HugePages_Total": 0, + "HugePages_Free": 0, + "HugePages_Rsvd": 0, + "HugePages_Surp": 0, + "Hugepagesize": 2048, + "Hugetlb": 0, + "DirectMap4k": 192320, + "DirectMap2M": 4001792, + "DirectMap1G": 2097152 + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_modules.md b/docs/parsers/proc_modules.md new file mode 100644 index 00000000..f300ae06 --- /dev/null +++ b/docs/parsers/proc_modules.md @@ -0,0 +1,132 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_modules + +jc - JSON Convert `/proc/modules` file parser + +Usage (cli): + + $ cat /proc/modules | jc --proc + +or + + $ jc /proc/modules + +or + + $ cat /proc/modules | jc --proc-modules + +Usage (module): + + import jc + result = jc.parse('proc', proc_modules_file) + +or + + import jc + result = jc.parse('proc_modules', proc_modules_file) + +Schema: + + [ + { + "module": string, + "size": integer, + "used": integer, + "used_by": [ + string + ], + "status": string, + "location": string + } + ] + +Examples: + + $ cat /proc/modules | jc --proc -p + [ + { + "module": "binfmt_misc", + "size": 24576, + "used": 1, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": 16384, + "used": 0, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": 36864, + "used": 1, + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] + + $ cat /proc/modules | jc --proc_modules -p -r + [ + { + "module": "binfmt_misc", + "size": "24576", + "used": "1", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": "16384", + "used": "0", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": "36864", + "used": "1", + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_mtrr.md b/docs/parsers/proc_mtrr.md new file mode 100644 index 00000000..d6e905ab --- /dev/null +++ b/docs/parsers/proc_mtrr.md @@ -0,0 +1,111 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_mtrr + +jc - JSON Convert `/proc/mtrr` file parser + +Usage (cli): + + $ cat /proc/mtrr | jc --proc + +or + + $ jc /proc/mtrr + +or + + $ cat /proc/mtrr | jc --proc-mtrr + +Usage (module): + + import jc + result = jc.parse('proc', proc_mtrr_file) + +or + + import jc + result = jc.parse('proc_mtrr', proc_mtrr_file) + +Schema: + + [ + { + "register": string, + "type": string, + "base": string, + "base_mb": integer, + "size": integer, + "count": integer, + "": string # additional key/values are strings + } + ] + +Examples: + + $ cat /proc/mtrr | jc --proc -p + [ + { + "register": "reg00", + "type": "write-back", + "base": "0x000000000", + "base_mb": 0, + "size": 2048, + "count": 1 + }, + { + "register": "reg01", + "type": "write-back", + "base": "0x080000000", + "base_mb": 2048, + "size": 1024, + "count": 1 + }, + ... + ] + + $ cat /proc/mtrr | jc --proc_mtrr -p -r + [ + { + "register": "reg00", + "type": "write-back", + "base": "0x000000000", + "base_mb": "0", + "size": "2048MB", + "count": "1" + }, + { + "register": "reg01", + "type": "write-back", + "base": "0x080000000", + "base_mb": "2048", + "size": "1024MB", + "count": "1" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_pagetypeinfo.md b/docs/parsers/proc_pagetypeinfo.md new file mode 100644 index 00000000..f1cfb990 --- /dev/null +++ b/docs/parsers/proc_pagetypeinfo.md @@ -0,0 +1,141 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_pagetypeinfo + +jc - JSON Convert `/proc/pagetypeinfo` file parser + +Usage (cli): + + $ cat /proc/pagetypeinfo | jc --proc + +or + + $ jc /proc/pagetypeinfo + +or + + $ cat /proc/pagetypeinfo | jc --proc-pagetypeinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_pagetypeinfo_file) + +or + + import jc + result = jc.parse('proc_pagetypeinfo', proc_pagetypeinfo_file) + +Schema: + + { + "page_block_order": integer, + "pages_per_block": integer, + "free_pages": [ + { + "node": integer, + "zone": string, + "type": string, + "free": [ + integer # [0] + ] + ], + "num_blocks_type": [ + { + "node": integer, + "zone": string, + "unmovable": integer, + "movable": integer, + "reclaimable": integer, + "high_atomic": integer, + "isolate": integer + } + ] + } + + [0] array index correlates to the Order number. + E.g. free[0] is the value for Order 0 + +Examples: + + $ cat /proc/pagetypeinfo | jc --proc -p + { + "page_block_order": 9, + "pages_per_block": 512, + "free_pages": [ + { + "node": 0, + "zone": "DMA", + "type": "Unmovable", + "free": [ + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0 + ] + }, + ... + ], + "num_blocks_type": [ + { + "node": 0, + "zone": "DMA", + "unmovable": 1, + "movable": 7, + "reclaimable": 0, + "high_atomic": 0, + "isolate": 0 + }, + { + "node": 0, + "zone": "DMA32", + "unmovable": 8, + "movable": 1472, + "reclaimable": 48, + "high_atomic": 0, + "isolate": 0 + }, + { + "node": 0, + "zone": "Normal", + "unmovable": 120, + "movable": 345, + "reclaimable": 47, + "high_atomic": 0, + "isolate": 0 + } + ] + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_partitions.md b/docs/parsers/proc_partitions.md new file mode 100644 index 00000000..78e0b3f1 --- /dev/null +++ b/docs/parsers/proc_partitions.md @@ -0,0 +1,100 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_partitions + +jc - JSON Convert `/proc/partitions` file parser + +Usage (cli): + + $ cat /proc/partitions | jc --proc + +or + + $ jc /proc/partitions + +or + + $ cat /proc/partitions | jc --proc-partitions + +Usage (module): + + import jc + result = jc.parse('proc', proc_partitions_file) + +or + + import jc + result = jc.parse('proc_partitions', proc_partitions_file) + +Schema: + + [ + { + "major": integer, + "minor": integer, + "num_blocks": integer, + "name": string + } + ] + +Examples: + + $ cat /proc/partitions | jc --proc -p + [ + { + "major": 7, + "minor": 0, + "num_blocks": 56896, + "name": "loop0" + }, + { + "major": 7, + "minor": 1, + "num_blocks": 56868, + "name": "loop1" + }, + ... + ] + + $ cat /proc/partitions | jc --proc_partitions -p -r + [ + { + "major": "7", + "minor": "0", + "num_blocks": "56896", + "name": "loop0" + }, + { + "major": "7", + "minor": "1", + "num_blocks": "56868", + "name": "loop1" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_pid_fdinfo.md b/docs/parsers/proc_pid_fdinfo.md new file mode 100644 index 00000000..2d946fbc --- /dev/null +++ b/docs/parsers/proc_pid_fdinfo.md @@ -0,0 +1,127 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_pid\_fdinfo + +jc - JSON Convert `/proc//fdinfo/` file parser + +Usage (cli): + + $ cat /proc/1/fdinfo/5 | jc --proc + +or + + $ jc /proc/1/fdinfo/5 + +or + + $ cat /proc/1/fdinfo/5 | jc --proc-pid-fdinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_fdinfo_file) + +or + + import jc + result = jc.parse('proc_pid_fdinfo', proc_pid_fdinfo_file) + +Schema: + +Any unspecified fields are strings. + + { + "pos": integer, + "flags": integer, + "mnt_id": integer, + "scm_fds": string, + "ino": integer, + "lock": string, + "epoll": { + "tfd": integer, + "events": string, + "data": string, + "pos": integer, + "ino": string, + "sdev": string + }, + "inotify": { + "wd": integer, + "ino": string, + "sdev": string, + "mask": string, + "ignored_mask": string, + "fhandle-bytes": string, + "fhandle-type": string, + "f_handle": string + }, + "fanotify": { + "flags": string, + "event-flags": string, + "mnt_id": string, + "mflags": string, + "mask": string, + "ignored_mask": string, + "ino": string, + "sdev": string, + "fhandle-bytes": string, + "fhandle-type": string, + "f_handle": string + }, + "clockid": integer, + "ticks": integer, + "settime flags": integer, + "it_value": [ + integer + ], + "it_interval": [ + integer + ] + } + +Examples: + + $ cat /proc/1/fdinfo/5 | jc --proc -p + { + "pos": 0, + "flags": 2, + "mnt_id": 9, + "ino": 63107, + "clockid": 0, + "ticks": 0, + "settime flags": 1, + "it_value": [ + 0, + 49406829 + ], + "it_interval": [ + 1, + 0 + ] + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_pid_io.md b/docs/parsers/proc_pid_io.md new file mode 100644 index 00000000..63884858 --- /dev/null +++ b/docs/parsers/proc_pid_io.md @@ -0,0 +1,74 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_pid\_io + +jc - JSON Convert `/proc//io` file parser + +Usage (cli): + + $ cat /proc/1/io | jc --proc + +or + + $ jc /proc/1/io + +or + + $ cat /proc/1/io | jc --proc-pid-io + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_io_file) + +or + + import jc + result = jc.parse('proc_pid_io', proc_pid_io_file) + +Schema: + +All values are integers. + + { + integer + } + +Examples: + + $ cat /proc/1/io | jc --proc -p + { + "rchar": 4699288382, + "wchar": 2931802997, + "syscr": 661897, + "syscw": 890910, + "read_bytes": 168468480, + "write_bytes": 27357184, + "cancelled_write_bytes": 16883712 + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_pid_maps.md b/docs/parsers/proc_pid_maps.md new file mode 100644 index 00000000..7ca1557b --- /dev/null +++ b/docs/parsers/proc_pid_maps.md @@ -0,0 +1,125 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_pid\_maps + +jc - JSON Convert `/proc//maps` file parser + +Usage (cli): + + $ cat /proc/1/maps | jc --proc + +or + + $ jc /proc/1/maps + +or + + $ cat /proc/1/maps | jc --proc-pid-maps + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_maps_file) + +or + + import jc + result = jc.parse('proc_pid_maps', proc_pid_maps_file) + +Schema: + + [ + { + "start": string, + "end": string, + "perms": [ + string + ], + "offset": string, + "inode": integer, + "pathname": string, + "maj": string, + "min": string + } + ] + +Examples: + + $ cat /proc/1/maps | jc --proc -p + [ + { + "perms": [ + "read", + "private" + ], + "offset": "00000000", + "inode": 798126, + "pathname": "/usr/lib/systemd/systemd", + "start": "55a9e753c000", + "end": "55a9e7570000", + "maj": "fd", + "min": "00" + }, + { + "perms": [ + "read", + "execute", + "private" + ], + "offset": "00034000", + "inode": 798126, + "pathname": "/usr/lib/systemd/systemd", + "start": "55a9e7570000", + "end": "55a9e763a000", + "maj": "fd", + "min": "00" + }, + ... + ] + + $ cat /proc/1/maps | jc --proc-pid-maps -p -r + [ + { + "address": "55a9e753c000-55a9e7570000", + "perms": "r--p", + "offset": "00000000", + "dev": "fd:00", + "inode": "798126", + "pathname": "/usr/lib/systemd/systemd" + }, + { + "address": "55a9e7570000-55a9e763a000", + "perms": "r-xp", + "offset": "00034000", + "dev": "fd:00", + "inode": "798126", + "pathname": "/usr/lib/systemd/systemd" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_pid_mountinfo.md b/docs/parsers/proc_pid_mountinfo.md new file mode 100644 index 00000000..9e0a4e2e --- /dev/null +++ b/docs/parsers/proc_pid_mountinfo.md @@ -0,0 +1,168 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_pid\_mountinfo + +jc - JSON Convert `/proc//mountinfo` file parser + +Usage (cli): + + $ cat /proc/1/mountinfo | jc --proc + +or + + $ jc /proc/1/mountinfo + +or + + $ cat /proc/1/mountinfo | jc --proc-pid-mountinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_mountinfo_file) + +or + + import jc + result = jc.parse('proc_pid_mountinfo', proc_pid_mountinfo_file) + +Schema: + + [ + { + "mount_id": integer, + "parent_id": integer, + "maj": integer, + "min": integer, + "root": string, + "mount_point": string, + "mount_options": [ + string + ], + "optional_fields": { # [0] + "": integer # [1] + }, + "fs_type": string, + "mount_source": string, + "super_options": [ + string + ], + "super_options_fields": { + "": string + } + } + ] + + [0] if empty, then private mount + [1] unbindable will always have a value of 0 + +Examples: + + $ cat /proc/1/mountinfo | jc --proc -p + [ + { + "mount_id": 24, + "parent_id": 30, + "maj": 0, + "min": 22, + "root": "/", + "mount_point": "/sys", + "mount_options": [ + "rw", + "nosuid", + "nodev", + "noexec", + "relatime" + ], + "optional_fields": { + "master": 1, + "shared": 7 + }, + "fs_type": "sysfs", + "mount_source": "sysfs", + "super_options": [ + "rw" + ] + }, + { + "mount_id": 25, + "parent_id": 30, + "maj": 0, + "min": 23, + "root": "/", + "mount_point": "/proc", + "mount_options": [ + "rw", + "nosuid", + "nodev", + "noexec", + "relatime" + ], + "optional_fields": { + "shared": 14 + }, + "fs_type": "proc", + "mount_source": "proc", + "super_options": [ + "rw" + ] + }, + ... + ] + + $ cat /proc/1/mountinfo | jc --proc_pid-mountinfo -p -r + [ + { + "mount_id": "24", + "parent_id": "30", + "maj": "0", + "min": "22", + "root": "/", + "mount_point": "/sys", + "mount_options": "rw,nosuid,nodev,noexec,relatime", + "optional_fields": "master:1 shared:7 ", + "fs_type": "sysfs", + "mount_source": "sysfs", + "super_options": "rw" + }, + { + "mount_id": "25", + "parent_id": "30", + "maj": "0", + "min": "23", + "root": "/", + "mount_point": "/proc", + "mount_options": "rw,nosuid,nodev,noexec,relatime", + "optional_fields": "shared:14 ", + "fs_type": "proc", + "mount_source": "proc", + "super_options": "rw" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_pid_numa_maps.md b/docs/parsers/proc_pid_numa_maps.md new file mode 100644 index 00000000..94e444a6 --- /dev/null +++ b/docs/parsers/proc_pid_numa_maps.md @@ -0,0 +1,126 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_pid\_numa\_maps + +jc - JSON Convert `/proc//numa_maps` file parser + +This parser will attempt to convert number values to integers. If that is +not desired, please use the `--raw` option (cli) or `raw=True` argument +(module). + +Usage (cli): + + $ cat /proc/1/numa_maps | jc --proc + +or + + $ jc /proc/1/numa_maps + +or + + $ cat /proc/1/numa_maps | jc --proc-numa-maps + +Usage (module): + + import jc + result = jc.parse('proc', proc_numa_maps_file) + +or + + import jc + result = jc.parse('proc_numa_maps', proc_numa_maps_file) + +Schema: + +Integer conversion for Key/value pairs will be attempted. + + [ + { + "address": string, + "policy": string, + "": string/integer, + "options": [ + string # [0] + ] + } + ] + + [0] remaining individual words that are not part of a key/value pair + +Examples: + + $ cat /proc/1/numa_maps | jc --proc -p + [ + { + "address": "7f53b5083000", + "policy": "default", + "file": "/usr/lib/x86_64-linux-gnu/ld-2.32.so", + "anon": 2, + "dirty": 2, + "N0": 2, + "kernelpagesize_kB": 4 + }, + { + "address": "7ffd1b23e000", + "policy": "default", + "anon": 258, + "dirty": 258, + "N0": 258, + "kernelpagesize_kB": 4, + "options": [ + "stack" + ] + }, + ... + ] + + $ cat /proc/1/numa_maps | jc --proc_numa_maps -p -r + [ + { + "address": "7f53b5083000", + "policy": "default", + "file": "/usr/lib/x86_64-linux-gnu/ld-2.32.so", + "anon": "2", + "dirty": "2", + "N0": "2", + "kernelpagesize_kB": "4" + }, + { + "address": "7ffd1b23e000", + "policy": "default", + "anon": "258", + "dirty": "258", + "N0": "258", + "kernelpagesize_kB": "4", + "options": [ + "stack" + ] + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_slabinfo.md b/docs/parsers/proc_slabinfo.md new file mode 100644 index 00000000..736a5576 --- /dev/null +++ b/docs/parsers/proc_slabinfo.md @@ -0,0 +1,100 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_slabinfo + +jc - JSON Convert `/proc/slabinfo` file parser + +Usage (cli): + + $ cat /proc/slabinfo | jc --proc + +or + + $ jc /proc/slabinfo + +or + + $ cat /proc/slabinfo | jc --proc-slabinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_slabinfo_file) + +or + + import jc + result = jc.parse('proc_slabinfo', proc_slabinfo_file) + +Schema: + + [ + { + "name": string, + "active_objs": integer, + "num_objs": integer, + "obj_size": integer, + "obj_per_slab": integer, + "pages_per_slab": integer, + "tunables": { + "limit": integer, + "batch_count": integer, + "shared_factor": integer + }, + "slabdata": { + "active_slabs": integer, + "num_slabs": integer, + "shared_avail": integer + } + ] + +Examples: + + $ cat /proc/slabinfo | jc --proc -p + [ + { + "name": "ext4_groupinfo_4k", + "active_objs": 224, + "num_objs": 224, + "obj_size": 144, + "obj_per_slab": 56, + "pages_per_slab": 2, + "tunables": { + "limit": 0, + "batch_count": 0, + "shared_factor": 0 + }, + "slabdata": { + "active_slabs": 4, + "num_slabs": 4, + "shared_avail": 0 + } + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_softirqs.md b/docs/parsers/proc_softirqs.md new file mode 100644 index 00000000..150b5a73 --- /dev/null +++ b/docs/parsers/proc_softirqs.md @@ -0,0 +1,85 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_softirqs + +jc - JSON Convert `/proc/softirqs` file parser + +Usage (cli): + + $ cat /proc/softirqs | jc --proc + +or + + $ jc /proc/softirqs + +or + + $ cat /proc/softirqs | jc --proc-softirqs + +Usage (module): + + import jc + result = jc.parse('proc', proc_softirqs_file) + +or + + import jc + result = jc.parse('proc_softirqs', proc_softirqs_file) + +Schema: + + [ + { + "counter": string, + "CPU": integer, + } + ] + +Examples: + + $ cat /proc/softirqs | jc --proc -p + [ + { + "counter": "HI", + "CPU0": 1, + "CPU1": 34056, + "CPU2": 0, + "CPU3": 0, + "CPU4": 0 + }, + { + "counter": "TIMER", + "CPU0": 322970, + "CPU1": 888166, + "CPU2": 0, + "CPU3": 0, + "CPU4": 0 + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_stat.md b/docs/parsers/proc_stat.md new file mode 100644 index 00000000..1e7dc002 --- /dev/null +++ b/docs/parsers/proc_stat.md @@ -0,0 +1,161 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_stat + +jc - JSON Convert `/proc/stat` file parser + +Usage (cli): + + $ cat /proc/stat | jc --proc + +or + + $ jc /proc/stat + +or + + $ cat /proc/stat | jc --proc-stat + +Usage (module): + + import jc + result = jc.parse('proc', proc_stat_file) + +or + + import jc + result = jc.parse('proc_stat', proc_stat_file) + +Schema: + + { + "cpu": { + "user": integer, + "nice": integer, + "system": integer, + "idle": integer, + "iowait": integer, + "irq": integer, + "softirq": integer, + "steal": integer, + "guest": integer, + "guest_nice": integer + }, + "cpu": { + "user": integer, + "nice": integer, + "system": integer, + "idle": integer, + "iowait": integer, + "irq": integer, + "softirq": integer, + "steal": integer, + "guest": integer, + "guest_nice": integer + }, + "interrupts": [ + integer + ], + "context_switches": integer, + "boot_time": integer, + "processes": integer, + "processes_running": integer, + "processes_blocked": integer, + "softirq": [ + integer + ] + } + +Examples: + + $ cat /proc/stat | jc --proc -p + { + "cpu": { + "user": 6002, + "nice": 152, + "system": 8398, + "idle": 3444436, + "iowait": 448, + "irq": 0, + "softirq": 1174, + "steal": 0, + "guest": 0, + "guest_nice": 0 + }, + "cpu0": { + "user": 2784, + "nice": 137, + "system": 4367, + "idle": 1732802, + "iowait": 225, + "irq": 0, + "softirq": 221, + "steal": 0, + "guest": 0, + "guest_nice": 0 + }, + "cpu1": { + "user": 3218, + "nice": 15, + "system": 4031, + "idle": 1711634, + "iowait": 223, + "irq": 0, + "softirq": 953, + "steal": 0, + "guest": 0, + "guest_nice": 0 + }, + "interrupts": [ + 2496709, + 18, + 73, + 0, + 0, + ... + ], + "context_switches": 4622716, + "boot_time": 1662154781, + "processes": 9831, + "processes_running": 1, + "processes_blocked": 0, + "softirq": [ + 3478985, + 35230, + 1252057, + 3467, + 128583, + 51014, + 0, + 171199, + 1241297, + 0, + 596138 + ] + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_swaps.md b/docs/parsers/proc_swaps.md new file mode 100644 index 00000000..47237358 --- /dev/null +++ b/docs/parsers/proc_swaps.md @@ -0,0 +1,91 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_swaps + +jc - JSON Convert `/proc/swaps` file parser + +Usage (cli): + + $ cat /proc/swaps | jc --proc + +or + + $ jc /proc/swaps + +or + + $ cat /proc/swaps | jc --proc-swaps + +Usage (module): + + import jc + result = jc.parse('proc', proc_swaps_file) + +or + + import jc + result = jc.parse('proc_swaps', proc_swaps_file) + +Schema: + + [ + { + "filename": string, + "type": string, + "size": integer, + "used": integer, + "priority": integer + } + ] + +Examples: + + $ cat /proc/swaps | jc --proc -p + [ + { + "filename": "/swap.img", + "type": "file", + "size": 3996668, + "used": 0, + "priority": -2 + }, + ... + ] + + $ cat /proc/swaps | jc --proc_swaps -p -r + [ + { + "filename": "/swap.img", + "type": "file", + "size": "3996668", + "used": "0", + "priority": "-2" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_uptime.md b/docs/parsers/proc_uptime.md new file mode 100644 index 00000000..47fadf70 --- /dev/null +++ b/docs/parsers/proc_uptime.md @@ -0,0 +1,68 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_uptime + +jc - JSON Convert `/proc/uptime` file parser + +Usage (cli): + + $ cat /proc/uptime | jc --proc + +or + + $ jc /proc/uptime + +or + + $ cat /proc/uptime | jc --proc-uptime + +Usage (module): + + import jc + result = jc.parse('proc', proc_uptime_file) + +or + + import jc + result = jc.parse('proc_uptime', proc_uptime_file) + +Schema: + + { + "up_time": float, + "idle_time": float + } + +Examples: + + $ cat /proc/uptime | jc --proc -p + { + "up_time": 46901.13, + "idle_time": 46856.66 + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_version.md b/docs/parsers/proc_version.md new file mode 100644 index 00000000..5234e916 --- /dev/null +++ b/docs/parsers/proc_version.md @@ -0,0 +1,79 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_version + +jc - JSON Convert `/proc/version` file parser + +> Note: This parser will parse `/proc/version` files that follow the +> common format used by most popular linux distributions. + +Usage (cli): + + $ cat /proc/version | jc --proc + +or + + $ jc /proc/version + +or + + $ cat /proc/version | jc --proc-version + +Usage (module): + + import jc + result = jc.parse('proc', proc_version_file) + +or + + import jc + result = jc.parse('proc_version', proc_version_file) + +Schema: + + { + "version": string, + "email": string, + "gcc": string, + "build": string, + "flags": string/null, + "date": string + } + +Examples: + + $ cat /proc/version | jc --proc -p + { + "version": "5.8.0-63-generic", + "email": "buildd@lcy01-amd64-028", + "gcc": "gcc (Ubuntu 10.3.0-1ubuntu1~20.10) 10.3.0, GNU ld (GNU Binutils for Ubuntu) 2.35.1", + "build": "#71-Ubuntu", + "flags": "SMP", + "date": "Tue Jul 13 15:59:12 UTC 2021" + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_vmallocinfo.md b/docs/parsers/proc_vmallocinfo.md new file mode 100644 index 00000000..1eb11bf0 --- /dev/null +++ b/docs/parsers/proc_vmallocinfo.md @@ -0,0 +1,126 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_vmallocinfo + +jc - JSON Convert `/proc/vmallocinfo` file parser + +This parser will attempt to convert number values to integers. If that is +not desired, please use the `--raw` option (cli) or `raw=True` argument +(module). + +Usage (cli): + + $ cat /proc/vmallocinfo | jc --proc + +or + + $ jc /proc/vmallocinfo + +or + + $ cat /proc/vmallocinfo | jc --proc-vmallocinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_vmallocinfo_file) + +or + + import jc + result = jc.parse('proc_vmallocinfo', proc_vmallocinfo_file) + +Schema: + + [ + { + "start": string, + "end": string, + "size": integer, + "caller": string, + "options": [ + string + ], + "phys": string + "pages": integer, + "N": integer + } + ] + +Examples: + + $ cat /proc/vmallocinfo | jc --proc -p + [ + { + "start": "0xffffb3c1c0000000", + "end": "0xffffb3c1c0005000", + "size": 20480, + "caller": "map_irq_stack+0x93/0xe0", + "options": [ + "vmap" + ], + "phys": "0x00000000bfefe000" + }, + { + "start": "0xffffb3c1c0005000", + "end": "0xffffb3c1c0007000", + "size": 8192, + "caller": "acpi_os_map_iomem+0x1ac/0x1c0", + "options": [ + "ioremap" + ], + "phys": "0x00000000bfeff000" + }, + ... + ] + + $ cat /proc/vmallocinfo | jc --proc -p -r + [ + { + "start": "0xffffb3c1c0000000", + "end": "0xffffb3c1c0005000", + "size": "20480", + "caller": "map_irq_stack+0x93/0xe0", + "options": [ + "vmap" + ], + "phys": "0x00000000bfefe000" + }, + { + "start": "0xffffb3c1c0005000", + "end": "0xffffb3c1c0007000", + "size": "8192", + "caller": "acpi_os_map_iomem+0x1ac/0x1c0", + "options": [ + "ioremap" + ], + "phys": "0x00000000bfeff000" + }, + ... + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_vmstat.md b/docs/parsers/proc_vmstat.md new file mode 100644 index 00000000..d1e6a098 --- /dev/null +++ b/docs/parsers/proc_vmstat.md @@ -0,0 +1,84 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_vmstat + +jc - JSON Convert `/proc/vmstat` file parser + +Usage (cli): + + $ cat /proc/vmstat | jc --proc + +or + + $ jc /proc/vmstat + +or + + $ cat /proc/vmstat | jc --proc-vmstat + +Usage (module): + + import jc + result = jc.parse('proc', proc_vmstat_file) + +or + + import jc + result = jc.parse('proc_vmstat', proc_vmstat_file) + +Schema: + +All values are integers. + + { + integer + } + +Examples: + + $ cat /proc/vmstat | jc --proc -p + { + "nr_free_pages": 615337, + "nr_zone_inactive_anon": 39, + "nr_zone_active_anon": 34838, + "nr_zone_inactive_file": 104036, + "nr_zone_active_file": 130601, + "nr_zone_unevictable": 4897, + "nr_zone_write_pending": 45, + "nr_mlock": 4897, + "nr_page_table_pages": 548, + "nr_kernel_stack": 5984, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 1910597, + "numa_miss": 0, + "numa_foreign": 0, + ... + } + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + Dictionary. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/proc_zoneinfo.md b/docs/parsers/proc_zoneinfo.md new file mode 100644 index 00000000..e21faf8a --- /dev/null +++ b/docs/parsers/proc_zoneinfo.md @@ -0,0 +1,334 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.proc\_zoneinfo + +jc - JSON Convert `/proc/zoneinfo` file parser + +Usage (cli): + + $ cat /proc/zoneinfo | jc --proc + +or + + $ jc /proc/zoneinfo + +or + + $ cat /proc/zoneinfo | jc --proc-zoneinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_zoneinfo_file) + +or + + import jc + result = jc.parse('proc_zoneinfo', proc_zoneinfo_file) + +Schema: + +All values are integers. + + [ + { + "node": integer, + "": { + "pages": { + "free": integer, + "min": integer, + "low": integer, + "high": integer, + "spanned": integer, + "present": integer, + "managed": integer, + "protection": [ + integer + ], + "": integer + }, + "pagesets": [ + { + "cpu": integer, + "count": integer, + "high": integer, + "batch": integer, + "vm stats threshold": integer, + "": integer + } + ] + }, + "": integer, # [0] + } + ] + + [0] per-node stats + +Examples: + + $ cat /proc/zoneinfo | jc --proc -p + [ + { + "node": 0, + "DMA": { + "pages": { + "free": 3832, + "min": 68, + "low": 85, + "high": 102, + "spanned": 4095, + "present": 3997, + "managed": 3976, + "protection": [ + 0, + 2871, + 3795, + 3795, + 3795 + ], + "nr_free_pages": 3832, + "nr_zone_inactive_anon": 0, + "nr_zone_active_anon": 0, + "nr_zone_inactive_file": 0, + "nr_zone_active_file": 0, + "nr_zone_unevictable": 0, + "nr_zone_write_pending": 0, + "nr_mlock": 0, + "nr_page_table_pages": 0, + "nr_kernel_stack": 0, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 3, + "numa_miss": 0, + "numa_foreign": 0, + "numa_interleave": 1, + "numa_local": 3, + "numa_other": 0 + }, + "pagesets": [ + { + "cpu": 0, + "count": 0, + "high": 0, + "batch": 1, + "vm stats threshold": 4 + }, + { + "cpu": 1, + "count": 0, + "high": 0, + "batch": 1, + "vm stats threshold": 4, + "node_unreclaimable": 0, + "start_pfn": 1 + } + ] + }, + "nr_inactive_anon": 39, + "nr_active_anon": 34839, + "nr_inactive_file": 104172, + "nr_active_file": 130748, + "nr_unevictable": 4897, + "nr_slab_reclaimable": 49017, + "nr_slab_unreclaimable": 26177, + "nr_isolated_anon": 0, + "nr_isolated_file": 0, + "workingset_nodes": 0, + "workingset_refault": 0, + "workingset_activate": 0, + "workingset_restore": 0, + "workingset_nodereclaim": 0, + "nr_anon_pages": 40299, + "nr_mapped": 25140, + "nr_file_pages": 234396, + "nr_dirty": 0, + "nr_writeback": 0, + "nr_writeback_temp": 0, + "nr_shmem": 395, + "nr_shmem_hugepages": 0, + "nr_shmem_pmdmapped": 0, + "nr_file_hugepages": 0, + "nr_file_pmdmapped": 0, + "nr_anon_transparent_hugepages": 0, + "nr_vmscan_write": 0, + "nr_vmscan_immediate_reclaim": 0, + "nr_dirtied": 168223, + "nr_written": 144616, + "nr_kernel_misc_reclaimable": 0, + "nr_foll_pin_acquired": 0, + "nr_foll_pin_released": 0, + "DMA32": { + "pages": { + "free": 606010, + "min": 12729, + "low": 15911, + "high": 19093, + "spanned": 1044480, + "present": 782288, + "managed": 758708, + "protection": [ + 0, + 0, + 924, + 924, + 924 + ], + "nr_free_pages": 606010, + "nr_zone_inactive_anon": 4, + "nr_zone_active_anon": 17380, + "nr_zone_inactive_file": 41785, + "nr_zone_active_file": 64545, + "nr_zone_unevictable": 5, + "nr_zone_write_pending": 0, + "nr_mlock": 5, + "nr_page_table_pages": 101, + "nr_kernel_stack": 224, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 576595, + "numa_miss": 0, + "numa_foreign": 0, + "numa_interleave": 2, + "numa_local": 576595, + "numa_other": 0 + }, + "pagesets": [ + { + "cpu": 0, + "count": 253, + "high": 378, + "batch": 63, + "vm stats threshold": 24 + }, + { + "cpu": 1, + "count": 243, + "high": 378, + "batch": 63, + "vm stats threshold": 24, + "node_unreclaimable": 0, + "start_pfn": 4096 + } + ] + }, + "Normal": { + "pages": { + "free": 5113, + "min": 4097, + "low": 5121, + "high": 6145, + "spanned": 262144, + "present": 262144, + "managed": 236634, + "protection": [ + 0, + 0, + 0, + 0, + 0 + ], + "nr_free_pages": 5113, + "nr_zone_inactive_anon": 35, + "nr_zone_active_anon": 17459, + "nr_zone_inactive_file": 62387, + "nr_zone_active_file": 66203, + "nr_zone_unevictable": 4892, + "nr_zone_write_pending": 0, + "nr_mlock": 4892, + "nr_page_table_pages": 447, + "nr_kernel_stack": 5760, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 1338441, + "numa_miss": 0, + "numa_foreign": 0, + "numa_interleave": 66037, + "numa_local": 1338441, + "numa_other": 0 + }, + "pagesets": [ + { + "cpu": 0, + "count": 340, + "high": 378, + "batch": 63, + "vm stats threshold": 16 + }, + { + "cpu": 1, + "count": 174, + "high": 378, + "batch": 63, + "vm stats threshold": 16, + "node_unreclaimable": 0, + "start_pfn": 1048576 + } + ] + }, + "Movable": { + "pages": { + "free": 0, + "min": 0, + "low": 0, + "high": 0, + "spanned": 0, + "present": 0, + "managed": 0, + "protection": [ + 0, + 0, + 0, + 0, + 0 + ] + } + }, + "Device": { + "pages": { + "free": 0, + "min": 0, + "low": 0, + "high": 0, + "spanned": 0, + "present": 0, + "managed": 0, + "protection": [ + 0, + 0, + 0, + 0, + 0 + ] + } + } + } + ] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/jc/cli.py b/jc/cli.py index a53ad99d..9c35ee95 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -11,8 +11,9 @@ import signal import shlex import subprocess from .lib import (__version__, parser_info, all_parser_info, parsers, - _get_parser, _parser_is_streaming, standard_parser_mod_list, - plugin_parser_mod_list, streaming_parser_mod_list) + _get_parser, _parser_is_streaming, parser_mod_list, + standard_parser_mod_list, plugin_parser_mod_list, + streaming_parser_mod_list) from . import utils from .cli_data import long_options_map, new_pygments_colors, old_pygments_colors from .shell_completions import bash_completion, zsh_completion @@ -120,11 +121,11 @@ def parser_shortname(parser_arg): return parser_arg[2:] -def parsers_text(indent=0, pad=0): +def parsers_text(indent=0, pad=0, show_hidden=False): """Return the argument and description information from each parser""" ptext = '' padding_char = ' ' - for p in all_parser_info(): + for p in all_parser_info(show_hidden=show_hidden): parser_arg = p.get('argument', 'UNKNOWN') padding = pad - len(parser_arg) parser_desc = p.get('description', 'No description available.') @@ -164,28 +165,37 @@ def about_jc(): 'license': info.license, 'python_version': '.'.join((str(sys.version_info.major), str(sys.version_info.minor), str(sys.version_info.micro))), 'python_path': sys.executable, - 'parser_count': len(all_parser_info()), + 'parser_count': len(parser_mod_list()), 'standard_parser_count': len(standard_parser_mod_list()), 'streaming_parser_count': len(streaming_parser_mod_list()), 'plugin_parser_count': len(plugin_parser_mod_list()), - 'parsers': all_parser_info() + 'parsers': all_parser_info(show_hidden=True) } -def helptext(): +def helptext(show_hidden=False): """Return the help text with the list of parsers""" - parsers_string = parsers_text(indent=4, pad=20) + parsers_string = parsers_text(indent=4, pad=20, show_hidden=show_hidden) options_string = options_text(indent=4, pad=20) helptext_string = f'''\ -jc converts the output of many commands and file-types to JSON or YAML +jc converts the output of many commands, file-types, and strings to JSON or YAML Usage: - COMMAND | jc PARSER [OPTIONS] - or magic syntax: + Standard syntax: - jc [OPTIONS] COMMAND + COMMAND | jc [OPTIONS] PARSER + + cat FILE | jc [OPTIONS] PARSER + + echo STRING | jc [OPTIONS] PARSER + + Magic syntax: + + jc [OPTIONS] COMMAND + + jc [OPTIONS] /proc/ Parsers: {parsers_string} @@ -193,19 +203,24 @@ Options: {options_string} Examples: Standard Syntax: - $ dig www.google.com | jc --dig --pretty + $ dig www.google.com | jc --pretty --dig + $ cat /proc/meminfo | jc --pretty --proc Magic Syntax: $ jc --pretty dig www.google.com + $ jc --pretty /proc/meminfo Parser Documentation: $ jc --help --dig + + Show Hidden Parsers: + $ jc -hh ''' return helptext_string -def help_doc(options): +def help_doc(options, show_hidden=False): """ Returns the parser documentation if a parser is found in the arguments, otherwise the general help text is returned. @@ -228,7 +243,7 @@ def help_doc(options): utils._safe_pager(doc_text) return - utils._safe_print(helptext()) + utils._safe_print(helptext(show_hidden=show_hidden)) return @@ -419,6 +434,11 @@ def magic_parser(args): ) +def open_text_file(path_string): + with open(path_string, 'r') as f: + return f.read() + + def run_user_command(command): """ Use subprocess to run the user's command. Returns the STDOUT, STDERR, @@ -525,6 +545,7 @@ def main(): force_color = 'C' in options mono = ('m' in options or bool(os.getenv('NO_COLOR'))) and not force_color help_me = 'h' in options + verbose_help = options.count('h') > 1 pretty = 'p' in options quiet = 'q' in options ignore_exceptions = options.count('q') > 1 @@ -552,7 +573,7 @@ def main(): sys.exit(0) if help_me: - help_doc(sys.argv) + help_doc(sys.argv, show_hidden=verbose_help) sys.exit(0) if version_info: @@ -569,13 +590,38 @@ def main(): # if magic syntax used, try to run the command and error if it's not found, etc. magic_stdout, magic_stderr, magic_exit_code = None, None, 0 + run_command_str = '' if run_command: try: run_command_str = shlex.join(run_command) # python 3.8+ except AttributeError: run_command_str = ' '.join(run_command) # older python versions - if valid_command: + if run_command_str.startswith('/proc'): + try: + magic_found_parser = 'proc' + magic_stdout = open_text_file(run_command_str) + + except OSError as e: + if debug: + raise + + error_msg = os.strerror(e.errno) + utils.error_message([ + f'"{run_command_str}" file could not be opened: {error_msg}.' + ]) + sys.exit(combined_exit_code(magic_exit_code, JC_ERROR_EXIT)) + + except Exception: + if debug: + raise + + utils.error_message([ + f'"{run_command_str}" file could not be opened. For details use the -d or -dd option.' + ]) + sys.exit(combined_exit_code(magic_exit_code, JC_ERROR_EXIT)) + + elif valid_command: try: magic_stdout, magic_stderr, magic_exit_code = run_user_command(run_command) if magic_stderr: @@ -623,12 +669,7 @@ def main(): utils.error_message(['Missing or incorrect arguments. Use "jc -h" for help.']) sys.exit(combined_exit_code(magic_exit_code, JC_ERROR_EXIT)) - # check for input errors (pipe vs magic) - if not sys.stdin.isatty() and magic_stdout: - utils.error_message(['Piped data and Magic syntax used simultaneously. Use "jc -h" for help.']) - sys.exit(combined_exit_code(magic_exit_code, JC_ERROR_EXIT)) - - elif sys.stdin.isatty() and magic_stdout is None: + if sys.stdin.isatty() and magic_stdout is None: utils.error_message(['Missing piped data. Use "jc -h" for help.']) sys.exit(combined_exit_code(magic_exit_code, JC_ERROR_EXIT)) diff --git a/jc/lib.py b/jc/lib.py index 98c5084e..da8bf7a9 100644 --- a/jc/lib.py +++ b/jc/lib.py @@ -84,6 +84,39 @@ parsers = [ 'pip-show', 'plist', 'postconf', + 'proc', + 'proc-buddyinfo', + 'proc-consoles', + 'proc-cpuinfo', + 'proc-crypto', + 'proc-devices', + 'proc-diskstats', + 'proc-driver-rtc', + 'proc-filesystems', + 'proc-interrupts', + 'proc-iomem', + 'proc-ioports', + 'proc-loadavg', + 'proc-locks', + 'proc-meminfo', + 'proc-modules', + 'proc-mtrr', + 'proc-pagetypeinfo', + 'proc-partitions', + 'proc-slabinfo', + 'proc-softirqs', + 'proc-stat', + 'proc-swaps', + 'proc-uptime', + 'proc-version', + 'proc-vmallocinfo', + 'proc-vmstat', + 'proc-zoneinfo', + 'proc-pid-fdinfo', + 'proc-pid-io', + 'proc-pid-maps', + 'proc-pid-mountinfo', + 'proc-pid-numa-maps', 'ps', 'route', 'rpm-qi', @@ -339,7 +372,9 @@ def parser_info(parser_mod_name: str, documentation: bool = False) -> Dict: return info_dict -def all_parser_info(documentation: bool = False) -> List[Dict]: +def all_parser_info(documentation: bool = False, + show_hidden: bool = False +) -> List[Dict]: """ Returns a list of dictionaries that includes metadata for all parser modules. @@ -347,8 +382,22 @@ def all_parser_info(documentation: bool = False) -> List[Dict]: Parameters: documentation: (boolean) include parser docstrings if True + show_hidden: (boolean) also show parsers marked as hidden + in their info metadata. """ - return [parser_info(p, documentation=documentation) for p in parsers] + temp_list = [parser_info(p, documentation=documentation) for p in parsers] + + p_list = [] + if show_hidden: + p_list = temp_list + + else: + for item in temp_list: + if not item.get('hidden', None): + p_list.append(item) + + return p_list + def get_help(parser_mod_name: str) -> None: """ diff --git a/jc/parsers/id.py b/jc/parsers/id.py index 897ba494..d3f310a2 100644 --- a/jc/parsers/id.py +++ b/jc/parsers/id.py @@ -100,12 +100,13 @@ Examples: } } """ +import re import jc.utils class info(): """Provides parser metadata (version, author, etc.)""" - version = '1.5' + version = '1.6' description = '`id` command parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -170,28 +171,28 @@ def parse(data, raw=False, quiet=False): raw_output = {} - # Clear any blank lines - cleandata = list(filter(None, data.split())) + # re.split produces first element empty + cleandata = re.split(r' ?(uid|gid|groups|context)=', data.strip())[1:] if jc.utils.has_data(data): - for section in cleandata: - if section.startswith('uid'): - uid_parsed = section.replace('(', '=').replace(')', '=') + for key, value in zip(cleandata[0::2], cleandata[1::2]): + if key == 'uid': + uid_parsed = value.replace('(', '=').replace(')', '=') uid_parsed = uid_parsed.split('=') raw_output['uid'] = {} - raw_output['uid']['id'] = uid_parsed[1] - raw_output['uid']['name'] = _get_item(uid_parsed, 2) + raw_output['uid']['id'] = uid_parsed[0] + raw_output['uid']['name'] = _get_item(uid_parsed, 1) - if section.startswith('gid'): - gid_parsed = section.replace('(', '=').replace(')', '=') + if key == 'gid': + gid_parsed = value.replace('(', '=').replace(')', '=') gid_parsed = gid_parsed.split('=') raw_output['gid'] = {} - raw_output['gid']['id'] = gid_parsed[1] - raw_output['gid']['name'] = _get_item(gid_parsed, 2) + raw_output['gid']['id'] = gid_parsed[0] + raw_output['gid']['name'] = _get_item(gid_parsed, 1) - if section.startswith('groups'): - groups_parsed = section.replace('(', '=').replace(')', '=') + if key == 'groups': + groups_parsed = value.replace('(', '=').replace(')', '=') groups_parsed = groups_parsed.replace('groups=', '') groups_parsed = groups_parsed.split(',') raw_output['groups'] = [] @@ -203,9 +204,8 @@ def parse(data, raw=False, quiet=False): group_dict['name'] = _get_item(grp_parsed, 1) raw_output['groups'].append(group_dict) - if section.startswith('context'): - context_parsed = section.replace('context=', '') - context_parsed = context_parsed.split(':', maxsplit=3) + if key == 'context': + context_parsed = value.split(':', maxsplit=3) raw_output['context'] = {} raw_output['context']['user'] = context_parsed[0] raw_output['context']['role'] = context_parsed[1] diff --git a/jc/parsers/lsof.py b/jc/parsers/lsof.py index ef14cd56..ac167fd0 100644 --- a/jc/parsers/lsof.py +++ b/jc/parsers/lsof.py @@ -124,7 +124,7 @@ class info(): description = '`lsof` command parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' - compatible = ['linux'] + compatible = ['linux', 'darwin', 'aix', 'freebsd'] magic_commands = ['lsof'] diff --git a/jc/parsers/proc.py b/jc/parsers/proc.py new file mode 100644 index 00000000..cfe59399 --- /dev/null +++ b/jc/parsers/proc.py @@ -0,0 +1,277 @@ +"""jc - JSON Convert Proc file output parser + +This parser automatically identifies the Proc file and calls the +corresponding parser to peform the parsing. + +Magic syntax for converting `/proc` files is also supported by running +`jc /proc/`. Any `jc` options must be specified before the +`/proc` path. + +specific Proc file parsers can also be called directly, if desired and have +a naming convention of `proc-` (cli) or `proc_` (module). + +Usage (cli): + + $ cat /proc/meminfo | jc --proc + +or + + $ jc /proc/meminfo + +or + + $ cat /proc/meminfo | jc --proc-memifno + +Usage (module): + + import jc + result = jc.parse('proc', proc_file) + +Schema: + +See the specific Proc parser for the schema: + + $ jc --help --proc- + +For example: + + $ jc --help --proc-meminfo + +Specific Proc file parser names can be found with `jc -hh` or `jc -a`. + +Schemas can also be found online at: + + https://kellyjonbrazil.github.io/jc/docs/parsers/proc_ + +For example: + + https://kellyjonbrazil.github.io/jc/docs/parsers/proc_meminfo + +Examples: + + $ cat /proc/modules | jc --proc -p + [ + { + "module": "binfmt_misc", + "size": 24576, + "used": 1, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": 16384, + "used": 0, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": 36864, + "used": 1, + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] + + $ proc_modules | jc --proc_modules -p -r + [ + { + "module": "binfmt_misc", + "size": "24576", + "used": "1", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": "16384", + "used": "0", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": "36864", + "used": "1", + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] +""" +import re +import importlib +from typing import List, Dict +import jc.utils +from jc.exceptions import ParseError + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + + +__version__ = info.version + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.input_type_check(data) + + if jc.utils.has_data(data): + # signatures + buddyinfo_p = re.compile(r'^Node \d+, zone\s+\w+\s+(?:\d+\s+){11}\n') + consoles_p = re.compile(r'^\w+\s+[\-WUR]{3} \([ECBpba ]+\)\s+\d+:\d+\n') + cpuinfo_p = re.compile(r'^processor\t+: \d+.*bogomips\t+: \d+.\d\d\n', re.DOTALL) + crypto_p = re.compile(r'^name\s+:.*\ndriver\s+:.*\nmodule\s+:.*\n') + devices_p = re.compile(r'^Character devices:\n\s+\d+ .*\n') + diskstats_p = re.compile(r'^\s*\d+\s+\d\s\w+\s(?:\d+\s){10,16}\d+\n') + filesystems_p = re.compile(r'^(?:(?:nodev\t|\t)\w+\n){3}') + interrupts_p = re.compile(r'^\s+(?:CPU\d+ +)+\n\s*\d+:\s+\d+') + iomem_p = re.compile(r'^00000000-[0-9a-f]{8} : .*\n[0-9a-f]{8}-[0-9a-f]{8} : ') + ioports_p = re.compile(r'^0000-[0-9a-f]{4} : .*\n\s*0000-[0-9a-f]{4} : ') + loadavg_p = re.compile(r'^\d+.\d\d \d+.\d\d \d+.\d\d \d+/\d+ \d+$') + locks_p = re.compile(r'^\d+: (?:POSIX|FLOCK|OFDLCK)\s+(?:ADVISORY|MANDATORY)\s+(?:READ|WRITE) ') + meminfo_p = re.compile(r'^MemTotal:.*\nMemFree:.*\nMemAvailable:.*\n') + modules_p = re.compile(r'^\w+ \d+ \d+ (?:-|\w+,).*0x[0-9a-f]{16}\n') + mtrr_p = re.compile(r'^reg\d+: base=0x[0-9a-f]+ \(') + pagetypeinfo_p = re.compile(r'^Page block order:\s+\d+\nPages per block:\s+\d+\n\n') + partitions_p = re.compile(r'^major minor #blocks name\n\n\s*\d+\s+\d+\s+\d+ \w+\n') + slabinfo_p = re.compile(r'^slabinfo - version: \d+.\d+\n') + softirqs_p = re.compile(r'^\s+(CPU\d+\s+)+\n\s+HI:\s+\d') + stat_p = re.compile(r'^cpu\s+(?: \d+){7,10}.*intr ', re.DOTALL) + swaps_p = re.compile(r'^Filename\t\t\t\tType\t\tSize\t\tUsed\t\tPriority\n') + uptime_p = re.compile(r'^\d+.\d\d \d+.\d\d$') + version_p = re.compile(r'^.+\sversion\s[^\n]+$') + vmallocinfo_p = re.compile(r'^0x[0-9a-f]{16}-0x[0-9a-f]{16}\s+\d+ \w+\+\w+/\w+ ') + vmstat_p = re.compile(r'nr_free_pages \d+\n.* \d$', re.DOTALL) + zoneinfo_p = re.compile(r'^Node \d+, zone\s+\w+\n') + + driver_rtc_p = re.compile(r'^rtc_time\t: .*\nrtc_date\t: .*\nalrm_time\t: .*\n') + + net_arp_p = re.compile(r'^IP address\s+HW type\s+Flags\s+HW address\s+Mask\s+Device\n') + net_dev_p = re.compile(r'^Inter-\|\s+Receive\s+\|\s+Transmit\n') + net_dev_mcast_p = re.compile(r'^\d+\s+\w+\s+\d+\s+\d+\s+[0-9a-f]{12}') + net_if_inet6_p = re.compile(r'^[0-9a-f]{32} \d\d \d\d \d\d \d\d\s+\w+') + net_igmp_p = re.compile(r'^Idx\tDevice\s+:\s+Count\s+Querier\tGroup\s+Users\s+Timer\tReporter\n') + net_igmp6_p = re.compile(r'^\d+\s+\w+\s+[0-9a-f]{32}\s+\d+\s+[0-9A-F]{8}\s+\d+') + net_ipv6_route_p = re.compile(r'^[0-9a-f]{32} \d\d [0-9a-f]{32} \d\d [0-9a-f]{32} (?:[0-9a-f]{8} ){4}\s+\w+') + net_netlink_p = re.compile(r'^sk\s+Eth Pid\s+Groups\s+Rmem\s+Wmem') + net_netstat_p = re.compile(r'^TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed') + net_packet_p = re.compile(r'^sk RefCnt Type Proto Iface R Rmem User Inode\n') + net_protocols_p = re.compile(r'^protocol size sockets memory press maxhdr slab module cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n') + net_route_p = re.compile(r'^Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT\s+\n') + net_unix_p = re.compile(r'^Num RefCount Protocol Flags Type St Inode Path\n') + + pid_fdinfo_p = re.compile(r'^pos:\t\d+\nflags:\t\d+\nmnt_id:\t\d+\n') + pid_io_p = re.compile(r'^rchar: \d+\nwchar: \d+\nsyscr: \d+\n') + pid_maps_p = re.compile(r'^[0-9a-f]{12}-[0-9a-f]{12} [rwxsp\-]{4} [0-9a-f]{8} [0-9a-f]{2}:[0-9a-f]{2} \d+ ') + pid_mountinfo_p = re.compile(r'^\d+ \d+ \d+:\d+ /.+\n') + pid_numa_maps_p = re.compile(r'^[a-f0-9]{12} default [^\n]+\n') + pid_smaps_p = re.compile(r'^[0-9a-f]{12}-[0-9a-f]{12} [rwxsp\-]{4} [0-9a-f]{8} [0-9a-f]{2}:[0-9a-f]{2} \d+ [^\n]+\nSize:\s+\d+ \S\S\n') + pid_statm_p = re.compile(r'^\d+ \d+ \d+\s\d+\s\d+\s\d+\s\d+$') + pid_status_p = re.compile(r'^Name:\t.+\nUmask:\t\d+\nState:\t.+\nTgid:\t\d+\n') + pid_stat_p = re.compile(r'^\d+ \(.{1,16}\) \w \d+ \d+ \d+ \d+ -?\d+ (?:\d+ ){43}\d+$') + + scsi_device_info = re.compile(r"^'\w+' '.+' 0x\d+") + scsi_scsi_p = re.compile(r'^Attached devices:\nHost: \w+ ') + + procmap = { + buddyinfo_p: 'proc_buddyinfo', + consoles_p: 'proc_consoles', + cpuinfo_p: 'proc_cpuinfo', + crypto_p: 'proc_crypto', + devices_p: 'proc_devices', + diskstats_p: 'proc_diskstats', + filesystems_p: 'proc_filesystems', + interrupts_p: 'proc_interrupts', + iomem_p: 'proc_iomem', + ioports_p: 'proc_ioports', + loadavg_p: 'proc_loadavg', + locks_p: 'proc_locks', + meminfo_p: 'proc_meminfo', + modules_p: 'proc_modules', + mtrr_p: 'proc_mtrr', + pagetypeinfo_p: 'proc_pagetypeinfo', + partitions_p: 'proc_partitions', + slabinfo_p: 'proc_slabinfo', + softirqs_p: 'proc_softirqs', + stat_p: 'proc_stat', + swaps_p: 'proc_swaps', + uptime_p: 'proc_uptime', + version_p: 'proc_version', + vmallocinfo_p: 'proc_vmallocinfo', + zoneinfo_p: 'proc_zoneinfo', # before vmstat + vmstat_p: 'proc_vmstat', # after zoneinfo + + driver_rtc_p: 'proc_driver_rtc', + + net_arp_p: 'proc_net_arp', + net_dev_p: 'proc_net_dev', + net_if_inet6_p: 'proc_net_if_inet6', + net_igmp_p: 'proc_net_igmp', + net_igmp6_p: 'proc_net_igmp6', + net_netlink_p: 'proc_net_netlink', + net_netstat_p: 'proc_net_netstat', + net_packet_p: 'proc_net_packet', + net_protocols_p: 'proc_net_protocols', + net_route_p: 'proc_net_route', + net_unix_p: 'proc_net_unix', + net_ipv6_route_p: 'proc_net_ipv6_route', # before net_dev_mcast + net_dev_mcast_p: 'proc_net_dev_mcast', # after net_ipv6_route + + pid_fdinfo_p: 'proc_pid_fdinfo', + pid_io_p: 'proc_pid_io', + pid_mountinfo_p: 'proc_pid_mountinfo', + pid_numa_maps_p: 'proc_pid_numa_maps', + pid_stat_p: 'proc_pid_stat', + pid_statm_p: 'proc_pid_statm', + pid_status_p: 'proc_pid_status', + pid_smaps_p: 'proc_pid_smaps', # before pid_maps + pid_maps_p: 'proc_pid_maps', # after pid_smaps + + scsi_device_info: 'proc_scsi_device_info', + scsi_scsi_p: 'proc_scsi_scsi' + } + + for reg_pattern, parse_mod in procmap.items(): + if reg_pattern.search(data): + try: + procparser = importlib.import_module('jc.parsers.' + parse_mod) + return procparser.parse(data, quiet=quiet, raw=raw) + except ModuleNotFoundError: + raise ParseError('Proc file type not yet implemented.') + + raise ParseError('Proc file could not be identified.') diff --git a/jc/parsers/proc_buddyinfo.py b/jc/parsers/proc_buddyinfo.py new file mode 100644 index 00000000..1efd5680 --- /dev/null +++ b/jc/parsers/proc_buddyinfo.py @@ -0,0 +1,179 @@ +"""jc - JSON Convert `/proc/buddyinfo` file parser + +Usage (cli): + + $ cat /proc/buddyinfo | jc --proc + +or + + $ jc /proc/buddyinfo + +or + + $ cat /proc/buddyinfo | jc --proc-buddyinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_buddyinfo_file) + +or + + import jc + result = jc.parse('proc_buddyinfo', proc_buddyinfo_file) + +Schema: + +All values are integers. + + [ + { + "node": integer, + "zone": string, + "free_chunks": [ + integer # [0] + ] + } + ] + + [0] array index correlates to the Order number. + E.g. free_chunks[0] is the value for Order 0 + + +Examples: + + $ cat /proc/buddyinfo | jc --proc -p + [ + { + "node": 0, + "zone": "DMA", + "free_chunks": [ + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 3 + ] + }, + { + "node": 0, + "zone": "DMA32", + "free_chunks": [ + 78, + 114, + 82, + 52, + 38, + 25, + 13, + 9, + 3, + 4, + 629 + ] + }, + { + "node": 0, + "zone": "Normal", + "free_chunks": [ + 0, + 22, + 8, + 10, + 1, + 1, + 2, + 11, + 13, + 0, + 0 + ] + } + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/buddyinfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'node'} + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = jc.utils.convert_to_int(entry[key]) + + if 'free_chunks' in entry: + entry['free_chunks'] = [int(x) for x in entry['free_chunks']] + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + buddy_list = line.split() + + raw_output.append( + { + 'node': buddy_list[1][:-1], + 'zone': buddy_list[3], + 'free_chunks': buddy_list[4:] + } + ) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_consoles.py b/jc/parsers/proc_consoles.py new file mode 100644 index 00000000..3423d0b0 --- /dev/null +++ b/jc/parsers/proc_consoles.py @@ -0,0 +1,188 @@ +"""jc - JSON Convert `/proc/consoles` file parser + +Usage (cli): + + $ cat /proc/consoles | jc --proc + +or + + $ jc /proc/consoles + +or + + $ cat /proc/consoles | jc --proc-consoles + +Usage (module): + + import jc + result = jc.parse('proc', proc_consoles_file) + +or + + import jc + result = jc.parse('proc_consoles', proc_consoles_file) + +Schema: + + [ + { + "device": string, + "operations": string, + "operations_list": [ + string # [0] + ], + "flags": string, + "flags_list": [ + string # [1] + ], + "major": integer, + "minor": integer + } + ] + + [0] Values: read, write, unblank + [1] Values: enabled, preferred, primary boot, prink buffer, + braille device, safe when CPU offline + +Examples: + + $ cat /proc/consoles | jc --proc -p + [ + { + "device": "tty0", + "operations": "-WU", + "operations_list": [ + "write", + "unblank" + ], + "flags": "ECp", + "flags_list": [ + "enabled", + "preferred", + "printk buffer" + ], + "major": 4, + "minor": 7 + }, + { + "device": "ttyS0", + "operations": "-W-", + "operations_list": [ + "write" + ], + "flags": "Ep", + "flags_list": [ + "enabled", + "printk buffer" + ], + "major": 4, + "minor": 64 + } + ] +""" +import shlex +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/consoles` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'major', 'minor'} + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = jc.utils.convert_to_int(entry[key]) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + operations_map = { + 'R': 'read', + 'W': 'write', + 'U': 'unblank' + } + + flags_map = { + 'E': 'enabled', + 'C': 'preferred', + 'B': 'primary boot', + 'p': 'printk buffer', + 'b': 'braille device', + 'a': 'safe when CPU offline' + } + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + # since parens are acting like quotation marks, use shlex.split() + # after converting parens to quotes. + line = line.replace('(', '"'). replace(')', '"') + device, operations, flags, maj_min = shlex.split(line) + + operations_str = operations.replace('-', '') + operations_list = [operations_map[i] for i in operations_str] + + flags_str = flags.replace (' ', '') + flags_list = [flags_map[i] for i in flags_str] + + raw_output.append( + { + 'device': device, + 'operations': operations, + 'operations_list': operations_list, + 'flags': flags, + 'flags_list': flags_list, + 'major': maj_min.split(':')[0], + 'minor': maj_min.split(':')[1] + } + ) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_cpuinfo.py b/jc/parsers/proc_cpuinfo.py new file mode 100644 index 00000000..5de13991 --- /dev/null +++ b/jc/parsers/proc_cpuinfo.py @@ -0,0 +1,329 @@ +"""jc - JSON Convert `/proc/cpuinfo` file parser + +Usage (cli): + + $ cat /proc/cpuinfo | jc --proc + +or + + $ jc /proc/cpuinfo + +or + + $ cat /proc/cpuinfo | jc --proc-cpuinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_cpuinfo_file) + +or + + import jc + result = jc.parse('proc_cpuinfo', proc_cpuinfo_file) + +Schema: + +Integer, float, and boolean ("yes"/"no") conversions are attempted. Blank +strings are converted to `null`. + +"Well-known" keys like `cache size`, `address types`, `bugs`, and `flags` +are processed into sensible data types. (see below) + +If this is not desired, then use the `--raw` (CLI) or `raw=True` (Module) +option. + + [ + { + "processor": integer, + "address sizes": string, + "address_size_physical": integer, # in bits + "address_size_virtual": integer, # in bits + "cache size": string, + "cache_size_num": integer, + "cache_size_unit": string, + "flags": [ + string + ], + "bugs": [ + string + ], + "bogomips": float, + : string/int/float/boolean/null + } + ] + +Examples: + + $ cat /proc/cpuinfo | jc --proc -p + [ + { + "processor": 0, + "vendor_id": "GenuineIntel", + "cpu family": 6, + "model": 142, + "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz", + "stepping": 10, + "cpu MHz": 2400.0, + "cache size": "6144 KB", + "physical id": 0, + "siblings": 1, + "core id": 0, + "cpu cores": 1, + "apicid": 0, + "initial apicid": 0, + "fpu": true, + "fpu_exception": true, + "cpuid level": 22, + "wp": true, + "bogomips": 4800.0, + "clflush size": 64, + "cache_alignment": 64, + "address sizes": "45 bits physical, 48 bits virtual", + "power management": null, + "address_size_physical": 45, + "address_size_virtual": 48, + "cache_size_num": 6144, + "cache_size_unit": "KB", + "flags": [ + "fpu", + "vme", + "de", + "pse", + "tsc", + "msr", + "pae", + "mce", + "cx8", + "apic", + "sep", + "mtrr", + "pge", + "mca", + "cmov", + "pat", + "pse36", + "clflush", + "mmx", + "fxsr", + "sse", + "sse2", + "ss", + "syscall", + "nx", + "pdpe1gb", + "rdtscp", + "lm", + "constant_tsc", + "arch_perfmon", + "nopl", + "xtopology", + "tsc_reliable", + "nonstop_tsc", + "cpuid", + "pni", + "pclmulqdq", + "ssse3", + "fma", + "cx16", + "pcid", + "sse4_1", + "sse4_2", + "x2apic", + "movbe", + "popcnt", + "tsc_deadline_timer", + "aes", + "xsave", + "avx", + "f16c", + "rdrand", + "hypervisor", + "lahf_lm", + "abm", + "3dnowprefetch", + "cpuid_fault", + "invpcid_single", + "pti", + "ssbd", + "ibrs", + "ibpb", + "stibp", + "fsgsbase", + "tsc_adjust", + "bmi1", + "avx2", + "smep", + "bmi2", + "invpcid", + "rdseed", + "adx", + "smap", + "clflushopt", + "xsaveopt", + "xsavec", + "xgetbv1", + "xsaves", + "arat", + "md_clear", + "flush_l1d", + "arch_capabilities" + ], + "bugs": [ + "cpu_meltdown", + "spectre_v1", + "spectre_v2", + "spec_store_bypass", + "l1tf", + "mds", + "swapgs", + "itlb_multihit", + "srbds" + ] + }, + ... + ] + + $ cat /proc/cpuinfo | jc --proc_cpuinfo -p -r + [ + { + "processor": "0", + "vendor_id": "GenuineIntel", + "cpu family": "6", + "model": "142", + "model name": "Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz", + "stepping": "10", + "cpu MHz": "2400.000", + "cache size": "6144 KB", + "physical id": "0", + "siblings": "1", + "core id": "0", + "cpu cores": "1", + "apicid": "0", + "initial apicid": "0", + "fpu": "yes", + "fpu_exception": "yes", + "cpuid level": "22", + "wp": "yes", + "flags": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge ...", + "bugs": "cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass ...", + "bogomips": "4800.00", + "clflush size": "64", + "cache_alignment": "64", + "address sizes": "45 bits physical, 48 bits virtual", + "power management": "" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/cpuinfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + for entry in proc_data: + for key in entry: + if entry[key] == '': + entry[key] = None + + try: + entry[key] = int(entry[key]) + except Exception: + pass + + try: + if isinstance(entry[key], str) and (entry[key] == 'yes' or entry[key] == 'no'): + entry[key] = jc.utils.convert_to_bool(entry[key]) + except Exception: + pass + + try: + if isinstance(entry[key], str) and '.' in entry[key]: + entry[key] = float(entry[key]) + except Exception: + pass + + if 'address sizes' in entry: + phy = int(entry['address sizes'].split()[0]) + virt = int(entry['address sizes'].split()[3]) + entry['address_size_physical'] = phy + entry['address_size_virtual'] = virt + + if 'cache size' in entry: + cache_size_int, unit = entry['cache size'].split() + entry['cache_size_num'] = int(cache_size_int) + entry['cache_size_unit'] = unit + + if 'flags' in entry: + entry['flags'] = entry['flags'].split() + + if 'bugs' in entry: + entry['bugs'] = entry['bugs'].split() + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + output_line: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + if line.startswith('processor'): + if output_line: + raw_output.append(output_line) + output_line = {} + + key, val = line.split(':', maxsplit=1) + output_line[key.strip()] = val.strip() + + if output_line: + raw_output.append(output_line) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_crypto.py b/jc/parsers/proc_crypto.py new file mode 100644 index 00000000..93cab164 --- /dev/null +++ b/jc/parsers/proc_crypto.py @@ -0,0 +1,196 @@ +"""jc - JSON Convert `/proc/crypto` file parser + +Usage (cli): + + $ cat /proc/crypto | jc --proc + +or + + $ jc /proc/crypto + +or + + $ cat /proc/crypto | jc --proc-crypto + +Usage (module): + + import jc + result = jc.parse('proc', proc_crypto_file) + +or + + import jc + result = jc.parse('proc_crypto', proc_crypto_file) + +Schema: + +"Well-known" keys like `priority` and `refcnt` are converted to integers. +Also, keynames ending in "size" are converted to integers. + +If this is not desired, then use the `--raw` (CLI) or `raw=True` (Module) +option. + + [ + { + "name": string, + "driver": string, + "module": string, + "priority": integer, + "refcnt": integer, + "selftest": string, + "internal": string, + "type": string, + "*size": integer + } + ] + +Examples: + + $ cat /proc/crypto | jc --proc -p + [ + { + "name": "ecdh", + "driver": "ecdh-generic", + "module": "ecdh_generic", + "priority": 100, + "refcnt": 1, + "selftest": "passed", + "internal": "no", + "type": "kpp" + }, + { + "name": "blake2b-512", + "driver": "blake2b-512-generic", + "module": "blake2b_generic", + "priority": 100, + "refcnt": 1, + "selftest": "passed", + "internal": "no", + "type": "shash", + "blocksize": 128, + "digestsize": 64 + }, + ... + ] + + $ cat /proc/crypto | jc --proc_crypto -p -r + [ + { + "name": "ecdh", + "driver": "ecdh-generic", + "module": "ecdh_generic", + "priority": "100", + "refcnt": "1", + "selftest": "passed", + "internal": "no", + "type": "kpp" + }, + { + "name": "blake2b-512", + "driver": "blake2b-512-generic", + "module": "blake2b_generic", + "priority": "100", + "refcnt": "1", + "selftest": "passed", + "internal": "no", + "type": "shash", + "blocksize": "128", + "digestsize": "64" + }, + { + "name": "blake2b-384", + "driver": "blake2b-384-generic", + "module": "blake2b_generic", + "priority": "100", + "refcnt": "1", + "selftest": "passed", + "internal": "no", + "type": "shash", + "blocksize": "128", + "digestsize": "48" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/crypto` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'priority', 'refcnt'} + + for entry in proc_data: + for key in entry: + if key in int_list or key.endswith('size'): + try: + entry[key] = int(entry[key]) + except Exception: + pass + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + output_line: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + if line.startswith('name'): + if output_line: + raw_output.append(output_line) + output_line = {} + + key, val = line.split(':', maxsplit=1) + output_line[key.strip()] = val.strip() + + if output_line: + raw_output.append(output_line) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_devices.py b/jc/parsers/proc_devices.py new file mode 100644 index 00000000..4d2a4441 --- /dev/null +++ b/jc/parsers/proc_devices.py @@ -0,0 +1,166 @@ +"""jc - JSON Convert `/proc/devices` file parser + +Usage (cli): + + $ cat /proc/devices | jc --proc + +or + + $ jc /proc/devices + +or + + $ cat /proc/devices | jc --proc-devices + +Usage (module): + + import jc + result = jc.parse('proc', proc_devices_file) + +or + + import jc + result = jc.parse('proc_devices', proc_devices_file) + +Schema: + +Since devices can be members of multiple groups, the value for each device +is a list. + + { + "character": { + "": [ + string + ] + }, + "block": { + "": [ + string + ] + } + } + +Examples: + + $ cat /proc/devices | jc --proc -p + { + "character": { + "1": [ + "mem" + ], + "4": [ + "/dev/vc/0", + "tty", + "ttyS" + ], + "5": [ + "/dev/tty", + "/dev/console", + "/dev/ptmx", + "ttyprintk" + ], + "block": { + "7": [ + "loop" + ], + "8": [ + "sd" + ], + "9": [ + "md" + ] + } + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/devices` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + character: Dict = {} + block: Dict = {} + section = '' + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + if 'Character devices:' in line: + section = 'character' + continue + + if 'Block devices:' in line: + section = 'block' + continue + + devnum, group = line.split() + + if section == 'character': + if not devnum in character: + character[devnum] = [] + + character[devnum].append(group) + continue + + if section == 'block': + if not devnum in block: + block[devnum] = [] + + block[devnum].append(group) + continue + + if character or block: + raw_output = { + 'character': character, + 'block': block + } + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_diskstats.py b/jc/parsers/proc_diskstats.py new file mode 100644 index 00000000..c230b2f8 --- /dev/null +++ b/jc/parsers/proc_diskstats.py @@ -0,0 +1,248 @@ +"""jc - JSON Convert `/proc/diskstats` file parser + +Usage (cli): + + $ cat /proc/diskstats | jc --proc + +or + + $ jc /proc/diskstats + +or + + $ cat /proc/diskstats | jc --proc-diskstats + +Usage (module): + + import jc + result = jc.parse('proc', proc_diskstats_file) + +or + + import jc + result = jc.parse('proc_diskstats', proc_diskstats_file) + +Schema: + + [ + { + "maj": integer, + "min": integer, + "device": string, + "reads_completed": integer, + "reads_merged": integer, + "sectors_read": integer, + "read_time_ms": integer, + "writes_completed": integer, + "writes_merged": integer, + "sectors_written": integer, + "write_time_ms": integer, + "io_in_progress": integer, + "io_time_ms": integer, + "weighted_io_time_ms": integer, + "discards_completed_successfully": integer, + "discards_merged": integer, + "sectors_discarded": integer, + "discarding_time_ms": integer, + "flush_requests_completed_successfully": integer, + "flushing_time_ms": integer + } + ] + +Examples: + + $ cat /proc/diskstats | jc --proc -p + [ + { + "maj": 7, + "min": 0, + "device": "loop0", + "reads_completed": 48, + "reads_merged": 0, + "sectors_read": 718, + "read_time_ms": 19, + "writes_completed": 0, + "writes_merged": 0, + "sectors_written": 0, + "write_time_ms": 0, + "io_in_progress": 0, + "io_time_ms": 36, + "weighted_io_time_ms": 19, + "discards_completed_successfully": 0, + "discards_merged": 0, + "sectors_discarded": 0, + "discarding_time_ms": 0, + "flush_requests_completed_successfully": 0, + "flushing_time_ms": 0 + }, + { + "maj": 7, + "min": 1, + "device": "loop1", + "reads_completed": 41, + "reads_merged": 0, + "sectors_read": 688, + "read_time_ms": 17, + "writes_completed": 0, + "writes_merged": 0, + "sectors_written": 0, + "write_time_ms": 0, + "io_in_progress": 0, + "io_time_ms": 28, + "weighted_io_time_ms": 17, + "discards_completed_successfully": 0, + "discards_merged": 0, + "sectors_discarded": 0, + "discarding_time_ms": 0, + "flush_requests_completed_successfully": 0, + "flushing_time_ms": 0 + }, + ... + ] + + $ cat /proc/diskstats | jc --proc_diskstats -p -r + [ + { + "maj": "7", + "min": "0", + "device": "loop0", + "reads_completed": "48", + "reads_merged": "0", + "sectors_read": "718", + "read_time_ms": "19", + "writes_completed": "0", + "writes_merged": "0", + "sectors_written": "0", + "write_time_ms": "0", + "io_in_progress": "0", + "io_time_ms": "36", + "weighted_io_time_ms": "19", + "discards_completed_successfully": "0", + "discards_merged": "0", + "sectors_discarded": "0", + "discarding_time_ms": "0", + "flush_requests_completed_successfully": "0", + "flushing_time_ms": "0" + }, + { + "maj": "7", + "min": "1", + "device": "loop1", + "reads_completed": "41", + "reads_merged": "0", + "sectors_read": "688", + "read_time_ms": "17", + "writes_completed": "0", + "writes_merged": "0", + "sectors_written": "0", + "write_time_ms": "0", + "io_in_progress": "0", + "io_time_ms": "28", + "weighted_io_time_ms": "17", + "discards_completed_successfully": "0", + "discards_merged": "0", + "sectors_discarded": "0", + "discarding_time_ms": "0", + "flush_requests_completed_successfully": "0", + "flushing_time_ms": "0" + }, + { + "maj": "7", + "min": "2", + "device": "loop2", + "reads_completed": "119", + "reads_merged": "0", + "sectors_read": "2956", + "read_time_ms": "18", + "writes_completed": "0", + "writes_merged": "0", + "sectors_written": "0", + "write_time_ms": "0", + "io_in_progress": "0", + "io_time_ms": "56", + "weighted_io_time_ms": "18", + "discards_completed_successfully": "0", + "discards_merged": "0", + "sectors_discarded": "0", + "discarding_time_ms": "0", + "flush_requests_completed_successfully": "0", + "flushing_time_ms": "0" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils +from jc.parsers.universal import simple_table_parse + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/diskstats` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + for entry in proc_data: + for key in entry: + if key != 'device': + entry[key] = int(entry[key]) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + header = ( + 'maj min device reads_completed reads_merged sectors_read read_time_ms ' + 'writes_completed writes_merged sectors_written write_time_ms io_in_progress ' + 'io_time_ms weighted_io_time_ms discards_completed_successfully discards_merged ' + 'sectors_discarded discarding_time_ms flush_requests_completed_successfully ' + 'flushing_time_ms\n' + ) + data = header + data + cleandata = filter(None, data.splitlines()) + raw_output = simple_table_parse(cleandata) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_driver_rtc.py b/jc/parsers/proc_driver_rtc.py new file mode 100644 index 00000000..2bc40f33 --- /dev/null +++ b/jc/parsers/proc_driver_rtc.py @@ -0,0 +1,173 @@ +"""jc - JSON Convert `/proc/driver_rtc` file parser + +Usage (cli): + + $ cat /proc/driver_rtc | jc --proc + +or + + $ jc /proc/driver_rtc + +or + + $ cat /proc/driver_rtc | jc --proc-driver-rtc + +Usage (module): + + import jc + result = jc.parse('proc', proc_driver_rtc_file) + +or + + import jc + result = jc.parse('proc_driver_rtc', proc_driver_rtc_file) + +Schema: + +"yes" and "no" values are converted to `true`/`false`. Integer conversions +are attempted. If you do not want this behavior, then use `--raw` (cli) or +`raw=True` (module). + + { + "rtc_time": string, + "rtc_date": string, + "alrm_time": string, + "alrm_date": string, + "alarm_IRQ": boolean, + "alrm_pending": boolean, + "update IRQ enabled": boolean, + "periodic IRQ enabled": boolean, + "periodic IRQ frequency": integer, + "max user IRQ frequency": integer, + "24hr": boolean, + "periodic_IRQ": boolean, + "update_IRQ": boolean, + "HPET_emulated": boolean, + "BCD": boolean, + "DST_enable": boolean, + "periodic_freq": integer, + "batt_status": string + } + +Examples: + + $ cat /proc/driver_rtc | jc --proc -p + { + "rtc_time": "16:09:21", + "rtc_date": "2022-09-03", + "alrm_time": "00:00:00", + "alrm_date": "2022-09-03", + "alarm_IRQ": false, + "alrm_pending": false, + "update IRQ enabled": false, + "periodic IRQ enabled": false, + "periodic IRQ frequency": 1024, + "max user IRQ frequency": 64, + "24hr": true, + "periodic_IRQ": false, + "update_IRQ": false, + "HPET_emulated": true, + "BCD": true, + "DST_enable": false, + "periodic_freq": 1024, + "batt_status": "okay" + } + + $ cat /proc/driver_rtc | jc --proc -p -r + { + "rtc_time": "16:09:21", + "rtc_date": "2022-09-03", + "alrm_time": "00:00:00", + "alrm_date": "2022-09-03", + "alarm_IRQ": "no", + "alrm_pending": "no", + "update IRQ enabled": "no", + "periodic IRQ enabled": "no", + "periodic IRQ frequency": "1024", + "max user IRQ frequency": "64", + "24hr": "yes", + "periodic_IRQ": "no", + "update_IRQ": "no", + "HPET_emulated": "yes", + "BCD": "yes", + "DST_enable": "no", + "periodic_freq": "1024", + "batt_status": "okay" + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/driver_rtc` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + for key, val in proc_data.items(): + try: + proc_data[key] = int(val) + except: + pass + + if val == 'yes': + proc_data[key] = True + + if val == 'no': + proc_data[key] = False + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + split_line = line.split(':', maxsplit=1) + key = split_line[0].strip() + val = split_line[1].rsplit(maxsplit=1)[0] + raw_output[key] = val + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_filesystems.py b/jc/parsers/proc_filesystems.py new file mode 100644 index 00000000..91170de4 --- /dev/null +++ b/jc/parsers/proc_filesystems.py @@ -0,0 +1,122 @@ +"""jc - JSON Convert `/proc/filesystems` file parser + +Usage (cli): + + $ cat /proc/filesystems | jc --proc + +or + + $ jc /proc/filesystems + +or + + $ cat /proc/filesystems | jc --proc-filesystems + +Usage (module): + + import jc + result = jc.parse('proc', proc_filesystems_file) + +or + + import jc + result = jc.parse('proc_filesystems', proc_filesystems_file) + +Schema: + + [ + { + "filesystem": string, + "nodev": boolean + } + ] + +Examples: + + $ cat /proc/filesystems | jc --proc -p + [ + { + "filesystem": "sysfs", + "nodev": true + }, + { + "filesystem": "tmpfs", + "nodev": true + }, + { + "filesystem": "bdev", + "nodev": true + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/filesystems` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + split_line = line.split() + output_line = {'filesystem': split_line[-1]} + + if len(split_line) == 2: + output_line['nodev'] = True # type: ignore + else: + output_line['nodev'] = False # type: ignore + + raw_output.append(output_line) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_interrupts.py b/jc/parsers/proc_interrupts.py new file mode 100644 index 00000000..606cadc1 --- /dev/null +++ b/jc/parsers/proc_interrupts.py @@ -0,0 +1,207 @@ +"""jc - JSON Convert `/proc/interrupts` file parser + +Usage (cli): + + $ cat /proc/interrupts | jc --proc + +or + + $ jc /proc/interrupts + +or + + $ cat /proc/interrupts | jc --proc-interrupts + +Usage (module): + + import jc + result = jc.parse('proc', proc_interrupts_file) + +or + + import jc + result = jc.parse('proc_interrupts', proc_interrupts_file) + +Schema: + + [ + { + "irq": string, + "cpu_num": integer, + "interrupts": [ + integer + ], + "type": string, + "device": [ + string + ] + } + ] + +Examples: + + $ cat /proc/interrupts | jc --proc -p + [ + { + "irq": "0", + "cpu_num": 2, + "interrupts": [ + 18, + 0 + ], + "type": "IO-APIC", + "device": [ + "2-edge", + "timer" + ] + }, + { + "irq": "1", + "cpu_num": 2, + "interrupts": [ + 0, + 73 + ], + "type": "IO-APIC", + "device": [ + "1-edge", + "i8042" + ] + }, + ... + ] + + $ cat /proc/interrupts | jc --proc_interrupts -p -r + [ + { + "irq": "0", + "cpu_num": 2, + "interrupts": [ + "18", + "0" + ], + "type": "IO-APIC", + "device": [ + "2-edge", + "timer" + ] + }, + { + "irq": "1", + "cpu_num": 2, + "interrupts": [ + "0", + "73" + ], + "type": "IO-APIC", + "device": [ + "1-edge", + "i8042" + ] + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/interrupts` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + for entry in proc_data: + entry['interrupts'] = [int(x) for x in entry['interrupts']] + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + data_lines = data.splitlines() + + # get the number of cpus + cpu_num = len(data_lines[0].split()) + + for line in filter(None, data_lines): + + # skip non-data lines + if not ':' in line: + continue + + # process data lines + split_line = line.split() + irq = split_line.pop(0)[:-1] + + interrupts = [] + if irq == 'ERR' or irq == 'MIS': + interrupts.extend(split_line) + + elif irq.isdigit(): + for _ in range(cpu_num): + interrupts.append(split_line.pop(0)) + + interrupt_type = split_line.pop(0) + device = split_line + + else: + for _ in range(cpu_num): + interrupts.append(split_line.pop(0)) + + interrupt_type = ' '.join(split_line) + device = [] + + raw_output.append( + { + 'irq': irq, + 'cpu_num': cpu_num, + 'interrupts': interrupts, + 'type': interrupt_type, + 'device': device or None + } + ) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_iomem.py b/jc/parsers/proc_iomem.py new file mode 100644 index 00000000..4b526d7a --- /dev/null +++ b/jc/parsers/proc_iomem.py @@ -0,0 +1,130 @@ +"""jc - JSON Convert `/proc/iomem` file parser + +Usage (cli): + + $ cat /proc/iomem | jc --proc + +or + + $ jc /proc/iomem + +or + + $ cat /proc/iomem | jc --proc-iomem + +Usage (module): + + import jc + result = jc.parse('proc', proc_iomem_file) + +or + + import jc + result = jc.parse('proc_iomem', proc_iomem_file) + +Schema: + + [ + { + "start": string, + "end": string, + "device": string + } + ] + +Examples: + + $ cat /proc/iomem | jc --proc -p + [ + { + "start": "00000000", + "end": "00000fff", + "device": "Reserved" + }, + { + "start": "00001000", + "end": "0009e7ff", + "device": "System RAM" + }, + { + "start": "0009e800", + "end": "0009ffff", + "device": "Reserved" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/iomem` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + colon_split = line.split(':', maxsplit=1) + device = colon_split[1].strip() + mem_split = colon_split[0].split('-', maxsplit=1) + start = mem_split[0].strip() + end = mem_split[1].strip() + + raw_output.append( + { + 'start': start, + 'end': end, + 'device': device + } + ) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_ioports.py b/jc/parsers/proc_ioports.py new file mode 100644 index 00000000..0c861b0d --- /dev/null +++ b/jc/parsers/proc_ioports.py @@ -0,0 +1,113 @@ +"""jc - JSON Convert `/proc/ioports` file parser + +Usage (cli): + + $ cat /proc/ioports | jc --proc + +or + + $ jc /proc/ioports + +or + + $ cat /proc/ioports | jc --proc-ioports + +Usage (module): + + import jc + result = jc.parse('proc', proc_ioports_file) + +or + + import jc + result = jc.parse('proc_ioports', proc_ioports_file) + +Schema: + + [ + { + "start": string, + "end": string, + "device": string + } + ] + +Examples: + + $ cat /proc/ioports | jc --proc -p + [ + { + "start": "0000", + "end": "0cf7", + "device": "PCI Bus 0000:00" + }, + { + "start": "0000", + "end": "001f", + "device": "dma1" + }, + { + "start": "0020", + "end": "0021", + "device": "PNP0001:00" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils +import jc.parsers.proc_iomem as proc_iomem + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/ioports` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = proc_iomem.parse(data) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_loadavg.py b/jc/parsers/proc_loadavg.py new file mode 100644 index 00000000..dc234c71 --- /dev/null +++ b/jc/parsers/proc_loadavg.py @@ -0,0 +1,139 @@ +"""jc - JSON Convert `/proc/loadavg` file parser + +Usage (cli): + + $ cat /proc/loadavg | jc --proc + +or + + $ jc /proc/loadavg + +or + + $ cat /proc/loadavg | jc --proc-loadavg + +Usage (module): + + import jc + result = jc.parse('proc', proc_loadavg_file) + +or + + import jc + result = jc.parse('proc_loadavg', proc_loadavg_file) + +Schema: + +All values are integers. + + { + "load_1m": float, + "load_5m": float, + "load_15m": float, + "running": integer, + "available": integer, + "last_pid": integer + } + +Examples: + + $ cat /proc/loadavg | jc --proc -p + { + "load_1m": 0.0, + "load_5m": 0.01, + "load_15m": 0.03, + "running": 2, + "available": 111, + "last_pid": 2039 + } + + $ cat /proc/loadavg | jc --proc -p -r + { + "load_1m": "0.00", + "load_5m": "0.01", + "load_15m": "0.03", + "running": "2", + "available": "111", + "last_pid": "2039" + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/loadavg` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + float_list = {'load_1m', 'load_5m', 'load_15m'} + int_list = {'running', 'available', 'last_pid'} + + for key in proc_data: + if key in float_list: + proc_data[key] = float(proc_data[key]) + + if key in int_list: + proc_data[key] = int(proc_data[key]) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + load_1m, load_5m, load_15m, runnable, last_pid = data.split() + running, available = runnable.split('/') + + raw_output = { + 'load_1m': load_1m, + 'load_5m': load_5m, + 'load_15m': load_15m, + 'running': running, + 'available': available, + 'last_pid': last_pid + } + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_locks.py b/jc/parsers/proc_locks.py new file mode 100644 index 00000000..24d3cd58 --- /dev/null +++ b/jc/parsers/proc_locks.py @@ -0,0 +1,186 @@ +"""jc - JSON Convert `/proc/locks` file parser + +Usage (cli): + + $ cat /proc/locks | jc --proc + +or + + $ jc /proc/locks + +or + + $ cat /proc/locks | jc --proc-locks + +Usage (module): + + import jc + result = jc.parse('proc', proc_locks_file) + +or + + import jc + result = jc.parse('proc_locks', proc_locks_file) + +Schema: + + [ + { + "id": integer, + "class": string, + "type": string, + "access": string, + "pid": integer, + "maj": string, + "min": string, + "inode": integer, + "start": string, + "end": string + } + ] + +Examples: + + $ cat /proc/locks | jc --proc -p + [ + { + "id": 1, + "class": "POSIX", + "type": "ADVISORY", + "access": "WRITE", + "pid": 877, + "maj": "00", + "min": "19", + "inode": 812, + "start": "0", + "end": "EOF" + }, + { + "id": 2, + "class": "FLOCK", + "type": "ADVISORY", + "access": "WRITE", + "pid": 854, + "maj": "00", + "min": "19", + "inode": 805, + "start": "0", + "end": "EOF" + }, + ... + ] + + $ cat /proc/locks | jc --proc_locks -p -r + [ + { + "id": "1", + "class": "POSIX", + "type": "ADVISORY", + "access": "WRITE", + "pid": "877", + "maj": "00", + "min": "19", + "inode": "812", + "start": "0", + "end": "EOF" + }, + { + "id": "2", + "class": "FLOCK", + "type": "ADVISORY", + "access": "WRITE", + "pid": "854", + "maj": "00", + "min": "19", + "inode": "805", + "start": "0", + "end": "EOF" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/locks` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'id', 'pid', 'inode'} + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = int(entry[key]) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + id, class_, type_, access, pid, file, start, end = line.split() + maj, min, inode = file.split(':') + + raw_output.append( + { + 'id': id[:-1], + 'class': class_, + 'type': type_, + 'access': access, + 'pid': pid, + 'maj': maj, + 'min': min, + 'inode': inode, + 'start': start, + 'end': end + } + ) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_meminfo.py b/jc/parsers/proc_meminfo.py new file mode 100644 index 00000000..bf378374 --- /dev/null +++ b/jc/parsers/proc_meminfo.py @@ -0,0 +1,151 @@ +"""jc - JSON Convert `/proc/meminfo` file parser + +Usage (cli): + + $ cat /proc/meminfo | jc --proc + +or + + $ jc /proc/meminfo + +or + + $ cat /proc/meminfo | jc --proc-meminfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_meminfo_file) + +or + + import jc + result = jc.parse('proc_meminfo', proc_meminfo_file) + +Schema: + +All values are integers. + + { + integer + } + +Examples: + + $ cat /proc/meminfo | jc --proc -p + { + "MemTotal": 3997272, + "MemFree": 2760316, + "MemAvailable": 3386876, + "Buffers": 40452, + "Cached": 684856, + "SwapCached": 0, + "Active": 475816, + "Inactive": 322064, + "Active(anon)": 70216, + "Inactive(anon)": 148, + "Active(file)": 405600, + "Inactive(file)": 321916, + "Unevictable": 19476, + "Mlocked": 19476, + "SwapTotal": 3996668, + "SwapFree": 3996668, + "Dirty": 152, + "Writeback": 0, + "AnonPages": 92064, + "Mapped": 79464, + "Shmem": 1568, + "KReclaimable": 188216, + "Slab": 288096, + "SReclaimable": 188216, + "SUnreclaim": 99880, + "KernelStack": 5872, + "PageTables": 1812, + "NFS_Unstable": 0, + "Bounce": 0, + "WritebackTmp": 0, + "CommitLimit": 5995304, + "Committed_AS": 445240, + "VmallocTotal": 34359738367, + "VmallocUsed": 21932, + "VmallocChunk": 0, + "Percpu": 107520, + "HardwareCorrupted": 0, + "AnonHugePages": 0, + "ShmemHugePages": 0, + "ShmemPmdMapped": 0, + "FileHugePages": 0, + "FilePmdMapped": 0, + "HugePages_Total": 0, + "HugePages_Free": 0, + "HugePages_Rsvd": 0, + "HugePages_Surp": 0, + "Hugepagesize": 2048, + "Hugetlb": 0, + "DirectMap4k": 192320, + "DirectMap2M": 4001792, + "DirectMap1G": 2097152 + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/meminfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + key, val, *_ = line.replace(':', '').split() + raw_output[key] = int(val) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_modules.py b/jc/parsers/proc_modules.py new file mode 100644 index 00000000..18e35b15 --- /dev/null +++ b/jc/parsers/proc_modules.py @@ -0,0 +1,184 @@ +"""jc - JSON Convert `/proc/modules` file parser + +Usage (cli): + + $ cat /proc/modules | jc --proc + +or + + $ jc /proc/modules + +or + + $ cat /proc/modules | jc --proc-modules + +Usage (module): + + import jc + result = jc.parse('proc', proc_modules_file) + +or + + import jc + result = jc.parse('proc_modules', proc_modules_file) + +Schema: + + [ + { + "module": string, + "size": integer, + "used": integer, + "used_by": [ + string + ], + "status": string, + "location": string + } + ] + +Examples: + + $ cat /proc/modules | jc --proc -p + [ + { + "module": "binfmt_misc", + "size": 24576, + "used": 1, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": 16384, + "used": 0, + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": 36864, + "used": 1, + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] + + $ cat /proc/modules | jc --proc_modules -p -r + [ + { + "module": "binfmt_misc", + "size": "24576", + "used": "1", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0ab4000" + }, + { + "module": "vsock_loopback", + "size": "16384", + "used": "0", + "used_by": [], + "status": "Live", + "location": "0xffffffffc0a14000" + }, + { + "module": "vmw_vsock_virtio_transport_common", + "size": "36864", + "used": "1", + "used_by": [ + "vsock_loopback" + ], + "status": "Live", + "location": "0xffffffffc0a03000" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/modules` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'size', 'used'} + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = jc.utils.convert_to_int(entry[key]) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + module, size, used, used_by, status, location = line.split() + used_by_list = used_by.split(',')[:-1] + + raw_output.append( + { + 'module': module, + 'size': size, + 'used': used, + 'used_by': used_by_list, + 'status': status, + 'location': location + } + ) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_mtrr.py b/jc/parsers/proc_mtrr.py new file mode 100644 index 00000000..ea6e89e8 --- /dev/null +++ b/jc/parsers/proc_mtrr.py @@ -0,0 +1,182 @@ +"""jc - JSON Convert `/proc/mtrr` file parser + +Usage (cli): + + $ cat /proc/mtrr | jc --proc + +or + + $ jc /proc/mtrr + +or + + $ cat /proc/mtrr | jc --proc-mtrr + +Usage (module): + + import jc + result = jc.parse('proc', proc_mtrr_file) + +or + + import jc + result = jc.parse('proc_mtrr', proc_mtrr_file) + +Schema: + + [ + { + "register": string, + "type": string, + "base": string, + "base_mb": integer, + "size": integer, + "count": integer, + "": string # additional key/values are strings + } + ] + +Examples: + + $ cat /proc/mtrr | jc --proc -p + [ + { + "register": "reg00", + "type": "write-back", + "base": "0x000000000", + "base_mb": 0, + "size": 2048, + "count": 1 + }, + { + "register": "reg01", + "type": "write-back", + "base": "0x080000000", + "base_mb": 2048, + "size": 1024, + "count": 1 + }, + ... + ] + + $ cat /proc/mtrr | jc --proc_mtrr -p -r + [ + { + "register": "reg00", + "type": "write-back", + "base": "0x000000000", + "base_mb": "0", + "size": "2048MB", + "count": "1" + }, + { + "register": "reg01", + "type": "write-back", + "base": "0x080000000", + "base_mb": "2048", + "size": "1024MB", + "count": "1" + }, + ... + ] +""" +import re +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/mtrr` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'size', 'count', 'base_mb'} + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = jc.utils.convert_to_int(entry[key]) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + split_line = re.split(r',|:', line) + register = split_line.pop(0) + type_ = None + key_vals: list = [] + + base, base_mb = split_line.pop(0).split(maxsplit=1) + key_vals.append(base) + + base_mb = base_mb.replace('(', '').replace(')', '').replace('MB', '').strip() + key_vals.append(f'base_mb={base_mb}') + + for item in split_line: + if '=' in item: + key_vals.append(item.strip()) + + else: + type_ = item.strip() + + output_line = { + 'register': register, + 'type': type_ + } + + kv_dict = {} + + for item in key_vals: + key, val = item.split('=') + kv_dict[key.strip()] = val.strip() + + output_line.update(kv_dict) + raw_output.append(output_line) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_pagetypeinfo.py b/jc/parsers/proc_pagetypeinfo.py new file mode 100644 index 00000000..08ef08ba --- /dev/null +++ b/jc/parsers/proc_pagetypeinfo.py @@ -0,0 +1,224 @@ +"""jc - JSON Convert `/proc/pagetypeinfo` file parser + +Usage (cli): + + $ cat /proc/pagetypeinfo | jc --proc + +or + + $ jc /proc/pagetypeinfo + +or + + $ cat /proc/pagetypeinfo | jc --proc-pagetypeinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_pagetypeinfo_file) + +or + + import jc + result = jc.parse('proc_pagetypeinfo', proc_pagetypeinfo_file) + +Schema: + + { + "page_block_order": integer, + "pages_per_block": integer, + "free_pages": [ + { + "node": integer, + "zone": string, + "type": string, + "free": [ + integer # [0] + ] + ], + "num_blocks_type": [ + { + "node": integer, + "zone": string, + "unmovable": integer, + "movable": integer, + "reclaimable": integer, + "high_atomic": integer, + "isolate": integer + } + ] + } + + [0] array index correlates to the Order number. + E.g. free[0] is the value for Order 0 + +Examples: + + $ cat /proc/pagetypeinfo | jc --proc -p + { + "page_block_order": 9, + "pages_per_block": 512, + "free_pages": [ + { + "node": 0, + "zone": "DMA", + "type": "Unmovable", + "free": [ + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0 + ] + }, + ... + ], + "num_blocks_type": [ + { + "node": 0, + "zone": "DMA", + "unmovable": 1, + "movable": 7, + "reclaimable": 0, + "high_atomic": 0, + "isolate": 0 + }, + { + "node": 0, + "zone": "DMA32", + "unmovable": 8, + "movable": 1472, + "reclaimable": 48, + "high_atomic": 0, + "isolate": 0 + }, + { + "node": 0, + "zone": "Normal", + "unmovable": 120, + "movable": 345, + "reclaimable": 47, + "high_atomic": 0, + "isolate": 0 + } + ] + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/pagetypeinfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + section = '' + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + if line.startswith('Page block order:'): + raw_output['page_block_order'] = int(line.split(':', maxsplit=1)[1]) + continue + + if line.startswith('Pages per block:'): + raw_output['pages_per_block'] = int(line.split(':', maxsplit=1)[1]) + continue + + if line.startswith('Free pages count per migrate type at order'): + section = 'free_pages' + raw_output['free_pages'] = [] + continue + + if line.startswith('Number of blocks type'): + section = 'num_blocks_type' + raw_output['num_blocks_type'] = [] + continue + + # Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10 + # Node 0, zone DMA, type Unmovable 0 0 0 1 1 1 1 1 0 0 0 + if section == 'free_pages': + split_line = line.replace(',', ' ').split() + + output_line = { + 'node': int(split_line[1]), + 'zone': split_line[3], + 'type': split_line[5], + 'free': [int(x) for x in split_line[6:]] + } + + raw_output['free_pages'].append(output_line) + continue + + # Number of blocks type Unmovable Movable Reclaimable HighAtomic Isolate + # Node 0, zone DMA 1 7 0 0 0 + if section == 'num_blocks_type': + split_line = line.replace(',', ' ').split() + + output_line = { + 'node': int(split_line[1]), + 'zone': split_line[3], + 'unmovable': int(split_line[4]), + 'movable': int(split_line[5]), + 'reclaimable': int(split_line[6]), + 'high_atomic': int(split_line[7]), + 'isolate': int(split_line[8]), + } + + raw_output['num_blocks_type'].append(output_line) + continue + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_partitions.py b/jc/parsers/proc_partitions.py new file mode 100644 index 00000000..c04ab215 --- /dev/null +++ b/jc/parsers/proc_partitions.py @@ -0,0 +1,141 @@ +"""jc - JSON Convert `/proc/partitions` file parser + +Usage (cli): + + $ cat /proc/partitions | jc --proc + +or + + $ jc /proc/partitions + +or + + $ cat /proc/partitions | jc --proc-partitions + +Usage (module): + + import jc + result = jc.parse('proc', proc_partitions_file) + +or + + import jc + result = jc.parse('proc_partitions', proc_partitions_file) + +Schema: + + [ + { + "major": integer, + "minor": integer, + "num_blocks": integer, + "name": string + } + ] + +Examples: + + $ cat /proc/partitions | jc --proc -p + [ + { + "major": 7, + "minor": 0, + "num_blocks": 56896, + "name": "loop0" + }, + { + "major": 7, + "minor": 1, + "num_blocks": 56868, + "name": "loop1" + }, + ... + ] + + $ cat /proc/partitions | jc --proc_partitions -p -r + [ + { + "major": "7", + "minor": "0", + "num_blocks": "56896", + "name": "loop0" + }, + { + "major": "7", + "minor": "1", + "num_blocks": "56868", + "name": "loop1" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils +from jc.parsers.universal import simple_table_parse + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/partitions` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + for entry in proc_data: + for key in entry: + try: + entry[key] = int(entry[key]) + except Exception: + pass + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + cleandata = list(filter(None, data.splitlines())) + cleandata[0] = cleandata[0].replace('#', 'num_') + raw_output = simple_table_parse(cleandata) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_pid_fdinfo.py b/jc/parsers/proc_pid_fdinfo.py new file mode 100644 index 00000000..e8e99460 --- /dev/null +++ b/jc/parsers/proc_pid_fdinfo.py @@ -0,0 +1,217 @@ +"""jc - JSON Convert `/proc//fdinfo/` file parser + +Usage (cli): + + $ cat /proc/1/fdinfo/5 | jc --proc + +or + + $ jc /proc/1/fdinfo/5 + +or + + $ cat /proc/1/fdinfo/5 | jc --proc-pid-fdinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_fdinfo_file) + +or + + import jc + result = jc.parse('proc_pid_fdinfo', proc_pid_fdinfo_file) + +Schema: + +Any unspecified fields are strings. + + { + "pos": integer, + "flags": integer, + "mnt_id": integer, + "scm_fds": string, + "ino": integer, + "lock": string, + "epoll": { + "tfd": integer, + "events": string, + "data": string, + "pos": integer, + "ino": string, + "sdev": string + }, + "inotify": { + "wd": integer, + "ino": string, + "sdev": string, + "mask": string, + "ignored_mask": string, + "fhandle-bytes": string, + "fhandle-type": string, + "f_handle": string + }, + "fanotify": { + "flags": string, + "event-flags": string, + "mnt_id": string, + "mflags": string, + "mask": string, + "ignored_mask": string, + "ino": string, + "sdev": string, + "fhandle-bytes": string, + "fhandle-type": string, + "f_handle": string + }, + "clockid": integer, + "ticks": integer, + "settime flags": integer, + "it_value": [ + integer + ], + "it_interval": [ + integer + ] + } + +Examples: + + $ cat /proc/1/fdinfo/5 | jc --proc -p + { + "pos": 0, + "flags": 2, + "mnt_id": 9, + "ino": 63107, + "clockid": 0, + "ticks": 0, + "settime flags": 1, + "it_value": [ + 0, + 49406829 + ], + "it_interval": [ + 1, + 0 + ] + } +""" +import re +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc//fdinfo/` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + root_int_list = {'pos', 'flags', 'mnt_id', 'ino', 'clockid', 'ticks', + 'settime flags', 'size', 'count'} + epoll_int_list = {'tfd', 'pos'} + inotify_int_list = {'wd'} + + for key, val in proc_data.items(): + if key in root_int_list: + proc_data[key] = int(val) + + if 'epoll' in proc_data: + for key, val in proc_data['epoll'].items(): + if key in epoll_int_list: + proc_data['epoll'][key] = int(val) + + if 'inotify' in proc_data: + for key, val in proc_data['inotify'].items(): + if key in inotify_int_list: + proc_data['inotify'][key] = int(val) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + split_me = {'it_value:', 'it_interval:'} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + # epoll files + if line.startswith('tfd:'): + line_match = re.findall(r'(?P\S+):(?:\s+)?(?P\S+s*)', line) + if line_match: + raw_output.update({'epoll': {k.strip(): v.strip() for k, v in line_match}}) + continue + + # inotify files + if line.startswith('inotify'): + split_line = line[8:].split() + raw_output['inotify'] = {} + for item in split_line: + k, v = item.split(':', maxsplit=1) + raw_output['inotify'][k] = v + continue + + # fanotify files + if line.startswith('fanotify'): + split_line = line[9:].split() + + if not 'fanotify' in raw_output: + raw_output['fanotify'] = {} + + for item in split_line: + k, v = item.split(':', maxsplit=1) + raw_output['fanotify'][k] = v + continue + + # timerfd files + if line.split()[0] in split_me: + split_line = line.replace(':', '').replace('(', '').replace(')', '').replace(',', '').split() + raw_output[split_line[0]] = [int(x) for x in split_line[1:]] + continue + + key, val = line.split(':', maxsplit=1) + raw_output[key.strip()] = val.strip() + continue + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_pid_io.py b/jc/parsers/proc_pid_io.py new file mode 100644 index 00000000..8bfe71c1 --- /dev/null +++ b/jc/parsers/proc_pid_io.py @@ -0,0 +1,107 @@ +"""jc - JSON Convert `/proc//io` file parser + +Usage (cli): + + $ cat /proc/1/io | jc --proc + +or + + $ jc /proc/1/io + +or + + $ cat /proc/1/io | jc --proc-pid-io + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_io_file) + +or + + import jc + result = jc.parse('proc_pid_io', proc_pid_io_file) + +Schema: + +All values are integers. + + { + integer + } + +Examples: + + $ cat /proc/1/io | jc --proc -p + { + "rchar": 4699288382, + "wchar": 2931802997, + "syscr": 661897, + "syscw": 890910, + "read_bytes": 168468480, + "write_bytes": 27357184, + "cancelled_write_bytes": 16883712 + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc//io` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + key, val = line.split(':', maxsplit=1) + raw_output[key] = int(val) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_pid_maps.py b/jc/parsers/proc_pid_maps.py new file mode 100644 index 00000000..22c8765b --- /dev/null +++ b/jc/parsers/proc_pid_maps.py @@ -0,0 +1,191 @@ +"""jc - JSON Convert `/proc//maps` file parser + +Usage (cli): + + $ cat /proc/1/maps | jc --proc + +or + + $ jc /proc/1/maps + +or + + $ cat /proc/1/maps | jc --proc-pid-maps + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_maps_file) + +or + + import jc + result = jc.parse('proc_pid_maps', proc_pid_maps_file) + +Schema: + + [ + { + "start": string, + "end": string, + "perms": [ + string + ], + "offset": string, + "inode": integer, + "pathname": string, + "maj": string, + "min": string + } + ] + +Examples: + + $ cat /proc/1/maps | jc --proc -p + [ + { + "perms": [ + "read", + "private" + ], + "offset": "00000000", + "inode": 798126, + "pathname": "/usr/lib/systemd/systemd", + "start": "55a9e753c000", + "end": "55a9e7570000", + "maj": "fd", + "min": "00" + }, + { + "perms": [ + "read", + "execute", + "private" + ], + "offset": "00034000", + "inode": 798126, + "pathname": "/usr/lib/systemd/systemd", + "start": "55a9e7570000", + "end": "55a9e763a000", + "maj": "fd", + "min": "00" + }, + ... + ] + + $ cat /proc/1/maps | jc --proc-pid-maps -p -r + [ + { + "address": "55a9e753c000-55a9e7570000", + "perms": "r--p", + "offset": "00000000", + "dev": "fd:00", + "inode": "798126", + "pathname": "/usr/lib/systemd/systemd" + }, + { + "address": "55a9e7570000-55a9e763a000", + "perms": "r-xp", + "offset": "00034000", + "dev": "fd:00", + "inode": "798126", + "pathname": "/usr/lib/systemd/systemd" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils +from jc.parsers.universal import simple_table_parse + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc//maps` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'inode'} + + perms_map = { + 'r': 'read', + 'w': 'write', + 'x': 'execute', + 's': 'shared', + 'p': 'private', + '-': None + } + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = int(entry[key]) + + if 'address' in entry: + start, end = entry['address'].split('-') + entry['start'] = start + entry['end'] = end + del entry['address'] + + if 'perms' in entry: + perms_list = [perms_map[x] for x in entry['perms'] if perms_map[x]] + entry['perms'] = perms_list + + if 'dev' in entry: + maj, min = entry['dev'].split(':', maxsplit=1) + entry['maj'] = maj + entry['min'] = min + del entry['dev'] + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + header = 'address perms offset dev inode pathname\n' + data = header + data + raw_output = simple_table_parse(data.splitlines()) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_pid_mountinfo.py b/jc/parsers/proc_pid_mountinfo.py new file mode 100644 index 00000000..72399911 --- /dev/null +++ b/jc/parsers/proc_pid_mountinfo.py @@ -0,0 +1,258 @@ +"""jc - JSON Convert `/proc//mountinfo` file parser + +Usage (cli): + + $ cat /proc/1/mountinfo | jc --proc + +or + + $ jc /proc/1/mountinfo + +or + + $ cat /proc/1/mountinfo | jc --proc-pid-mountinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_pid_mountinfo_file) + +or + + import jc + result = jc.parse('proc_pid_mountinfo', proc_pid_mountinfo_file) + +Schema: + + [ + { + "mount_id": integer, + "parent_id": integer, + "maj": integer, + "min": integer, + "root": string, + "mount_point": string, + "mount_options": [ + string + ], + "optional_fields": { # [0] + "": integer # [1] + }, + "fs_type": string, + "mount_source": string, + "super_options": [ + string + ], + "super_options_fields": { + "": string + } + } + ] + + [0] if empty, then private mount + [1] unbindable will always have a value of 0 + +Examples: + + $ cat /proc/1/mountinfo | jc --proc -p + [ + { + "mount_id": 24, + "parent_id": 30, + "maj": 0, + "min": 22, + "root": "/", + "mount_point": "/sys", + "mount_options": [ + "rw", + "nosuid", + "nodev", + "noexec", + "relatime" + ], + "optional_fields": { + "master": 1, + "shared": 7 + }, + "fs_type": "sysfs", + "mount_source": "sysfs", + "super_options": [ + "rw" + ] + }, + { + "mount_id": 25, + "parent_id": 30, + "maj": 0, + "min": 23, + "root": "/", + "mount_point": "/proc", + "mount_options": [ + "rw", + "nosuid", + "nodev", + "noexec", + "relatime" + ], + "optional_fields": { + "shared": 14 + }, + "fs_type": "proc", + "mount_source": "proc", + "super_options": [ + "rw" + ] + }, + ... + ] + + $ cat /proc/1/mountinfo | jc --proc_pid-mountinfo -p -r + [ + { + "mount_id": "24", + "parent_id": "30", + "maj": "0", + "min": "22", + "root": "/", + "mount_point": "/sys", + "mount_options": "rw,nosuid,nodev,noexec,relatime", + "optional_fields": "master:1 shared:7 ", + "fs_type": "sysfs", + "mount_source": "sysfs", + "super_options": "rw" + }, + { + "mount_id": "25", + "parent_id": "30", + "maj": "0", + "min": "23", + "root": "/", + "mount_point": "/proc", + "mount_options": "rw,nosuid,nodev,noexec,relatime", + "optional_fields": "shared:14 ", + "fs_type": "proc", + "mount_source": "proc", + "super_options": "rw" + }, + ... + ] +""" +import re +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc//mountinfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'mount_id', 'parent_id', 'maj', 'min'} + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = int(entry[key]) + + if 'mount_options' in entry: + entry['mount_options'] = entry['mount_options'].split(',') + + if 'optional_fields' in entry: + if 'unbindable' in entry['optional_fields']: + entry['optional_fields'] = {'unbindable': 0} + else: + entry['optional_fields'] = {x.split(':')[0]: int(x.split(':')[1]) for x in entry['optional_fields'].split()} + + if 'super_options' in entry: + if entry['super_options']: + super_options_split = entry['super_options'].split(',') + s_options = [x for x in super_options_split if '=' not in x] + s_options_fields = [x for x in super_options_split if '=' in x] + + if s_options: + entry['super_options'] = s_options + else: + del entry['super_options'] + + if s_options_fields: + if not 'super_options_fields' in entry: + entry['super_options_fields'] = {} + + for field in s_options_fields: + key, val = field.split('=') + entry['super_options_fields'][key] = val + + else: + del entry['super_options'] + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + line_pattern = re.compile(r''' + ^(?P\d+)\s + (?P\d+)\s + (?P\d+): + (?P\d+)\s + (?P\S+)\s + (?P\S+)\s + (?P\S+)\s? + # (?P(?:\s?\S+:\S+\s?)*)\s?-\s + (?P(?:\s?(?:\S+:\S+|unbindable)\s?)*)\s?-\s + (?P\S+)\s + (?P\S+)\s + (?P\S+)? + ''', re.VERBOSE + ) + + for line in filter(None, data.splitlines()): + + line_match = line_pattern.search(line) + if line_match: + raw_output.append(line_match.groupdict()) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_pid_numa_maps.py b/jc/parsers/proc_pid_numa_maps.py new file mode 100644 index 00000000..f05714bc --- /dev/null +++ b/jc/parsers/proc_pid_numa_maps.py @@ -0,0 +1,185 @@ +"""jc - JSON Convert `/proc//numa_maps` file parser + +This parser will attempt to convert number values to integers. If that is +not desired, please use the `--raw` option (cli) or `raw=True` argument +(module). + +Usage (cli): + + $ cat /proc/1/numa_maps | jc --proc + +or + + $ jc /proc/1/numa_maps + +or + + $ cat /proc/1/numa_maps | jc --proc-numa-maps + +Usage (module): + + import jc + result = jc.parse('proc', proc_numa_maps_file) + +or + + import jc + result = jc.parse('proc_numa_maps', proc_numa_maps_file) + +Schema: + +Integer conversion for Key/value pairs will be attempted. + + [ + { + "address": string, + "policy": string, + "": string/integer, + "options": [ + string # [0] + ] + } + ] + + [0] remaining individual words that are not part of a key/value pair + +Examples: + + $ cat /proc/1/numa_maps | jc --proc -p + [ + { + "address": "7f53b5083000", + "policy": "default", + "file": "/usr/lib/x86_64-linux-gnu/ld-2.32.so", + "anon": 2, + "dirty": 2, + "N0": 2, + "kernelpagesize_kB": 4 + }, + { + "address": "7ffd1b23e000", + "policy": "default", + "anon": 258, + "dirty": 258, + "N0": 258, + "kernelpagesize_kB": 4, + "options": [ + "stack" + ] + }, + ... + ] + + $ cat /proc/1/numa_maps | jc --proc_numa_maps -p -r + [ + { + "address": "7f53b5083000", + "policy": "default", + "file": "/usr/lib/x86_64-linux-gnu/ld-2.32.so", + "anon": "2", + "dirty": "2", + "N0": "2", + "kernelpagesize_kB": "4" + }, + { + "address": "7ffd1b23e000", + "policy": "default", + "anon": "258", + "dirty": "258", + "N0": "258", + "kernelpagesize_kB": "4", + "options": [ + "stack" + ] + }, + ... + ] +""" +from typing import List, Dict +import jc.utils +from jc.parsers.universal import simple_table_parse + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc//numa_maps` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + for entry in proc_data: + for key, val in entry.items(): + try: + entry[key] = int(val) + except Exception: + pass + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + header = 'address policy details\n' + data = header + data + + raw_output = simple_table_parse(data.splitlines()) + + for row in raw_output: + if 'details' in row: + detail_split = row['details'].split() + + options = [] + for item in detail_split: + if '=' in item: + key, val = item.split('=') + row.update({key: val}) + else: + options.append(item) + + if options: + row['options'] = options + + del row['details'] + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_slabinfo.py b/jc/parsers/proc_slabinfo.py new file mode 100644 index 00000000..9ebbde1e --- /dev/null +++ b/jc/parsers/proc_slabinfo.py @@ -0,0 +1,157 @@ +"""jc - JSON Convert `/proc/slabinfo` file parser + +Usage (cli): + + $ cat /proc/slabinfo | jc --proc + +or + + $ jc /proc/slabinfo + +or + + $ cat /proc/slabinfo | jc --proc-slabinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_slabinfo_file) + +or + + import jc + result = jc.parse('proc_slabinfo', proc_slabinfo_file) + +Schema: + + [ + { + "name": string, + "active_objs": integer, + "num_objs": integer, + "obj_size": integer, + "obj_per_slab": integer, + "pages_per_slab": integer, + "tunables": { + "limit": integer, + "batch_count": integer, + "shared_factor": integer + }, + "slabdata": { + "active_slabs": integer, + "num_slabs": integer, + "shared_avail": integer + } + ] + +Examples: + + $ cat /proc/slabinfo | jc --proc -p + [ + { + "name": "ext4_groupinfo_4k", + "active_objs": 224, + "num_objs": 224, + "obj_size": 144, + "obj_per_slab": 56, + "pages_per_slab": 2, + "tunables": { + "limit": 0, + "batch_count": 0, + "shared_factor": 0 + }, + "slabdata": { + "active_slabs": 4, + "num_slabs": 4, + "shared_avail": 0 + } + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/slabinfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + cleandata = data.splitlines()[2:] + + for line in filter(None, cleandata): + + line = line.replace(':', ' ') + split_line = line.split() + + raw_output.append( + { + 'name': split_line[0], + 'active_objs': int(split_line[1]), + 'num_objs': int(split_line[2]), + 'obj_size': int(split_line[3]), + 'obj_per_slab': int(split_line[4]), + 'pages_per_slab': int(split_line[5]), + 'tunables': { + 'limit': int(split_line[7]), + 'batch_count': int(split_line[8]), + 'shared_factor': int(split_line[9]) + }, + 'slabdata': { + 'active_slabs': int(split_line[11]), + 'num_slabs': int(split_line[12]), + 'shared_avail': int(split_line[13]) + } + } + ) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_softirqs.py b/jc/parsers/proc_softirqs.py new file mode 100644 index 00000000..d4068ec1 --- /dev/null +++ b/jc/parsers/proc_softirqs.py @@ -0,0 +1,129 @@ +"""jc - JSON Convert `/proc/softirqs` file parser + +Usage (cli): + + $ cat /proc/softirqs | jc --proc + +or + + $ jc /proc/softirqs + +or + + $ cat /proc/softirqs | jc --proc-softirqs + +Usage (module): + + import jc + result = jc.parse('proc', proc_softirqs_file) + +or + + import jc + result = jc.parse('proc_softirqs', proc_softirqs_file) + +Schema: + + [ + { + "counter": string, + "CPU": integer, + } + ] + +Examples: + + $ cat /proc/softirqs | jc --proc -p + [ + { + "counter": "HI", + "CPU0": 1, + "CPU1": 34056, + "CPU2": 0, + "CPU3": 0, + "CPU4": 0 + }, + { + "counter": "TIMER", + "CPU0": 322970, + "CPU1": 888166, + "CPU2": 0, + "CPU3": 0, + "CPU4": 0 + }, + ... + ] +""" +from typing import List, Dict +import jc.utils +from jc.parsers.universal import simple_table_parse + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/softirqs` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + cleandata = list(filter(None, data.splitlines())) + cleandata[0] = 'counter ' + cleandata[0] + raw_output = simple_table_parse(cleandata) + + for item in raw_output: + if 'counter' in item: + item['counter'] = item['counter'][:-1] + + for key in item: + try: + item[key] = int(item[key]) + except Exception: + pass + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_stat.py b/jc/parsers/proc_stat.py new file mode 100644 index 00000000..99f974cc --- /dev/null +++ b/jc/parsers/proc_stat.py @@ -0,0 +1,250 @@ +"""jc - JSON Convert `/proc/stat` file parser + +Usage (cli): + + $ cat /proc/stat | jc --proc + +or + + $ jc /proc/stat + +or + + $ cat /proc/stat | jc --proc-stat + +Usage (module): + + import jc + result = jc.parse('proc', proc_stat_file) + +or + + import jc + result = jc.parse('proc_stat', proc_stat_file) + +Schema: + + { + "cpu": { + "user": integer, + "nice": integer, + "system": integer, + "idle": integer, + "iowait": integer, + "irq": integer, + "softirq": integer, + "steal": integer, + "guest": integer, + "guest_nice": integer + }, + "cpu": { + "user": integer, + "nice": integer, + "system": integer, + "idle": integer, + "iowait": integer, + "irq": integer, + "softirq": integer, + "steal": integer, + "guest": integer, + "guest_nice": integer + }, + "interrupts": [ + integer + ], + "context_switches": integer, + "boot_time": integer, + "processes": integer, + "processes_running": integer, + "processes_blocked": integer, + "softirq": [ + integer + ] + } + +Examples: + + $ cat /proc/stat | jc --proc -p + { + "cpu": { + "user": 6002, + "nice": 152, + "system": 8398, + "idle": 3444436, + "iowait": 448, + "irq": 0, + "softirq": 1174, + "steal": 0, + "guest": 0, + "guest_nice": 0 + }, + "cpu0": { + "user": 2784, + "nice": 137, + "system": 4367, + "idle": 1732802, + "iowait": 225, + "irq": 0, + "softirq": 221, + "steal": 0, + "guest": 0, + "guest_nice": 0 + }, + "cpu1": { + "user": 3218, + "nice": 15, + "system": 4031, + "idle": 1711634, + "iowait": 223, + "irq": 0, + "softirq": 953, + "steal": 0, + "guest": 0, + "guest_nice": 0 + }, + "interrupts": [ + 2496709, + 18, + 73, + 0, + 0, + ... + ], + "context_switches": 4622716, + "boot_time": 1662154781, + "processes": 9831, + "processes_running": 1, + "processes_blocked": 0, + "softirq": [ + 3478985, + 35230, + 1252057, + 3467, + 128583, + 51014, + 0, + 171199, + 1241297, + 0, + 596138 + ] + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/stat` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + if line.startswith('cpu'): + split_line = line.split() + cpu_num = split_line[0] + raw_output[cpu_num] = { + 'user': int(split_line[1]), + 'nice': int(split_line[2]), + 'system': int(split_line[3]), + 'idle': int(split_line[4]) + } + + if len(split_line) > 5: + raw_output[cpu_num]['iowait'] = int(split_line[5]) + + if len(split_line) > 6: + raw_output[cpu_num]['irq'] = int(split_line[6]) + raw_output[cpu_num]['softirq'] = int(split_line[7]) + + if len(split_line) > 8: + raw_output[cpu_num]['steal'] = int(split_line[8]) + + if len(split_line) > 9: + raw_output[cpu_num]['guest'] = int(split_line[9]) + + if len(split_line) > 10: + raw_output[cpu_num]['guest_nice'] = int(split_line[10]) + + continue + + if line.startswith('intr '): + split_line = line.split() + raw_output['interrupts'] = [int(x) for x in split_line[1:]] + continue + + if line.startswith('ctxt '): + raw_output['context_switches'] = int(line.split(maxsplit=1)[1]) + continue + + if line.startswith('btime '): + raw_output['boot_time'] = int(line.split(maxsplit=1)[1]) + continue + + if line.startswith('processes '): + raw_output['processes'] = int(line.split(maxsplit=1)[1]) + continue + + if line.startswith('procs_running '): + raw_output['processes_running'] = int(line.split(maxsplit=1)[1]) + continue + + if line.startswith('procs_blocked '): + raw_output['processes_blocked'] = int(line.split(maxsplit=1)[1]) + continue + + if line.startswith('softirq '): + split_line = line.split() + raw_output['softirq'] = [int(x) for x in split_line[1:]] + continue + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_swaps.py b/jc/parsers/proc_swaps.py new file mode 100644 index 00000000..2669159d --- /dev/null +++ b/jc/parsers/proc_swaps.py @@ -0,0 +1,132 @@ +"""jc - JSON Convert `/proc/swaps` file parser + +Usage (cli): + + $ cat /proc/swaps | jc --proc + +or + + $ jc /proc/swaps + +or + + $ cat /proc/swaps | jc --proc-swaps + +Usage (module): + + import jc + result = jc.parse('proc', proc_swaps_file) + +or + + import jc + result = jc.parse('proc_swaps', proc_swaps_file) + +Schema: + + [ + { + "filename": string, + "type": string, + "size": integer, + "used": integer, + "priority": integer + } + ] + +Examples: + + $ cat /proc/swaps | jc --proc -p + [ + { + "filename": "/swap.img", + "type": "file", + "size": 3996668, + "used": 0, + "priority": -2 + }, + ... + ] + + $ cat /proc/swaps | jc --proc_swaps -p -r + [ + { + "filename": "/swap.img", + "type": "file", + "size": "3996668", + "used": "0", + "priority": "-2" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils +from jc.parsers.universal import simple_table_parse + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/swaps` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + int_list = {'size', 'used', 'priority'} + + for entry in proc_data: + for key in entry: + if key in int_list: + entry[key] = jc.utils.convert_to_int(entry[key]) + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + + cleandata = list(filter(None, data.splitlines())) + cleandata[0] = cleandata[0].lower() + raw_output = simple_table_parse(cleandata) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_uptime.py b/jc/parsers/proc_uptime.py new file mode 100644 index 00000000..abea777f --- /dev/null +++ b/jc/parsers/proc_uptime.py @@ -0,0 +1,104 @@ +"""jc - JSON Convert `/proc/uptime` file parser + +Usage (cli): + + $ cat /proc/uptime | jc --proc + +or + + $ jc /proc/uptime + +or + + $ cat /proc/uptime | jc --proc-uptime + +Usage (module): + + import jc + result = jc.parse('proc', proc_uptime_file) + +or + + import jc + result = jc.parse('proc_uptime', proc_uptime_file) + +Schema: + + { + "up_time": float, + "idle_time": float + } + +Examples: + + $ cat /proc/uptime | jc --proc -p + { + "up_time": 46901.13, + "idle_time": 46856.66 + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/uptime` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + uptime, idletime = data.split() + + raw_output = { + 'up_time': float(uptime), + 'idle_time': float(idletime) + } + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_version.py b/jc/parsers/proc_version.py new file mode 100644 index 00000000..8b888274 --- /dev/null +++ b/jc/parsers/proc_version.py @@ -0,0 +1,127 @@ +"""jc - JSON Convert `/proc/version` file parser + +> Note: This parser will parse `/proc/version` files that follow the +> common format used by most popular linux distributions. + +Usage (cli): + + $ cat /proc/version | jc --proc + +or + + $ jc /proc/version + +or + + $ cat /proc/version | jc --proc-version + +Usage (module): + + import jc + result = jc.parse('proc', proc_version_file) + +or + + import jc + result = jc.parse('proc_version', proc_version_file) + +Schema: + + { + "version": string, + "email": string, + "gcc": string, + "build": string, + "flags": string/null, + "date": string + } + +Examples: + + $ cat /proc/version | jc --proc -p + { + "version": "5.8.0-63-generic", + "email": "buildd@lcy01-amd64-028", + "gcc": "gcc (Ubuntu 10.3.0-1ubuntu1~20.10) 10.3.0, GNU ld (GNU Binutils for Ubuntu) 2.35.1", + "build": "#71-Ubuntu", + "flags": "SMP", + "date": "Tue Jul 13 15:59:12 UTC 2021" + } +""" +import re +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/version` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +# inspired by https://gist.github.com/ty2/ad61340e7a4067def2e3c709496bca9d +version_pattern = re.compile(r''' + Linux\ version\ (?P\S+)\s + \((?P\S+?)\)\s + \((?Pgcc.+)\)\s + (?P\#\d+(\S+)?)\s + (?P.*)? + (?P(Sun|Mon|Tue|Wed|Thu|Fri|Sat).+) + ''', re.VERBOSE +) + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + version_match = version_pattern.match(data) + + if version_match: + + ver_dict = version_match.groupdict() + raw_output = {x: y.strip() or None for x, y in ver_dict.items()} + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_vmallocinfo.py b/jc/parsers/proc_vmallocinfo.py new file mode 100644 index 00000000..86f58eed --- /dev/null +++ b/jc/parsers/proc_vmallocinfo.py @@ -0,0 +1,194 @@ +"""jc - JSON Convert `/proc/vmallocinfo` file parser + +This parser will attempt to convert number values to integers. If that is +not desired, please use the `--raw` option (cli) or `raw=True` argument +(module). + +Usage (cli): + + $ cat /proc/vmallocinfo | jc --proc + +or + + $ jc /proc/vmallocinfo + +or + + $ cat /proc/vmallocinfo | jc --proc-vmallocinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_vmallocinfo_file) + +or + + import jc + result = jc.parse('proc_vmallocinfo', proc_vmallocinfo_file) + +Schema: + + [ + { + "start": string, + "end": string, + "size": integer, + "caller": string, + "options": [ + string + ], + "phys": string + "pages": integer, + "N": integer + } + ] + +Examples: + + $ cat /proc/vmallocinfo | jc --proc -p + [ + { + "start": "0xffffb3c1c0000000", + "end": "0xffffb3c1c0005000", + "size": 20480, + "caller": "map_irq_stack+0x93/0xe0", + "options": [ + "vmap" + ], + "phys": "0x00000000bfefe000" + }, + { + "start": "0xffffb3c1c0005000", + "end": "0xffffb3c1c0007000", + "size": 8192, + "caller": "acpi_os_map_iomem+0x1ac/0x1c0", + "options": [ + "ioremap" + ], + "phys": "0x00000000bfeff000" + }, + ... + ] + + $ cat /proc/vmallocinfo | jc --proc -p -r + [ + { + "start": "0xffffb3c1c0000000", + "end": "0xffffb3c1c0005000", + "size": "20480", + "caller": "map_irq_stack+0x93/0xe0", + "options": [ + "vmap" + ], + "phys": "0x00000000bfefe000" + }, + { + "start": "0xffffb3c1c0005000", + "end": "0xffffb3c1c0007000", + "size": "8192", + "caller": "acpi_os_map_iomem+0x1ac/0x1c0", + "options": [ + "ioremap" + ], + "phys": "0x00000000bfeff000" + }, + ... + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/vmallocinfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + for entry in proc_data: + for key in entry: + if isinstance(entry[key], str): + try: + entry[key] = int(entry[key]) + except Exception: + pass + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + output_line: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + area, size, details = line.split(maxsplit=2) + start, end = area.split('-', maxsplit=1) + detail_split = details.split() + caller = '' + options: List = [] + + if details == 'unpurged vm_area': + caller = 'unpurged vm_area' + + else: + caller = detail_split[0] + for item in detail_split[1:]: + if '=' in item: + key, val = item.split('=') + output_line.update({key: val}) + else: + options.append(item) + + output_line = { + 'start': start, + 'end': end, + 'size': size, + 'caller': caller or None, + 'options': options + } + + if output_line: + raw_output.append(output_line) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_vmstat.py b/jc/parsers/proc_vmstat.py new file mode 100644 index 00000000..128d0f70 --- /dev/null +++ b/jc/parsers/proc_vmstat.py @@ -0,0 +1,117 @@ +"""jc - JSON Convert `/proc/vmstat` file parser + +Usage (cli): + + $ cat /proc/vmstat | jc --proc + +or + + $ jc /proc/vmstat + +or + + $ cat /proc/vmstat | jc --proc-vmstat + +Usage (module): + + import jc + result = jc.parse('proc', proc_vmstat_file) + +or + + import jc + result = jc.parse('proc_vmstat', proc_vmstat_file) + +Schema: + +All values are integers. + + { + integer + } + +Examples: + + $ cat /proc/vmstat | jc --proc -p + { + "nr_free_pages": 615337, + "nr_zone_inactive_anon": 39, + "nr_zone_active_anon": 34838, + "nr_zone_inactive_file": 104036, + "nr_zone_active_file": 130601, + "nr_zone_unevictable": 4897, + "nr_zone_write_pending": 45, + "nr_mlock": 4897, + "nr_page_table_pages": 548, + "nr_kernel_stack": 5984, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 1910597, + "numa_miss": 0, + "numa_foreign": 0, + ... + } +""" +from typing import Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/vmstat` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + key, val = line.split(maxsplit=1) + raw_output[key] = int(val) + + return raw_output if raw else _process(raw_output) diff --git a/jc/parsers/proc_zoneinfo.py b/jc/parsers/proc_zoneinfo.py new file mode 100644 index 00000000..ec3db99b --- /dev/null +++ b/jc/parsers/proc_zoneinfo.py @@ -0,0 +1,441 @@ +"""jc - JSON Convert `/proc/zoneinfo` file parser + +Usage (cli): + + $ cat /proc/zoneinfo | jc --proc + +or + + $ jc /proc/zoneinfo + +or + + $ cat /proc/zoneinfo | jc --proc-zoneinfo + +Usage (module): + + import jc + result = jc.parse('proc', proc_zoneinfo_file) + +or + + import jc + result = jc.parse('proc_zoneinfo', proc_zoneinfo_file) + +Schema: + +All values are integers. + + [ + { + "node": integer, + "": { + "pages": { + "free": integer, + "min": integer, + "low": integer, + "high": integer, + "spanned": integer, + "present": integer, + "managed": integer, + "protection": [ + integer + ], + "": integer + }, + "pagesets": [ + { + "cpu": integer, + "count": integer, + "high": integer, + "batch": integer, + "vm stats threshold": integer, + "": integer + } + ] + }, + "": integer, # [0] + } + ] + + [0] per-node stats + +Examples: + + $ cat /proc/zoneinfo | jc --proc -p + [ + { + "node": 0, + "DMA": { + "pages": { + "free": 3832, + "min": 68, + "low": 85, + "high": 102, + "spanned": 4095, + "present": 3997, + "managed": 3976, + "protection": [ + 0, + 2871, + 3795, + 3795, + 3795 + ], + "nr_free_pages": 3832, + "nr_zone_inactive_anon": 0, + "nr_zone_active_anon": 0, + "nr_zone_inactive_file": 0, + "nr_zone_active_file": 0, + "nr_zone_unevictable": 0, + "nr_zone_write_pending": 0, + "nr_mlock": 0, + "nr_page_table_pages": 0, + "nr_kernel_stack": 0, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 3, + "numa_miss": 0, + "numa_foreign": 0, + "numa_interleave": 1, + "numa_local": 3, + "numa_other": 0 + }, + "pagesets": [ + { + "cpu": 0, + "count": 0, + "high": 0, + "batch": 1, + "vm stats threshold": 4 + }, + { + "cpu": 1, + "count": 0, + "high": 0, + "batch": 1, + "vm stats threshold": 4, + "node_unreclaimable": 0, + "start_pfn": 1 + } + ] + }, + "nr_inactive_anon": 39, + "nr_active_anon": 34839, + "nr_inactive_file": 104172, + "nr_active_file": 130748, + "nr_unevictable": 4897, + "nr_slab_reclaimable": 49017, + "nr_slab_unreclaimable": 26177, + "nr_isolated_anon": 0, + "nr_isolated_file": 0, + "workingset_nodes": 0, + "workingset_refault": 0, + "workingset_activate": 0, + "workingset_restore": 0, + "workingset_nodereclaim": 0, + "nr_anon_pages": 40299, + "nr_mapped": 25140, + "nr_file_pages": 234396, + "nr_dirty": 0, + "nr_writeback": 0, + "nr_writeback_temp": 0, + "nr_shmem": 395, + "nr_shmem_hugepages": 0, + "nr_shmem_pmdmapped": 0, + "nr_file_hugepages": 0, + "nr_file_pmdmapped": 0, + "nr_anon_transparent_hugepages": 0, + "nr_vmscan_write": 0, + "nr_vmscan_immediate_reclaim": 0, + "nr_dirtied": 168223, + "nr_written": 144616, + "nr_kernel_misc_reclaimable": 0, + "nr_foll_pin_acquired": 0, + "nr_foll_pin_released": 0, + "DMA32": { + "pages": { + "free": 606010, + "min": 12729, + "low": 15911, + "high": 19093, + "spanned": 1044480, + "present": 782288, + "managed": 758708, + "protection": [ + 0, + 0, + 924, + 924, + 924 + ], + "nr_free_pages": 606010, + "nr_zone_inactive_anon": 4, + "nr_zone_active_anon": 17380, + "nr_zone_inactive_file": 41785, + "nr_zone_active_file": 64545, + "nr_zone_unevictable": 5, + "nr_zone_write_pending": 0, + "nr_mlock": 5, + "nr_page_table_pages": 101, + "nr_kernel_stack": 224, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 576595, + "numa_miss": 0, + "numa_foreign": 0, + "numa_interleave": 2, + "numa_local": 576595, + "numa_other": 0 + }, + "pagesets": [ + { + "cpu": 0, + "count": 253, + "high": 378, + "batch": 63, + "vm stats threshold": 24 + }, + { + "cpu": 1, + "count": 243, + "high": 378, + "batch": 63, + "vm stats threshold": 24, + "node_unreclaimable": 0, + "start_pfn": 4096 + } + ] + }, + "Normal": { + "pages": { + "free": 5113, + "min": 4097, + "low": 5121, + "high": 6145, + "spanned": 262144, + "present": 262144, + "managed": 236634, + "protection": [ + 0, + 0, + 0, + 0, + 0 + ], + "nr_free_pages": 5113, + "nr_zone_inactive_anon": 35, + "nr_zone_active_anon": 17459, + "nr_zone_inactive_file": 62387, + "nr_zone_active_file": 66203, + "nr_zone_unevictable": 4892, + "nr_zone_write_pending": 0, + "nr_mlock": 4892, + "nr_page_table_pages": 447, + "nr_kernel_stack": 5760, + "nr_bounce": 0, + "nr_zspages": 0, + "nr_free_cma": 0, + "numa_hit": 1338441, + "numa_miss": 0, + "numa_foreign": 0, + "numa_interleave": 66037, + "numa_local": 1338441, + "numa_other": 0 + }, + "pagesets": [ + { + "cpu": 0, + "count": 340, + "high": 378, + "batch": 63, + "vm stats threshold": 16 + }, + { + "cpu": 1, + "count": 174, + "high": 378, + "batch": 63, + "vm stats threshold": 16, + "node_unreclaimable": 0, + "start_pfn": 1048576 + } + ] + }, + "Movable": { + "pages": { + "free": 0, + "min": 0, + "low": 0, + "high": 0, + "spanned": 0, + "present": 0, + "managed": 0, + "protection": [ + 0, + 0, + 0, + 0, + 0 + ] + } + }, + "Device": { + "pages": { + "free": 0, + "min": 0, + "low": 0, + "high": 0, + "spanned": 0, + "present": 0, + "managed": 0, + "protection": [ + 0, + 0, + 0, + 0, + 0 + ] + } + } + } + ] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`/proc/zoneinfo` file parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + hidden = True + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + ouptput_line: Dict = {} + node = None + section = 'stats' # stats, pages, pagesets + pageset = None + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + + if line == ' per-node stats': + continue + + if line.startswith('Node ') and line.endswith('DMA'): + if ouptput_line: + raw_output.append(ouptput_line) + ouptput_line = {} + + section = 'stats' + _, node, _, zone = line.replace(',', '').split() + ouptput_line['node'] = int(node) + ouptput_line[zone] = {} + continue + + if line.startswith('Node '): + section = 'stats' + + if pageset: + ouptput_line[zone]['pagesets'].append(pageset) + pageset = {} + + _, node, _, zone = line.replace(',', '').split() + ouptput_line['node'] = int(node) + ouptput_line[zone] = {} + continue + + if line.startswith(' pages free '): + section = 'pages' + ouptput_line[zone]['pages'] = {} + ouptput_line[zone]['pages']['free'] = int(line.split()[-1]) + continue + + if line.startswith(' pagesets'): + section = 'pagesets' + ouptput_line[zone]['pagesets'] = [] + pageset = {} # type: ignore + continue + + if section == 'stats': + key, val = line.split(maxsplit=1) + ouptput_line[key] = int(val) + continue + + if section == 'pages' and line.startswith(' protection: '): + protection = line.replace('(', '').replace(')', '').replace(',', '').split()[1:] + ouptput_line[zone]['pages']['protection'] = [int(x) for x in protection] + continue + + if section == 'pages': + key, val = line.split(maxsplit=1) + ouptput_line[zone]['pages'][key] = int(val) + continue + + if section == 'pagesets' and line.startswith(' cpu: '): + if pageset: + ouptput_line[zone]['pagesets'].append(pageset) + + split_line = line.replace(':', '').split(maxsplit=1) + pageset = {"cpu": int(split_line[1])} + continue + + if section == 'pagesets': + key, val = line.split(':', maxsplit=1) + pageset[key.strip()] = int(val) + continue + + if ouptput_line: + if pageset: + ouptput_line[zone]['pagesets'].append(pageset) + + raw_output.append(ouptput_line) + + return raw_output if raw else _process(raw_output) diff --git a/man/jc.1 b/man/jc.1 index 8fb1459d..b177429e 100644 --- a/man/jc.1 +++ b/man/jc.1 @@ -1,13 +1,26 @@ -.TH jc 1 2022-08-29 1.21.2 "JSON Convert" +.TH jc 1 2022-09-19 1.21.2 "JSON Convert" .SH NAME -\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools and file-types +\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types, and strings .SH SYNOPSIS -COMMAND | jc PARSER [OPTIONS] -or "Magic" syntax: +Standard syntax: +.RS +COMMAND | \fBjc\fP [OPTIONS] PARSER + +cat FILE | \fBjc\fP [OPTIONS] PARSER + +echo STRING | \fBjc\fP [OPTIONS] PARSER +.RE + +Magic syntax: + +.RS \fBjc\fP [OPTIONS] COMMAND +\fBjc\fP [OPTIONS] /proc/ +.RE + .SH DESCRIPTION \fBjc\fP JSONifies the output of many CLI tools, file-types, and common strings for easier parsing in scripts. \fBjc\fP accepts piped input from \fBSTDIN\fP and outputs a JSON representation of the previous command's output to \fBSTDOUT\fP. Alternatively, the "Magic" syntax can be used by prepending \fBjc\fP to the command to be converted. Options can be passed to \fBjc\fP immediately before the command is given. (Note: "Magic" syntax does not support shell builtins or command aliases) @@ -392,6 +405,171 @@ PLIST file parser \fB--postconf\fP `postconf -M` command parser +.TP +.B +\fB--proc\fP +`/proc/` file parser + +.TP +.B +\fB--proc-buddyinfo\fP +`/proc/buddyinfo` file parser + +.TP +.B +\fB--proc-consoles\fP +`/proc/consoles` file parser + +.TP +.B +\fB--proc-cpuinfo\fP +`/proc/cpuinfo` file parser + +.TP +.B +\fB--proc-crypto\fP +`/proc/crypto` file parser + +.TP +.B +\fB--proc-devices\fP +`/proc/devices` file parser + +.TP +.B +\fB--proc-diskstats\fP +`/proc/diskstats` file parser + +.TP +.B +\fB--proc-driver-rtc\fP +`/proc/driver_rtc` file parser + +.TP +.B +\fB--proc-filesystems\fP +`/proc/filesystems` file parser + +.TP +.B +\fB--proc-interrupts\fP +`/proc/interrupts` file parser + +.TP +.B +\fB--proc-iomem\fP +`/proc/iomem` file parser + +.TP +.B +\fB--proc-ioports\fP +`/proc/ioports` file parser + +.TP +.B +\fB--proc-loadavg\fP +`/proc/loadavg` file parser + +.TP +.B +\fB--proc-locks\fP +`/proc/locks` file parser + +.TP +.B +\fB--proc-meminfo\fP +`/proc/meminfo` file parser + +.TP +.B +\fB--proc-modules\fP +`/proc/modules` file parser + +.TP +.B +\fB--proc-mtrr\fP +`/proc/mtrr` file parser + +.TP +.B +\fB--proc-pagetypeinfo\fP +`/proc/pagetypeinfo` file parser + +.TP +.B +\fB--proc-partitions\fP +`/proc/partitions` file parser + +.TP +.B +\fB--proc-slabinfo\fP +`/proc/slabinfo` file parser + +.TP +.B +\fB--proc-softirqs\fP +`/proc/softirqs` file parser + +.TP +.B +\fB--proc-stat\fP +`/proc/stat` file parser + +.TP +.B +\fB--proc-swaps\fP +`/proc/swaps` file parser + +.TP +.B +\fB--proc-uptime\fP +`/proc/uptime` file parser + +.TP +.B +\fB--proc-version\fP +`/proc/version` file parser + +.TP +.B +\fB--proc-vmallocinfo\fP +`/proc/vmallocinfo` file parser + +.TP +.B +\fB--proc-vmstat\fP +`/proc/vmstat` file parser + +.TP +.B +\fB--proc-zoneinfo\fP +`/proc/zoneinfo` file parser + +.TP +.B +\fB--proc-pid-fdinfo\fP +`/proc//fdinfo/` file parser + +.TP +.B +\fB--proc-pid-io\fP +`/proc//io` file parser + +.TP +.B +\fB--proc-pid-maps\fP +`/proc//maps` file parser + +.TP +.B +\fB--proc-pid-mountinfo\fP +`/proc//mountinfo` file parser + +.TP +.B +\fB--proc-pid-numa-maps\fP +`/proc//numa_maps` file parser + .TP .B \fB--ps\fP @@ -639,7 +817,7 @@ Debug - show traceback (use \fB-dd\fP for verbose traceback) .TP .B \fB-h\fP, \fB--help\fP -Help (\fB--help --parser_name\fP for parser documentation) +Help (\fB--help --parser_name\fP for parser documentation). Use twice to show hidden parsers (e.g. \fB-hh\fP) .TP .B \fB-m\fP, \fB--monochrome\fP @@ -872,17 +1050,21 @@ If a UTC timezone can be detected in the text of the command output, the timesta .SH EXAMPLES Standard Syntax: .RS -$ dig www.google.com | jc \fB--dig\fP \fB-p\fP +$ dig www.google.com | jc \fB-p\fP \fB--dig\fP + +$ cat /proc/meminfo | jc \fB--pretty\fP \fB--proc\fP .RE Magic Syntax: .RS -$ jc \fB-p\fP dig www.google.com +$ jc \fB--pretty\fP dig www.google.com + +$ jc \fB--pretty\fP /proc/meminfo .RE For parser documentation: .RS -$ jc \fB-h\fP \fB--dig\fP +$ jc \fB--help\fP \fB--dig\fP .RE .SH AUTHOR Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/readmegen.py b/readmegen.py index 5982d836..b408b93f 100755 --- a/readmegen.py +++ b/readmegen.py @@ -1,12 +1,15 @@ #!/usr/bin/env python3 # Genereate README.md from jc metadata using jinja2 templates import jc.cli +import jc.lib from jinja2 import Environment, FileSystemLoader file_loader = FileSystemLoader('templates') env = Environment(loader=file_loader) template = env.get_template('readme_template') -output = template.render(jc=jc.cli.about_jc()) +# output = template.render(jc=jc.cli.about_jc()) +output = template.render(parsers=jc.lib.all_parser_info(), + info=jc.cli.about_jc()) with open('README.md', 'w') as f: f.write(output) diff --git a/templates/manpage_template b/templates/manpage_template index c1bfacf6..8854f421 100644 --- a/templates/manpage_template +++ b/templates/manpage_template @@ -1,13 +1,26 @@ .TH jc 1 {{ today }} {{ jc.version}} "JSON Convert" .SH NAME -\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools and file-types +\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types, and strings .SH SYNOPSIS -COMMAND | jc PARSER [OPTIONS] -or "Magic" syntax: +Standard syntax: +.RS +COMMAND | \fBjc\fP [OPTIONS] PARSER + +cat FILE | \fBjc\fP [OPTIONS] PARSER + +echo STRING | \fBjc\fP [OPTIONS] PARSER +.RE + +Magic syntax: + +.RS \fBjc\fP [OPTIONS] COMMAND +\fBjc\fP [OPTIONS] /proc/ +.RE + .SH DESCRIPTION \fBjc\fP JSONifies the output of many CLI tools, file-types, and common strings for easier parsing in scripts. \fBjc\fP accepts piped input from \fBSTDIN\fP and outputs a JSON representation of the previous command's output to \fBSTDOUT\fP. Alternatively, the "Magic" syntax can be used by prepending \fBjc\fP to the command to be converted. Options can be passed to \fBjc\fP immediately before the command is given. (Note: "Magic" syntax does not support shell builtins or command aliases) @@ -44,7 +57,7 @@ Debug - show traceback (use \fB-dd\fP for verbose traceback) .TP .B \fB-h\fP, \fB--help\fP -Help (\fB--help --parser_name\fP for parser documentation) +Help (\fB--help --parser_name\fP for parser documentation). Use twice to show hidden parsers (e.g. \fB-hh\fP) .TP .B \fB-m\fP, \fB--monochrome\fP @@ -277,17 +290,21 @@ If a UTC timezone can be detected in the text of the command output, the timesta .SH EXAMPLES Standard Syntax: .RS -$ dig www.google.com | jc \fB--dig\fP \fB-p\fP +$ dig www.google.com | jc \fB-p\fP \fB--dig\fP + +$ cat /proc/meminfo | jc \fB--pretty\fP \fB--proc\fP .RE Magic Syntax: .RS -$ jc \fB-p\fP dig www.google.com +$ jc \fB--pretty\fP dig www.google.com + +$ jc \fB--pretty\fP /proc/meminfo .RE For parser documentation: .RS -$ jc \fB-h\fP \fB--dig\fP +$ jc \fB--help\fP \fB--dig\fP .RE .SH AUTHOR {{ jc.author }} ({{ jc.author_email }}) diff --git a/templates/readme_template b/templates/readme_template index 963c8176..5f25970a 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -70,7 +70,7 @@ values are converted, and, in some cases, additional semantic context fields are added. To access the raw, pre-processed JSON, use the `-r` cli option or the `raw=True` -function parameter in `parse()`. +function parameter in `parse()` when using `jc` as a python library. Schemas for each parser can be found at the documentation link beside each [**Parser**](#parsers) below. @@ -133,14 +133,18 @@ on Github. `jc` accepts piped input from `STDIN` and outputs a JSON representation of the previous command's output to `STDOUT`. ```bash -COMMAND | jc PARSER [OPTIONS] +COMMAND | jc [OPTIONS] PARSER +cat FILE | jc [OPTIONS] PARSER +echo STRING | jc [OPTIONS] PARSER ``` Alternatively, the "magic" syntax can be used by prepending `jc` to the command -to be converted. Options can be passed to `jc` immediately before the command is -given. (Note: command aliases and shell builtins are not supported) +to be converted or in front of the absolute path for Proc files. Options can be +passed to `jc` immediately before the command or Proc file path is given. +(Note: command aliases and shell builtins are not supported) ```bash jc [OPTIONS] COMMAND +jc [OPTIONS] /proc/ ``` The JSON output can be compact (default) or pretty formatted with the `-p` @@ -149,7 +153,7 @@ option. ### Parsers | Argument | Command or Filetype | Documentation | -|-------------------|---------------------------------------------------------|----------------------------------------------------------------------------|{% for parser in jc.parsers %} +|-------------------|---------------------------------------------------------|----------------------------------------------------------------------------|{% for parser in parsers %} | `{{ "{:>15}".format(parser.argument) }}` | {{ "{:<55}".format(parser.description) }} | {{ "{:<74}".format("[details](https://kellyjonbrazil.github.io/jc/docs/parsers/" + parser.name + ")") }} |{% endfor %} ### Options @@ -159,7 +163,7 @@ option. | `-a` | `--about` | About `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | | `-C` | `--force-color` | Force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | | `-d` | `--debug` | Debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h` | `--help` | Help. Use `jc -h --parser_name` for parser documentation | +| `-h` | `--help` | Help. Use `jc -h --parser_name` for parser documentation. Use twice to show hidden parsers (e.g. `-hh`) | | `-m` | `--monochrome` | Monochrome output | | `-M` | `--meta-out` | Add metadata to output including timestamp, parser name, magic command, magic command exit code, etc. | | | `-p` | `--pretty` | Pretty format the JSON output | @@ -418,12 +422,12 @@ that case you can suppress the warning message with the `-q` cli option or the macOS: ```bash -cat lsof.out | jc --lsof -q +cat lsof.out | jc -q --lsof ``` or Windows: ```bash -type lsof.out | jc --lsof -q +type lsof.out | jc -q --lsof ``` Tested on: @@ -467,7 +471,7 @@ documentation. ### arp ```bash -arp | jc --arp -p # or: jc -p arp +arp | jc -p --arp # or: jc -p arp ``` ```json [ @@ -506,7 +510,7 @@ cat homes.csv ... ``` ```bash -cat homes.csv | jc --csv -p +cat homes.csv | jc -p --csv ``` ```json [ @@ -547,7 +551,7 @@ cat homes.csv | jc --csv -p ``` ### /etc/hosts file ```bash -cat /etc/hosts | jc --hosts -p +cat /etc/hosts | jc -p --hosts ``` ```json [ @@ -574,7 +578,7 @@ cat /etc/hosts | jc --hosts -p ``` ### ifconfig ```bash -ifconfig | jc --ifconfig -p # or: jc -p ifconfig +ifconfig | jc -p --ifconfig # or: jc -p ifconfig ``` ```json [ @@ -632,7 +636,7 @@ Port = 50022 ForwardX11 = no ``` ```bash -cat example.ini | jc --ini -p +cat example.ini | jc -p --ini ``` ```json { @@ -654,7 +658,7 @@ cat example.ini | jc --ini -p ``` ### ls ```bash -$ ls -l /usr/bin | jc --ls -p # or: jc -p ls -l /usr/bin +$ ls -l /usr/bin | jc -p --ls # or: jc -p ls -l /usr/bin ``` ```json [ @@ -690,7 +694,7 @@ $ ls -l /usr/bin | jc --ls -p # or: jc -p ls -l /usr/bin ``` ### netstat ```bash -netstat -apee | jc --netstat -p # or: jc -p netstat -apee +netstat -apee | jc -p --netstat # or: jc -p netstat -apee ``` ```json [ @@ -778,7 +782,7 @@ netstat -apee | jc --netstat -p # or: jc -p netstat -apee ``` ### /etc/passwd file ```bash -cat /etc/passwd | jc --passwd -p +cat /etc/passwd | jc -p --passwd ``` ```json [ @@ -804,7 +808,7 @@ cat /etc/passwd | jc --passwd -p ``` ### ping ```bash -ping 8.8.8.8 -c 3 | jc --ping -p # or: jc -p ping 8.8.8.8 -c 3 +ping 8.8.8.8 -c 3 | jc -p --ping # or: jc -p ping 8.8.8.8 -c 3 ``` ```json { @@ -857,7 +861,7 @@ ping 8.8.8.8 -c 3 | jc --ping -p # or: jc -p ping 8.8.8.8 -c 3 ``` ### ps ```bash -ps axu | jc --ps -p # or: jc -p ps axu +ps axu | jc -p --ps # or: jc -p ps axu ``` ```json [ @@ -904,7 +908,7 @@ ps axu | jc --ps -p # or: jc -p ps axu ``` ### traceroute ```bash -traceroute -m 2 8.8.8.8 | jc --traceroute -p +traceroute -m 2 8.8.8.8 | jc -p --traceroute # or: jc -p traceroute -m 2 8.8.8.8 ``` ```json @@ -969,7 +973,7 @@ traceroute -m 2 8.8.8.8 | jc --traceroute -p ``` ### uptime ```bash -uptime | jc --uptime -p # or: jc -p uptime +uptime | jc -p --uptime # or: jc -p uptime ``` ```json { @@ -1014,7 +1018,7 @@ cat cd_catalog.xml ... ``` ```bash -cat cd_catalog.xml | jc --xml -p +cat cd_catalog.xml | jc -p --xml ``` ```json { @@ -1066,7 +1070,7 @@ spec: mode: ISTIO_MUTUAL ``` ```bash -cat istio.yaml | jc --yaml -p +cat istio.yaml | jc -p --yaml ``` ```json [ @@ -1104,4 +1108,4 @@ cat istio.yaml | jc --yaml -p ] ``` -{{ jc.copyright }} +{{ info.copyright }} diff --git a/tests/test_id.py b/tests/test_id.py index b3752dfe..bcd6a9eb 100644 --- a/tests/test_id.py +++ b/tests/test_id.py @@ -43,6 +43,30 @@ class MyTests(unittest.TestCase): {'uid': {'id': 1000, 'name': 'user'}, 'gid': {'id': 1000, 'name': None}, 'groups': [{'id': 1000, 'name': None}, {'id': 10, 'name': 'wheel'}]} ) + def test_id_space(self): + """ + Test 'id' with with space in name + """ + self.assertEqual( + jc.parsers.id.parse('uid=1000(user 1) gid=1000 groups=1000,10(wheel)', quiet=True), + {'uid': {'id': 1000, 'name': 'user 1'}, 'gid': {'id': 1000, 'name': None}, 'groups': [{'id': 1000, 'name': None}, {'id': 10, 'name': 'wheel'}]} + ) + + self.assertEqual( + jc.parsers.id.parse('uid=1000(user) gid=1000(group 1) groups=1000,10(wheel)', quiet=True), + {'uid': {'id': 1000, 'name': 'user'}, 'gid': {'id': 1000, 'name': 'group 1'}, 'groups': [{'id': 1000, 'name': None}, {'id': 10, 'name': 'wheel'}]} + ) + + self.assertEqual( + jc.parsers.id.parse('uid=1000(user) gid=1000 groups=1000,10(wheel 1)', quiet=True), + {'uid': {'id': 1000, 'name': 'user'}, 'gid': {'id': 1000, 'name': None}, 'groups': [{'id': 1000, 'name': None}, {'id': 10, 'name': 'wheel 1'}]} + ) + + self.assertEqual( + jc.parsers.id.parse('uid=1000(user 1) gid=1000(group 1) groups=1000,10(wheel 1)', quiet=True), + {'uid': {'id': 1000, 'name': 'user 1'}, 'gid': {'id': 1000, 'name': 'group 1'}, 'groups': [{'id': 1000, 'name': None}, {'id': 10, 'name': 'wheel 1'}]} + ) + def test_id_centos_7_7(self): """ Test 'id' on Centos 7.7 diff --git a/tests/test_jc_lib.py b/tests/test_jc_lib.py index a33a5ae9..609f1c3c 100644 --- a/tests/test_jc_lib.py +++ b/tests/test_jc_lib.py @@ -53,6 +53,11 @@ class MyTests(unittest.TestCase): def test_lib_all_parser_info_length(self): self.assertGreaterEqual(len(jc.lib.all_parser_info()), 80) + def test_lib_all_parser_hidden_length(self): + reg_length = len(jc.lib.all_parser_info()) + hidden_length = len(jc.lib.all_parser_info(show_hidden=True)) + self.assertGreater(hidden_length, reg_length) + def test_lib_plugin_parser_mod_list_is_list(self): self.assertIsInstance(jc.lib.plugin_parser_mod_list(), list)