mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c8d1aa55b4 | |||
| 25a70ac5a8 | |||
| 6235a51d7c | |||
| e1aec24e84 | |||
| d9a6fb3ccf | |||
| a47dd4570a | |||
| 8fa1b5a00b | |||
| e537ab902e | |||
| f0fb4a180a | |||
| f957d895cd | |||
| 73c3a9e684 | |||
| 2ee1387f34 | |||
| 10cefb3337 | |||
| 7b369318dd | |||
| cf2fb296f0 | |||
| 6cbd81f997 | |||
| 2025cf751f | |||
| 5a052103ae | |||
| 2ced5853b4 | |||
| 13edbb7d5e | |||
| 1643af4578 | |||
| c7ac1e63bd | |||
| fa3dd0ec20 | |||
| 34146c3f92 | |||
| 298ede17f5 | |||
| d66ace8121 | |||
| 2e89722ef0 | |||
| c8ad5f57d0 | |||
| d2317943c0 | |||
| 198c9fc052 | |||
| b3551f50a8 | |||
| 4ff360e621 | |||
| 87e8fa18cf | |||
| 4bd135c3c7 | |||
| f69350e8bd | |||
| 5768d55a08 | |||
| 538264a8cd | |||
| 7f09f0e4ad | |||
| e36084d7f2 | |||
| bd18166a21 | |||
| a6f2c38891 | |||
| 029a3f8f52 | |||
| dc87aef335 | |||
| d712806b39 | |||
| 2734724432 | |||
| 6176509076 | |||
| 1780efae07 | |||
| 922e8cbb2f | |||
| eef0dd4fa4 | |||
| f93f437f8b | |||
| 4e6d43e2ac | |||
| 922d29ee49 | |||
| 25475bdf42 | |||
| 09c413b1be | |||
| 8944c2f60d | |||
| ff3fe4bf43 | |||
| 5fe2e19277 | |||
| b8cf861aea | |||
| 6ca3576dbf | |||
| 7ea425db5e | |||
| 330ddb7adb | |||
| d69b9fab4a | |||
| 4e02dc8751 | |||
| 0c8be405ce | |||
| 24677dc561 | |||
| 7e7c38755d | |||
| 229cd6d194 | |||
| 776e5d41d7 | |||
| 8d7e8a87b5 | |||
| e24d8c936c | |||
| 39b6c4a273 | |||
| da9b96fb12 | |||
| 7d855acd07 | |||
| f961a2bf90 | |||
| 9f93af614f | |||
| d529ba07d3 | |||
| 0fffb05d01 | |||
| 92b8409207 | |||
| bc3134ba5a | |||
| c7f55a182f | |||
| 5078be45b8 | |||
| 2418ea93fc | |||
| 13cac5de44 | |||
| b6687925cc | |||
| 7ee51182bf | |||
| ec3e5b4a75 | |||
| 0b5aac3d79 | |||
| bea3180836 | |||
| 1ffd767977 | |||
| a4e396fdd7 | |||
| 972d4fe0a5 | |||
| 148460c235 | |||
| 8c2f6790fe | |||
| 044272ea25 | |||
| 7d67dc8f1c | |||
| 71461d80bf | |||
| 9eac2788d7 | |||
| 6ff8202fa9 | |||
| acf30de415 | |||
| a766411306 | |||
| cbcab61c65 | |||
| c3d179f06e | |||
| f42250ca9b | |||
| 7217903ce4 | |||
| 708abbf380 | |||
| 28dbec093b | |||
| daf02f75b1 | |||
| 71b0460d11 | |||
| ff62f4d425 | |||
| 53c523ab19 | |||
| 2285b9527b | |||
| b4648ec4bd | |||
| c6207db8fc | |||
| 1bd73c68f9 | |||
| 47016441f0 | |||
| eeed384a51 | |||
| cd5d6a5004 | |||
| e4733002da | |||
| 15158ee0ca | |||
| dc73c77d73 | |||
| 56529261db | |||
| fcb1f7efd1 | |||
| 72b5e8b313 | |||
| 225964875c | |||
| e580190074 | |||
| 8ef593904d | |||
| 51b9504720 | |||
| e9d0e267c5 | |||
| b028d4c254 |
@@ -0,0 +1,12 @@
|
|||||||
|
--max-line-length=100
|
||||||
|
--strict
|
||||||
|
|
||||||
|
# Not Linux therefore don't expect a Linux tree
|
||||||
|
--no-tree
|
||||||
|
|
||||||
|
# Ignore the following
|
||||||
|
--ignore PREFER_KERNEL_TYPES
|
||||||
|
--ignore EXECUTE_PERMISSIONS
|
||||||
|
--ignore FILE_PATH_CHANGES
|
||||||
|
--ignore NEW_TYPEDEFS
|
||||||
|
--ignore SPDX_LICENSE_TAG
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
# Must be compatible with clang-format 14
|
||||||
|
---
|
||||||
|
AccessModifierOffset: "-4"
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveBitFields: AcrossComments
|
||||||
|
AlignConsecutiveMacros: AcrossComments
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: false
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: "100"
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: "8"
|
||||||
|
ContinuationIndentWidth: "8"
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
# git grep -h '^#define [^[:space:]]*\(for_each\|iterate\)[^[:space:]]*(' \
|
||||||
|
# | sed "s,^#define \([^[:space:]]*\(for_each\|iterate\)[^[:space:]]*\)(.*$, - '\1'," \
|
||||||
|
# | LC_ALL=C sort -u
|
||||||
|
ForEachMacros:
|
||||||
|
- "dfi_cpu_iterate"
|
||||||
|
- "dfi_mem_chunk_iterate"
|
||||||
|
- "dfo_chunk_iterate"
|
||||||
|
- "for_each_rb_entry"
|
||||||
|
- "ns_range_for_each"
|
||||||
|
- "sd_cpu_item_enable_iterate"
|
||||||
|
- "sd_cpu_item_iterate"
|
||||||
|
- "sd_cpu_iterate"
|
||||||
|
- "sd_cpu_type_iterate"
|
||||||
|
- "sd_sys_item_enable_iterate"
|
||||||
|
- "sd_sys_item_iterate"
|
||||||
|
- "sd_sys_iterate"
|
||||||
|
- "table_col_iterate"
|
||||||
|
- "table_iterate_mark_keys"
|
||||||
|
- "util_list_iterate"
|
||||||
|
- "util_list_iterate_safe"
|
||||||
|
- "util_opt_iterate"
|
||||||
|
- "util_rec_iterate"
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
# Leave imports as is
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: .*
|
||||||
|
Priority: 1
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentGotoLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: "8"
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ""
|
||||||
|
MacroBlockEnd: ""
|
||||||
|
MaxEmptyLinesToKeep: "1"
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
PackConstructorInitializers: CurrentLine
|
||||||
|
PenaltyBreakAssignment: "10"
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: "30"
|
||||||
|
PenaltyBreakComment: "10"
|
||||||
|
PenaltyBreakFirstLessLess: "0"
|
||||||
|
PenaltyBreakString: "10"
|
||||||
|
PenaltyExcessCharacter: "100"
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: "60"
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatementsExceptForEachMacros
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: "1"
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
StatementMacros:
|
||||||
|
- "STATIC_ASSERT"
|
||||||
|
TabWidth: "8"
|
||||||
|
TypenameMacros:
|
||||||
|
- "STACK_OF"
|
||||||
|
UseTab: Always
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- "STRINGIFY"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[codespell]
|
||||||
|
ignore-words-list = parm,parms
|
||||||
|
skip = ''
|
||||||
|
count = ''
|
||||||
|
quiet-level = 3
|
||||||
@@ -9,6 +9,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Antoinette Kaschner
|
- Antoinette Kaschner
|
||||||
- Arnd Bergmann
|
- Arnd Bergmann
|
||||||
- Axel Wirbser
|
- Axel Wirbser
|
||||||
|
- Balint Reczey
|
||||||
- Benjamin Block
|
- Benjamin Block
|
||||||
- Brian C. Lane
|
- Brian C. Lane
|
||||||
- Carsten Otte
|
- Carsten Otte
|
||||||
|
|||||||
@@ -1,5 +1,52 @@
|
|||||||
Release history for s390-tools (MIT version)
|
Release history for s390-tools (MIT version)
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
|
* __v2.24.0 (2022-11-09)__
|
||||||
|
|
||||||
|
For Linux kernel version: 6.0
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- Provide config files for checkpatch, codespell, and clang-format
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- dbginfo.sh: Collect log from various distro tools (YaST, DNF, Anaconda)
|
||||||
|
- dbginfo.sh: add Kubernetes data collection
|
||||||
|
- libutil: Introduce util_lockfile
|
||||||
|
- zdev: Add site-aware device configuration
|
||||||
|
- zdump: Add support to read Protected Virtualization dumps
|
||||||
|
- zipl/boot: Add secure boot trailer
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- ap_tools/ap-check: Reject start for control domains without usage
|
||||||
|
- cpumf/lshwc: Fix incremented counter output
|
||||||
|
- cpumf/pai: Fix core dump when summary flag set
|
||||||
|
- dbginfo.sh: Ensure compatibility with /bin/dash shell
|
||||||
|
- dbginfo.sh: Save dbginfo.sh version to dbginfo.log
|
||||||
|
- zipl/src/zipl_helper.device-mapper: Fix bug in error path
|
||||||
|
|
||||||
|
* __v2.23.0 (2022-08-18)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.19
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- Makefile: use common Make definition for DRACUTDIR
|
||||||
|
- Makefile: use common Make definition for UDEVDIR and UDEVRULESDIR
|
||||||
|
- cpacfstats: Add PAI and hotplug support
|
||||||
|
- cpumf/pai: Omit file write progress information
|
||||||
|
- dbginfo.sh: Get more details on lspci command
|
||||||
|
- dumpconf: Prevent running the service in containers
|
||||||
|
- libcpumf: Detect PMU named pai_ext
|
||||||
|
- pvattest: Improve error reporting and logging
|
||||||
|
- zdev: Add some --type ap examples to manpages
|
||||||
|
- zkey: Use default benchmarked Argon2i with LUKS2
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- dbginfo.sh: Fix accidental ftrace buffer shrinkage/free
|
||||||
|
- genprotimg: Fix BIO_reset() returncode handling
|
||||||
|
- libpv: Fix dependency checking
|
||||||
|
- pvattest: Fix dependency checking
|
||||||
|
- zipl: Fix segmentation fault when no parmline is provided
|
||||||
|
|
||||||
* __v2.22.0 (2022-06-20)__
|
* __v2.22.0 (2022-06-20)__
|
||||||
|
|
||||||
For Linux kernel version: 5.18
|
For Linux kernel version: 5.18
|
||||||
|
|||||||
+37
-2
@@ -4,8 +4,10 @@ Coding guidelines for s390-tools
|
|||||||
For s390-tools the preferred language is C. We provide libraries, e.g.
|
For s390-tools the preferred language is C. We provide libraries, e.g.
|
||||||
[`libutil`](libutil) that should be used by all tools if possible.
|
[`libutil`](libutil) that should be used by all tools if possible.
|
||||||
|
|
||||||
The coding style is based on the Linux [kernel guidelines]. Therefore, use
|
The coding style is based on the Linux [kernel guidelines]. Therefore, use the
|
||||||
the [checkpatch] tool for verification before you submit a patch.
|
[checkpatch] tool for verification before you submit a patch. s390-tools
|
||||||
|
provides a CheckPatch configuration for this - see
|
||||||
|
[`.checkpatch.conf`](.checkpatch.conf).
|
||||||
|
|
||||||
[kernel guidelines]: https://www.kernel.org/doc/html/latest/process/coding-style.html
|
[kernel guidelines]: https://www.kernel.org/doc/html/latest/process/coding-style.html
|
||||||
[checkpatch]: https://github.com/torvalds/linux/blob/master/scripts/checkpatch.pl
|
[checkpatch]: https://github.com/torvalds/linux/blob/master/scripts/checkpatch.pl
|
||||||
@@ -17,6 +19,39 @@ This package started in 2001 and has a long "tradition" - therefore, older tools
|
|||||||
might not follow all recommendations. Note that when changing existing code,
|
might not follow all recommendations. Note that when changing existing code,
|
||||||
consistency could have priority over applying rules.
|
consistency could have priority over applying rules.
|
||||||
|
|
||||||
|
Automatic Code Formatting
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
> **NOTE:** clang-format is a helpful tool but please don't use it blindly!
|
||||||
|
|
||||||
|
s390-tools provides a ClangFormat (https://clang.llvm.org/docs/ClangFormat.html)
|
||||||
|
configuration file - see [`.clang-format`](.clang-format). It can be used to
|
||||||
|
format your C/C++ code automatically.
|
||||||
|
|
||||||
|
Clang-format can format a single file or multiple files at once. For example, to
|
||||||
|
format `main.c` in place, run the following command in a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clang-format -i main.c
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to format only your current staged changes use the clang-format git
|
||||||
|
plugin:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clang-format --staged
|
||||||
|
```
|
||||||
|
|
||||||
|
See also `git clang-format -h`.
|
||||||
|
|
||||||
|
Automatic Editor Configuration
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
s390-tools provides a EditorConfig (https://editorconfig.org/) configuration
|
||||||
|
file - see [`.editorconfig`](.editorconfig). EditorConfig defines coding style
|
||||||
|
rules (such as indentation size, use of tabs, etc.) and is supported by most
|
||||||
|
common editors natively or via plugins.
|
||||||
|
|
||||||
Standard abbreviations
|
Standard abbreviations
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ Package contents
|
|||||||
|
|
||||||
* zgetdump:
|
* zgetdump:
|
||||||
Retrieve system dumps from either tapes, DASDs, SCSIs or NVMes.
|
Retrieve system dumps from either tapes, DASDs, SCSIs or NVMes.
|
||||||
|
Decrypt Protected Virtualization (PV) dumps from IBM Secure Execution guests.
|
||||||
|
|
||||||
* qetharp:
|
* qetharp:
|
||||||
Read and flush the ARP cache on OSA Express network cards.
|
Read and flush the ARP cache on OSA Express network cards.
|
||||||
@@ -306,20 +307,19 @@ build options:
|
|||||||
| | | hsavmcore |
|
| | | hsavmcore |
|
||||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||||
| pfm | `HAVE_PFM` | cpacfstats |
|
|
||||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||||
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
||||||
| | | libkmipclient, pvattest |
|
| | | libkmipclient, pvattest, zgetdump |
|
||||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
|
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
|
||||||
| | | libkmipclient |
|
| | | libkmipclient |
|
||||||
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest |
|
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest, zgetdump |
|
||||||
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient,|
|
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient,|
|
||||||
| | | pvattest |
|
| | | pvattest |
|
||||||
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
||||||
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
||||||
| liblockfile | `HAVE_LOCKFILE` | ap-check |
|
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
|
||||||
|
|
||||||
This table lists additional build or install options:
|
This table lists additional build or install options:
|
||||||
|
|
||||||
@@ -376,6 +376,13 @@ the different tools are provided:
|
|||||||
- Packages: blktrace, multipath-tools, sg3-utils
|
- Packages: blktrace, multipath-tools, sg3-utils
|
||||||
- Tools: rsync, tar, lsscsi
|
- Tools: rsync, tar, lsscsi
|
||||||
|
|
||||||
|
* zgetdump
|
||||||
|
For building zgetdump you need OpenSSL version 1.1.0 or newer
|
||||||
|
installed (openssl-devel.rpm). Also required is glib2
|
||||||
|
(glib2-devel.rpm) and zlib (zlib-devel.rpm).
|
||||||
|
Tip: you may skip the zgetdump build by adding
|
||||||
|
`HAVE_OPENSSL=0`, `HAVE_GLIB2=0`, or `HAVE_ZLIB=0`.
|
||||||
|
|
||||||
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
||||||
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
||||||
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
|
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
|
||||||
@@ -403,14 +410,13 @@ the different tools are provided:
|
|||||||
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
|
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
|
||||||
|
|
||||||
* cpacfstats:
|
* cpacfstats:
|
||||||
For building the cpacfstats tools you need libpfm version 4 or
|
For building the cpacfstats tools you need libudev installed
|
||||||
newer installed (libpfm-devel.rpm). Tip: you may skip the cpacfstats
|
(systemd-devel.rpm). Tip: you may skip the cpacfstats build by
|
||||||
build by adding `HAVE_PFN=0` to the make invocation. To run the
|
adding `HAVE_LIBUDEV=0` to the make invocation. To run the
|
||||||
cpacfstats daemon the kernel needs to have performance
|
cpacfstats daemon the kernel needs to have performance events
|
||||||
events enabled (check for `CONFIG_PERF_EVENTS=y`) and you need libpfm
|
enabled (check for `CONFIG_PERF_EVENTS=y`). A new group 'cpacfstats'
|
||||||
version 4 or newer installed. A new group 'cpacfstats' needs to be
|
needs to be created and all users intending to use the tool should
|
||||||
created and all users intending to use the tool should be added to
|
be added to this group.
|
||||||
this group.
|
|
||||||
|
|
||||||
* zdev:
|
* zdev:
|
||||||
Depending on the boot loader and initial RAM-disk mechanism used by a
|
Depending on the boot loader and initial RAM-disk mechanism used by a
|
||||||
@@ -506,8 +512,7 @@ the different tools are provided:
|
|||||||
GNU awk for the build process.
|
GNU awk for the build process.
|
||||||
|
|
||||||
* ap-check:
|
* ap-check:
|
||||||
For building the ap-check mdevctl callout utility you need liblockfile
|
For building the ap-check mdevctl callout utility you need json-c version
|
||||||
version 1.14 or newer installed (liblockfile-devel.rpm). Also required is
|
0.13 or newer (json-c-devel.rpm).
|
||||||
json-c version 0.13 or newer (json-c-devel.rpm).
|
Tip: you may skip ap-check build by adding `HAVE_JSONC=0` to the make
|
||||||
Tip: you may skip ap-check build by adding `HAVE_LOCKFILE=0` or `HAVE_JSONC=0`
|
invocation.
|
||||||
to the make invocation.
|
|
||||||
|
|||||||
+2
-9
@@ -7,21 +7,14 @@ MDEVCTL_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
|
|||||||
libs = $(rootdir)/libap/libap.a \
|
libs = $(rootdir)/libap/libap.a \
|
||||||
$(rootdir)/libutil/libutil.a
|
$(rootdir)/libutil/libutil.a
|
||||||
|
|
||||||
ifeq (${HAVE_LOCKFILE},0)
|
ifeq (${HAVE_JSONC},0)
|
||||||
all:
|
|
||||||
$(SKIP) HAVE_LOCKFILE=0
|
|
||||||
|
|
||||||
install:
|
|
||||||
$(SKIP) HAVE_LOCKFILE=0
|
|
||||||
|
|
||||||
else ifeq (${HAVE_JSONC},0)
|
|
||||||
all:
|
all:
|
||||||
$(SKIP) HAVE_JSONC=0
|
$(SKIP) HAVE_JSONC=0
|
||||||
|
|
||||||
install:
|
install:
|
||||||
$(SKIP) HAVE_JSONC=0
|
$(SKIP) HAVE_JSONC=0
|
||||||
else
|
else
|
||||||
LDLIBS += -llockfile -ljson-c
|
LDLIBS += -ljson-c
|
||||||
|
|
||||||
all: ap-check
|
all: ap-check
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -133,7 +133,7 @@ static void ap_check_cleanup(struct ap_check_anchor *anc)
|
|||||||
if (anc->dev)
|
if (anc->dev)
|
||||||
vfio_ap_device_free(anc->dev);
|
vfio_ap_device_free(anc->dev);
|
||||||
if (anc->cleanup_lock)
|
if (anc->cleanup_lock)
|
||||||
ap_release_lock();
|
ap_release_lock_callout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -685,6 +685,14 @@ static int ap_check_handle_start(struct ap_check_anchor *anc)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure device with control domains also has usage domains */
|
||||||
|
if (util_list_is_empty(anc->dev->domains) &&
|
||||||
|
!util_list_is_empty(anc->dev->controls)) {
|
||||||
|
fprintf(stderr, "At least one usage domain must be specified\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check against all other active vfio-ap devices */
|
/* Check against all other active vfio-ap devices */
|
||||||
rc = check_other_mdevs_sysfs(anc);
|
rc = check_other_mdevs_sysfs(anc);
|
||||||
/* Check against the system sysfs values for apmask/aqmask */
|
/* Check against the system sysfs values for apmask/aqmask */
|
||||||
@@ -767,7 +775,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
static int ap_check_handle_post(void)
|
static int ap_check_handle_post(void)
|
||||||
{
|
{
|
||||||
return ap_release_lock();
|
return ap_release_lock_callout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For the specified device, print the attributes to stdout in JSON format */
|
/* For the specified device, print the attributes to stdout in JSON format */
|
||||||
|
|||||||
@@ -27,11 +27,7 @@ ENABLE_DOC = 0
|
|||||||
|
|
||||||
# https://www.gnu.org/software/make/manual/make.html#Directory-Variables
|
# https://www.gnu.org/software/make/manual/make.html#Directory-Variables
|
||||||
CHREIPLZFCPMPDIR = $(USRLIBDIR)/chreipl-fcp-mpath
|
CHREIPLZFCPMPDIR = $(USRLIBDIR)/chreipl-fcp-mpath
|
||||||
UDEVDIR = $(USRLIBDIR)/udev
|
|
||||||
UDEVRULESDIR = $(UDEVDIR)/rules.d
|
|
||||||
UDEVRUNDIR = /run/udev
|
UDEVRUNDIR = /run/udev
|
||||||
DRACUTDIR = $(USRLIBDIR)/dracut
|
|
||||||
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
|
|
||||||
DEBUGOUTDIR = $(UDEVRUNDIR)
|
DEBUGOUTDIR = $(UDEVRUNDIR)
|
||||||
|
|
||||||
INSTALL_EXEC = $(INSTALL) -g $(GROUP) -o $(OWNER) --preserve-timestamps
|
INSTALL_EXEC = $(INSTALL) -g $(GROUP) -o $(OWNER) --preserve-timestamps
|
||||||
|
|||||||
+9
-4
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
|||||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||||
VERSION = 2
|
VERSION = 2
|
||||||
RELEASE = 22
|
RELEASE = 24
|
||||||
PATCHLEVEL = 0
|
PATCHLEVEL = 0
|
||||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||||
@@ -91,7 +91,7 @@ ifneq ("${V}","1")
|
|||||||
else
|
else
|
||||||
echocmd=
|
echocmd=
|
||||||
endif
|
endif
|
||||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
|
DEFAULT_CFLAGS = -g -fstack-protector-all -W -Wall -Wformat-security
|
||||||
ifeq ("${W}","1")
|
ifeq ("${W}","1")
|
||||||
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
|
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
|
||||||
endif
|
endif
|
||||||
@@ -120,7 +120,7 @@ endif
|
|||||||
define check_header_prereq
|
define check_header_prereq
|
||||||
$(shell printf "#include <%s>\n int main(void) {return 0;}\n" $1 | \
|
$(shell printf "#include <%s>\n int main(void) {return 0;}\n" $1 | \
|
||||||
( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) \
|
( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) \
|
||||||
$2 -o /dev/null -xc - ) >/dev/null 2>&1 && echo -n yes)
|
$2 -o /dev/null -x c - ) >/dev/null 2>&1 && echo -n yes)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -133,7 +133,7 @@ endef
|
|||||||
# $5: Additional compiler & linker options (optional)
|
# $5: Additional compiler & linker options (optional)
|
||||||
#
|
#
|
||||||
check_dep=\
|
check_dep=\
|
||||||
printf "\#include <%s>\n int main(void) {return 0;}\n" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) $5 -o /dev/null -xc - ) > /dev/null 2>&1; \
|
printf "\#include <%s>\n int main(void) {return 0;}\n" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) $5 -o /dev/null -x c - ) > /dev/null 2>&1; \
|
||||||
if [ $$? != 0 ]; \
|
if [ $$? != 0 ]; \
|
||||||
then \
|
then \
|
||||||
printf " REQCHK %s (%s)\n" $1 $2; \
|
printf " REQCHK %s (%s)\n" $1 $2; \
|
||||||
@@ -193,6 +193,11 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
|
|||||||
SYSTEMDSYSTEMUNITDIR =
|
SYSTEMDSYSTEMUNITDIR =
|
||||||
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
|
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
|
||||||
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
|
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
|
||||||
|
UDEVDIR = $(USRLIBDIR)/udev
|
||||||
|
UDEVRULESDIR = $(UDEVDIR)/rules.d
|
||||||
|
DRACUTDIR = $(USRLIBDIR)/dracut
|
||||||
|
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
|
||||||
|
DRACUTMODDIR = $(DRACUTDIR)/modules.d
|
||||||
|
|
||||||
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
|
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
|
||||||
SOINSTALLDIR = $(USRLIB64DIR)
|
SOINSTALLDIR = $(USRLIB64DIR)
|
||||||
|
|||||||
+21
-2
@@ -1,11 +1,28 @@
|
|||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
||||||
|
ifeq (${HAVE_LIBUDEV},0)
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(SKIP) HAVE_LIBUDEV=0
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(SKIP) HAVE_LIBUDEV=0
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
check_dep:
|
||||||
|
$(call check_dep, \
|
||||||
|
"cpacfstatsd", \
|
||||||
|
"libudev.h", \
|
||||||
|
"systemd-devel", \
|
||||||
|
"HAVE_LIBUDEV=0")
|
||||||
|
|
||||||
ALL_CPPFLAGS += -DVERSION=$(VERSION)
|
ALL_CPPFLAGS += -DVERSION=$(VERSION)
|
||||||
|
|
||||||
all: cpacfstats cpacfstatsd
|
all: check_dep cpacfstats cpacfstatsd
|
||||||
|
|
||||||
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -ludev -lpthread -o $@
|
||||||
|
|
||||||
cpacfstats: cpacfstats.o stats_sock.o
|
cpacfstats: cpacfstats.o stats_sock.o
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
@@ -16,6 +33,8 @@ install: all
|
|||||||
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *~ cpacfstatsd cpacfstats
|
rm -f *.o *~ cpacfstatsd cpacfstats
|
||||||
|
|
||||||
|
|||||||
+370
-11
@@ -1,6 +1,6 @@
|
|||||||
.\" cpacfstats.1
|
.\" cpacfstats.1
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright IBM Corp. 2015, 2020
|
.\" Copyright IBM Corp. 2015, 2022
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
@@ -32,7 +32,9 @@ cpacfstats \- enable, disable and display CPACF statistical data
|
|||||||
.RB ]
|
.RB ]
|
||||||
.RB [ \-p | \-\-print
|
.RB [ \-p | \-\-print
|
||||||
.I counter
|
.I counter
|
||||||
|
.RB [ \-n | \-\-nonzero]
|
||||||
.RB ]
|
.RB ]
|
||||||
|
.RB [ \-j | \-\-json ]
|
||||||
.
|
.
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
The cpacfstats client application interacts with the cpacfstatsd daemon and
|
The cpacfstats client application interacts with the cpacfstatsd daemon and
|
||||||
@@ -44,12 +46,347 @@ All counters are initially disabled and must be switched on to measure
|
|||||||
CPACF activities of the system. There is a slight performance penalty with
|
CPACF activities of the system. There is a slight performance penalty with
|
||||||
CPACF counters enabled.
|
CPACF counters enabled.
|
||||||
|
|
||||||
Note: All cryptographic counters are bound to physical CPUs. If you use
|
CPACF activity counters come in two flavors: CPU-MF and PAI. CPU-MF
|
||||||
dedicated CPUs for your LPAR, you obtain only your CPACF activities. If
|
counters are only available on LPARs and have to be authorized. If
|
||||||
your CPUs are shared with other LPARs, their cryptographic activities might
|
they are available, the counters
|
||||||
distort the results. CPACF performance counters are available on LPARs
|
.B des,
|
||||||
only. For security reasons only members of the group \fIcpacfstats\fR are
|
.B aes,
|
||||||
allowed to run the cpacfstats client application.
|
.B sha,
|
||||||
|
.B rng,
|
||||||
|
and
|
||||||
|
.B ecc
|
||||||
|
are made available. These counters can individually be activated,
|
||||||
|
reset, printed, or deactivated. PAI counters are a lot more detailed.
|
||||||
|
The user interface only offers the counters
|
||||||
|
.B pai_user
|
||||||
|
and
|
||||||
|
.B pai_kernel
|
||||||
|
to count CPACF usage in user-space or kernel-space. When printing
|
||||||
|
these counters, detailed counters are shown. The detailed names are:
|
||||||
|
.RS
|
||||||
|
.IP \(bu
|
||||||
|
KM DES,
|
||||||
|
.IP \(bu
|
||||||
|
KM 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KM TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KM DES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KM 2key TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KM TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES-XTS 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES-XTS 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES-XTS 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KM AES-XTS 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMC DES,
|
||||||
|
.IP \(bu
|
||||||
|
KMC 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMC TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMC DES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMC 2key TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMC TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMC AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMC AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMC AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMC AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMC AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMC AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMC PRNG,
|
||||||
|
.IP \(bu
|
||||||
|
KMA AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMA AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMA AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMA AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMA AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMA AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMF DES,
|
||||||
|
.IP \(bu
|
||||||
|
KMF 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMF TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMF DES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMF 2key TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMF TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMF AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMF AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMF AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMF AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMF AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMF AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR DES,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR DES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR 2key TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMCTR AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMO DES,
|
||||||
|
.IP \(bu
|
||||||
|
KMO 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMO TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMO DES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMO 2key TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMO TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMO AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMO AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMO AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMO AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMO AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMO AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHA1,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHA256,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHA512,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHA3-224,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHA3-256,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHA3-384,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHA3-512,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHAKE 128,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD SHAKE 256,
|
||||||
|
.IP \(bu
|
||||||
|
KIMD GHASH,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHA1,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHA256,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHA512,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHA3-224,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHA3-256,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHA3-384,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHA3-512,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHAKE 128,
|
||||||
|
.IP \(bu
|
||||||
|
KLMD SHAKE 256,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC DES,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC TDES,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC DES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC 2key TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KMAC AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC DES,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC TDES,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC DES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC 2key TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC TDES protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC AES 192bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Last Block CMAC AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC XTS Parameter AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCC XTS Parameter AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCC XTS Parameter AES 128bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC XTS Parameter AES 256bit protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Scalar Mult P256,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Scalar Mult P384,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Scalar Mult P521,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Scalar Mult Ed25519,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Scalar Mult Ed448,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Scalar Mult X25519,
|
||||||
|
.IP \(bu
|
||||||
|
PCC Scalar Mult X448,
|
||||||
|
.IP \(bu
|
||||||
|
PRNO SHA512 DRNG,
|
||||||
|
.IP \(bu
|
||||||
|
PRNO TRNG Query Ratio,
|
||||||
|
.IP \(bu
|
||||||
|
PRNO TRNG,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Verify P256,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Verify P384,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Verify P521,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Sign P256,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Sign P384,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Sign P521,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Sign P256 protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Sign P384 protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA ECDSA Sign P521 protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA EdDSA Verify Ed25519,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA EdDSA Verify Ed448,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA EdDSA Sign Ed25519,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA EdDSA Sign Ed448,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA EdDSA Sign Ed25519 protected key,
|
||||||
|
.IP \(bu
|
||||||
|
KDSA EdDSA Sign Ed448 protected key,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO DES,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO 2key TDES,
|
||||||
|
.IP \(bu
|
||||||
|
PCMKO TDES,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO AES 128bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO AES 192bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCMKO AES 256bit,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO ECC P256,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO ECC P384,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO ECC P521,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO ECC Ed25519,
|
||||||
|
.IP \(bu
|
||||||
|
PCKMO ECC Ed448,
|
||||||
|
.IP \(bu
|
||||||
|
Reserved 1, and
|
||||||
|
.IP \(bu
|
||||||
|
Reserved 2.
|
||||||
|
.RE
|
||||||
|
Note that the counters starting with PCKMO and Reserved are only
|
||||||
|
available in the pai_kernel set. Also note that the counters are
|
||||||
|
designed to count successful operations. In the case of KMA this
|
||||||
|
means only complete GCM operations including final hashing are
|
||||||
|
counted.
|
||||||
|
|
||||||
|
Note: CPU-MF based CPACF performance counters are available on LPARs
|
||||||
|
only. PAI counters are available on all hypervisors. For security
|
||||||
|
reasons only members of the group \fIcpacfstats\fR are allowed to run
|
||||||
|
the cpacfstats client application.
|
||||||
|
|
||||||
Example usage scenario:
|
Example usage scenario:
|
||||||
.P
|
.P
|
||||||
@@ -101,12 +438,34 @@ argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR,
|
|||||||
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
|
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
|
||||||
performance counters are reset to 0.
|
performance counters are reset to 0.
|
||||||
.TP
|
.TP
|
||||||
\fB\-p\fR or \fB\-\-print\fR [counter]
|
\fB\-p\fR or \fB\-\-print\fR [\fB\-n\fR or \fB\-\-nonzero\fR] [counter]
|
||||||
Display the value of one or all CPACF performance counters. The
|
Display the value of one or all CPACF performance counters. The
|
||||||
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
|
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
|
||||||
\fBsha\fR, \fBprng\fR, \fBecc\fR, or \fBall\fR. If the counter
|
\fBsha\fR, \fBprng\fR, \fBecc\fR, \fBpai_user\fR, \fBpai_kernel\fR, or
|
||||||
argument is omitted or if there is no argument, all performance
|
\fBall\fR. If the counter argument is omitted or if there is no
|
||||||
counters are displayed.
|
argument, all performance counters are displayed. If the optional
|
||||||
|
\fB\-n\fR or \fB\-\-nonzero\fR argument is given, then only PAI
|
||||||
|
counters that have a non-zero value are printed.
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR or \fB\-\-json\fR
|
||||||
|
Display all activated counters in JSON format. The JSON contains an
|
||||||
|
array of counter objects. Each object contains the property
|
||||||
|
.B counter
|
||||||
|
specifying either a CPU-MF counter of one of the detailed PAI counter.
|
||||||
|
Additional properties include
|
||||||
|
.B error
|
||||||
|
an error number if the counter could not be read,
|
||||||
|
.B value
|
||||||
|
the counter value if the counter could be read,
|
||||||
|
.B space
|
||||||
|
for PAI counters to specify
|
||||||
|
.B user
|
||||||
|
or
|
||||||
|
.B kernel
|
||||||
|
space counter set, and
|
||||||
|
.B counterid
|
||||||
|
for PAI counters to specify the PAI counter number as specified in the
|
||||||
|
Principles of Operation.
|
||||||
.TP
|
.TP
|
||||||
The default command is --print all.
|
The default command is --print all.
|
||||||
.
|
.
|
||||||
|
|||||||
+366
-40
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* cpacfstats client implementation
|
* cpacfstats client implementation
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2015, 2020
|
* Copyright IBM Corp. 2015, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -39,17 +39,187 @@ static const char *const usage =
|
|||||||
"\t-d, --disable [counter] Disable one or all counters\n"
|
"\t-d, --disable [counter] Disable one or all counters\n"
|
||||||
"\t-r, --reset [counter] Reset one or all counter values\n"
|
"\t-r, --reset [counter] Reset one or all counter values\n"
|
||||||
"\t-p, --print [counter] Print one or all counter values\n"
|
"\t-p, --print [counter] Print one or all counter values\n"
|
||||||
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc' or 'all'\n";
|
"\t-n, --nonzero Print all PAI counters\n"
|
||||||
|
"\t-j, --json Print all counter values in JSON format\n"
|
||||||
|
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc'\n"
|
||||||
|
"\t 'pai_user' 'pai_kernel' or 'all'\n";
|
||||||
|
|
||||||
static const char *const counter_str[] = {
|
static const char *const counter_str[] = {
|
||||||
[DES_FUNCTIONS] = "des",
|
[DES_FUNCTIONS] = "des",
|
||||||
[AES_FUNCTIONS] = "aes",
|
[AES_FUNCTIONS] = "aes",
|
||||||
[SHA_FUNCTIONS] = "sha",
|
[SHA_FUNCTIONS] = "sha",
|
||||||
[PRNG_FUNCTIONS] = "rng",
|
[PRNG_FUNCTIONS] = "rng",
|
||||||
[ECC_FUNCTIONS] = "ecc",
|
[ECC_FUNCTIONS] = "ecc",
|
||||||
[ALL_COUNTER] = "all"
|
[ALL_COUNTER] = "all",
|
||||||
|
[PAI_USER] = "pai_user",
|
||||||
|
[PAI_KERNEL] = "pai_kernel"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Strings for the pai counter details. Note that this is 0-based
|
||||||
|
* while PoP is 1-based.
|
||||||
|
*/
|
||||||
|
static const char *const pai_str[] = {
|
||||||
|
[ 0] = "KM DES",
|
||||||
|
[ 1] = "KM 2key TDES",
|
||||||
|
[ 2] = "KM TDES",
|
||||||
|
[ 3] = "KM DES protected key",
|
||||||
|
[ 4] = "KM 2key TDES protected key",
|
||||||
|
[ 5] = "KM TDES protected key",
|
||||||
|
[ 6] = "KM AES 128bit",
|
||||||
|
[ 7] = "KM AES 192bit",
|
||||||
|
[ 8] = "KM AES 256bit",
|
||||||
|
[ 9] = "KM AES 128bit protected key",
|
||||||
|
[ 10] = "KM AES 192bit protected key",
|
||||||
|
[ 11] = "KM AES 256bit protected key",
|
||||||
|
[ 12] = "KM AES-XTS 128bit",
|
||||||
|
[ 13] = "KM AES-XTS 256bit",
|
||||||
|
[ 14] = "KM AES-XTS 128bit protected key",
|
||||||
|
[ 15] = "KM AES-XTS 256bit protected key",
|
||||||
|
[ 16] = "KMC DES",
|
||||||
|
[ 17] = "KMC 2key TDES",
|
||||||
|
[ 18] = "KMC TDES",
|
||||||
|
[ 19] = "KMC DES protected key",
|
||||||
|
[ 20] = "KMC 2key TDES protected key",
|
||||||
|
[ 21] = "KMC TDES protected key",
|
||||||
|
[ 22] = "KMC AES 128bit",
|
||||||
|
[ 23] = "KMC AES 192bit",
|
||||||
|
[ 24] = "KMC AES 256bit",
|
||||||
|
[ 25] = "KMC AES 128bit protected key",
|
||||||
|
[ 26] = "KMC AES 192bit protected key",
|
||||||
|
[ 27] = "KMC AES 256bit protected key",
|
||||||
|
[ 28] = "KMC PRNG",
|
||||||
|
[ 29] = "KMA AES 128bit",
|
||||||
|
[ 30] = "KMA AES 192bit",
|
||||||
|
[ 31] = "KMA AES 256bit",
|
||||||
|
[ 32] = "KMA AES 128bit protected key",
|
||||||
|
[ 33] = "KMA AES 192bit protected key",
|
||||||
|
[ 34] = "KMA AES 256bit protected key",
|
||||||
|
[ 35] = "KMF DES",
|
||||||
|
[ 36] = "KMF 2key TDES",
|
||||||
|
[ 37] = "KMF TDES",
|
||||||
|
[ 38] = "KMF DES protected key",
|
||||||
|
[ 39] = "KMF 2key TDES protected key",
|
||||||
|
[ 40] = "KMF TDES protected key",
|
||||||
|
[ 41] = "KMF AES 128bit",
|
||||||
|
[ 42] = "KMF AES 192bit",
|
||||||
|
[ 43] = "KMF AES 256bit",
|
||||||
|
[ 44] = "KMF AES 128bit protected key",
|
||||||
|
[ 45] = "KMF AES 192bit protected key",
|
||||||
|
[ 46] = "KMF AES 256bit protected key",
|
||||||
|
[ 47] = "KMCTR DES",
|
||||||
|
[ 48] = "KMCTR 2key TDES",
|
||||||
|
[ 49] = "KMCTR TDES",
|
||||||
|
[ 50] = "KMCTR DES protected key",
|
||||||
|
[ 51] = "KMCTR 2key TDES protected key",
|
||||||
|
[ 52] = "KMCTR TDES protected key",
|
||||||
|
[ 53] = "KMCTR AES 128bit",
|
||||||
|
[ 54] = "KMCTR AES 192bit",
|
||||||
|
[ 55] = "KMCTR AES 256bit",
|
||||||
|
[ 56] = "KMCTR AES 128bit protected key",
|
||||||
|
[ 57] = "KMCTR AES 192bit protected key",
|
||||||
|
[ 58] = "KMCTR AES 256bit protected key",
|
||||||
|
[ 59] = "KMO DES",
|
||||||
|
[ 60] = "KMO 2key TDES",
|
||||||
|
[ 61] = "KMO TDES",
|
||||||
|
[ 62] = "KMO DES protected key",
|
||||||
|
[ 63] = "KMO 2key TDES protected key",
|
||||||
|
[ 64] = "KMO TDES protected key",
|
||||||
|
[ 65] = "KMO AES 128bit",
|
||||||
|
[ 66] = "KMO AES 192bit",
|
||||||
|
[ 67] = "KMO AES 256bit",
|
||||||
|
[ 68] = "KMO AES 128bit protected key",
|
||||||
|
[ 69] = "KMO AES 192bit protected key",
|
||||||
|
[ 70] = "KMO AES 256bit protected key",
|
||||||
|
[ 71] = "KIMD SHA1",
|
||||||
|
[ 72] = "KIMD SHA256",
|
||||||
|
[ 73] = "KIMD SHA512",
|
||||||
|
[ 74] = "KIMD SHA3-224",
|
||||||
|
[ 75] = "KIMD SHA3-256",
|
||||||
|
[ 76] = "KIMD SHA3-384",
|
||||||
|
[ 77] = "KIMD SHA3-512",
|
||||||
|
[ 78] = "KIMD SHAKE 128",
|
||||||
|
[ 79] = "KIMD SHAKE 256",
|
||||||
|
[ 80] = "KIMD GHASH",
|
||||||
|
[ 81] = "KLMD SHA1",
|
||||||
|
[ 82] = "KLMD SHA256",
|
||||||
|
[ 83] = "KLMD SHA512",
|
||||||
|
[ 84] = "KLMD SHA3-224",
|
||||||
|
[ 85] = "KLMD SHA3-256",
|
||||||
|
[ 86] = "KLMD SHA3-384",
|
||||||
|
[ 87] = "KLMD SHA3-512",
|
||||||
|
[ 88] = "KLMD SHAKE 128",
|
||||||
|
[ 89] = "KLMD SHAKE 256",
|
||||||
|
[ 90] = "KMAC DES",
|
||||||
|
[ 91] = "KMAC 2key TDES",
|
||||||
|
[ 92] = "KMAC TDES",
|
||||||
|
[ 93] = "KMAC DES protected key",
|
||||||
|
[ 94] = "KMAC 2key TDES protected key",
|
||||||
|
[ 95] = "KMAC TDES protected key",
|
||||||
|
[ 96] = "KMAC AES 128bit",
|
||||||
|
[ 97] = "KMAC AES 192bit",
|
||||||
|
[ 98] = "KMAC AES 256bit",
|
||||||
|
[ 99] = "KMAC AES 128bit protected key",
|
||||||
|
[100] = "KMAC AES 192bit protected key",
|
||||||
|
[101] = "KMAC AES 256bit protected key",
|
||||||
|
[102] = "PCC Last Block CMAC DES",
|
||||||
|
[103] = "PCC Last Block CMAC 2key TDES",
|
||||||
|
[104] = "PCC Last Block CMAC TDES",
|
||||||
|
[105] = "PCC Last Block CMAC DES protected key",
|
||||||
|
[106] = "PCC Last Block CMAC 2key TDES protected key",
|
||||||
|
[107] = "PCC Last Block CMAC TDES protected key",
|
||||||
|
[108] = "PCC Last Block CMAC AES 128bit",
|
||||||
|
[109] = "PCC Last Block CMAC AES 192bit",
|
||||||
|
[110] = "PCC Last Block CMAC AES 256bit",
|
||||||
|
[111] = "PCC Last Block CMAC AES 128bit protected key",
|
||||||
|
[112] = "PCC Last Block CMAC AES 192bit protected key",
|
||||||
|
[113] = "PCC Last Block CMAC AES 256bit protected key",
|
||||||
|
[114] = "PCC XTS Parameter AES 128bit",
|
||||||
|
[115] = "PCC XTS Parameter AES 256bit",
|
||||||
|
[116] = "PCC XTS Parameter AES 128bit protected key",
|
||||||
|
[117] = "PCC XTS Parameter AES 256bit protected key",
|
||||||
|
[118] = "PCC Scalar Mult P256",
|
||||||
|
[119] = "PCC Scalar Mult P384",
|
||||||
|
[120] = "PCC Scalar Mult P521",
|
||||||
|
[121] = "PCC Scalar Mult Ed25519",
|
||||||
|
[122] = "PCC Scalar Mult Ed448",
|
||||||
|
[123] = "PCC Scalar Mult X25519",
|
||||||
|
[124] = "PCC Scalar Mult X448",
|
||||||
|
[125] = "PRNO SHA512 DRNG",
|
||||||
|
[126] = "PRNO TRNG Query Ratio",
|
||||||
|
[127] = "PRNO TRNG",
|
||||||
|
[128] = "KDSA ECDSA Verify P256",
|
||||||
|
[129] = "KDSA ECDSA Verify P384",
|
||||||
|
[130] = "KDSA ECDSA Verify P521",
|
||||||
|
[131] = "KDSA ECDSA Sign P256",
|
||||||
|
[132] = "KDSA ECDSA Sign P384",
|
||||||
|
[133] = "KDSA ECDSA Sign P521",
|
||||||
|
[134] = "KDSA ECDSA Sign P256 protected key",
|
||||||
|
[135] = "KDSA ECDSA Sign P384 protected key",
|
||||||
|
[136] = "KDSA ECDSA Sign P521 protected key",
|
||||||
|
[137] = "KDSA EdDSA Verify Ed25519",
|
||||||
|
[138] = "KDSA EdDSA Verify Ed448",
|
||||||
|
[139] = "KDSA EdDSA Sign Ed25519",
|
||||||
|
[140] = "KDSA EdDSA Sign Ed448",
|
||||||
|
[141] = "KDSA EdDSA Sign Ed25519 protected key",
|
||||||
|
[142] = "KDSA EdDSA Sign Ed448 protected key",
|
||||||
|
[143] = "PCKMO DES",
|
||||||
|
[144] = "PCKMO 2key TDES",
|
||||||
|
[145] = "PCMKO TDES",
|
||||||
|
[146] = "PCKMO AES 128bit",
|
||||||
|
[147] = "PCKMO AES 192bit",
|
||||||
|
[148] = "PCMKO AES 256bit",
|
||||||
|
[149] = "PCKMO ECC P256",
|
||||||
|
[150] = "PCKMO ECC P384",
|
||||||
|
[151] = "PCKMO ECC P521",
|
||||||
|
[152] = "PCKMO ECC Ed25519",
|
||||||
|
[153] = "PCKMO ECC Ed448",
|
||||||
|
[154] = "Reserved 1",
|
||||||
|
[155] = "Reserved 2"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int paiprintnonzero;
|
||||||
|
|
||||||
|
|
||||||
static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
|
static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
@@ -62,7 +232,7 @@ static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
|
|||||||
m.query.m_ctr = ctr;
|
m.query.m_ctr = ctr;
|
||||||
m.query.m_cmd = cmd;
|
m.query.m_cmd = cmd;
|
||||||
|
|
||||||
return send_msg(s, &m);
|
return send_msg(s, &m, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -71,7 +241,7 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
|
|||||||
struct msg m;
|
struct msg m;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = recv_msg(s, &m);
|
rc = recv_msg(s, &m, 0);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
if (m.head.m_ver != VERSION) {
|
if (m.head.m_ver != VERSION) {
|
||||||
eprint("Received msg with wrong version %d != %d\n",
|
eprint("Received msg with wrong version %d != %d\n",
|
||||||
@@ -92,9 +262,139 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void print_answer(int ctr, int state, uint64_t value)
|
static void printjsonsep(void)
|
||||||
{
|
{
|
||||||
if (state < 0)
|
static const char *jsonsep = "";
|
||||||
|
|
||||||
|
fputs(jsonsep, stdout);
|
||||||
|
jsonsep = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void json_print_virtual_counter_answer(int s, int ctr,
|
||||||
|
int state, uint64_t value)
|
||||||
|
{
|
||||||
|
int paictr = 0, paistate = 0, ec;
|
||||||
|
uint64_t i, paivalue = 0, maxnum;
|
||||||
|
const char *space;
|
||||||
|
|
||||||
|
switch (ctr) {
|
||||||
|
case HOTPLUG_DETECTED:
|
||||||
|
printjsonsep();
|
||||||
|
printf("{\"counter\":\"hotplug detected\",");
|
||||||
|
if (state < 0)
|
||||||
|
printf("\"error\":%d}", state);
|
||||||
|
else
|
||||||
|
printf("\"value\":%d}", !!value);
|
||||||
|
return;
|
||||||
|
case PAI_USER:
|
||||||
|
maxnum = NUM_PAI_USER;
|
||||||
|
space = "user";
|
||||||
|
break;
|
||||||
|
case PAI_KERNEL:
|
||||||
|
maxnum = NUM_PAI_KERNEL;
|
||||||
|
space = "kernel";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Here, we have validated the PAI counter retrieved, but not
|
||||||
|
* yet printed. */
|
||||||
|
if (state != ENABLED)
|
||||||
|
return;
|
||||||
|
if (value > maxnum) {
|
||||||
|
eprint("Incompatible versions detected!\n");
|
||||||
|
eprint("Expected %"PRIu64" counter space for %s, but got %"PRIu64"\n",
|
||||||
|
maxnum, space, value);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
for (i = 0; i < value; ++i) {
|
||||||
|
ec = recv_answer(s, &paictr, &paistate, &paivalue);
|
||||||
|
if (ec < 0 || paistate < 0) {
|
||||||
|
eprint("Error on receiving answer message from daemon\n");
|
||||||
|
/* No more data for this virtual event after error. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (paictr > NUM_PAI_KERNEL) {
|
||||||
|
eprint("Pai counter number too big: %d\n", paictr);
|
||||||
|
} else {
|
||||||
|
printjsonsep();
|
||||||
|
printf("{\"counter\":\"%s\",\"space\":\"%s\",\"counterid\":%d,",
|
||||||
|
pai_str[paictr], space, paictr + 1);
|
||||||
|
if (paistate < 0) {
|
||||||
|
printf("\"error\":%d}", paistate);
|
||||||
|
/* Protocol does not send furter counters. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("\"value\":%"PRIu64"}", paivalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void print_virtual_counter_answer(int s,
|
||||||
|
int ctr, int state, uint64_t value)
|
||||||
|
{
|
||||||
|
static const char *const states[] = {
|
||||||
|
[DISABLED] = "disabled",
|
||||||
|
[ENABLED] = "enabled",
|
||||||
|
[UNSUPPORTED] = "unsupported"
|
||||||
|
};
|
||||||
|
int paictr = 0, paistate = 0, ec;
|
||||||
|
uint64_t i, paivalue = 0, maxnum;
|
||||||
|
const char *ctrstr;
|
||||||
|
|
||||||
|
switch (ctr) {
|
||||||
|
case HOTPLUG_DETECTED:
|
||||||
|
if (state >= 0 && value > 0)
|
||||||
|
printf(" hotplug detected\n");
|
||||||
|
return;
|
||||||
|
case PAI_USER:
|
||||||
|
maxnum = NUM_PAI_USER;
|
||||||
|
ctrstr = "pai_user";
|
||||||
|
break;
|
||||||
|
case PAI_KERNEL:
|
||||||
|
maxnum = NUM_PAI_KERNEL;
|
||||||
|
ctrstr = "pai_kernel";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Here, we have validated the PAI counter retrieved, but not
|
||||||
|
* yet printed. */
|
||||||
|
if (state < 0 || state > UNSUPPORTED) {
|
||||||
|
printf(" %11s: error state %d\n", ctrstr, state);
|
||||||
|
/* No details follow if counter in error state. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf(" %-11s: %s\n", ctrstr, states[state]);
|
||||||
|
if (state != ENABLED)
|
||||||
|
return;
|
||||||
|
if (value > maxnum) {
|
||||||
|
eprint("Incompatible versions detected!\n");
|
||||||
|
eprint("Expected %"PRIu64" counters for %s, but got %"PRIu64"\n",
|
||||||
|
maxnum, ctrstr, value);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
for (i = 0; i < value; ++i) {
|
||||||
|
ec = recv_answer(s, &paictr, &paistate, &paivalue);
|
||||||
|
if (ec < 0 || paistate < 0) {
|
||||||
|
eprint("Error on receiving answer message from daemon\n");
|
||||||
|
/* No more data for this virtual event after error. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (paictr > NUM_PAI_KERNEL)
|
||||||
|
eprint("Pai counter number too big: %d\n", paictr);
|
||||||
|
else if (!paiprintnonzero || paivalue > 0)
|
||||||
|
printf(" %-45s: %"PRIu64"\n", pai_str[paictr], paivalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_answer(int s, int ctr, int state, uint64_t value)
|
||||||
|
{
|
||||||
|
if (ctr > ALL_COUNTER)
|
||||||
|
print_virtual_counter_answer(s, ctr, state, value);
|
||||||
|
else if (state < 0)
|
||||||
printf(" %s counter: error state %d\n",
|
printf(" %s counter: error state %d\n",
|
||||||
counter_str[ctr], state);
|
counter_str[ctr], state);
|
||||||
else if (state == DISABLED)
|
else if (state == DISABLED)
|
||||||
@@ -106,6 +406,22 @@ static void print_answer(int ctr, int state, uint64_t value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void json_print_answer(int s, int ctr, int state, uint64_t value)
|
||||||
|
{
|
||||||
|
if (ctr > ALL_COUNTER) {
|
||||||
|
json_print_virtual_counter_answer(s, ctr, state, value);
|
||||||
|
} else if (state < 0) {
|
||||||
|
printjsonsep();
|
||||||
|
printf("{\"counter\":\"%s\",", counter_str[ctr]);
|
||||||
|
printf("\"error\":%d}\n", state);
|
||||||
|
} else if (state == ENABLED) {
|
||||||
|
printjsonsep();
|
||||||
|
printf("{\"counter\":\"%s\",", counter_str[ctr]);
|
||||||
|
printf("\"value\":%"PRIu64"}", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int eprint(const char *format, ...)
|
int eprint(const char *format, ...)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@@ -128,7 +444,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
enum ctr_e ctr = ALL_COUNTER;
|
enum ctr_e ctr = ALL_COUNTER;
|
||||||
enum cmd_e cmd = PRINT;
|
enum cmd_e cmd = PRINT;
|
||||||
int i, j, s, state;
|
int i, j, s, state, num, json = 0;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
@@ -140,98 +456,108 @@ int main(int argc, char *argv[])
|
|||||||
{ "disable", 0, NULL, 'd' },
|
{ "disable", 0, NULL, 'd' },
|
||||||
{ "reset", 0, NULL, 'r' },
|
{ "reset", 0, NULL, 'r' },
|
||||||
{ "print", 0, NULL, 'p' },
|
{ "print", 0, NULL, 'p' },
|
||||||
|
{ "nonzero", 0, NULL, 'n' },
|
||||||
|
{ "json", 0, NULL, 'j' },
|
||||||
{ NULL, 0, NULL, 0 } };
|
{ NULL, 0, NULL, 0 } };
|
||||||
while (1) {
|
while (1) {
|
||||||
opt = getopt_long(argc, argv,
|
opt = getopt_long(argc, argv,
|
||||||
"hvedrp", long_opts, &idx);
|
"hvedrpnj", long_opts, &idx);
|
||||||
if (opt == -1)
|
if (opt == -1)
|
||||||
break; /* no more arguments */
|
break; /* no more arguments */
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
printf(usage, name);
|
printf(usage, name);
|
||||||
exit(0);
|
return 0;
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
|
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
|
||||||
"Version %s\n%s\n",
|
"Version %s\n%s\n",
|
||||||
name, RELEASE_STRING, COPYRIGHT);
|
name, RELEASE_STRING, COPYRIGHT);
|
||||||
exit(0);
|
return 0;
|
||||||
break;
|
|
||||||
case 'e':
|
case 'e':
|
||||||
cmd = ENABLE;
|
cmd = ENABLE;
|
||||||
|
json = 0;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
cmd = DISABLE;
|
cmd = DISABLE;
|
||||||
|
json = 0;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
cmd = RESET;
|
cmd = RESET;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
cmd = PRINT;
|
cmd = PRINT;
|
||||||
|
json = 0;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
paiprintnonzero = 1;
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
cmd = PRINT;
|
||||||
|
json = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
eprint("Invalid argument, try -h or --help for more information\n");
|
eprint("Invalid argument, try -h or --help for more information\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* there may be an optional counter argument */
|
/* there may be an optional counter argument */
|
||||||
if (optind > 0 && optind < argc) {
|
if (optind > 0 && optind < argc) {
|
||||||
for (i = 0; i <= ALL_COUNTER; i++)
|
for (i = 0; i < NUM_COUNTER; i++)
|
||||||
if (strcmp(argv[optind], counter_str[i]) == 0)
|
if (strcmp(argv[optind], counter_str[i]) == 0)
|
||||||
break;
|
break;
|
||||||
if (i > ALL_COUNTER) {
|
if (i >= NUM_COUNTER) {
|
||||||
eprint("Unknown counter '%s'\n", argv[optind]);
|
eprint("Unknown counter '%s'\n", argv[optind]);
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
ctr = (enum ctr_e) i;
|
ctr = (enum ctr_e) i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (json)
|
||||||
|
ctr = ALL_COUNTER;
|
||||||
|
|
||||||
/* try to open and connect socket to the cpacfstatsd daemon */
|
/* try to open and connect socket to the cpacfstatsd daemon */
|
||||||
s = open_socket(CLIENT);
|
s = open_socket(CLIENT);
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
eprint("Can't connect to daemon\n");
|
eprint("Can't connect to daemon\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send query */
|
/* send query */
|
||||||
if (send_query(s, cmd, ctr) != 0) {
|
if (send_query(s, cmd, ctr) != 0) {
|
||||||
eprint("Error on sending query message to daemon\n");
|
eprint("Error on sending query message to daemon\n");
|
||||||
close(s);
|
close(s);
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
/* The -1 is for ALL_COUNTER which is not sent, +1 for
|
||||||
/* receive answer */
|
* hotplug state. */
|
||||||
if (recv_answer(s, &j, &state, &value) != 0) {
|
num = NUM_COUNTER - 1 + 1;
|
||||||
eprint("Error on receiving answer message from daemon\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (state < 0) {
|
|
||||||
eprint("Received bad status code %d from daemon\n",
|
|
||||||
state);
|
|
||||||
close(s);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
print_answer(j, state, value);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
/* +1 for hotplug state */
|
||||||
|
num = 1 + 1;
|
||||||
|
}
|
||||||
|
if (json)
|
||||||
|
putchar('[');
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
/* receive answer */
|
/* receive answer */
|
||||||
if (recv_answer(s, &j, &state, &value) != 0) {
|
if (recv_answer(s, &j, &state, &value) != 0) {
|
||||||
eprint("Error on receiving answer message from daemon\n");
|
eprint("Error on receiving answer message from daemon\n");
|
||||||
close(s);
|
return EXIT_FAILURE;
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
if (state < 0) {
|
if (state < 0) {
|
||||||
eprint("Received bad status code %d from daemon\n",
|
eprint("Received bad status code %d from daemon\n",
|
||||||
state);
|
state);
|
||||||
close(s);
|
close(s);
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
print_answer(j, state, value);
|
if (json)
|
||||||
|
json_print_answer(s, j, state, value);
|
||||||
|
else
|
||||||
|
print_answer(s, j, state, value);
|
||||||
}
|
}
|
||||||
|
if (json)
|
||||||
|
putchar(']');
|
||||||
|
|
||||||
/* close connection */
|
/* close connection */
|
||||||
close(s);
|
close(s);
|
||||||
|
|||||||
+30
-9
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* common function prototypes and definitions
|
* common function prototypes and definitions
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2015, 2020
|
* Copyright IBM Corp. 2015, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -14,13 +14,27 @@
|
|||||||
|
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
#define COPYRIGHT "Copyright IBM Corp. 2015, 2020"
|
#define COPYRIGHT "Copyright IBM Corp. 2015, 2022"
|
||||||
|
|
||||||
|
#define DEFAULT_SEND_TIMEOUT (30 * 1000)
|
||||||
|
#define DEFAULT_RECV_TIMEOUT (30 * 1000)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of PAI counters for user space. This excludes PCKMO since
|
||||||
|
* this instruction is privileged.
|
||||||
|
*/
|
||||||
|
#define NUM_PAI_USER 143
|
||||||
|
/* Number of PAI counters for kernel space. Contains all counters. */
|
||||||
|
#define NUM_PAI_KERNEL 156
|
||||||
|
|
||||||
int eprint(const char *format, ...);
|
int eprint(const char *format, ...);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Counter names
|
* Counter names
|
||||||
* ALL_COUNTER must always be the last member of the enum
|
* ALL_COUNTER specifies the number of physical counters. Virtual
|
||||||
|
* counters might be added afterwards. NUM_COUNTER is the last
|
||||||
|
* managed counter (i.e., a counter that can be activated, reset,
|
||||||
|
* deactivated).
|
||||||
*/
|
*/
|
||||||
enum ctr_e {
|
enum ctr_e {
|
||||||
DES_FUNCTIONS = 0,
|
DES_FUNCTIONS = 0,
|
||||||
@@ -28,7 +42,11 @@ enum ctr_e {
|
|||||||
SHA_FUNCTIONS,
|
SHA_FUNCTIONS,
|
||||||
PRNG_FUNCTIONS,
|
PRNG_FUNCTIONS,
|
||||||
ECC_FUNCTIONS,
|
ECC_FUNCTIONS,
|
||||||
ALL_COUNTER
|
ALL_COUNTER,
|
||||||
|
PAI_USER,
|
||||||
|
PAI_KERNEL,
|
||||||
|
NUM_COUNTER,
|
||||||
|
HOTPLUG_DETECTED = 0xffff
|
||||||
};
|
};
|
||||||
|
|
||||||
enum type_e {
|
enum type_e {
|
||||||
@@ -50,7 +68,7 @@ enum state_e {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* query send from clent to daemon
|
* query send from client to daemon
|
||||||
* Consist of:
|
* Consist of:
|
||||||
* enum counter
|
* enum counter
|
||||||
* enum command
|
* enum command
|
||||||
@@ -63,7 +81,7 @@ struct msg_query {
|
|||||||
/*
|
/*
|
||||||
* answer send from daemon to client
|
* answer send from daemon to client
|
||||||
* Consist of:
|
* Consist of:
|
||||||
* enum counter
|
* enum counter or PAI counter number if following PAI_USER or PAI_KERNEL
|
||||||
* status code: < 0 error, 0 disabled, > 0 enabled
|
* status code: < 0 error, 0 disabled, > 0 enabled
|
||||||
* counter value
|
* counter value
|
||||||
*/
|
*/
|
||||||
@@ -99,17 +117,20 @@ struct msg {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
int open_socket(int mode);
|
int open_socket(int mode);
|
||||||
int send_msg(int sfd, struct msg *m);
|
int send_msg(int sfd, struct msg *m, int timeout);
|
||||||
int recv_msg(int sfd, struct msg *m);
|
int recv_msg(int sfd, struct msg *m, int timeout);
|
||||||
|
|
||||||
/* perf_crypto.c */
|
/* perf_crypto.c */
|
||||||
|
|
||||||
int perf_init(void);
|
int perf_init(void);
|
||||||
|
void perf_stop(void);
|
||||||
void perf_close(void);
|
void perf_close(void);
|
||||||
int perf_enable_ctr(enum ctr_e ctr);
|
int perf_enable_ctr(enum ctr_e ctr);
|
||||||
int perf_disable_ctr(enum ctr_e ctr);
|
int perf_disable_ctr(enum ctr_e ctr);
|
||||||
int perf_reset_ctr(enum ctr_e ctr);
|
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value);
|
||||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
|
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
|
||||||
int perf_ecc_supported(void);
|
int perf_ecc_supported(void);
|
||||||
|
int perf_ctr_state(enum ctr_e ctr);
|
||||||
|
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+124
-62
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* cpacfstatsd daemon implementation
|
* cpacfstatsd daemon implementation
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2015, 2017
|
* Copyright IBM Corp. 2015, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
#include "cpacfstats.h"
|
#include "cpacfstats.h"
|
||||||
|
|
||||||
|
static volatile int stopsig;
|
||||||
|
|
||||||
static const char *const name = "cpacfstatsd";
|
static const char *const name = "cpacfstatsd";
|
||||||
|
|
||||||
@@ -43,15 +44,12 @@ static const char *const usage =
|
|||||||
|
|
||||||
static int daemonized;
|
static int daemonized;
|
||||||
|
|
||||||
static int ctr_state[ALL_COUNTER];
|
|
||||||
|
|
||||||
|
|
||||||
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
||||||
{
|
{
|
||||||
struct msg m;
|
struct msg m;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = recv_msg(s, &m);
|
rc = recv_msg(s, &m, DEFAULT_RECV_TIMEOUT);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
if (m.head.m_ver != VERSION) {
|
if (m.head.m_ver != VERSION) {
|
||||||
eprint("Received msg with wrong version %d != %d\n",
|
eprint("Received msg with wrong version %d != %d\n",
|
||||||
@@ -83,38 +81,82 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
|
|||||||
m.answer.m_state = state;
|
m.answer.m_state = state;
|
||||||
m.answer.m_value = value;
|
m.answer.m_value = value;
|
||||||
|
|
||||||
return send_msg(s, &m);
|
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print according to protocol for PAI:
|
||||||
|
* - first the state and the number of PAI counters that follow
|
||||||
|
* - if state is ENABLED:
|
||||||
|
* - for each PAI counter the value with state ENABLED
|
||||||
|
* Note that the PAI counters are 0-based, not 1 based as in PoP!
|
||||||
|
* Sending ends with the first error.
|
||||||
|
*/
|
||||||
|
static int do_send_pai(int s, int user)
|
||||||
|
{
|
||||||
|
int ctr, state, i, maxctr, rc = 0;
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
ctr = PAI_USER;
|
||||||
|
maxctr = NUM_PAI_USER;
|
||||||
|
} else {
|
||||||
|
ctr = PAI_KERNEL;
|
||||||
|
maxctr = NUM_PAI_KERNEL;
|
||||||
|
}
|
||||||
|
state = perf_ctr_state(ctr);
|
||||||
|
if (state != ENABLED)
|
||||||
|
return rc;
|
||||||
|
for (i = 0; i < maxctr; ++i) {
|
||||||
|
rc = perf_read_pai_ctr(i, user, &value);
|
||||||
|
if (rc != 0) {
|
||||||
|
send_answer(s, i, rc, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
send_answer(s, i, state, value);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_enable(int s, enum ctr_e ctr)
|
static int do_enable(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
uint64_t value;
|
uint64_t value = 0;
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
|
int state;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < NUM_COUNTER; i++) {
|
||||||
|
if (i == ALL_COUNTER)
|
||||||
|
continue;
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == DISABLED) {
|
state = perf_ctr_state(i);
|
||||||
|
if (state == DISABLED) {
|
||||||
rc = perf_enable_ctr(i);
|
rc = perf_enable_ctr(i);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ctr_state[i] = ENABLED;
|
state = ENABLED;
|
||||||
}
|
}
|
||||||
if (ctr_state[i] == UNSUPPORTED) {
|
if (state != UNSUPPORTED) {
|
||||||
send_answer(s, i, UNSUPPORTED, 0);
|
|
||||||
} else {
|
|
||||||
rc = perf_read_ctr(i, &value);
|
rc = perf_read_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
send_answer(s, i, ENABLED, value);
|
|
||||||
}
|
}
|
||||||
|
send_answer(s, i, state, value);
|
||||||
|
if (i == PAI_USER)
|
||||||
|
rc = do_send_pai(s, 1);
|
||||||
|
if (i == PAI_KERNEL)
|
||||||
|
rc = do_send_pai(s, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,67 +164,90 @@ static int do_enable(int s, enum ctr_e ctr)
|
|||||||
static int do_disable(int s, enum ctr_e ctr)
|
static int do_disable(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < NUM_COUNTER; i++) {
|
||||||
|
if (i == ALL_COUNTER)
|
||||||
|
continue;
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
if (perf_ctr_state(i) == ENABLED) {
|
||||||
rc = perf_disable_ctr(i);
|
rc = perf_disable_ctr(i);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ctr_state[i] = 0;
|
|
||||||
}
|
}
|
||||||
send_answer(s, i, ctr_state[i], 0);
|
send_answer(s, i, perf_ctr_state(i), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_reset(int s, enum ctr_e ctr)
|
static int do_reset(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0, state;
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < NUM_COUNTER; i++) {
|
||||||
|
if (i == ALL_COUNTER)
|
||||||
|
continue;
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
state = perf_ctr_state(i);
|
||||||
rc = perf_reset_ctr(i);
|
if (state == ENABLED) {
|
||||||
|
rc = perf_reset_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
send_answer(s, i, ENABLED, 0);
|
|
||||||
} else {
|
|
||||||
send_answer(s, i, ctr_state[i], 0);
|
|
||||||
}
|
}
|
||||||
|
send_answer(s, i, state, value);
|
||||||
|
if (i == PAI_USER)
|
||||||
|
rc = do_send_pai(s, 1);
|
||||||
|
if (i == PAI_KERNEL)
|
||||||
|
rc = do_send_pai(s, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_print(int s, enum ctr_e ctr)
|
static int do_print(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0, state;
|
||||||
uint64_t value;
|
uint64_t value = 0;
|
||||||
|
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
for (i = 0; i < NUM_COUNTER; i++) {
|
||||||
|
if (i == ALL_COUNTER)
|
||||||
|
continue;
|
||||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
state = perf_ctr_state(i);
|
||||||
|
if (state == ENABLED) {
|
||||||
rc = perf_read_ctr(i, &value);
|
rc = perf_read_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
send_answer(s, i, ENABLED, value);
|
|
||||||
} else {
|
|
||||||
send_answer(s, i, ctr_state[i], 0);
|
|
||||||
}
|
}
|
||||||
|
send_answer(s, i, state, value);
|
||||||
|
if (i == PAI_USER)
|
||||||
|
rc = do_send_pai(s, 1);
|
||||||
|
if (i == PAI_KERNEL)
|
||||||
|
rc = do_send_pai(s, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||||
|
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,18 +389,8 @@ static void remove_pidfile(void)
|
|||||||
|
|
||||||
void signalhandler(int sig)
|
void signalhandler(int sig)
|
||||||
{
|
{
|
||||||
if (sig == SIGTERM)
|
perf_stop();
|
||||||
eprint("Caught signal SIGTERM, terminating...\n");
|
stopsig = sig;
|
||||||
else if (sig == SIGINT)
|
|
||||||
eprint("Caught signal SIGINT, terminating...\n");
|
|
||||||
else
|
|
||||||
eprint("Caught signal %d, terminating...\n", sig);
|
|
||||||
|
|
||||||
remove_sock();
|
|
||||||
perf_close();
|
|
||||||
remove_pidfile();
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -381,7 +436,7 @@ int main(int argc, char *argv[])
|
|||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
printf(usage, name);
|
printf(usage, name);
|
||||||
exit(0);
|
return 0;
|
||||||
case 'f':
|
case 'f':
|
||||||
foreground = 1;
|
foreground = 1;
|
||||||
break;
|
break;
|
||||||
@@ -389,40 +444,37 @@ int main(int argc, char *argv[])
|
|||||||
printf("%s: Linux on System z CPACF Crypto Activity Counters Daemon\n"
|
printf("%s: Linux on System z CPACF Crypto Activity Counters Daemon\n"
|
||||||
"Version %s\n%s\n",
|
"Version %s\n%s\n",
|
||||||
name, RELEASE_STRING, COPYRIGHT);
|
name, RELEASE_STRING, COPYRIGHT);
|
||||||
exit(0);
|
return 0;
|
||||||
default:
|
default:
|
||||||
printf("%s: Invalid argument, try -h or --help for more information\n",
|
printf("%s: Invalid argument, try -h or --help for more information\n",
|
||||||
name);
|
name);
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_pidfile() != 0) {
|
if (check_pidfile() != 0) {
|
||||||
eprint("Stalled pid file or daemon allready running, terminating\n");
|
eprint("Stalled pid file or daemon allready running, terminating\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foreground) {
|
if (!foreground) {
|
||||||
if (become_daemon() != 0) {
|
if (become_daemon() != 0) {
|
||||||
eprint("Couldn't daemonize\n");
|
eprint("Couldn't daemonize\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perf_init() != 0) {
|
if (perf_init() != 0) {
|
||||||
eprint("Couldn't initialize perf lib\n");
|
eprint("Couldn't initialize perf lib\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
atexit(perf_close);
|
atexit(perf_close);
|
||||||
|
|
||||||
if (!perf_ecc_supported())
|
|
||||||
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
|
||||||
|
|
||||||
sfd = open_socket(SERVER);
|
sfd = open_socket(SERVER);
|
||||||
if (sfd < 0) {
|
if (sfd < 0) {
|
||||||
eprint("Couldn't initialize server socket\n");
|
eprint("Couldn't initialize server socket\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
atexit(remove_sock);
|
atexit(remove_sock);
|
||||||
|
|
||||||
@@ -432,17 +484,19 @@ int main(int argc, char *argv[])
|
|||||||
if (sigaction(SIGINT, &act, 0) != 0) {
|
if (sigaction(SIGINT, &act, 0) != 0) {
|
||||||
eprint("Couldn't establish signal handler for SIGINT, errno=%d [%s]\n",
|
eprint("Couldn't establish signal handler for SIGINT, errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (sigaction(SIGTERM, &act, 0) != 0) {
|
if (sigaction(SIGTERM, &act, 0) != 0) {
|
||||||
eprint("Couldn't establish signal handler for SIGTERM, errno=%d [%s]\n",
|
eprint("Couldn't establish signal handler for SIGTERM, errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
/* Ignore SIGPIPE such that we see EPIPE as return from write. */
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
eprint("Running\n");
|
eprint("Running\n");
|
||||||
|
|
||||||
while (1) {
|
while (!stopsig) {
|
||||||
enum ctr_e ctr;
|
enum ctr_e ctr;
|
||||||
enum cmd_e cmd;
|
enum cmd_e cmd;
|
||||||
int s;
|
int s;
|
||||||
@@ -453,7 +507,7 @@ int main(int argc, char *argv[])
|
|||||||
continue;
|
continue;
|
||||||
eprint("Accept() failure, errno=%d [%s]\n",
|
eprint("Accept() failure, errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = recv_query(s, &ctr, &cmd);
|
rc = recv_query(s, &ctr, &cmd);
|
||||||
@@ -480,5 +534,13 @@ cleanup:
|
|||||||
close(s);
|
close(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stopsig == SIGTERM)
|
||||||
|
eprint("Caught signal SIGTERM, terminating...\n");
|
||||||
|
else if (stopsig == SIGINT)
|
||||||
|
eprint("Caught signal SIGINT, terminating...\n");
|
||||||
|
else
|
||||||
|
eprint("Caught signal %d, terminating...\n", stopsig);
|
||||||
|
remove_pidfile();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+615
-124
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* low level perf functions
|
* low level perf functions
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2015, 2020
|
* Copyright IBM Corp. 2015, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -16,14 +16,21 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libudev.h>
|
||||||
|
|
||||||
#include "cpacfstats.h"
|
#include "cpacfstats.h"
|
||||||
|
#include "../include/lib/zt_common.h"
|
||||||
|
|
||||||
/* correlation between counter and perf counter string */
|
/* correlation between counter and perf counter string */
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -38,25 +45,83 @@ static const struct {
|
|||||||
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
static struct pmf_data {
|
||||||
* We need one filedescriptor per CPU per counter.
|
int pmutype;
|
||||||
* So perf_init builds this:
|
int eventid;
|
||||||
*
|
} pmf_counter_data[ALL_COUNTER];
|
||||||
* ctr_fds - is an array of pointers to file descriptor arrays.
|
|
||||||
* Each file descriptor array has space for number of logical CPUs + 1
|
|
||||||
* filedescriptors (int values). The last element of each file descriptor
|
|
||||||
* array is always 0, assuming there will never appear a filedescriptor
|
|
||||||
* with value 0:
|
|
||||||
*
|
|
||||||
* ctr_fds:
|
|
||||||
* ctr_fds[0] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
|
|
||||||
* ctr_fds[1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
|
|
||||||
* ...
|
|
||||||
* ctr_fds[ALL_COUNTER-1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
|
|
||||||
*/
|
|
||||||
static int *ctr_fds[ALL_COUNTER];
|
|
||||||
|
|
||||||
static int ecc_supported;
|
struct percpucounter {
|
||||||
|
int ctr_fds[ALL_COUNTER];
|
||||||
|
int pai_user[NUM_PAI_USER];
|
||||||
|
int pai_kernel[NUM_PAI_KERNEL];
|
||||||
|
unsigned int cpunum;
|
||||||
|
struct percpucounter *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct percpucounter *root;
|
||||||
|
pthread_mutex_t rootmux = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static volatile int hotplugdetected;
|
||||||
|
static unsigned int enabledcounter;
|
||||||
|
pthread_t hotplugthread;
|
||||||
|
|
||||||
|
#define foreachcpu(PCPU) if (pthread_mutex_lock(&rootmux)) return -1; \
|
||||||
|
for ((PCPU) = root; (PCPU) != NULL; (PCPU) = (PCPU)->next)
|
||||||
|
#define endforeachcpu() pthread_mutex_unlock(&rootmux)
|
||||||
|
|
||||||
|
static int ctr_state[NUM_COUNTER];
|
||||||
|
|
||||||
|
static volatile int stoprequested;
|
||||||
|
|
||||||
|
static int paipmutype, paipmueventstart;
|
||||||
|
|
||||||
|
static struct percpucounter *allocpercpucounter(unsigned int cpunum)
|
||||||
|
{
|
||||||
|
struct percpucounter *ppc;
|
||||||
|
|
||||||
|
ppc = malloc(sizeof(struct percpucounter));
|
||||||
|
if (ppc) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ALL_COUNTER; ++i)
|
||||||
|
ppc->ctr_fds[i] = -1;
|
||||||
|
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||||
|
ppc->pai_user[i] = -1;
|
||||||
|
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||||
|
ppc->pai_kernel[i] = -1;
|
||||||
|
ppc->cpunum = cpunum;
|
||||||
|
ppc->next = NULL;
|
||||||
|
}
|
||||||
|
return ppc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freepercpucounter(struct percpucounter *pcpu)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ALL_COUNTER; ++i)
|
||||||
|
(void)close(pcpu->ctr_fds[i]);
|
||||||
|
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||||
|
(void)close(pcpu->pai_user[i]);
|
||||||
|
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||||
|
(void)close(pcpu->pai_kernel[i]);
|
||||||
|
free(pcpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct percpucounter *findcpu(unsigned int cpunum, int unlinkflag)
|
||||||
|
{
|
||||||
|
struct percpucounter **prev = &root, *walk = root;
|
||||||
|
|
||||||
|
while (walk) {
|
||||||
|
if (walk->cpunum == cpunum) {
|
||||||
|
if (unlinkflag)
|
||||||
|
*prev = walk->next;
|
||||||
|
return walk;
|
||||||
|
}
|
||||||
|
prev = &(walk->next);
|
||||||
|
walk = walk->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||||
int cpu, int group_fd, unsigned long flags)
|
int cpu, int group_fd, unsigned long flags)
|
||||||
@@ -85,12 +150,43 @@ static int perf_counter_supported(const char *pmu, const char *counter)
|
|||||||
return !access(buf, R_OK);
|
return !access(buf, R_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_event_encode(struct perf_event_attr *attr,
|
static int cpumf_authorized(void)
|
||||||
|
{
|
||||||
|
unsigned vermin, vermax, auth;
|
||||||
|
int res = 0, found = 0;
|
||||||
|
size_t linesize = 0;
|
||||||
|
char *line = NULL;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
f = fopen("/proc/service_levels", "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
eprint("Failed to open /proc/service_levels (%d:%s)\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (getline(&line, &linesize, f) >= 0) {
|
||||||
|
if (sscanf(line,
|
||||||
|
"CPU-MF: Counter facility: version=%d.%d authorization=%x",
|
||||||
|
&vermin, &vermax, &auth) == 3) {
|
||||||
|
if (auth & 0x8)
|
||||||
|
res = 1;
|
||||||
|
else
|
||||||
|
eprint("CPU-MF counters not authorized.\n");
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
eprint("CPU-MF counters not available.\n");
|
||||||
|
free(line);
|
||||||
|
fclose(f);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int perf_event_encode(int *pmutype, int *eventid,
|
||||||
const char *pmu, const char *event)
|
const char *pmu, const char *event)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int eventid;
|
|
||||||
int pmutype;
|
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
||||||
@@ -104,7 +200,7 @@ static int perf_event_encode(struct perf_event_attr *attr,
|
|||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fscanf(f, "event=0x%x\n", &eventid) != 1) {
|
if (fscanf(f, "event=0x%x\n", eventid) != 1) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
eprint("Event file %s has invalid format\n", buf);
|
eprint("Event file %s has invalid format\n", buf);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -121,21 +217,257 @@ static int perf_event_encode(struct perf_event_attr *attr,
|
|||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fscanf(f, "%d\n", &pmutype) != 1) {
|
if (fscanf(f, "%d\n", pmutype) != 1) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
eprint("Type file %s has invalid format\n", buf);
|
eprint("Type file %s has invalid format\n", buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
attr->type = pmutype;
|
|
||||||
attr->config = eventid;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int activatecpu(unsigned int cpu)
|
||||||
|
{
|
||||||
|
struct perf_event_attr pfm_event;
|
||||||
|
struct percpucounter *ppc;
|
||||||
|
int fd, i, rc = 0;
|
||||||
|
|
||||||
|
ppc = allocpercpucounter(cpu);
|
||||||
|
if (ppc == NULL) {
|
||||||
|
eprint("Failed to allocate per cpu counter data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (pthread_mutex_lock(&rootmux)) {
|
||||||
|
freepercpucounter(ppc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* activate CPU-MF */
|
||||||
|
for (i = 0; i < ALL_COUNTER; ++i) {
|
||||||
|
if (ctr_state[i] == UNSUPPORTED)
|
||||||
|
continue;
|
||||||
|
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||||
|
pfm_event.size = sizeof(pfm_event);
|
||||||
|
pfm_event.type = pmf_counter_data[i].pmutype;
|
||||||
|
pfm_event.config = pmf_counter_data[i].eventid;
|
||||||
|
|
||||||
|
/* fetch file descriptor for this perf event
|
||||||
|
* the counter event should start disabled
|
||||||
|
*/
|
||||||
|
pfm_event.disabled = ctr_state[i] == DISABLED;
|
||||||
|
fd = perf_event_open(
|
||||||
|
&pfm_event,
|
||||||
|
-1, /* pid -1 means all processes */
|
||||||
|
cpu,
|
||||||
|
-1, /* group filedescriptor */
|
||||||
|
0); /* flags */
|
||||||
|
if (fd < 0) {
|
||||||
|
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
ctr_state[i] = UNSUPPORTED;
|
||||||
|
} else {
|
||||||
|
ppc->ctr_fds[i] = fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* activate pai_user and pai_kernel */
|
||||||
|
/* invariant:
|
||||||
|
(ctr_state[PAI_USER] == UNSUPPORTED) ==
|
||||||
|
(ctr_state[PAI_KERNEL] == UNSUPPORTED) */
|
||||||
|
if (ctr_state[PAI_USER] != UNSUPPORTED) {
|
||||||
|
for (i = 1; i <= NUM_PAI_USER; ++i) {
|
||||||
|
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||||
|
pfm_event.size = sizeof(pfm_event);
|
||||||
|
pfm_event.type = paipmutype;
|
||||||
|
pfm_event.config = paipmueventstart + i;
|
||||||
|
pfm_event.exclude_kernel = 1;
|
||||||
|
pfm_event.exclude_user = 0;
|
||||||
|
pfm_event.disabled = ctr_state[PAI_USER] == DISABLED;
|
||||||
|
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||||
|
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||||
|
goto outevents;
|
||||||
|
} else {
|
||||||
|
ppc->pai_user[i - 1] = fd;
|
||||||
|
}
|
||||||
|
pfm_event.exclude_kernel = 0;
|
||||||
|
pfm_event.exclude_user = 1;
|
||||||
|
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
|
||||||
|
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||||
|
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||||
|
goto outevents;
|
||||||
|
} else {
|
||||||
|
ppc->pai_kernel[i - 1] = fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i <= NUM_PAI_KERNEL; ++i) {
|
||||||
|
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||||
|
pfm_event.size = sizeof(pfm_event);
|
||||||
|
pfm_event.type = paipmutype;
|
||||||
|
pfm_event.config = paipmueventstart + i;
|
||||||
|
pfm_event.exclude_kernel = 0;
|
||||||
|
pfm_event.exclude_user = 1;
|
||||||
|
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
|
||||||
|
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||||
|
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||||
|
goto outevents;
|
||||||
|
} else {
|
||||||
|
ppc->pai_kernel[i - 1] = fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outevents:
|
||||||
|
ppc->next = root;
|
||||||
|
root = ppc;
|
||||||
|
if (enabledcounter)
|
||||||
|
hotplugdetected = 1;
|
||||||
|
pthread_mutex_unlock(&rootmux);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deactivatecpu(unsigned int cpunum)
|
||||||
|
{
|
||||||
|
struct percpucounter *pcpu;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (pthread_mutex_lock(&rootmux))
|
||||||
|
return;
|
||||||
|
pcpu = findcpu(cpunum, 1);
|
||||||
|
if (pcpu != NULL) {
|
||||||
|
for (i = 0; i < ALL_COUNTER; ++i)
|
||||||
|
(void)close(pcpu->ctr_fds[i]);
|
||||||
|
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||||
|
(void)close(pcpu->pai_user[i]);
|
||||||
|
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||||
|
(void)close(pcpu->pai_kernel[i]);
|
||||||
|
free(pcpu);
|
||||||
|
if (enabledcounter)
|
||||||
|
hotplugdetected = 1;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&rootmux);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int addallcpus(void)
|
||||||
|
{
|
||||||
|
unsigned int start, end;
|
||||||
|
int scanned, rc = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
/* comma separated list of intervals */
|
||||||
|
if ((fp = fopen("/sys/devices/system/cpu/online", "r")) == NULL) {
|
||||||
|
eprint("Failed to get online cpus (%d:%s)\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(fp)) {
|
||||||
|
/* scan all intervals of online cpus */
|
||||||
|
scanned = fscanf(fp, "%u-%u", &start, &end);
|
||||||
|
/* take care of singleton intervals */
|
||||||
|
if (scanned == 1)
|
||||||
|
end = start;
|
||||||
|
for (; start <= end; ++start) {
|
||||||
|
if (activatecpu(start)) {
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Skip comma separator */
|
||||||
|
(void)fgetc(fp);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
fclose(fp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int perf_load_counter_data(void)
|
||||||
|
{
|
||||||
|
int i, res = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ALL_COUNTER; ++i) {
|
||||||
|
if (ctr_state[i] != UNSUPPORTED)
|
||||||
|
res |= perf_event_encode(&pmf_counter_data[i].pmutype,
|
||||||
|
&pmf_counter_data[i].eventid,
|
||||||
|
pmf_counter_name[i].pmu,
|
||||||
|
pmf_counter_name[i].pfm_name);
|
||||||
|
}
|
||||||
|
if (ctr_state[PAI_USER] != UNSUPPORTED)
|
||||||
|
res |= perf_event_encode(&paipmutype, &paipmueventstart,
|
||||||
|
"pai_crypto", "CRYPTO_ALL");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *hotplughandler(void *UNUSED(unused))
|
||||||
|
{
|
||||||
|
struct udev *hotplug;
|
||||||
|
struct udev_monitor *monitor;
|
||||||
|
struct pollfd item;
|
||||||
|
|
||||||
|
hotplug = udev_new();
|
||||||
|
if (!hotplug) {
|
||||||
|
eprint("Failed to create hotplug device\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
monitor = udev_monitor_new_from_netlink(hotplug, "udev");
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(monitor, "cpu", NULL);
|
||||||
|
udev_monitor_enable_receiving(monitor);
|
||||||
|
item.fd = udev_monitor_get_fd(monitor);
|
||||||
|
item.events = POLLIN;
|
||||||
|
item.revents = 0;
|
||||||
|
while (!stoprequested) {
|
||||||
|
struct udev_device *dev;
|
||||||
|
const char *path, *action;
|
||||||
|
unsigned int cpunum;
|
||||||
|
int rc, on, off;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
rc = poll(&item, 1, -1);
|
||||||
|
if (rc == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dev = udev_monitor_receive_device(monitor);
|
||||||
|
if (dev == NULL)
|
||||||
|
continue;
|
||||||
|
action = udev_device_get_action(dev);
|
||||||
|
if (action == NULL)
|
||||||
|
continue;
|
||||||
|
off = strcmp(action, "offline") == 0;
|
||||||
|
on = strcmp(action, "online") == 0;
|
||||||
|
if (!on && !off)
|
||||||
|
continue;
|
||||||
|
path = udev_device_get_devpath(dev);
|
||||||
|
if (sscanf(path, "/devices/system/cpu/cpu%u", &cpunum) != 1)
|
||||||
|
continue;
|
||||||
|
if (on && activatecpu(cpunum))
|
||||||
|
eprint("Failed to attach to hotplugged CPU %u\n", cpunum);
|
||||||
|
if (off)
|
||||||
|
deactivatecpu(cpunum);
|
||||||
|
}
|
||||||
|
udev_monitor_unref(monitor);
|
||||||
|
udev_unref(hotplug);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int perf_init(void)
|
int perf_init(void)
|
||||||
{
|
{
|
||||||
int i, cpus, ctr, cpu, *fds;
|
int ecc_supported, i, num;
|
||||||
|
unsigned long maxfd;
|
||||||
memset(ctr_fds, 0, sizeof(ctr_fds));
|
struct rlimit rlim;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
/* initialize performance monitoring library */
|
/* initialize performance monitoring library */
|
||||||
if (!perf_supported()) {
|
if (!perf_supported()) {
|
||||||
@@ -143,99 +475,105 @@ int perf_init(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We currently support all cpumf counters plus two virtual
|
||||||
|
* counters for PAI. */
|
||||||
|
num = ALL_COUNTER + 2;
|
||||||
/* Check if ECC is supported on current hardware */
|
/* Check if ECC is supported on current hardware */
|
||||||
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
||||||
|
|
||||||
/* get number of logical processors */
|
if (!cpumf_authorized()) {
|
||||||
cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
for (i = 0; i < ALL_COUNTER; ++i)
|
||||||
|
ctr_state[i] = UNSUPPORTED;
|
||||||
/* for each counter */
|
num -= ALL_COUNTER;
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
} else if (!ecc_supported) {
|
||||||
|
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
||||||
/* Skip ECC counters completely if unsupported */
|
--num;
|
||||||
if (ctr == ECC_FUNCTIONS && !ecc_supported)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* allocate an array of ints to store for each CPU
|
|
||||||
* one filedescriptor + a terminating 0
|
|
||||||
*/
|
|
||||||
fds = (int *) calloc(sizeof(int), cpus+1);
|
|
||||||
if (!fds) {
|
|
||||||
eprint("Malloc() of %d byte failed, errno=%d [%s]\n",
|
|
||||||
(int)(sizeof(int) * (cpus+1)),
|
|
||||||
errno, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctr_fds[ctr] = fds;
|
|
||||||
|
|
||||||
/* search for the counter's corresponding pfm name */
|
|
||||||
for (i = ALL_COUNTER-1; i >= 0; i--)
|
|
||||||
if ((int) pmf_counter_name[i].ctr == ctr)
|
|
||||||
break;
|
|
||||||
if (i < 0) {
|
|
||||||
eprint("Pfm ctr name not found for counter %d, please adjust pmf_counter_name[] in %s\n",
|
|
||||||
ctr, __FILE__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cpu = 0; cpu < cpus; cpu++) {
|
|
||||||
struct perf_event_attr pfm_event;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
|
||||||
pfm_event.size = sizeof(pfm_event);
|
|
||||||
if (perf_event_encode(&pfm_event,
|
|
||||||
pmf_counter_name[i].pmu,
|
|
||||||
pmf_counter_name[i].pfm_name)) {
|
|
||||||
eprint("Failed to initialize counter %s for pmu %s\n",
|
|
||||||
pmf_counter_name[i].pfm_name,
|
|
||||||
pmf_counter_name[i].pmu);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fetch file descriptor for this perf event
|
|
||||||
* the counter event should start disabled
|
|
||||||
*/
|
|
||||||
pfm_event.disabled = 1;
|
|
||||||
fd = perf_event_open(
|
|
||||||
&pfm_event,
|
|
||||||
-1, /* pid -1 means all processes */
|
|
||||||
cpu,
|
|
||||||
-1, /* group filedescriptor */
|
|
||||||
0); /* flags */
|
|
||||||
if (fd < 0) {
|
|
||||||
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
|
||||||
errno, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fds[cpu] = fd;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (!perf_counter_supported("pai_crypto", "CRYPTO_ALL")) {
|
||||||
|
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||||
|
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||||
|
num -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num == 0) {
|
||||||
|
eprint("No crypto counters supported!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (perf_load_counter_data())
|
||||||
|
return -1;
|
||||||
|
/* We have to adjust the number of FDs possible since we might
|
||||||
|
* need more than 1024 (the typical soft limit) */
|
||||||
|
f = fopen("/proc/sys/fs/nr_open", "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
eprint("fopen failed for /proc/sys/fs/nr_open with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (fscanf(f, "%lu", &maxfd) != 1) {
|
||||||
|
fclose(f);
|
||||||
|
eprint("Failed to parse /proc/sys/fs/nr_open\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
rlim.rlim_cur = maxfd;
|
||||||
|
rlim.rlim_max = maxfd;
|
||||||
|
if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
|
||||||
|
eprint("setrlimit failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(&hotplugthread, NULL, hotplughandler, NULL)) {
|
||||||
|
eprint("Failed to start hotplug handler thread\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return addallcpus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void perf_stop(void)
|
||||||
|
{
|
||||||
|
stoprequested = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void perf_close(void)
|
void perf_close(void)
|
||||||
{
|
{
|
||||||
int ctr, *fds;
|
struct percpucounter *walk, *next;
|
||||||
|
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
pthread_kill(hotplugthread, SIGINT);
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
pthread_join(hotplugthread, NULL);
|
||||||
close(*fds);
|
walk = root;
|
||||||
*fds = 0;
|
while (walk) {
|
||||||
}
|
next = walk->next;
|
||||||
free(ctr_fds[ctr]);
|
freepercpucounter(walk);
|
||||||
ctr_fds[ctr] = NULL;
|
walk = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int enable_array(int *arr, int size)
|
||||||
|
{
|
||||||
|
int i, ec, rc = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; ++i) {
|
||||||
|
ec = ioctl(arr[i], PERF_EVENT_IOC_ENABLE, 0);
|
||||||
|
if (ec < 0) {
|
||||||
|
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int perf_enable_ctr(enum ctr_e ctr)
|
int perf_enable_ctr(enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
@@ -243,24 +581,64 @@ int perf_enable_ctr(enum ctr_e ctr)
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_ENABLE, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_ENABLE, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctr_state[ctr] = ENABLED;
|
||||||
|
++enabledcounter;
|
||||||
|
endforeachcpu();
|
||||||
|
} else if (ctr == PAI_USER) {
|
||||||
|
foreachcpu(pcpu) {
|
||||||
|
ec = enable_array(pcpu->pai_user, NUM_PAI_USER);
|
||||||
|
if (ec < 0)
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
ctr_state[ctr] = ENABLED;
|
||||||
|
++enabledcounter;
|
||||||
|
endforeachcpu();
|
||||||
|
} else if (ctr == PAI_KERNEL) {
|
||||||
|
foreachcpu(pcpu) {
|
||||||
|
ec = enable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||||
|
if (ec < 0)
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
ctr_state[ctr] = ENABLED;
|
||||||
|
++enabledcounter;
|
||||||
|
endforeachcpu();
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int disable_array(int *arr, int size)
|
||||||
|
{
|
||||||
|
int i, ec, rc = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; ++i) {
|
||||||
|
ec = ioctl(arr[i], PERF_EVENT_IOC_DISABLE, 0);
|
||||||
|
if (ec < 0) {
|
||||||
|
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int perf_disable_ctr(enum ctr_e ctr)
|
int perf_disable_ctr(enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
@@ -268,70 +646,183 @@ int perf_disable_ctr(enum ctr_e ctr)
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_DISABLE, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_DISABLE, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctr_state[ctr] = DISABLED;
|
||||||
|
--enabledcounter;
|
||||||
|
if (enabledcounter == 0)
|
||||||
|
hotplugdetected = 0;
|
||||||
|
endforeachcpu();
|
||||||
|
} else if (ctr == PAI_USER) {
|
||||||
|
foreachcpu(pcpu) {
|
||||||
|
ec = disable_array(pcpu->pai_user, NUM_PAI_USER);
|
||||||
|
if (ec < 0)
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
ctr_state[ctr] = DISABLED;
|
||||||
|
--enabledcounter;
|
||||||
|
if (enabledcounter == 0)
|
||||||
|
hotplugdetected = 0;
|
||||||
|
endforeachcpu();
|
||||||
|
} else if (ctr == PAI_KERNEL) {
|
||||||
|
foreachcpu(pcpu) {
|
||||||
|
ec = disable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||||
|
if (ec < 0)
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
ctr_state[ctr] = DISABLED;
|
||||||
|
--enabledcounter;
|
||||||
|
if (enabledcounter == 0)
|
||||||
|
hotplugdetected = 0;
|
||||||
|
endforeachcpu();
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int perf_reset_ctr(enum ctr_e ctr)
|
static int reset_array(int *arr, int size)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
int ec, rc = 0, i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; ++i) {
|
||||||
|
ec = ioctl(arr[i], PERF_EVENT_IOC_RESET, 0);
|
||||||
|
if (ec < 0) {
|
||||||
|
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
|
||||||
|
{
|
||||||
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
rc = perf_reset_ctr(ctr);
|
rc = perf_reset_ctr(ctr, value);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_RESET, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_RESET, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
} else if (ctr == PAI_USER) {
|
||||||
|
foreachcpu(pcpu) {
|
||||||
|
ec = reset_array(pcpu->pai_user, NUM_PAI_USER);
|
||||||
|
if (ec < 0)
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
} else if (ctr == PAI_KERNEL) {
|
||||||
|
foreachcpu(pcpu) {
|
||||||
|
ec = reset_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||||
|
if (ec < 0)
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
if (rc == 0)
|
||||||
|
rc = perf_read_ctr(ctr, value);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = -1;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (ctr == HOTPLUG_DETECTED) {
|
||||||
|
*value = hotplugdetected;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ctr == PAI_USER) {
|
||||||
|
*value = NUM_PAI_USER;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ctr == PAI_KERNEL) {
|
||||||
|
*value = NUM_PAI_KERNEL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ctr >= ALL_COUNTER)
|
||||||
|
return -1;
|
||||||
*value = 0;
|
*value = 0;
|
||||||
|
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = read(*fds, &val, sizeof(val));
|
ec = read(pcpu->ctr_fds[ctr], &val, sizeof(val));
|
||||||
if (ec != sizeof(val)) {
|
if (ec != sizeof(val)) {
|
||||||
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
} else {
|
} else {
|
||||||
*value += val;
|
*value += val;
|
||||||
rc = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_ecc_supported(void)
|
int perf_ecc_supported(void)
|
||||||
{
|
{
|
||||||
return ecc_supported;
|
return ctr_state[ECC_FUNCTIONS] != UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int perf_ctr_state(enum ctr_e ctr) {
|
||||||
|
if (ctr < NUM_COUNTER)
|
||||||
|
return ctr_state[ctr];
|
||||||
|
return UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value)
|
||||||
|
{
|
||||||
|
struct percpucounter *pcpu;
|
||||||
|
unsigned int maxctr;
|
||||||
|
int *arr, ec, rc = 0;
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
|
*value = 0;
|
||||||
|
maxctr = user ? NUM_PAI_USER : NUM_PAI_KERNEL;
|
||||||
|
if (ctrnum >= maxctr)
|
||||||
|
return -1;
|
||||||
|
foreachcpu(pcpu) {
|
||||||
|
arr = user ? pcpu->pai_user : pcpu->pai_kernel;
|
||||||
|
ec = read(arr[ctrnum], &val, sizeof(val));
|
||||||
|
if (ec != sizeof(val)) {
|
||||||
|
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
||||||
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
} else {
|
||||||
|
*value += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-6
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* basic socket and receive/send functions
|
* basic socket and receive/send functions
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2015, 2017
|
* Copyright IBM Corp. 2015, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -148,7 +149,51 @@ static int __read(int fd, void *buf, int buflen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int send_msg(int sfd, struct msg *m)
|
static int __timedwrite(int fd, const void *buf, int buflen, int timeout)
|
||||||
|
{
|
||||||
|
struct pollfd pfd = { .fd = fd, .events = POLLOUT };
|
||||||
|
int i = 0, n;
|
||||||
|
|
||||||
|
while (poll(&pfd, 1, timeout) == 1) {
|
||||||
|
n = write(fd, buf + i, buflen - i);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
return n;
|
||||||
|
} else if (n == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i += n;
|
||||||
|
if (buflen == i)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __timedread(int fd, void *buf, int buflen, int timeout)
|
||||||
|
{
|
||||||
|
struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
||||||
|
int i = 0, n;
|
||||||
|
|
||||||
|
while (poll(&pfd, 1, timeout) == 1) {
|
||||||
|
n = read(fd, buf + i, buflen - i);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
return n;
|
||||||
|
} else if (n == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i += n;
|
||||||
|
if (buflen == i)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_msg(int sfd, struct msg *m, int timeout)
|
||||||
{
|
{
|
||||||
int n, len;
|
int n, len;
|
||||||
|
|
||||||
@@ -166,7 +211,7 @@ int send_msg(int sfd, struct msg *m)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = __write(sfd, m, len);
|
n = timeout ? __timedwrite(sfd, m, len, timeout) : __write(sfd, m, len);
|
||||||
if (n != len) {
|
if (n != len) {
|
||||||
eprint("Write() error: write()=%d expected %d, errno=%d [%s]\n",
|
eprint("Write() error: write()=%d expected %d, errno=%d [%s]\n",
|
||||||
n, len, errno, strerror(errno));
|
n, len, errno, strerror(errno));
|
||||||
@@ -176,12 +221,12 @@ int send_msg(int sfd, struct msg *m)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int recv_msg(int sfd, struct msg *m)
|
int recv_msg(int sfd, struct msg *m, int timeout)
|
||||||
{
|
{
|
||||||
int n, len;
|
int n, len;
|
||||||
|
|
||||||
len = sizeof(m->head);
|
len = sizeof(m->head);
|
||||||
n = __read(sfd, m, len);
|
n = timeout ? __timedread(sfd, m, len, timeout) : __read(sfd, m, len);
|
||||||
if (n != len) {
|
if (n != len) {
|
||||||
eprint("Recv() error: read()=%d expected %d, errno=%d [%s]\n",
|
eprint("Recv() error: read()=%d expected %d, errno=%d [%s]\n",
|
||||||
n, len, errno, strerror(errno));
|
n, len, errno, strerror(errno));
|
||||||
@@ -200,7 +245,8 @@ int recv_msg(int sfd, struct msg *m)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = __read(sfd, ((char *)m) + sizeof(m->head), len);
|
n = timeout ? __timedread(sfd, ((char *)m) + sizeof(m->head), len, timeout) :
|
||||||
|
__read(sfd, ((char *)m) + sizeof(m->head), len);
|
||||||
if (n != len) {
|
if (n != len) {
|
||||||
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
|
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
|
||||||
n, len, errno, strerror(errno));
|
n, len, errno, strerror(errno));
|
||||||
|
|||||||
+5
-3
@@ -26,6 +26,7 @@
|
|||||||
#include "lib/util_arch.h"
|
#include "lib/util_arch.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
|
|
||||||
#include "lib/libcpumf.h"
|
#include "lib/libcpumf.h"
|
||||||
@@ -3318,17 +3319,18 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
||||||
* Check for existence of file /sys/devices/cpum_cf/events/DLFT_CCERROR.
|
* Check for existence of file /sys/devices/cpum_cf/events/DLFT_CCERROR.
|
||||||
*/
|
*/
|
||||||
#define CCERROR "/sys/devices/cpum_cf/events/DFLT_CCERROR"
|
|
||||||
static void read_ccerror(struct counters *cp, size_t cp_cnt)
|
static void read_ccerror(struct counters *cp, size_t cp_cnt)
|
||||||
{
|
{
|
||||||
|
char *ctrname, *path;
|
||||||
struct stat sbuf;
|
struct stat sbuf;
|
||||||
char *ctrname;
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
if (!stat(CCERROR, &sbuf))
|
path = util_path_sysfs("devices/cpum_cf/events/DFLT_CCERROR");
|
||||||
|
if (!stat(path, &sbuf))
|
||||||
ctrname = "DFLT_CCERROR";
|
ctrname = "DFLT_CCERROR";
|
||||||
else
|
else
|
||||||
ctrname = "DFLT_CCFINISH";
|
ctrname = "DFLT_CCFINISH";
|
||||||
|
free(path);
|
||||||
/* Find DFLT_CC{FINISH,ERROR} in table and set name */
|
/* Find DFLT_CC{FINISH,ERROR} in table and set name */
|
||||||
for (struct counters *p = cp; i < cp_cnt; ++i, ++p)
|
for (struct counters *p = cp; i < cp_cnt; ++i, ++p)
|
||||||
if (p->ctrnum == 265) {
|
if (p->ctrnum == 265) {
|
||||||
|
|||||||
+4
-4
@@ -356,6 +356,8 @@ static void line(char *header)
|
|||||||
putchar(',');
|
putchar(',');
|
||||||
printf("%ld", ctrname[i].total);
|
printf("%ld", ctrname[i].total);
|
||||||
comma = true;
|
comma = true;
|
||||||
|
ctrname[i].total = 0;
|
||||||
|
ctrname[i].hitcnt = false;
|
||||||
}
|
}
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
@@ -446,7 +448,7 @@ static bool add_countervalue(size_t idx, unsigned int cpu, unsigned long value)
|
|||||||
ctrname[idx].ccv = calloc(max_possible_cpus,
|
ctrname[idx].ccv = calloc(max_possible_cpus,
|
||||||
sizeof(unsigned long));
|
sizeof(unsigned long));
|
||||||
if (ctrname[idx].ccv)
|
if (ctrname[idx].ccv)
|
||||||
ctrname[idx].ccv[cpu] += value;
|
ctrname[idx].ccv[cpu] = value;
|
||||||
ctrname[idx].total += value;
|
ctrname[idx].total += value;
|
||||||
ctrname[idx].hitcnt = true;
|
ctrname[idx].hitcnt = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -458,10 +460,8 @@ static int test_read(struct s390_hwctr_read *read)
|
|||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
/* Clear previous hit counters */
|
/* Clear previous hit counters */
|
||||||
for (unsigned int i = 0; i < max_possible_cpus; ++i) {
|
for (unsigned int i = 0; i < max_possible_cpus; ++i)
|
||||||
check[i].sets_hit = 0;
|
|
||||||
check[i].cpu_hit = false;
|
check[i].cpu_hit = false;
|
||||||
}
|
|
||||||
|
|
||||||
/* Iterate over all CPUs */
|
/* Iterate over all CPUs */
|
||||||
for (unsigned int i = 0; i < read->no_cpus; ++i) {
|
for (unsigned int i = 0; i < read->no_cpus; ++i) {
|
||||||
|
|||||||
+36
-32
@@ -32,6 +32,7 @@
|
|||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
#include "lib/util_file.h"
|
||||||
#include "lib/util_libc.h"
|
#include "lib/util_libc.h"
|
||||||
#include "lib/util_list.h"
|
#include "lib/util_list.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
@@ -56,6 +57,7 @@ static cpu_set_t cpu_online_mask;
|
|||||||
static int verbose, humantime;
|
static int verbose, humantime;
|
||||||
static struct util_list list_pai_event;
|
static struct util_list list_pai_event;
|
||||||
static struct util_list list_pmu_event;
|
static struct util_list list_pmu_event;
|
||||||
|
static bool summary;
|
||||||
|
|
||||||
/* System call to perf_event_open(2) */
|
/* System call to perf_event_open(2) */
|
||||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||||
@@ -114,7 +116,7 @@ static void ev_alloc(int enr, int cpu, int flags)
|
|||||||
warnx("NNPA does not support kernel/user space selector");
|
warnx("NNPA does not support kernel/user space selector");
|
||||||
flags &= ~as;
|
flags &= ~as;
|
||||||
}
|
}
|
||||||
event->attr.type = libcpumf_pmutype(S390_SYSFS_PAI_NNPA);
|
event->attr.type = libcpumf_pmutype(S390_SYSFS_PAI_EXT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
event->attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_CPU |
|
event->attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_CPU |
|
||||||
@@ -263,9 +265,11 @@ static int savemap(int fd, void *data, struct data_pos *dp)
|
|||||||
int wrapped;
|
int wrapped;
|
||||||
|
|
||||||
d_head_old = d_head;
|
d_head_old = d_head;
|
||||||
printf("Data head:%#llx tail:%#llx offset:%#llx size:%#llx\n",
|
if (verbose) {
|
||||||
dp->data_head, dp->data_tail, dp->data_offset,
|
printf("Data head:%#llx tail:%#llx offset:%#llx size:%#llx\n",
|
||||||
dp->data_size);
|
dp->data_head, dp->data_tail, dp->data_offset,
|
||||||
|
dp->data_size);
|
||||||
|
}
|
||||||
if (!diff)
|
if (!diff)
|
||||||
return 0;
|
return 0;
|
||||||
wrapped = d_head / dp->data_size != d_prev / dp->data_size;
|
wrapped = d_head / dp->data_size != d_prev / dp->data_size;
|
||||||
@@ -280,13 +284,16 @@ static int savemap(int fd, void *data, struct data_pos *dp)
|
|||||||
int part2 = dp->data_size - d_prev;
|
int part2 = dp->data_size - d_prev;
|
||||||
|
|
||||||
diff -= part2;
|
diff -= part2;
|
||||||
printf("Write %d bytes [%ld,%lld)\n", part2, d_prev,
|
if (verbose) {
|
||||||
dp->data_size);
|
printf("Write %d bytes [%ld,%lld)\n", part2, d_prev,
|
||||||
|
dp->data_size);
|
||||||
|
}
|
||||||
if (write(fd, data + d_prev, part2) == -1)
|
if (write(fd, data + d_prev, part2) == -1)
|
||||||
err(EXIT_FAILURE, "write error for event file");
|
err(EXIT_FAILURE, "write error for event file");
|
||||||
d_prev = 0; /* Start at position zero */
|
d_prev = 0; /* Start at position zero */
|
||||||
}
|
}
|
||||||
printf("Write %d bytes [%ld,%ld)\n", diff, d_prev, d_head);
|
if (verbose)
|
||||||
|
printf("Write %d bytes [%ld,%ld)\n", diff, d_prev, d_head);
|
||||||
if (write(fd, data + d_prev, diff) == -1)
|
if (write(fd, data + d_prev, diff) == -1)
|
||||||
err(EXIT_FAILURE, "write error for event file");
|
err(EXIT_FAILURE, "write error for event file");
|
||||||
|
|
||||||
@@ -299,7 +306,10 @@ static void readmap(int fd)
|
|||||||
struct pai_event *p = perffd_2_event(fd);
|
struct pai_event *p = perffd_2_event(fd);
|
||||||
struct perf_event_mmap_page *area;
|
struct perf_event_mmap_page *area;
|
||||||
|
|
||||||
printf("Ring buffer for fd %d %s(%d)\n", fd, p->file_name, p->file_fd);
|
if (verbose) {
|
||||||
|
printf("Ring buffer for fd %d %s(%d)\n", fd, p->file_name,
|
||||||
|
p->file_fd);
|
||||||
|
}
|
||||||
area = p->map_addr;
|
area = p->map_addr;
|
||||||
savemap(p->file_fd, p->map_addr + area->data_offset,
|
savemap(p->file_fd, p->map_addr + area->data_offset,
|
||||||
(struct data_pos *)&area->data_head);
|
(struct data_pos *)&area->data_head);
|
||||||
@@ -383,7 +393,10 @@ static int evtraw_show(__u64 evtnum, unsigned char *p)
|
|||||||
offset += sizeof(ctr);
|
offset += sizeof(ctr);
|
||||||
value = *(__u64 *)(p + offset);
|
value = *(__u64 *)(p + offset);
|
||||||
offset += sizeof(value);
|
offset += sizeof(value);
|
||||||
printf("%c%hd:%#llx", offset > 14 ? ',' : ' ', ctr, value);
|
if (!summary) {
|
||||||
|
printf("%c%hd:%#llx", offset > 14 ? ',' : ' ', ctr,
|
||||||
|
value);
|
||||||
|
}
|
||||||
lookup_event(evtnum, ctr, value);
|
lookup_event(evtnum, ctr, value);
|
||||||
if (offset + sizeof(ctr) + sizeof(value) > bytes)
|
if (offset + sizeof(ctr) + sizeof(value) > bytes)
|
||||||
break;
|
break;
|
||||||
@@ -412,6 +425,12 @@ static const char *evt_selector(struct perf_event_attr *pa)
|
|||||||
|
|
||||||
static void evt_show(__u64 evtnum, const char *evtsel, struct pai_event_out *ev)
|
static void evt_show(__u64 evtnum, const char *evtsel, struct pai_event_out *ev)
|
||||||
{
|
{
|
||||||
|
if (summary) {
|
||||||
|
if (ev->type == PERF_RECORD_SAMPLE && ev->raw)
|
||||||
|
evtraw_show(evtnum, ev->raw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
timestamp(ev->time);
|
timestamp(ev->time);
|
||||||
printf("%d ", ev->cpu);
|
printf("%d ", ev->cpu);
|
||||||
|
|
||||||
@@ -633,30 +652,13 @@ bypass:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read perf_event_open() config value for event. */
|
|
||||||
static int read_event(char *dirname, char *filename)
|
|
||||||
{
|
|
||||||
int config, rc = 0;
|
|
||||||
char *pathname;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
util_asprintf(&pathname, "%s/%s", dirname, filename);
|
|
||||||
fp = fopen(pathname, "r");
|
|
||||||
if (fp) {
|
|
||||||
rc = fscanf(fp, "event=%x", &config);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
free(pathname);
|
|
||||||
return rc == 1 ? config : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scan event directory and fill event list. */
|
/* Scan event directory and fill event list. */
|
||||||
static int scan_events(struct pmu_events *p)
|
static int scan_events(struct pmu_events *p)
|
||||||
{
|
{
|
||||||
|
char *evtname, *evtdir, *path;
|
||||||
struct dirent **de_vec;
|
struct dirent **de_vec;
|
||||||
struct event_name *ep;
|
struct event_name *ep;
|
||||||
char *evtdir, *path;
|
int evtnr, count, rc;
|
||||||
int count, rc;
|
|
||||||
|
|
||||||
path = util_path_sysfs("devices");
|
path = util_path_sysfs("devices");
|
||||||
rc = util_asprintf(&evtdir, "%s/%s/events", path, p->name);
|
rc = util_asprintf(&evtdir, "%s/%s/events", path, p->name);
|
||||||
@@ -677,8 +679,10 @@ static int scan_events(struct pmu_events *p)
|
|||||||
if (de_vec[i]->d_type == DT_DIR)
|
if (de_vec[i]->d_type == DT_DIR)
|
||||||
continue;
|
continue;
|
||||||
ep->name = util_strdup(de_vec[i]->d_name);
|
ep->name = util_strdup(de_vec[i]->d_name);
|
||||||
rc = read_event(evtdir, de_vec[i]->d_name);
|
util_asprintf(&evtname, "%s/%s", evtdir, de_vec[i]->d_name);
|
||||||
if (rc == -1 || !ep->name) {
|
rc = util_file_read_va(evtname, "event=%x", &evtnr);
|
||||||
|
free(evtname);
|
||||||
|
if (rc != 1) {
|
||||||
for (ep = p->lst, rc = 0; rc < p->lstlen; ++rc, ++ep)
|
for (ep = p->lst, rc = 0; rc < p->lstlen; ++rc, ++ep)
|
||||||
free(ep->name);
|
free(ep->name);
|
||||||
free(p->lst);
|
free(p->lst);
|
||||||
@@ -686,7 +690,7 @@ static int scan_events(struct pmu_events *p)
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ep->config = rc;
|
ep->config = evtnr;
|
||||||
if (p->base > ep->config)
|
if (p->base > ep->config)
|
||||||
p->base = ep->config;
|
p->base = ep->config;
|
||||||
++p->lstlen;
|
++p->lstlen;
|
||||||
@@ -1005,7 +1009,7 @@ static unsigned long check_mapsize(unsigned long n)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
bool crypto_record = false, report = false, summary = false;
|
bool crypto_record = false, report = false;
|
||||||
bool nnpa_record = false;
|
bool nnpa_record = false;
|
||||||
unsigned long loop_count = 1;
|
unsigned long loop_count = 1;
|
||||||
int ch, group = 0;
|
int ch, group = 0;
|
||||||
|
|||||||
+2
-2
@@ -1107,8 +1107,8 @@ static void dasdfmt_write_labels(volume_label_t *vlabel,
|
|||||||
} else {
|
} else {
|
||||||
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
|
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
|
||||||
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
|
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
|
||||||
rc = write(fd, &vlabel->vollbl, (sizeof(*vlabel)
|
rc = write(fd, (void *)vlabel + sizeof(vlabel->volkey),
|
||||||
- sizeof(vlabel->volkey)));
|
(sizeof(*vlabel) - sizeof(vlabel->volkey)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
||||||
|
|||||||
+5
-6
@@ -29,6 +29,7 @@
|
|||||||
#include "lib/dasd_sys.h"
|
#include "lib/dasd_sys.h"
|
||||||
#include "lib/libzds.h"
|
#include "lib/libzds.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
#include "lib/util_libc.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
#include "lib/util_sys.h"
|
#include "lib/util_sys.h"
|
||||||
@@ -1788,10 +1789,8 @@ dasdview_print_format1(unsigned int size, unsigned char *dumpstr)
|
|||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
if ((i / 16) * 16 == i) {
|
if ((i / 16) * 16 == i) {
|
||||||
printf("\n| ");
|
printf("\n| ");
|
||||||
strncpy(asc, (char *)dumpstr + i, 16);
|
util_strlcpy(asc, (char *)dumpstr + i, 16);
|
||||||
strncpy(ebc, (char *)dumpstr + i, 16);
|
util_strlcpy(ebc, (char *)dumpstr + i, 16);
|
||||||
asc[16] = '\0';
|
|
||||||
ebc[16] = '\0';
|
|
||||||
}
|
}
|
||||||
printf("%02X", dumpstr[i]);
|
printf("%02X", dumpstr[i]);
|
||||||
if (((i + 1) / 4) * 4 == i + 1)
|
if (((i + 1) / 4) * 4 == i + 1)
|
||||||
@@ -1822,8 +1821,8 @@ dasdview_print_format2(unsigned int size, unsigned char *dumpstr,
|
|||||||
begin + (unsigned long long)i,
|
begin + (unsigned long long)i,
|
||||||
begin + (unsigned long long)i);
|
begin + (unsigned long long)i);
|
||||||
|
|
||||||
strncpy(asc, (char *)dumpstr + i, 8);
|
util_strlcpy(asc, (char *)dumpstr + i, 8);
|
||||||
strncpy(ebc, (char *)dumpstr + i, 8);
|
util_strlcpy(ebc, (char *)dumpstr + i, 8);
|
||||||
}
|
}
|
||||||
printf("%02X", dumpstr[i]);
|
printf("%02X", dumpstr[i]);
|
||||||
if (((i + 1) / 4) * 4 == i + 1)
|
if (((i + 1) / 4) * 4 == i + 1)
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ host.
|
|||||||
Specifies the certificate that is used to establish a chain of trust
|
Specifies the certificate that is used to establish a chain of trust
|
||||||
for the verification of the host-key documents. Specify this option
|
for the verification of the host-key documents. Specify this option
|
||||||
twice to specify the IBM Z signing key and the intermediate CA
|
twice to specify the IBM Z signing key and the intermediate CA
|
||||||
certificate (signed by the root CA). Required.
|
certificate (signed by the root CA).
|
||||||
|
Required. Ignored if \fB--no-verify\fP is specified.
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
||||||
Specifies the output file. Required.
|
Specifies the output file. Required.
|
||||||
@@ -91,8 +92,9 @@ the system wide root CAs installed on the system is used. Use
|
|||||||
this only if you trust the specified certificate. Optional.
|
this only if you trust the specified certificate. Optional.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no-verify\fR
|
\fB\-\-no-verify\fR
|
||||||
Do not require the host-key documents to be valid. For testing
|
Does not require the host-key documents to be valid.
|
||||||
purposes, do not use for a production image. Optional.
|
Do not use for a production image unless you verified
|
||||||
|
the host-key document before. Optional.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
|
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
|
||||||
Specifies the encryption key you want to use for the PV guest dump. Use a
|
Specifies the encryption key you want to use for the PV guest dump. Use a
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#define GETTEXT_PACKAGE "genprotimg"
|
#define GETTEXT_PACKAGE "genprotimg"
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gi18n-lib.h>
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
#include "boot/linux_layout.h"
|
#include "boot/linux_layout.h"
|
||||||
#include "boot/s390.h"
|
#include "boot/s390.h"
|
||||||
|
|||||||
@@ -280,7 +280,8 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
.arg_data = &args->host_keys,
|
.arg_data = &args->host_keys,
|
||||||
.description =
|
.description =
|
||||||
_("FILE specifies a host-key document. At least\n" INDENT
|
_("FILE specifies a host-key document. At least\n" INDENT
|
||||||
"one is required."),
|
"one is required Specify this option multiple times\n" INDENT
|
||||||
|
"to enable the image to run on more than one host."),
|
||||||
.arg_description = _("FILE") },
|
.arg_description = _("FILE") },
|
||||||
{ .long_name = "cert",
|
{ .long_name = "cert",
|
||||||
.short_name = 'C',
|
.short_name = 'C',
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ static X509_CRL *load_crl_from_bio(BIO *bio)
|
|||||||
return g_steal_pointer(&crl);
|
return g_steal_pointer(&crl);
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
rc = BIO_reset(bio);
|
rc = BIO_reset(bio);
|
||||||
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE))
|
if (rc != 1 && !(rc == 0 && BIO_method_type(bio) == BIO_TYPE_FILE))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* maybe the CRL is stored in DER format */
|
/* maybe the CRL is stored in DER format */
|
||||||
@@ -533,7 +533,7 @@ X509 *load_cert_from_file(const char *path, GError **err)
|
|||||||
return g_steal_pointer(&cert);
|
return g_steal_pointer(&cert);
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
rc = BIO_reset(bio);
|
rc = BIO_reset(bio);
|
||||||
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE)) {
|
if (rc != 1 && !(rc == 0 && BIO_method_type(bio) == BIO_TYPE_FILE)) {
|
||||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||||
_("unable to load certificate: '%s'"), path);
|
_("unable to load certificate: '%s'"), path);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -90,5 +90,6 @@ void ap_list_remove_all(struct util_list *list);
|
|||||||
int ap_get_lock(void);
|
int ap_get_lock(void);
|
||||||
int ap_get_lock_callout(void);
|
int ap_get_lock_callout(void);
|
||||||
int ap_release_lock(void);
|
int ap_release_lock(void);
|
||||||
|
int ap_release_lock_callout(void);
|
||||||
|
|
||||||
#endif /* LIB_AP_H */
|
#endif /* LIB_AP_H */
|
||||||
|
|||||||
+10
-1
@@ -17,7 +17,8 @@
|
|||||||
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
|
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||||
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
|
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
|
||||||
#define S390_SYSFS_PAI_CRYPTO "/sys/devices/pai_crypto/"
|
#define S390_SYSFS_PAI_CRYPTO "/sys/devices/pai_crypto/"
|
||||||
#define S390_SYSFS_PAI_NNPA "/sys/devices/pai_nnpa/"
|
#define S390_SYSFS_PAI_EXT "/sys/devices/pai_ext/"
|
||||||
|
#define S390_SYSFS_PAI_NNPA S390_SYSFS_PAI_EXT "events/NNPA_ALL"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read out the PMU type from a given file.
|
* Read out the PMU type from a given file.
|
||||||
@@ -146,6 +147,14 @@ bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
|
|||||||
*/
|
*/
|
||||||
bool libcpumf_have_pai_crypto(void);
|
bool libcpumf_have_pai_crypto(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if PAI_EXTENSION Facility is supported.
|
||||||
|
*
|
||||||
|
* @retval true PAI_EXTENSION counter Facility is available
|
||||||
|
* @retval false PAI_EXTENSION counter Facility is not available
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_pai_ext(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if PAI_NNPA counter Facility is supported. This PMU facility
|
* Return true if PAI_NNPA counter Facility is supported. This PMU facility
|
||||||
* supports the Neural Network Processing Assist (NNPA) counter set.
|
* supports the Neural Network Processing Assist (NNPA) counter set.
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup util_lockfile_h util_lockfile: File locking utility
|
||||||
|
* @{
|
||||||
|
* @brief Create file-based locks
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIB_UTIL_LOCKFILE_H
|
||||||
|
#define LIB_UTIL_LOCKFILE_H
|
||||||
|
|
||||||
|
#define UTIL_LOCKFILE_OK 0 /* Lock acquired/released successfully */
|
||||||
|
#define UTIL_LOCKFILE_LOCK_FAIL 1 /* Lock already held, ran out of retries */
|
||||||
|
#define UTIL_LOCKFILE_RELEASE_NONE 2 /* Lock not held */
|
||||||
|
#define UTIL_LOCKFILE_RELEASE_FAIL 3 /* Lock not held by specified pid */
|
||||||
|
#define UTIL_LOCKFILE_ERR 4 /* Other, unexpected error conditions */
|
||||||
|
|
||||||
|
int util_lockfile_lock(char *lockfile, int retries);
|
||||||
|
int util_lockfile_parent_lock(char *lockfile, int retries);
|
||||||
|
|
||||||
|
int util_lockfile_release(char *lockfile);
|
||||||
|
int util_lockfile_parent_release(char *lockfile);
|
||||||
|
|
||||||
|
#endif /** LIB_UTIL_LOCKFILE_H @} */
|
||||||
@@ -21,15 +21,21 @@
|
|||||||
* Usage example:
|
* Usage example:
|
||||||
* #define IMAGE_ENTRY _AC(0x10000, UL)
|
* #define IMAGE_ENTRY _AC(0x10000, UL)
|
||||||
*/
|
*/
|
||||||
|
#ifndef _AC
|
||||||
#ifdef __ASSEMBLER__
|
#ifdef __ASSEMBLER__
|
||||||
#define _AC(X, TYPE) X
|
#define _AC(X, TYPE) X
|
||||||
#else
|
#else
|
||||||
#define _AC(X, TYPE) X##TYPE
|
#define _AC(X, TYPE) X##TYPE
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#ifndef sizeof_field
|
||||||
|
#define sizeof_field(type, field) (sizeof((type *)0)->field)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef UNUSED
|
#ifdef UNUSED
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||||||
@@ -48,6 +54,10 @@
|
|||||||
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
|
#ifndef ROUNDUP
|
||||||
|
# define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE)
|
#define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE)
|
||||||
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
||||||
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
||||||
@@ -60,6 +70,7 @@
|
|||||||
#define __may_alias __attribute__((may_alias))
|
#define __may_alias __attribute__((may_alias))
|
||||||
#define __section(x) __attribute__((__section__(#x)))
|
#define __section(x) __attribute__((__section__(#x)))
|
||||||
#define __noinline __attribute__((__noinline__))
|
#define __noinline __attribute__((__noinline__))
|
||||||
|
#define __big_endian
|
||||||
/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
||||||
* __always_inline. Therefore undefine it first to allow the headers
|
* __always_inline. Therefore undefine it first to allow the headers
|
||||||
* to be included first.
|
* to be included first.
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ typedef enum {
|
|||||||
PV_CERT_ERROR_MALFORMED_ROOT_CA,
|
PV_CERT_ERROR_MALFORMED_ROOT_CA,
|
||||||
PV_CERT_ERROR_NO_CRL,
|
PV_CERT_ERROR_NO_CRL,
|
||||||
PV_CERT_ERROR_NO_CRLDP,
|
PV_CERT_ERROR_NO_CRLDP,
|
||||||
|
PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||||
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
||||||
PV_CERT_ERROR_NO_PUBLIC_KEY,
|
PV_CERT_ERROR_NO_PUBLIC_KEY,
|
||||||
PV_CERT_ERROR_READ_CERTIFICATE,
|
PV_CERT_ERROR_READ_CERTIFICATE,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "libpv/glib-helper.h"
|
#include "libpv/glib-helper.h"
|
||||||
|
|
||||||
#include <glib/gi18n-lib.h>
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
#include "libpv/openssl-compat.h"
|
#include "libpv/openssl-compat.h"
|
||||||
#include "libpv/macros.h"
|
#include "libpv/macros.h"
|
||||||
|
|||||||
@@ -42,11 +42,14 @@ enum PvCryptoMode {
|
|||||||
PV_DECRYPT,
|
PV_DECRYPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** pv_get_openssl_error:
|
/** pv_get_openssl_errors:
|
||||||
*
|
*
|
||||||
* Returns: (transfer full): String representing the error.
|
* Returns the last OpenSSL error messages.
|
||||||
|
* Caller is responsible to free the returned value.
|
||||||
|
*
|
||||||
|
* Returns: String representing the error.
|
||||||
*/
|
*/
|
||||||
const char *pv_get_openssl_error(void);
|
char *pv_get_openssl_errors(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pv_BIO_reset:
|
* pv_BIO_reset:
|
||||||
@@ -181,7 +184,6 @@ typedef enum {
|
|||||||
PV_CRYPTO_ERROR_KEYGENERATION,
|
PV_CRYPTO_ERROR_KEYGENERATION,
|
||||||
PV_CRYPTO_ERROR_RANDOMIZATION,
|
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||||
PV_CRYPTO_ERROR_READ_FILE,
|
PV_CRYPTO_ERROR_READ_FILE,
|
||||||
PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
|
||||||
PV_CRYPTO_ERROR_NO_MATCH_TAG,
|
PV_CRYPTO_ERROR_NO_MATCH_TAG,
|
||||||
} PvCryptoErrors;
|
} PvCryptoErrors;
|
||||||
|
|
||||||
|
|||||||
@@ -102,9 +102,12 @@ FILE *pv_file_open(const char *filename, const char *mode, GError **error);
|
|||||||
|
|
||||||
/** pv_gbytes_memcpy:
|
/** pv_gbytes_memcpy:
|
||||||
*
|
*
|
||||||
* memcpy with size check.
|
* memcpy with size check. In case @dst_size is smaller than the size of @src
|
||||||
|
* the error value %NULL is returned and @copied and @dst are left unchanged.
|
||||||
|
*
|
||||||
|
* If @dst and @src data overlap, the behavior is undefined.
|
||||||
*/
|
*/
|
||||||
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src);
|
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src, size_t *copied);
|
||||||
|
|
||||||
#define PV_GLIB_HELPER_ERROR g_quark_from_static_string("pv-glib-helper_error-quark")
|
#define PV_GLIB_HELPER_ERROR g_quark_from_static_string("pv-glib-helper_error-quark")
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -10,7 +10,12 @@
|
|||||||
#ifndef LIBPV_MACROS_H
|
#ifndef LIBPV_MACROS_H
|
||||||
#define LIBPV_MACROS_H
|
#define LIBPV_MACROS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define PV_NONNULL(...)
|
#define PV_NONNULL(...)
|
||||||
#define DO_PRAGMA(x) _Pragma(#x)
|
#define DO_PRAGMA(x) _Pragma(#x)
|
||||||
|
|
||||||
|
/* Most significant bit */
|
||||||
|
#define PV_MSB(idx) ((uint64_t)1 << (63 - (idx)))
|
||||||
|
|
||||||
#endif /* LIBPV_MACROS_H */
|
#endif /* LIBPV_MACROS_H */
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "boot/s390.h"
|
#include "boot/s390.h"
|
||||||
#include "libpv/crypto.h"
|
#include "libpv/crypto.h"
|
||||||
|
#include "libpv/macros.h"
|
||||||
|
|
||||||
/* Magic number which is used to identify the file containing the PV
|
/* Magic number which is used to identify the file containing the PV
|
||||||
* header
|
* header
|
||||||
@@ -22,20 +23,17 @@
|
|||||||
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||||
#define PV_VERSION_1 0x00000100U
|
#define PV_VERSION_1 0x00000100U
|
||||||
|
|
||||||
/* Internal helper macro */
|
|
||||||
#define __PV_BIT(nr) (1ULL << (63 - (nr)))
|
|
||||||
|
|
||||||
/* Plaintext control flags */
|
/* Plaintext control flags */
|
||||||
/* dumping of the configuration is allowed */
|
/* dumping of the configuration is allowed */
|
||||||
#define PV_PCF_ALLOW_DUMPING __PV_BIT(34)
|
#define PV_PCF_ALLOW_DUMPING PV_MSB(34)
|
||||||
/* prevent Ultravisor decryption during unpack operation */
|
/* prevent Ultravisor decryption during unpack operation */
|
||||||
#define PV_PCF_NO_DECRYPTION __PV_BIT(35)
|
#define PV_PCF_NO_DECRYPTION PV_MSB(35)
|
||||||
/* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
/* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
||||||
#define PV_PCF_PCKMO_DEA_TDEA __PV_BIT(56)
|
#define PV_PCF_PCKMO_DEA_TDEA PV_MSB(56)
|
||||||
/* PCKMO encrypt-AES-key functions allowed */
|
/* PCKMO encrypt-AES-key functions allowed */
|
||||||
#define PV_PCF_PCKMO_AES __PV_BIT(57)
|
#define PV_PCF_PCKMO_AES PV_MSB(57)
|
||||||
/* PCKMO encrypt-ECC-key functions allowed */
|
/* PCKMO encrypt-ECC-key functions allowed */
|
||||||
#define PV_PCF_PCKM_ECC __PV_BIT(58)
|
#define PV_PCF_PCKM_ECC PV_MSB(58)
|
||||||
|
|
||||||
/* maxima for the PV version 1 */
|
/* maxima for the PV version 1 */
|
||||||
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ extern ssize_t __write(int, const void*, size_t);
|
|||||||
extern int strmatch(const char *, const char *);
|
extern int strmatch(const char *, const char *);
|
||||||
extern int is_regex_valid(const char *);
|
extern int is_regex_valid(const char *);
|
||||||
extern int is_client_allowed(const char *, const struct iucvterm_cfg *);
|
extern int is_client_allowed(const char *, const struct iucvterm_cfg *);
|
||||||
extern void userid_cpy(char [8], const char [8]);
|
extern void userid_cpy(char [9], const char [8]);
|
||||||
|
|
||||||
extern void iucv_msg_error(const char *, uint32_t);
|
extern void iucv_msg_error(const char *, uint32_t);
|
||||||
extern void program_error(const char *, const char *);
|
extern void program_error(const char *, const char *);
|
||||||
|
|||||||
+1
-12
@@ -2,17 +2,6 @@ include ../common.mak
|
|||||||
|
|
||||||
lib = libap.a
|
lib = libap.a
|
||||||
|
|
||||||
check-dep-lock:
|
|
||||||
touch check-dep-lock
|
|
||||||
ifneq (${HAVE_LOCKFILE},0)
|
|
||||||
$(call check_dep, \
|
|
||||||
"libap", \
|
|
||||||
"lockfile.h", \
|
|
||||||
"liblockfile-devel", \
|
|
||||||
"HAVE_LOCKFILE=0")
|
|
||||||
ALL_CPPFLAGS += -DHAVE_LOCKFILE
|
|
||||||
endif
|
|
||||||
|
|
||||||
check-dep-json:
|
check-dep-json:
|
||||||
touch check-dep-json
|
touch check-dep-json
|
||||||
ifneq (${HAVE_JSONC},0)
|
ifneq (${HAVE_JSONC},0)
|
||||||
@@ -29,7 +18,7 @@ objects = ap.o
|
|||||||
|
|
||||||
$(lib): $(objects)
|
$(lib): $(objects)
|
||||||
|
|
||||||
$(objects): check-dep-lock check-dep-json
|
$(objects): check-dep-json
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|
||||||
|
|||||||
+12
-33
@@ -22,13 +22,10 @@
|
|||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
#endif /* HAVE_JSONC */
|
#endif /* HAVE_JSONC */
|
||||||
|
|
||||||
#ifdef HAVE_LOCKFILE
|
|
||||||
#include <lockfile.h>
|
|
||||||
#endif /* HAVE_LOCKFILE */
|
|
||||||
|
|
||||||
#include "lib/ap.h"
|
#include "lib/ap.h"
|
||||||
#include "lib/util_file.h"
|
#include "lib/util_file.h"
|
||||||
#include "lib/util_libc.h"
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/util_lockfile.h"
|
||||||
#include "lib/util_panic.h"
|
#include "lib/util_panic.h"
|
||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_udev.h"
|
#include "lib/util_udev.h"
|
||||||
@@ -701,33 +698,28 @@ void ap_list_remove_all(struct util_list *list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LOCKFILE
|
|
||||||
static int ap_lockfile_create(int flags)
|
|
||||||
{
|
|
||||||
return lockfile_create(AP_LOCKFILE, AP_LOCK_RETRIES, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acquire the ap config lock using this process PID (L_PID)
|
* Acquire the ap config lock using this Process ID
|
||||||
|
*
|
||||||
|
* @retval 0 Lock acquired on behalf of this process
|
||||||
*
|
*
|
||||||
* @retval 0 Lock successfully acquired on behalf of L_PID
|
|
||||||
* @retval != 0 Error, lock was not obtained
|
* @retval != 0 Error, lock was not obtained
|
||||||
*/
|
*/
|
||||||
int ap_get_lock(void)
|
int ap_get_lock(void)
|
||||||
{
|
{
|
||||||
return ap_lockfile_create(L_PID);
|
return util_lockfile_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acquire the ap config lock using the parent process PID (L_PPID) -- intended
|
* Acquire the ap config lock using the Parent Process ID -- intended for use
|
||||||
* for use by the mdevctl callout ap-check utility
|
* by the mdevctl callout ap-check utility
|
||||||
*
|
*
|
||||||
* @retval 0 Lock successfully acquired on behalf of L_PPID
|
* @retval 0 Lock acquired on behalf of parent process
|
||||||
* @retval != 0 Error, lock was not obtained
|
* @retval != 0 Error, lock was not obtained
|
||||||
*/
|
*/
|
||||||
int ap_get_lock_callout(void)
|
int ap_get_lock_callout(void)
|
||||||
{
|
{
|
||||||
return ap_lockfile_create(L_PPID);
|
return util_lockfile_parent_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -738,23 +730,10 @@ int ap_get_lock_callout(void)
|
|||||||
*/
|
*/
|
||||||
int ap_release_lock(void)
|
int ap_release_lock(void)
|
||||||
{
|
{
|
||||||
return lockfile_remove(AP_LOCKFILE);
|
return util_lockfile_release(AP_LOCKFILE);
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* If no liblockfile, actions are performed without acquiring the file lock */
|
|
||||||
int ap_get_lock(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ap_get_lock_callout(void)
|
int ap_release_lock_callout(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return util_lockfile_parent_release(AP_LOCKFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ap_release_lock(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAVE_LOCKFILE */
|
|
||||||
|
|||||||
@@ -85,5 +85,6 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("PAI NNPA support %d\n", libcpumf_have_pai_nnpa());
|
printf("PAI NNPA support %d\n", libcpumf_have_pai_nnpa());
|
||||||
|
printf("PAI EXTENSION support %d\n", libcpumf_have_pai_ext());
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,13 @@ bool libcpumf_have_pai_crypto(void)
|
|||||||
return (stat(S390_SYSFS_PAI_CRYPTO, &statbuf) == -1) ? false : true;
|
return (stat(S390_SYSFS_PAI_CRYPTO, &statbuf) == -1) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool libcpumf_have_pai_ext(void)
|
||||||
|
{
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
return (stat(S390_SYSFS_PAI_EXT, &statbuf) == -1) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
bool libcpumf_have_pai_nnpa(void)
|
bool libcpumf_have_pai_nnpa(void)
|
||||||
{
|
{
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|||||||
+3
-3
@@ -51,7 +51,7 @@ endif
|
|||||||
sources := $(wildcard *.c)
|
sources := $(wildcard *.c)
|
||||||
objects := $(patsubst %.c,%.o,$(sources))
|
objects := $(patsubst %.c,%.o,$(sources))
|
||||||
|
|
||||||
all: $(BUILD_TARGETS) .check_dep-$(LIB)
|
all: $(BUILD_TARGETS)
|
||||||
|
|
||||||
$(LIB): $(objects)
|
$(LIB): $(objects)
|
||||||
$(LIB): ALL_CFLAGS += -fPIC
|
$(LIB): ALL_CFLAGS += -fPIC
|
||||||
@@ -74,7 +74,7 @@ skip-$(LIB):
|
|||||||
.detect-openssl.dep.c:
|
.detect-openssl.dep.c:
|
||||||
echo "#include <openssl/evp.h>" > $@
|
echo "#include <openssl/evp.h>" > $@
|
||||||
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
|
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
|
||||||
echo " #error openssl version 1.1.0 is required" >> $@
|
echo " #error openssl version 1.1.1 is required" >> $@
|
||||||
echo "#endif" >> $@
|
echo "#endif" >> $@
|
||||||
echo "static void __attribute__((unused)) test(void) {" >> $@
|
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||||
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||||
@@ -90,7 +90,7 @@ skip-$(LIB):
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"$(LIB)", \
|
"$(LIB)", \
|
||||||
$^, \
|
$^, \
|
||||||
"openssl-devel / libssl-dev version >= 1.1.0", \
|
"openssl-devel / libssl-dev version >= 1.1.1", \
|
||||||
"HAVE_OPENSSL=0", \
|
"HAVE_OPENSSL=0", \
|
||||||
"-I.")
|
"-I.")
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
|
|||||||
+22
-13
@@ -290,7 +290,9 @@ static char *pv_X509_NAME_oneline(const X509_NAME *name)
|
|||||||
long len;
|
long len;
|
||||||
|
|
||||||
if (X509_NAME_print_ex(key_bio, name, 0, XN_FLAG_RFC2253) == -1) {
|
if (X509_NAME_print_ex(key_bio, name, 0, XN_FLAG_RFC2253) == -1) {
|
||||||
g_warning(_("Cannot receive X509-NAME from CRL: %s"), pv_get_openssl_error());
|
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||||
|
|
||||||
|
g_warning(_("Cannot receive X509-NAME from CRL: %s"), openssl_err_msg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +494,9 @@ static X509_CRL *load_crl_by_dist_point(DIST_POINT *crldp, GError **error)
|
|||||||
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error)
|
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error)
|
||||||
{
|
{
|
||||||
g_autoptr(STACK_OF_DIST_POINT) crldps = NULL;
|
g_autoptr(STACK_OF_DIST_POINT) crldps = NULL;
|
||||||
|
g_autoptr(GError) last_error = NULL;
|
||||||
g_autoptr(X509_CRL) ret = NULL;
|
g_autoptr(X509_CRL) ret = NULL;
|
||||||
|
int dist_points_cnt;
|
||||||
|
|
||||||
g_assert(cert);
|
g_assert(cert);
|
||||||
|
|
||||||
@@ -503,19 +507,24 @@ X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < sk_DIST_POINT_num(crldps); i++) {
|
dist_points_cnt = sk_DIST_POINT_num(crldps);
|
||||||
|
for (int i = 0; i < dist_points_cnt; i++) {
|
||||||
DIST_POINT *crldp = sk_DIST_POINT_value(crldps, i);
|
DIST_POINT *crldp = sk_DIST_POINT_value(crldps, i);
|
||||||
|
|
||||||
g_assert(crldp);
|
g_assert(crldp);
|
||||||
|
|
||||||
/* ignore error */
|
g_clear_error(&last_error);
|
||||||
ret = load_crl_by_dist_point(crldp, NULL);
|
ret = load_crl_by_dist_point(crldp, &last_error);
|
||||||
if (ret)
|
if (ret)
|
||||||
return g_steal_pointer(&ret);
|
return g_steal_pointer(&ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
/* relabel error */
|
||||||
_("failed to download CRL"));
|
if (last_error)
|
||||||
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
||||||
|
"%s", last_error->message);
|
||||||
|
else
|
||||||
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
||||||
|
_("failed to download CRL"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,7 +792,7 @@ int pv_store_set_verify_param(X509_STORE *store, GError **error)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||||
_("X509 store initialization failed"));
|
_("X509 store initialization failed"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1368,14 +1377,14 @@ int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error)
|
|||||||
|
|
||||||
ca_x509_subject = X509_get_subject_name(ca);
|
ca_x509_subject = X509_get_subject_name(ca);
|
||||||
if (!ca_x509_subject) {
|
if (!ca_x509_subject) {
|
||||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||||
_("subject of the root CA cannot be retrieved"));
|
_("subject of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ca_subject = pv_X509_NAME_oneline(ca_x509_subject);
|
ca_subject = pv_X509_NAME_oneline(ca_x509_subject);
|
||||||
if (!ca_subject) {
|
if (!ca_subject) {
|
||||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||||
_("subject name of the root CA cannot be retrieved"));
|
_("subject name of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1469,11 +1478,11 @@ static STACK_OF_X509 *get_ibm_signing_certs(STACK_OF_X509 *certs, GError **error
|
|||||||
ibm_signing_certs = pv_remove_ibm_signing_certs(certs);
|
ibm_signing_certs = pv_remove_ibm_signing_certs(certs);
|
||||||
ibm_signing_certs_count = sk_X509_num(ibm_signing_certs);
|
ibm_signing_certs_count = sk_X509_num(ibm_signing_certs);
|
||||||
if (ibm_signing_certs_count < 1) {
|
if (ibm_signing_certs_count < 1) {
|
||||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||||
_("Specify at least one IBM Z signing key"));
|
_("Specify at least one IBM Z signing key"));
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (ibm_signing_certs_count > 1) {
|
} else if (ibm_signing_certs_count > 1) {
|
||||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||||
_("Specify only one IBM Z signing key"));
|
_("Specify only one IBM Z signing key"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1504,7 +1513,7 @@ static gboolean download_crls(X509_STORE *trusted, PvCertWithPathList *host_key_
|
|||||||
X509_CRL *crl = sk_X509_CRL_value(downloaded_ibm_signing_crls, i);
|
X509_CRL *crl = sk_X509_CRL_value(downloaded_ibm_signing_crls, i);
|
||||||
|
|
||||||
if (X509_STORE_add_crl(trusted, crl) != 1) {
|
if (X509_STORE_add_crl(trusted, crl) != 1) {
|
||||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||||
_("failed to load CRL"));
|
_("failed to load CRL"));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-8
@@ -19,18 +19,18 @@
|
|||||||
#include "libpv/glib-helper.h"
|
#include "libpv/glib-helper.h"
|
||||||
#include "libpv/hash.h"
|
#include "libpv/hash.h"
|
||||||
|
|
||||||
const char *pv_get_openssl_error(void)
|
char *pv_get_openssl_errors(void)
|
||||||
{
|
{
|
||||||
const char *ret;
|
char *ret;
|
||||||
BIO *bio;
|
|
||||||
char *buf;
|
char *buf;
|
||||||
|
BIO *bio;
|
||||||
long len;
|
long len;
|
||||||
|
|
||||||
bio = BIO_new(BIO_s_mem());
|
bio = BIO_new(BIO_s_mem());
|
||||||
ERR_print_errors(bio);
|
ERR_print_errors(bio);
|
||||||
len = BIO_get_mem_data(bio, &buf);
|
len = BIO_get_mem_data(bio, &buf);
|
||||||
if (len < 0)
|
if (len <= 0 || !buf)
|
||||||
ret = "Cannot receive OpenSSL error message.";
|
ret = g_strdup("Cannot receive OpenSSL error message.");
|
||||||
else
|
else
|
||||||
ret = g_strndup(buf, (size_t)len);
|
ret = g_strndup(buf, (size_t)len);
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
@@ -41,7 +41,7 @@ int pv_BIO_reset(BIO *b)
|
|||||||
{
|
{
|
||||||
int rc = BIO_reset(b);
|
int rc = BIO_reset(b);
|
||||||
|
|
||||||
if (rc != 1 && (BIO_method_type(b) == BIO_TYPE_FILE && rc != 0))
|
if (rc != 1 && !(BIO_method_type(b) == BIO_TYPE_FILE && rc == 0))
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -276,7 +276,7 @@ int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherP
|
|||||||
}
|
}
|
||||||
|
|
||||||
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
|
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
|
||||||
const EVP_MD *md, G_GNUC_UNUSED GError **error)
|
const EVP_MD *md, GError **error)
|
||||||
{
|
{
|
||||||
const unsigned char *salt_data, *key_data, *info_data;
|
const unsigned char *salt_data, *key_data, *info_data;
|
||||||
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
|
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
|
||||||
@@ -354,7 +354,6 @@ GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *
|
|||||||
if (EVP_PKEY_derive(ctx, derived_key, &derived_key_len) != 1) {
|
if (EVP_PKEY_derive(ctx, derived_key, &derived_key_len) != 1) {
|
||||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
|
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
|
||||||
"FAILED to derive key via HKDF");
|
"FAILED to derive key via HKDF");
|
||||||
printf("%s\n", pv_get_openssl_error());
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -168,12 +168,14 @@ GBytes *pv_file_get_content_as_secure_bytes(const char *filename)
|
|||||||
return pv_sec_gbytes_new_take(g_steal_pointer(&data), data_size);
|
return pv_sec_gbytes_new_take(g_steal_pointer(&data), data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src)
|
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src, size_t *copied)
|
||||||
{
|
{
|
||||||
size_t src_size;
|
size_t src_size;
|
||||||
const void *src_data = g_bytes_get_data(src, &src_size);
|
const void *src_data = g_bytes_get_data(src, &src_size);
|
||||||
|
|
||||||
if (dst_size < src_size)
|
if (dst_size < src_size)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (copied)
|
||||||
|
*copied = src_size;
|
||||||
return memcpy(dst, src_data, src_size);
|
return memcpy(dst, src_data, src_size);
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -97,8 +97,10 @@ HMAC_CTX *pv_hmac_ctx_new(GBytes *key, const EVP_MD *md, GError **error)
|
|||||||
key_data = g_bytes_get_data(key, &key_size);
|
key_data = g_bytes_get_data(key, &key_size);
|
||||||
|
|
||||||
if (HMAC_Init_ex(ctx, key_data, (int)key_size, md, NULL) != 1) {
|
if (HMAC_Init_ex(ctx, key_data, (int)key_size, md, NULL) != 1) {
|
||||||
|
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||||
|
|
||||||
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
||||||
"unable to create HMAC context: %s", pv_get_openssl_error());
|
"unable to create HMAC context: %s", openssl_err_msg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return g_steal_pointer(&ctx);
|
return g_steal_pointer(&ctx);
|
||||||
@@ -110,8 +112,10 @@ int pv_hmac_ctx_update_raw(HMAC_CTX *ctx, const void *buf, size_t size, GError *
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (HMAC_Update(ctx, buf, size) != 1) {
|
if (HMAC_Update(ctx, buf, size) != 1) {
|
||||||
|
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||||
|
|
||||||
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
||||||
"unable to add data to HMAC context: %s", pv_get_openssl_error());
|
"unable to add data to HMAC context: %s", openssl_err_msg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -139,8 +143,10 @@ GBytes *pv_hamc_ctx_finalize(HMAC_CTX *ctx, GError **error)
|
|||||||
hmac = g_malloc0((unsigned int)md_size);
|
hmac = g_malloc0((unsigned int)md_size);
|
||||||
|
|
||||||
if (HMAC_Final(ctx, hmac, &hmac_size) != 1) {
|
if (HMAC_Final(ctx, hmac, &hmac_size) != 1) {
|
||||||
|
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||||
|
|
||||||
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
||||||
"unable to calculate HMAC: %s", pv_get_openssl_error());
|
"unable to calculate HMAC: %s", openssl_err_msg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return g_bytes_new_take(g_steal_pointer(&hmac), hmac_size);
|
return g_bytes_new_take(g_steal_pointer(&hmac), hmac_size);
|
||||||
|
|||||||
+8
-9
@@ -107,13 +107,12 @@ const char *util_arch_machine_type_to_str(int type)
|
|||||||
*/
|
*/
|
||||||
unsigned long util_arch_hsa_maxsize(void)
|
unsigned long util_arch_hsa_maxsize(void)
|
||||||
{
|
{
|
||||||
unsigned long size = HSA_SIZE_32M;
|
switch (util_arch_machine_type()) {
|
||||||
int type;
|
case UTIL_ARCH_MACHINE_TYPE_Z15:
|
||||||
|
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
|
||||||
type = util_arch_machine_type();
|
case UTIL_ARCH_MACHINE_TYPE_Z16:
|
||||||
if (type != UTIL_ARCH_MACHINE_TYPE_UNKNOWN &&
|
return HSA_SIZE_512M;
|
||||||
type >= UTIL_ARCH_MACHINE_TYPE_Z15)
|
default:
|
||||||
size = HSA_SIZE_512M;
|
return HSA_SIZE_32M;
|
||||||
|
}
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* util - Utility function library
|
||||||
|
*
|
||||||
|
* Created file-based locks
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/util_lockfile.h"
|
||||||
|
#include "lib/util_panic.h"
|
||||||
|
|
||||||
|
#define WAITPID 120 /* Time to wait for pid to be written */
|
||||||
|
#define WAITINC 5 /* Additional time to wait each retry */
|
||||||
|
#define MAXWAIT 60 /* Maximum wait between retries */
|
||||||
|
#define BUFSIZE 40 /* Buffer must be large enough to fit pid string */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there is a process that exists with the specified identifier.
|
||||||
|
*
|
||||||
|
* @param[in] pid Process Identifier to check
|
||||||
|
*
|
||||||
|
* @retval true Process exists or we lack privelege to check
|
||||||
|
* @retval false Process does not exist
|
||||||
|
*/
|
||||||
|
static bool pid_exists(int pid)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Use sig 0 to determine if the owner is still alive */
|
||||||
|
rc = kill(pid, 0);
|
||||||
|
if (rc != 0) {
|
||||||
|
switch (errno) {
|
||||||
|
case EPERM:
|
||||||
|
/* Privilege issue, just assume PID exists */
|
||||||
|
break;
|
||||||
|
case ESRCH:
|
||||||
|
/* PID does not exist, this lock is stale */
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
util_assert(false, "Unexpected return from kill: %d\n", rc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for an existing lock that is deemed stale (either the associated PID
|
||||||
|
* is gone or no PID has been written to the file in a reasonable timeframe).
|
||||||
|
* In the case a stale lock is found, remove it.
|
||||||
|
*
|
||||||
|
* @param[in] lockfile Path to the lock file
|
||||||
|
*
|
||||||
|
* @retval 0 Either no lock or stale lock was found and removed
|
||||||
|
* @retval 1 Lock is held by another PID and is not stale
|
||||||
|
*/
|
||||||
|
static int handle_stale_lock(char *lockfile)
|
||||||
|
{
|
||||||
|
int fd, rc, pid, len;
|
||||||
|
struct stat info;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
time_t curr;
|
||||||
|
|
||||||
|
fd = open(lockfile, O_RDONLY);
|
||||||
|
|
||||||
|
if (fd >= 0) {
|
||||||
|
/* Lock exists, see who owns it */
|
||||||
|
len = read(fd, buf, sizeof(buf));
|
||||||
|
if (len > 0) {
|
||||||
|
buf[len] = 0; /* Ensure null terminated string */
|
||||||
|
pid = atoi(buf);
|
||||||
|
if (!pid_exists(pid)) {
|
||||||
|
/* Stale lock detected unlink and retry now */
|
||||||
|
close(fd);
|
||||||
|
unlink(lockfile);
|
||||||
|
return 0;
|
||||||
|
} else if (pid != 0) {
|
||||||
|
/* Lock is held by an active pid, delay */
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If we reach this point, the PID was 0 which is
|
||||||
|
* unexpected. Proceed under the assumption that the
|
||||||
|
* proper PID hasn't been written yet.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* PID hasn't been written yet? Either a bad lock or a very
|
||||||
|
* new one.
|
||||||
|
*/
|
||||||
|
time(&curr);
|
||||||
|
rc = fstat(fd, &info);
|
||||||
|
close(fd);
|
||||||
|
if (rc != 0) {
|
||||||
|
/* Can't read file anymore, retry now */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (curr > info.st_mtime + WAITPID) {
|
||||||
|
/*
|
||||||
|
* PID should be in the file within 2 minutes,
|
||||||
|
* something went wrong. Treat as stale.
|
||||||
|
*/
|
||||||
|
unlink(lockfile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Otherwise, assume file was newly created and delay */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Couldn't open, try again immediately */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to create a lockfile at the specified path.
|
||||||
|
*
|
||||||
|
* @param[in] lockfile Path to the lock file
|
||||||
|
* @param[in] retries Number of times to retry if lock fails initially
|
||||||
|
* @param[in] pid PID to use for lock ownership
|
||||||
|
*
|
||||||
|
* @retval 0 Lock created with PID as owner
|
||||||
|
* @retval !=0 Lock was not created
|
||||||
|
*/
|
||||||
|
static int do_lockfile_lock(char *lockfile, unsigned int retries, int pid)
|
||||||
|
{
|
||||||
|
int fd, plen, len, rc = 0, snooze = 0;
|
||||||
|
unsigned int tries = retries + 1;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
char *tpath;
|
||||||
|
|
||||||
|
if (!lockfile)
|
||||||
|
return UTIL_LOCKFILE_ERR;
|
||||||
|
|
||||||
|
plen = snprintf(buf, sizeof(buf), "%d\n", pid);
|
||||||
|
if (plen < 0 || (plen > ((int)sizeof(buf) - 1)))
|
||||||
|
return UTIL_LOCKFILE_ERR;
|
||||||
|
|
||||||
|
/* Allocate temporary lock file with a sufficiently unique path */
|
||||||
|
len = util_asprintf(&tpath, "%s%05d%02x", lockfile, getpid(),
|
||||||
|
(unsigned int)time(NULL) & 255);
|
||||||
|
if (len < 0)
|
||||||
|
return UTIL_LOCKFILE_ERR;
|
||||||
|
|
||||||
|
/* Open the temporary lockfile, write the specified pid */
|
||||||
|
fd = open(tpath, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0644);
|
||||||
|
if (fd < 0) {
|
||||||
|
rc = UTIL_LOCKFILE_ERR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = write(fd, buf, plen);
|
||||||
|
if (close(fd) != 0) {
|
||||||
|
rc = UTIL_LOCKFILE_ERR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (len != plen) {
|
||||||
|
/* Failed to write the temp lockfile, bail out */
|
||||||
|
rc = UTIL_LOCKFILE_ERR;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link the temprorary file to the real path */
|
||||||
|
do {
|
||||||
|
rc = link(tpath, lockfile);
|
||||||
|
if (rc == 0) {
|
||||||
|
/* Lock successfully acquired */
|
||||||
|
rc = UTIL_LOCKFILE_OK;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
/* Lock already held - check for stale lock */
|
||||||
|
rc = handle_stale_lock(lockfile);
|
||||||
|
/* Only wait if the lock was not stale */
|
||||||
|
if (rc != 0) {
|
||||||
|
tries--;
|
||||||
|
if (tries > 0) {
|
||||||
|
snooze += WAITINC;
|
||||||
|
snooze = (snooze > MAXWAIT) ? MAXWAIT : snooze;
|
||||||
|
sleep(snooze);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (tries > 0);
|
||||||
|
|
||||||
|
/* Exhausted specified number of retries, exit on failure */
|
||||||
|
rc = UTIL_LOCKFILE_LOCK_FAIL;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
unlink(tpath);
|
||||||
|
free(tpath);
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to release a lockfile at the specified path.
|
||||||
|
*
|
||||||
|
* @param[in] lockfile Path to the lock file
|
||||||
|
* @param[in] pid PID that should own the lock
|
||||||
|
*
|
||||||
|
* @retval 0 Lock released
|
||||||
|
* @retval !=0 Lock was not released or did not exist
|
||||||
|
*/
|
||||||
|
static int do_lockfile_release(char *lockfile, int pid)
|
||||||
|
{
|
||||||
|
int fd, len, lpid;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
|
||||||
|
if (!lockfile)
|
||||||
|
return UTIL_LOCKFILE_ERR;
|
||||||
|
|
||||||
|
/* Open lockfile, read the owning pid if it exists */
|
||||||
|
fd = open(lockfile, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return UTIL_LOCKFILE_RELEASE_NONE;
|
||||||
|
len = read(fd, buf, sizeof(buf));
|
||||||
|
close(fd);
|
||||||
|
if (len <= 0)
|
||||||
|
return UTIL_LOCKFILE_RELEASE_FAIL;
|
||||||
|
buf[len] = 0;
|
||||||
|
lpid = atoi(buf);
|
||||||
|
|
||||||
|
/* Only release the lock if its held by the right pid */
|
||||||
|
if (pid != lpid)
|
||||||
|
return UTIL_LOCKFILE_RELEASE_FAIL;
|
||||||
|
|
||||||
|
unlink(lockfile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to create a lockfile owned by this process at the specified path.
|
||||||
|
*
|
||||||
|
* @param[in] lockfile Path to the lock file
|
||||||
|
* @param[in] retries Number of times to retry if lock fails initially
|
||||||
|
*
|
||||||
|
* @retval 0 Lock created
|
||||||
|
* @retval !=0 Lock was not created
|
||||||
|
*/
|
||||||
|
int util_lockfile_lock(char *lockfile, int retries)
|
||||||
|
{
|
||||||
|
return do_lockfile_lock(lockfile, retries, getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to create a lockfile owned by the parent of this process at the
|
||||||
|
* specified path.
|
||||||
|
*
|
||||||
|
* @param[in] lockfile Path to the lock file
|
||||||
|
* @param[in] retries Number of times to retry if lock fails initially
|
||||||
|
*
|
||||||
|
* @retval 0 Lock created
|
||||||
|
* @retval !=0 Lock was not created
|
||||||
|
*/
|
||||||
|
int util_lockfile_parent_lock(char *lockfile, int retries)
|
||||||
|
{
|
||||||
|
return do_lockfile_lock(lockfile, retries, getppid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to release a lockfile owned by this process at the specified path.
|
||||||
|
*
|
||||||
|
* @param[in] lockfile Path to the lock file
|
||||||
|
*
|
||||||
|
* @retval 0 Lock released
|
||||||
|
* @retval !=0 Lock was not released or did not exist
|
||||||
|
*/
|
||||||
|
int util_lockfile_release(char *lockfile)
|
||||||
|
{
|
||||||
|
return do_lockfile_release(lockfile, getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to release a lockfile owned by the parent of this process at the
|
||||||
|
* specified path.
|
||||||
|
*
|
||||||
|
* @param[in] lockfile Path to the lock file
|
||||||
|
*
|
||||||
|
* @retval 0 Lock released
|
||||||
|
* @retval !=0 Lock was not released or did not exist
|
||||||
|
*/
|
||||||
|
int util_lockfile_parent_release(char *lockfile)
|
||||||
|
{
|
||||||
|
return do_lockfile_release(lockfile, getppid());
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
/**
|
||||||
|
* util_lockfile_example - Example program for util_lockfile
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//! [code]
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "lib/util_opt.h"
|
||||||
|
#include "lib/util_prg.h"
|
||||||
|
#include "lib/util_lockfile.h"
|
||||||
|
|
||||||
|
static const struct util_prg prg = {
|
||||||
|
.desc = "Example for util_lockfile.",
|
||||||
|
.copyright_vec = { {
|
||||||
|
.owner = "IBM Corp.",
|
||||||
|
.pub_first = 2022,
|
||||||
|
.pub_last = 2022,
|
||||||
|
},
|
||||||
|
UTIL_PRG_COPYRIGHT_END }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct util_opt opt_vec[] = {
|
||||||
|
UTIL_OPT_SECTION("OPTIONS"),
|
||||||
|
{
|
||||||
|
.option = { "file", required_argument, NULL, 'f' },
|
||||||
|
.argument = "PATH",
|
||||||
|
.desc = "Use the specified path for a lockfile.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "lock", required_argument, NULL, 'l' },
|
||||||
|
.argument = "RETRIES",
|
||||||
|
.desc = "Acquire the specified file lock using the parent "
|
||||||
|
"process id of this process. If not immediately "
|
||||||
|
"successful, retry for the specified number of times",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "release", 0, NULL, 'r' },
|
||||||
|
.desc = "Release the specified lock file using the parent "
|
||||||
|
"process id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "lock-and-release", required_argument, NULL, 'L' },
|
||||||
|
.argument = "RETRIES",
|
||||||
|
.desc = "Acquire the specified file lock using this process "
|
||||||
|
"id, then release it. If not immediately successful, "
|
||||||
|
"retry for the specified number of times.",
|
||||||
|
},
|
||||||
|
UTIL_OPT_HELP,
|
||||||
|
UTIL_OPT_VERSION,
|
||||||
|
UTIL_OPT_END
|
||||||
|
};
|
||||||
|
|
||||||
|
enum prg_action {
|
||||||
|
ACTION_NONE = 0,
|
||||||
|
ACTION_LOCK,
|
||||||
|
ACTION_RELEASE,
|
||||||
|
ACTION_LOCK_AND_RELEASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print_single_action_error(void)
|
||||||
|
{
|
||||||
|
warnx("Only a single action (--lock, --lock-parent, --release, "
|
||||||
|
"--release-parent) is allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
enum prg_action action_id = ACTION_NONE;
|
||||||
|
int opt, rc, retries = 0;
|
||||||
|
char *endp, *path = NULL;
|
||||||
|
|
||||||
|
util_prg_init(&prg);
|
||||||
|
util_opt_init(opt_vec, NULL);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
opt = util_opt_getopt_long(argc, argv);
|
||||||
|
if (opt == -1)
|
||||||
|
break;
|
||||||
|
switch (opt) {
|
||||||
|
case 'f':
|
||||||
|
path = optarg;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
if (action_id != ACTION_NONE) {
|
||||||
|
print_single_action_error();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
retries = strtol(optarg, &endp, 0);
|
||||||
|
if (*optarg == '\0' || *endp != '\0' || retries < 0) {
|
||||||
|
warnx("Invalid retry value for "
|
||||||
|
"--lock-and-release: '%s'",
|
||||||
|
optarg);
|
||||||
|
util_prg_print_parse_error();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
action_id = ACTION_LOCK_AND_RELEASE;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (action_id != ACTION_NONE) {
|
||||||
|
print_single_action_error();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
retries = strtol(optarg, &endp, 0);
|
||||||
|
if (*optarg == '\0' || *endp != '\0' || retries < 0) {
|
||||||
|
warnx("Invalid retry value for "
|
||||||
|
"--parent-lock: '%s'",
|
||||||
|
optarg);
|
||||||
|
util_prg_print_parse_error();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
action_id = ACTION_LOCK;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (action_id != ACTION_NONE) {
|
||||||
|
print_single_action_error();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
action_id = ACTION_RELEASE;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
util_prg_print_help();
|
||||||
|
util_opt_print_help();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'v':
|
||||||
|
util_prg_print_version();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
default:
|
||||||
|
util_opt_print_parse_error(opt, argv);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
warnx("--file is required, see --help for more information");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action_id == ACTION_NONE) {
|
||||||
|
warnx("One of the following actions must be specified: "
|
||||||
|
"--lock, --release, --lock-and-release");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine which util_lockfile function to call */
|
||||||
|
switch (action_id) {
|
||||||
|
case ACTION_LOCK:
|
||||||
|
rc = util_lockfile_parent_lock(path, retries);
|
||||||
|
switch (rc) {
|
||||||
|
case UTIL_LOCKFILE_OK:
|
||||||
|
printf("lock acquired successfully\n");
|
||||||
|
break;
|
||||||
|
case UTIL_LOCKFILE_LOCK_FAIL:
|
||||||
|
warnx("lock was not acquired; already held");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
case UTIL_LOCKFILE_ERR:
|
||||||
|
warnx("lock was not acquired; file error");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
default:
|
||||||
|
warnx("Unknown util_lockfile rc %d", rc);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACTION_RELEASE:
|
||||||
|
rc = util_lockfile_parent_release(path);
|
||||||
|
switch (rc) {
|
||||||
|
case UTIL_LOCKFILE_OK:
|
||||||
|
printf("lock released successfully\n");
|
||||||
|
break;
|
||||||
|
case UTIL_LOCKFILE_RELEASE_NONE:
|
||||||
|
warnx("lock file did not exist");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
case UTIL_LOCKFILE_RELEASE_FAIL:
|
||||||
|
warnx("lock was not held by the specified pid");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
case UTIL_LOCKFILE_ERR:
|
||||||
|
warnx("lock was not released; file error");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
default:
|
||||||
|
warnx("Unknown util_lockfile rc %d", rc);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACTION_LOCK_AND_RELEASE:
|
||||||
|
rc = util_lockfile_lock(path, retries);
|
||||||
|
switch (rc) {
|
||||||
|
case UTIL_LOCKFILE_OK:
|
||||||
|
printf("lock acquired successfully, holding for 2 seconds\n");
|
||||||
|
break;
|
||||||
|
case UTIL_LOCKFILE_LOCK_FAIL:
|
||||||
|
warnx("lock was not acquired; already held");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
case UTIL_LOCKFILE_ERR:
|
||||||
|
warnx("lock was not acquired; file error");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
default:
|
||||||
|
warnx("Unknown util_lockfile rc %d", rc);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
/* Briefly sleep while holding the lock */
|
||||||
|
sleep(2);
|
||||||
|
rc = util_lockfile_release(path);
|
||||||
|
switch (rc) {
|
||||||
|
case UTIL_LOCKFILE_OK:
|
||||||
|
printf("lock released successfully\n");
|
||||||
|
break;
|
||||||
|
case UTIL_LOCKFILE_RELEASE_NONE:
|
||||||
|
warnx("lock file did not exist");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
case UTIL_LOCKFILE_RELEASE_FAIL:
|
||||||
|
warnx("lock was not held by the specified pid");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
case UTIL_LOCKFILE_ERR:
|
||||||
|
warnx("lock was not released; file error");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
default:
|
||||||
|
warnx("Unknown util_lockfile rc %d", rc);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnx("Unknown util_lockfile action");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
//! [code]
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
/*
|
/*
|
||||||
* Obtain a backtrace and print it to stderr
|
* Obtain a backtrace and print it to stderr
|
||||||
*
|
*
|
||||||
* To get symbols, compile the code with "-rdynamic".
|
* To get symbols, link the code with "-rdynamic".
|
||||||
*/
|
*/
|
||||||
static void print_backtrace(void)
|
static void print_backtrace(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public:
|
|||||||
RegisterSet64 getRegisterSet(int cpu);
|
RegisterSet64 getRegisterSet(int cpu);
|
||||||
void addRegisterSet(const RegisterSet64&);
|
void addRegisterSet(const RegisterSet64&);
|
||||||
inline int getNumCpus(void) const { return nrCpus; }
|
inline int getNumCpus(void) const { return nrCpus; }
|
||||||
|
RegisterContent64& operator=(const RegisterContent64&) = default;
|
||||||
|
|
||||||
RegisterSet64 regSets[MAX_CPUS];
|
RegisterSet64 regSets[MAX_CPUS];
|
||||||
private:
|
private:
|
||||||
@@ -64,6 +65,7 @@ public:
|
|||||||
RegisterSet32 getRegisterSet(int cpu);
|
RegisterSet32 getRegisterSet(int cpu);
|
||||||
void addRegisterSet(const RegisterSet32&);
|
void addRegisterSet(const RegisterSet32&);
|
||||||
inline int getNumCpus(void) const { return nrCpus; }
|
inline int getNumCpus(void) const { return nrCpus; }
|
||||||
|
RegisterContent32& operator=(const RegisterContent32&) = default;
|
||||||
|
|
||||||
RegisterSet32 regSets[MAX_CPUS];
|
RegisterSet32 regSets[MAX_CPUS];
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ static void count_users(void)
|
|||||||
proc_sum.users = 0;
|
proc_sum.users = 0;
|
||||||
setutent();
|
setutent();
|
||||||
while ((temp = getutent())) {
|
while ((temp = getutent())) {
|
||||||
if ((temp->ut_type == USER_PROCESS) && (temp->ut_name))
|
if (temp->ut_type == USER_PROCESS)
|
||||||
proc_sum.users++;
|
proc_sum.users++;
|
||||||
}
|
}
|
||||||
endutent();
|
endutent();
|
||||||
@@ -859,8 +859,6 @@ static void read_tasks(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((entry = readdir(proc_dir))) {
|
while ((entry = readdir(proc_dir))) {
|
||||||
if (!entry->d_name)
|
|
||||||
break;
|
|
||||||
if (!isdigit(entry->d_name[0]) || !atoi(entry->d_name))
|
if (!isdigit(entry->d_name[0]) || !atoi(entry->d_name))
|
||||||
continue;
|
continue;
|
||||||
memset(&task, 0, sizeof(struct task_t));
|
memset(&task, 0, sizeof(struct task_t));
|
||||||
|
|||||||
@@ -9,16 +9,22 @@
|
|||||||
\fBpvattest [OPTION?] create [OPTIONS] \fP- create an attestation measurement request
|
\fBpvattest [OPTION?] create [OPTIONS] \fP- create an attestation measurement request
|
||||||
\fB
|
\fB
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Prepare attestation measurement requests for an IBM Secure Execution guest. Only prepare attestation requests in a trusted environment, such as your workstation. The 'pvattest create' command creates a randomly generated key to protect the attestation request. This key is only valid for this specific request.In order to avoid compromising the attestation, do not publish the protection key and delete it after verification. Every 'create' command generates a new, random protection key.
|
Prepare attestation measurement requests for an IBM Secure Execution guest.
|
||||||
|
Only prepare attestation requests in a trusted environment, such as your workstation.
|
||||||
|
The 'pvattest create' command creates a randomly generated key to protect the attestation request.
|
||||||
|
This key is only valid for this specific request. In order to avoid compromising the attestation,
|
||||||
|
do not publish the protection key and delete it after verification.
|
||||||
|
Every 'create' command generates a new, random protection key.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB-h\fP, \fB--help\fP
|
\fB-h\fP, \fB--help\fP
|
||||||
Show help options
|
Prints usage information, then exits.
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB-k\fP, \fB--host-key-document\fP=\fBFILE\fP
|
\fB-k\fP, \fB--host-key-document\fP=\fBFILE\fP
|
||||||
Specify one or more host key documents.
|
Specify one or more host key documents. At least one is required.
|
||||||
|
Specify this option multiple times to enable the image to run on more than one host.
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB-C\fP, \fB--cert\fP=\fBFILE\fP
|
\fB-C\fP, \fB--cert\fP=\fBFILE\fP
|
||||||
@@ -26,11 +32,14 @@ Specifies the certificate that is used to establish a chain of trust for the v
|
|||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB--crl\fP=\fBFILE\fP
|
\fB--crl\fP=\fBFILE\fP
|
||||||
Specify \fBFILE\fP to be a certificate revocation list (optional).
|
Specifies the revocation list that is used to check whether a certificate of the chain of trust is
|
||||||
|
revoked. Specify this option multiple times to use multiple CRLs (optional).
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB--root-ca\fP=\fBFILE\fP
|
\fB--root-ca\fP=\fBFILE\fP
|
||||||
Use \fBFILE\fP as the trusted root CA instead the root CAs that are installed on the system (optional).
|
Specifies the root CA certificate for the verification. If omitted,
|
||||||
|
the system wide root CAs installed on the system are used. Use
|
||||||
|
this only if you trust the specified certificate. Optional.
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB-o\fP, \fB--output\fP=\fBFILE\fP
|
\fB-o\fP, \fB--output\fP=\fBFILE\fP
|
||||||
@@ -42,15 +51,16 @@ Save the protection key as GCM-AES256 key in \fBFILE\fP Do not publish this key,
|
|||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB--no-verify\fP
|
\fB--no-verify\fP
|
||||||
Disable the host-key-document verification. Does not require the host-key documents to be valid. For testing purposes, do not use for a production image. (Optional)
|
Disable the host-key document verification. Does not require the host-key documents to be valid. Do
|
||||||
|
not use for a production request unless you verified the host-key document before (optional).
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB--offline\fP
|
\fB--offline\fP
|
||||||
Don't download CRLs (optional).
|
Specifies offline mode, in which no attempt is made to download CRLs. (optional).
|
||||||
.TP
|
.TP
|
||||||
.B
|
.B
|
||||||
\fB-V\fP, \fB--verbose\fP
|
\fB-V\fP, \fB--verbose\fP
|
||||||
Provide more detailed output (optional)
|
Provide more detailed output (optional).
|
||||||
.SH EXAMPLE
|
.SH EXAMPLE
|
||||||
Create an attestation request with the protection key 'arp.key', write the request to 'arcb.bin', and verify the host-key document using the CA-signed key 'DigiCertCA.crt' and the intermediate key 'IbmSigningKey.crt'.
|
Create an attestation request with the protection key 'arp.key', write the request to 'arcb.bin', and verify the host-key document using the CA-signed key 'DigiCertCA.crt' and the intermediate key 'IbmSigningKey.crt'.
|
||||||
.PP
|
.PP
|
||||||
|
|||||||
@@ -9,7 +9,10 @@
|
|||||||
\fBpvattest [OPTION?] perform [OPTIONS] \fP- execute an attestation measurement request
|
\fBpvattest [OPTION?] perform [OPTIONS] \fP- execute an attestation measurement request
|
||||||
\fB
|
\fB
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Run a measurement of this system using '/dev/uv'. Works only if this device is available and the attestation Ultravisor facility is present. The input must be an attestation request created with 'pvattest create'. Output will contain the original request, the attestation measurement result, the configuration UID, and if requested in the request Additional Data.
|
Run a measurement of this system using '/dev/uv'. Works only if this device is
|
||||||
|
available and the attestation Ultravisor facility is present.
|
||||||
|
The input must be an attestation request created with 'pvattest create'.
|
||||||
|
Output will contain the original request and the response from the Ultravisor.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ BIN_PROGRAM = pvattest
|
|||||||
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/$(BIN_PROGRAM)"
|
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/$(BIN_PROGRAM)"
|
||||||
|
|
||||||
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||||
ROOT_DIR = $(rootdir)
|
PVATTESTDIR := $(rootdir)/pvattest
|
||||||
PVATTESTDIR := $(ROOT_DIR)/pvattest
|
INCLUDE_PATHS = "$(SRC_DIR)" "$(rootdir)/include"
|
||||||
INCLUDE_PATHS = "$(SRC_DIR)" "$(ROOT_DIR)/include"
|
|
||||||
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
|
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
|
||||||
|
|
||||||
LIBPV_DIR = $(ROOT_DIR)/libpv
|
LIBPV_DIR = $(rootdir)/libpv
|
||||||
LIBPV = $(LIBPV_DIR)/libpv.a
|
LIBPV = $(LIBPV_DIR)/libpv.a
|
||||||
|
|
||||||
WARNINGS := -Wall -Wextra -Wshadow \
|
WARNINGS := -Wall -Wextra -Wshadow \
|
||||||
@@ -73,7 +72,7 @@ endif
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: $(BUILD_TARGETS) .check-dep-$(BIN_PROGRAM)
|
all: $(BUILD_TARGETS)
|
||||||
|
|
||||||
install: $(INSTALL_TARGETS)
|
install: $(INSTALL_TARGETS)
|
||||||
|
|
||||||
@@ -97,7 +96,7 @@ $($(BIN_PROGRAM)_OBJS): .check-dep-$(BIN_PROGRAM)
|
|||||||
.detect-openssl.dep.c:
|
.detect-openssl.dep.c:
|
||||||
echo "#include <openssl/evp.h>" > $@
|
echo "#include <openssl/evp.h>" > $@
|
||||||
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
|
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
|
||||||
echo " #error openssl version 1.1.0 is required" >> $@
|
echo " #error openssl version 1.1.1 is required" >> $@
|
||||||
echo "#endif" >> $@
|
echo "#endif" >> $@
|
||||||
echo "static void __attribute__((unused)) test(void) {" >> $@
|
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||||
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||||
@@ -112,8 +111,8 @@ $($(BIN_PROGRAM)_OBJS): .check-dep-$(BIN_PROGRAM)
|
|||||||
"HAVE_GLIB2=0")
|
"HAVE_GLIB2=0")
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"$(BIN_PROGRAM)", \
|
"$(BIN_PROGRAM)", \
|
||||||
"openssl/evp.h", \
|
$^, \
|
||||||
"openssl-devel / libssl-dev version >= 1.1.0", \
|
"openssl-devel / libssl-dev version >= 1.1.1", \
|
||||||
"HAVE_OPENSSL=0", \
|
"HAVE_OPENSSL=0", \
|
||||||
"-I.")
|
"-I.")
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
|
|||||||
+4
-4
@@ -171,9 +171,9 @@ int arcb_v1_add_key_slot(arcb_v1_t *arcb, EVP_PKEY *evp_host, GError **error)
|
|||||||
g_assert(g_bytes_get_size(phkh) == sizeof(key_slot->phkh));
|
g_assert(g_bytes_get_size(phkh) == sizeof(key_slot->phkh));
|
||||||
|
|
||||||
key_slot = g_malloc0(sizeof(*key_slot));
|
key_slot = g_malloc0(sizeof(*key_slot));
|
||||||
pv_gbytes_memcpy(key_slot->warpk, sizeof(key_slot->warpk), warpk);
|
pv_gbytes_memcpy(key_slot->warpk, sizeof(key_slot->warpk), warpk, NULL);
|
||||||
pv_gbytes_memcpy(key_slot->kst, sizeof(key_slot->warpk), tag);
|
pv_gbytes_memcpy(key_slot->kst, sizeof(key_slot->warpk), tag, NULL);
|
||||||
pv_gbytes_memcpy(key_slot->phkh, sizeof(key_slot->warpk), phkh);
|
pv_gbytes_memcpy(key_slot->phkh, sizeof(key_slot->warpk), phkh, NULL);
|
||||||
|
|
||||||
arcb->host_key_slots = g_slist_prepend(arcb->host_key_slots, g_steal_pointer(&key_slot));
|
arcb->host_key_slots = g_slist_prepend(arcb->host_key_slots, g_steal_pointer(&key_slot));
|
||||||
return 0;
|
return 0;
|
||||||
@@ -246,7 +246,7 @@ GBytes *arcb_v1_serialize(const arcb_v1_t *arcb, GError **error)
|
|||||||
/* copy plain data to contiguous memory */
|
/* copy plain data to contiguous memory */
|
||||||
hdr.arl = GUINT32_TO_BE((uint32_t)att_req_len);
|
hdr.arl = GUINT32_TO_BE((uint32_t)att_req_len);
|
||||||
|
|
||||||
pv_gbytes_memcpy(hdr.iv, ARCB_V1_IV_SIZE, arcb->iv);
|
pv_gbytes_memcpy(hdr.iv, ARCB_V1_IV_SIZE, arcb->iv, NULL);
|
||||||
hdr.nks = (uint8_t)nks;
|
hdr.nks = (uint8_t)nks;
|
||||||
hdr.sea = GUINT32_TO_BE((uint32_t)sea);
|
hdr.sea = GUINT32_TO_BE((uint32_t)sea);
|
||||||
ecdh_cpk = pv_evp_pkey_to_ecdh_pub_key(arcb->evp_cust_pub_key, error);
|
ecdh_cpk = pv_evp_pkey_to_ecdh_pub_key(arcb->evp_cust_pub_key, error);
|
||||||
|
|||||||
+6
-6
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
#include "libpv/crypto.h"
|
#include "libpv/crypto.h"
|
||||||
|
#include "libpv/macros.h"
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
@@ -28,18 +29,17 @@
|
|||||||
#define ARCB_V1_IV_SIZE 12
|
#define ARCB_V1_IV_SIZE 12
|
||||||
#define ARCB_V1_PHKH_SIZE 32
|
#define ARCB_V1_PHKH_SIZE 32
|
||||||
|
|
||||||
#define BIT(bit) ((uint64_t)1 << (63 - (bit)))
|
|
||||||
/* Optional nonce in ARCB */
|
/* Optional nonce in ARCB */
|
||||||
#define ARCB_V1_PAF_NONCE BIT(1)
|
#define ARCB_V1_PAF_NONCE PV_MSB(1)
|
||||||
/* Public host key hash used to unseal SE header added to additional data to be measured */
|
/* Public host key hash used to unseal SE header added to additional data to be measured */
|
||||||
#define ARCB_V1_PAF_AAD_PHKH_HEADER BIT(2)
|
#define ARCB_V1_PAF_AAD_PHKH_HEADER PV_MSB(2)
|
||||||
/* Public host key hash used to unseal this attestation added to additional data to be measured */
|
/* Public host key hash used to unseal this attestation added to additional data to be measured */
|
||||||
#define ARCB_V1_PAF_AAD_PHKH_ATTEST BIT(3)
|
#define ARCB_V1_PAF_AAD_PHKH_ATTEST PV_MSB(3)
|
||||||
/* Temporary backup-host-key use allowed */
|
/* Temporary backup-host-key use allowed */
|
||||||
#define ARCB_V1_PAF_TMP_BACKUP_ALLOWED BIT(62)
|
#define ARCB_V1_PAF_TMP_BACKUP_ALLOWED PV_MSB(62)
|
||||||
|
|
||||||
/* Global not-host-specific key allowed */
|
/* Global not-host-specific key allowed */
|
||||||
#define ARCB_V1_PAF_GLOBAL_NHS_KEY_ALLOWED BIT(63)
|
#define ARCB_V1_PAF_GLOBAL_NHS_KEY_ALLOWED PV_MSB(63)
|
||||||
|
|
||||||
#define ARCB_V1_PAF_ALL \
|
#define ARCB_V1_PAF_ALL \
|
||||||
(ARCB_V1_PAF_NONCE | ARCB_V1_PAF_AAD_PHKH_HEADER | ARCB_V1_PAF_AAD_PHKH_ATTEST | \
|
(ARCB_V1_PAF_NONCE | ARCB_V1_PAF_AAD_PHKH_HEADER | ARCB_V1_PAF_AAD_PHKH_ATTEST | \
|
||||||
|
|||||||
+61
-65
@@ -156,76 +156,75 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
|
|||||||
|
|
||||||
/************************* SHARED OPTIONS *************************************/
|
/************************* SHARED OPTIONS *************************************/
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
#define _entry_host_key_document(__arg_data, __indent) \
|
#define _entry_host_key_document(__arg_data, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "host-key-document", .short_name = 'k', .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "host-key-document", .short_name = 'k', .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||||
.description = "Specify one or more host key documents.\n", \
|
.description = \
|
||||||
.arg_description = "FILE", \
|
"FILE specifies a host-key document. At least one is required.\n" __indent \
|
||||||
|
"Specify this option multiple times to enable the request for\n" __indent \
|
||||||
|
"more than one host.\n", \
|
||||||
|
.arg_description = "FILE", \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
#define _entry_certs(__arg_data, __indent) \
|
#define _entry_certs(__arg_data, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "cert", .short_name = 'C', .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "cert", .short_name = 'C', .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||||
.description = \
|
.description = "FILE contains a certificate that is used to\n" __indent \
|
||||||
"Specifies the certificate that is used to establish a chain\n" __indent \
|
"establish a chain of trust for the verification\n" __indent \
|
||||||
"of trust for the verification of the host-key documents. Specify\n" __indent \
|
"of the host-key documents. The IBM Z signing\n" __indent \
|
||||||
"this option twice to specify the IBM Z signing key and the\n" __indent \
|
"key and intermediate CA certificate (signed\n" __indent \
|
||||||
"intermediate CA certificate (signed by the root CA). Required.\n" __indent \
|
"by the root CA) are required.\n", \
|
||||||
"Ignored when --no-verify is specified.\n", \
|
.arg_description = "FILE", \
|
||||||
.arg_description = "FILE", \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
#define _entry_crls(__arg_data, __indent) \
|
#define _entry_crls(__arg_data, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "crl", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "crl", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||||
.description = "Specify FILE to be a certificate revocation list\n" __indent \
|
.description = "FILE contains a certificate revocation list (optional).\n", \
|
||||||
"(optional).", \
|
.arg_description = "FILE", \
|
||||||
.arg_description = "FILE", \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
#define _entry_root_ca(__arg_data, __indent) \
|
#define _entry_root_ca(__arg_data, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "root-ca", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "root-ca", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||||
.description = "Use FILE as the trusted root CA instead the\n" __indent \
|
.description = "Use FILE as the trusted root CA instead the\n" __indent \
|
||||||
"root CAs that are installed on the system (optional).", \
|
"root CAs that are installed on the system (optional).\n", \
|
||||||
.arg_description = "FILE", \
|
.arg_description = "FILE", \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
#define _entry_guest_hdr(__arg_data, __indent) \
|
#define _entry_guest_hdr(__arg_data, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "hdr", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "hdr", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||||
.description = \
|
.description = "FILE specifies the header of the guest image.\n" __indent \
|
||||||
"Specify the header of the guest image. Exactly one is required.\n", \
|
"Exactly one is required.\n", \
|
||||||
.arg_description = "FILE", \
|
.arg_description = "FILE", \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
#define _entry_input(__arg_data, __additional_text, __indent) \
|
#define _entry_input(__arg_data, __additional_text, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "input", .short_name = 'i', .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "input", .short_name = 'i', .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||||
.description = "FILE specifies the " __additional_text "\n" __indent \
|
.description = "FILE specifies the " __additional_text " as input.\n", \
|
||||||
" as input.\n", \
|
.arg_description = "FILE", \
|
||||||
.arg_description = "FILE", \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
#define _entry_output(__arg_data, __additional_text, __indent) \
|
#define _entry_output(__arg_data, __additional_text, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "output", .short_name = 'o', .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "output", .short_name = 'o', .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||||
.description = "FILE specifies the output for the\n" __indent __additional_text \
|
.description = "FILE specifies the output for the " __additional_text "\n", \
|
||||||
".\n", \
|
.arg_description = "FILE", \
|
||||||
.arg_description = "FILE", \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE REQUIRED */
|
/* NOTE REQUIRED */
|
||||||
@@ -254,7 +253,7 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
|
|||||||
{ \
|
{ \
|
||||||
.long_name = "x-phkh-img", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "x-phkh-img", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||||
.description = "add the public host key hash of the\n" __indent \
|
.description = "Add the public host key hash of the\n" __indent \
|
||||||
"image header used to decrypt\n" __indent \
|
"image header used to decrypt\n" __indent \
|
||||||
"the secure guest to the measurement. (optional)\n" \
|
"the secure guest to the measurement. (optional)\n" \
|
||||||
}
|
}
|
||||||
@@ -263,34 +262,31 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
|
|||||||
{ \
|
{ \
|
||||||
.long_name = "x-phkh-att", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "x-phkh-att", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||||
.description = "add the public host key hash of the\n" __indent \
|
.description = "Add the public host key hash of the\n" __indent \
|
||||||
"attestation header used to decrypt\n" __indent \
|
"attestation header used to decrypt\n" __indent \
|
||||||
"the attestation request to the measurement. (optional)\n" \
|
"the attestation request to the measurement. (optional)\n" \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _entry_no_verify(__arg_data, __indent) \
|
#define _entry_no_verify(__arg_data, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "no-verify", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
.long_name = "no-verify", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||||
.description = \
|
.description = "Disable the host-key document verification.\n" __indent \
|
||||||
"Disable the host-key-document verification.\n" __indent \
|
"(optional)\n", \
|
||||||
"Does not require the host-key documents to be valid.\n" __indent \
|
|
||||||
"For testing purposes, do not use for a production image.\n" __indent \
|
|
||||||
"(optional)\n", \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _entry_offline_maps_to_online(__arg_data, __indent) \
|
#define _entry_offline_maps_to_online(__arg_data, __indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "offline", .short_name = 0, .flags = G_OPTION_FLAG_REVERSE, \
|
.long_name = "offline", .short_name = 0, .flags = G_OPTION_FLAG_REVERSE, \
|
||||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||||
.description = "Don't download CRLs (optional).\n", \
|
.description = "Don't download CRLs. (optional)\n", \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _entry_verbose(__indent) \
|
#define _entry_verbose(__indent) \
|
||||||
{ \
|
{ \
|
||||||
.long_name = "verbose", .short_name = 'V', .flags = G_OPTION_FLAG_NO_ARG, \
|
.long_name = "verbose", .short_name = 'V', .flags = G_OPTION_FLAG_NO_ARG, \
|
||||||
.arg = G_OPTION_ARG_CALLBACK, .arg_data = &increase_log_lvl, \
|
.arg = G_OPTION_ARG_CALLBACK, .arg_data = &increase_log_lvl, \
|
||||||
.description = "Provide more detailed output (optional)\n", \
|
.description = "Provide more detailed output. (optional)\n", \
|
||||||
.arg_description = NULL, \
|
.arg_description = NULL, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ void att_add_uid(att_meas_ctx_t *meas_ctx, GBytes *config_uid)
|
|||||||
pv_wrapped_g_assert(config_uid);
|
pv_wrapped_g_assert(config_uid);
|
||||||
|
|
||||||
g_assert(g_bytes_get_size(config_uid) == ATT_CONFIG_UID_SIZE);
|
g_assert(g_bytes_get_size(config_uid) == ATT_CONFIG_UID_SIZE);
|
||||||
pv_gbytes_memcpy(meas_ctx->config_uid, ATT_CONFIG_UID_SIZE, config_uid);
|
pv_gbytes_memcpy(meas_ctx->config_uid, ATT_CONFIG_UID_SIZE, config_uid, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean att_verify_measurement(const GBytes *calculated_measurement,
|
gboolean att_verify_measurement(const GBytes *calculated_measurement,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
/* Must be included before any other header */
|
/* Must be included before any other header */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <glib/gi18n-lib.h>
|
#include <glib/gi18n.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "libpv/glib-helper.h"
|
#include "libpv/glib-helper.h"
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ exchange_format_ctx_t *exchange_ctx_from_file(const char *filename, GError **err
|
|||||||
}
|
}
|
||||||
ctx->req_meas_size = GUINT32_FROM_BE(hdr_v1->measurement.size);
|
ctx->req_meas_size = GUINT32_FROM_BE(hdr_v1->measurement.size);
|
||||||
ctx->req_add_size = GUINT32_FROM_BE(hdr_v1->additional_data.size);
|
ctx->req_add_size = GUINT32_FROM_BE(hdr_v1->additional_data.size);
|
||||||
ctx->version = GUINT32_TO_BE(hdr->version);
|
ctx->version = GUINT32_FROM_BE(hdr->version);
|
||||||
|
|
||||||
return g_steal_pointer(&ctx);
|
return g_steal_pointer(&ctx);
|
||||||
}
|
}
|
||||||
@@ -455,8 +455,8 @@ static void print_entry(const char *name, GBytes *data, const gboolean print_dat
|
|||||||
fprintf(stream, _("%s (%#lx bytes)"), name, g_bytes_get_size(data));
|
fprintf(stream, _("%s (%#lx bytes)"), name, g_bytes_get_size(data));
|
||||||
if (print_data) {
|
if (print_data) {
|
||||||
fprintf(stream, ":\n");
|
fprintf(stream, ":\n");
|
||||||
printf_hexdump(g_bytes_get_data(data, NULL), g_bytes_get_size(data), 16, " ",
|
pvattest_hexdump(g_bytes_get_data(data, NULL), g_bytes_get_size(data), 16, " ",
|
||||||
stream);
|
stream);
|
||||||
}
|
}
|
||||||
fprintf(stream, "\n");
|
fprintf(stream, "\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-10
@@ -131,26 +131,35 @@ void pvattest_log_plain_logger(const char *log_domain G_GNUC_UNUSED, GLogLevelFl
|
|||||||
_log_logger(level, message, log_level, FALSE, "");
|
_log_logger(level, message, log_level, FALSE, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void hexdump(const void *data, size_t size, size_t len, const char *prefix, GLogLevelFlags log_lvl)
|
void pvattest_log_bytes(const void *data, size_t size, size_t width, const char *prefix,
|
||||||
|
gboolean beautify, GLogLevelFlags log_lvl)
|
||||||
{
|
{
|
||||||
const uint8_t *data_b = data;
|
const uint8_t *data_b = data;
|
||||||
|
|
||||||
pv_wrapped_g_assert(data);
|
pv_wrapped_g_assert(data);
|
||||||
|
|
||||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "%s0x0000 ", prefix);
|
if (beautify)
|
||||||
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "%s0x0000 ", prefix);
|
||||||
|
else
|
||||||
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "%s", prefix);
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "%02x", data_b[i]);
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "%02x", data_b[i]);
|
||||||
if (i % 2 == 1)
|
if (i % 2 == 1 && beautify)
|
||||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, " ");
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, " ");
|
||||||
if (i == size - 1)
|
if (i == size - 1)
|
||||||
break;
|
break;
|
||||||
if (i % len == len - 1)
|
if (i % width == width - 1) {
|
||||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "\n%s0x%04lx ", prefix, i + 1);
|
if (beautify)
|
||||||
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "\n%s0x%04lx ", prefix,
|
||||||
|
i + 1);
|
||||||
|
else
|
||||||
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "\n%s", prefix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "\n");
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void printf_hexdump(const void *data, size_t size, size_t len, const char *prefix, FILE *stream)
|
void pvattest_hexdump(const void *data, size_t size, size_t width, const char *prefix, FILE *stream)
|
||||||
{
|
{
|
||||||
const uint8_t *data_b = data;
|
const uint8_t *data_b = data;
|
||||||
|
|
||||||
@@ -164,7 +173,7 @@ void printf_hexdump(const void *data, size_t size, size_t len, const char *prefi
|
|||||||
fprintf(stream, " ");
|
fprintf(stream, " ");
|
||||||
if (i == size - 1)
|
if (i == size - 1)
|
||||||
break;
|
break;
|
||||||
if (i % len == len - 1)
|
if (i % width == width - 1)
|
||||||
fprintf(stream, "\n%s0x%04lx ", prefix, i + 1);
|
fprintf(stream, "\n%s0x%04lx ", prefix, i + 1);
|
||||||
}
|
}
|
||||||
fprintf(stream, "\n");
|
fprintf(stream, "\n");
|
||||||
|
|||||||
+15
-15
@@ -23,7 +23,7 @@
|
|||||||
#define PVATTEST_LOG_LVL_DEFAULT PVATTEST_LOG_LVL_WARNING
|
#define PVATTEST_LOG_LVL_DEFAULT PVATTEST_LOG_LVL_WARNING
|
||||||
#define PVATTEST_LOG_LVL_MAX PVATTEST_LOG_LVL_DEBUG
|
#define PVATTEST_LOG_LVL_MAX PVATTEST_LOG_LVL_DEBUG
|
||||||
|
|
||||||
#define PVATTEST_HEXDUMP_LOG_DOMAIN "pvattest_hdump"
|
#define PVATTEST_BYTES_LOG_DOMAIN "pvattest_bytes"
|
||||||
|
|
||||||
void pvattest_log_increase_log_lvl(int *log_lvl);
|
void pvattest_log_increase_log_lvl(int *log_lvl);
|
||||||
void pvattest_log_error(const char *format, ...);
|
void pvattest_log_error(const char *format, ...);
|
||||||
@@ -45,22 +45,22 @@ void pvattest_log_default_logger(const char *log_domain, GLogLevelFlags level, c
|
|||||||
*/
|
*/
|
||||||
void pvattest_log_plain_logger(const char *log_domain, GLogLevelFlags level, const char *message,
|
void pvattest_log_plain_logger(const char *log_domain, GLogLevelFlags level, const char *message,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
#define dhexdump(v, s) \
|
#define dhexdump(v, s) \
|
||||||
{ \
|
|
||||||
pvattest_log_debug("%s (%li byte):", #v, s); \
|
|
||||||
hexdump(v, s, 16L, " ", PVATTEST_LOG_LVL_DEBUG); \
|
|
||||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
|
||||||
}
|
|
||||||
#define gbhexdump(v) \
|
|
||||||
{ \
|
{ \
|
||||||
pvattest_log_debug("%s:(%li byte):", #v, g_bytes_get_size(v)); \
|
pvattest_log_debug("%s (%li byte):", #v, s); \
|
||||||
hexdump(g_bytes_get_data(v, NULL), g_bytes_get_size(v), 16L, " ", \
|
pvattest_log_bytes(v, s, 16L, " ", TRUE, PVATTEST_LOG_LVL_DEBUG); \
|
||||||
PVATTEST_LOG_LVL_DEBUG); \
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
||||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
|
||||||
}
|
}
|
||||||
void hexdump(const void *data, size_t size, size_t len, const char *prefix, GLogLevelFlags log_lvl)
|
#define gbhexdump(v) \
|
||||||
PV_NONNULL(1);
|
{ \
|
||||||
void printf_hexdump(const void *data, size_t size, size_t len, const char *prefix, FILE *stream)
|
pvattest_log_debug("%s:(%li byte):", #v, g_bytes_get_size(v)); \
|
||||||
|
pvattest_log_bytes(g_bytes_get_data(v, NULL), g_bytes_get_size(v), 16L, " ", \
|
||||||
|
TRUE, PVATTEST_LOG_LVL_DEBUG); \
|
||||||
|
g_log(PVATTEST_BYTES_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
||||||
|
}
|
||||||
|
void pvattest_log_bytes(const void *data, size_t size, size_t width, const char *prefix,
|
||||||
|
gboolean beautify, GLogLevelFlags log_lvl) PV_NONNULL(1);
|
||||||
|
void pvattest_hexdump(const void *data, size_t size, size_t width, const char *prefix, FILE *stream)
|
||||||
PV_NONNULL(1, 5);
|
PV_NONNULL(1, 5);
|
||||||
void pvattest_log_GError(const char *info, GError *error) PV_NONNULL(1);
|
void pvattest_log_GError(const char *info, GError *error) PV_NONNULL(1);
|
||||||
|
|
||||||
|
|||||||
+11
-2
@@ -322,8 +322,17 @@ static int do_verify(pvattest_verify_config_t *verify_config)
|
|||||||
return PVATTEST_EXIT_MEASURE_NOT_VERIFIED;
|
return PVATTEST_EXIT_MEASURE_NOT_VERIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
pvattest_log_debug(_("Measurement verified."));
|
pvattest_log_info(_("Attestation measurement verified"));
|
||||||
|
pvattest_log_info(_("Config UID:"));
|
||||||
|
pvattest_log_bytes(g_bytes_get_data(config_uid, NULL), g_bytes_get_size(config_uid), 16L,
|
||||||
|
"", FALSE, PVATTEST_LOG_LVL_INFO);
|
||||||
|
|
||||||
|
if (additional_data) {
|
||||||
|
pvattest_log_info(_("\nAdditional Data:"));
|
||||||
|
pvattest_log_bytes(g_bytes_get_data(additional_data, NULL),
|
||||||
|
g_bytes_get_size(additional_data), 16L, "", FALSE,
|
||||||
|
PVATTEST_LOG_LVL_INFO);
|
||||||
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
@@ -355,7 +364,7 @@ int main(int argc, char *argv[])
|
|||||||
* message)to filter messages based on the log level specified by the
|
* message)to filter messages based on the log level specified by the
|
||||||
* user.
|
* user.
|
||||||
*/
|
*/
|
||||||
g_log_set_handler(PVATTEST_HEXDUMP_LOG_DOMAIN,
|
g_log_set_handler(PVATTEST_BYTES_LOG_DOMAIN,
|
||||||
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
|
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
|
||||||
&pvattest_log_plain_logger, &appl_log_lvl);
|
&pvattest_log_plain_logger, &appl_log_lvl);
|
||||||
|
|
||||||
|
|||||||
+19
-14
@@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
/* Must be included before any other header */
|
/* Must be included before any other header */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
#ifdef PVATTEST_COMPILE_PERFORM
|
#ifdef PVATTEST_COMPILE_PERFORM
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -42,26 +43,29 @@ uvio_attest_t *build_attestation_v1_ioctl(GBytes *serialized_arcb, GBytes *user_
|
|||||||
uvio_attest = g_malloc0(sizeof(*uvio_attest));
|
uvio_attest = g_malloc0(sizeof(*uvio_attest));
|
||||||
uvio_attest->arcb_addr = PTR_TO_U64(g_steal_pointer(&arcb));
|
uvio_attest->arcb_addr = PTR_TO_U64(g_steal_pointer(&arcb));
|
||||||
g_assert_cmpuint(arcb_size, <, UINT32_MAX);
|
g_assert_cmpuint(arcb_size, <, UINT32_MAX);
|
||||||
uvio_attest->arcb_len = GUINT32_TO_BE((uint32_t)arcb_size);
|
uvio_attest->arcb_len = (uint32_t)arcb_size;
|
||||||
/* transferred the local ownership of the arcb from this function to uvio_attest; nullify pointer */
|
/* transferred the local ownership of the arcb from this function to uvio_attest; nullify pointer */
|
||||||
g_steal_pointer(&serialized_arcb);
|
g_steal_pointer(&serialized_arcb);
|
||||||
|
|
||||||
if (user_data) {
|
if (user_data) {
|
||||||
if (g_bytes_get_size(user_data) > sizeof(uvio_attest->user_data)) {
|
size_t copied_data_size;
|
||||||
|
|
||||||
|
if (pv_gbytes_memcpy(uvio_attest->user_data, sizeof(uvio_attest->user_data),
|
||||||
|
user_data, &copied_data_size) == NULL) {
|
||||||
g_set_error(error, ATT_ERROR, ATT_ERR_INVALID_USER_DATA,
|
g_set_error(error, ATT_ERROR, ATT_ERR_INVALID_USER_DATA,
|
||||||
_("User data larger than %li bytes"),
|
_("User data %li bytes is larger than %li bytes"),
|
||||||
sizeof(uvio_attest->user_data));
|
g_bytes_get_size(user_data), sizeof(uvio_attest->user_data));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
uvio_attest->user_data_len = GUINT16_TO_BE((uint16_t)g_bytes_get_size(user_data));
|
STATIC_ASSERT(sizeof(uvio_attest->user_data) <= UINT16_MAX);
|
||||||
pv_gbytes_memcpy(uvio_attest->user_data, uvio_attest->user_data_len, user_data);
|
uvio_attest->user_data_len = (uint16_t)copied_data_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uvio_attest->meas_len = GUINT32_TO_BE(measurement_size);
|
uvio_attest->meas_addr = PTR_TO_U64(g_malloc0(measurement_size));
|
||||||
uvio_attest->meas_addr = PTR_TO_U64(g_malloc0(uvio_attest->meas_len));
|
uvio_attest->meas_len = measurement_size;
|
||||||
|
|
||||||
uvio_attest->add_data_len = GUINT32_TO_BE(add_data_size);
|
uvio_attest->add_data_addr = PTR_TO_U64(g_malloc0(add_data_size));
|
||||||
uvio_attest->add_data_addr = PTR_TO_U64(g_malloc0(uvio_attest->add_data_len));
|
uvio_attest->add_data_len = add_data_size;
|
||||||
|
|
||||||
return g_steal_pointer(&uvio_attest);
|
return g_steal_pointer(&uvio_attest);
|
||||||
}
|
}
|
||||||
@@ -83,7 +87,7 @@ GBytes *uvio_get_measurement(const uvio_attest_t *attest)
|
|||||||
|
|
||||||
if (attest->meas_addr == (__u64)0)
|
if (attest->meas_addr == (__u64)0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return g_bytes_new(U64_TO_PTR(attest->meas_addr), GUINT32_FROM_BE(attest->meas_len));
|
return g_bytes_new(U64_TO_PTR(attest->meas_addr), attest->meas_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
GBytes *uvio_get_additional_data(const uvio_attest_t *attest)
|
GBytes *uvio_get_additional_data(const uvio_attest_t *attest)
|
||||||
@@ -92,8 +96,7 @@ GBytes *uvio_get_additional_data(const uvio_attest_t *attest)
|
|||||||
|
|
||||||
if (attest->add_data_addr == (__u64)0)
|
if (attest->add_data_addr == (__u64)0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return g_bytes_new(U64_TO_PTR(attest->add_data_addr),
|
return g_bytes_new(U64_TO_PTR(attest->add_data_addr), attest->add_data_len);
|
||||||
GUINT32_FROM_BE(attest->add_data_len));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GBytes *uvio_get_config_uid(const uvio_attest_t *attest)
|
GBytes *uvio_get_config_uid(const uvio_attest_t *attest)
|
||||||
@@ -127,7 +130,7 @@ uint16_t uvio_ioctl(const int uv_fd, const unsigned int cmd, const uint32_t flag
|
|||||||
g_set_error(error, UVIO_ERROR, UVIO_ERR_UV_NOT_OK,
|
g_set_error(error, UVIO_ERROR, UVIO_ERR_UV_NOT_OK,
|
||||||
_("Ultravisor call returned '%#x' (%s)"), uv_ioctl->uv_rc,
|
_("Ultravisor call returned '%#x' (%s)"), uv_ioctl->uv_rc,
|
||||||
uvio_uv_rc_to_str(uv_ioctl->uv_rc));
|
uvio_uv_rc_to_str(uv_ioctl->uv_rc));
|
||||||
return GUINT16_FROM_BE(uv_ioctl->uv_rc);
|
return uv_ioctl->uv_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t uvio_ioctl_attest(const int uv_fd, uvio_attest_t *attest, GError **error)
|
uint16_t uvio_ioctl_attest(const int uv_fd, uvio_attest_t *attest, GError **error)
|
||||||
@@ -156,6 +159,8 @@ int uvio_open(const char *uv_path, GError **error)
|
|||||||
const char *uvio_uv_rc_to_str(const int rc)
|
const char *uvio_uv_rc_to_str(const int rc)
|
||||||
{
|
{
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
|
case 0x02:
|
||||||
|
return _("Invalid UV command");
|
||||||
case 0x106:
|
case 0x106:
|
||||||
return _("Unsupported attestation request version");
|
return _("Unsupported attestation request version");
|
||||||
case 0x108:
|
case 0x108:
|
||||||
|
|||||||
Executable
+88
@@ -0,0 +1,88 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# pvattest-info - get additional information from an attestation measurement
|
||||||
|
#
|
||||||
|
# Sample:
|
||||||
|
# ./pvattest-info attestresp.bin
|
||||||
|
#
|
||||||
|
# Copyright IBM Corp. 2022
|
||||||
|
#
|
||||||
|
# s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
set -e
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<-EOF
|
||||||
|
Usage: $(basename "$0") FILE
|
||||||
|
|
||||||
|
Prints config UID and additional data if available.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_is_pvattest_binary() {
|
||||||
|
local input="$1"
|
||||||
|
local size
|
||||||
|
local version
|
||||||
|
|
||||||
|
size=$(wc -c <"$input")
|
||||||
|
if [ "$size" -lt 64 ]; then
|
||||||
|
echo "ERROR: Input file is too small." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
xxd -l 16 "${input}" | grep -q pvattest ||
|
||||||
|
{ echo "ERROR: ${input} does not contain a pvattest binary output." >&2 && exit 1; }
|
||||||
|
|
||||||
|
size=$(xxd -s 12 -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
|
||||||
|
if [ $((size)) -lt 64 ]; then
|
||||||
|
echo "ERROR: ${input} does not contain a pvattest binary output." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
version=$(xxd -s 8 -l 4 "$input")
|
||||||
|
echo "$version" | grep -q "0000 0100" ||
|
||||||
|
{ echo -n "WARNING: unknown hdr version " >&2 &&
|
||||||
|
echo "$version" | awk '{print "0x" $2 $3}'>&2 ; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function print_entry() {
|
||||||
|
local file_off="$1"
|
||||||
|
local text="$2"
|
||||||
|
local input="$3"
|
||||||
|
local size
|
||||||
|
local off
|
||||||
|
|
||||||
|
size=$(xxd -s $((file_off)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
|
||||||
|
off=$(xxd -s $((file_off + 4)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
|
||||||
|
|
||||||
|
if [[ $size != "0x00000000" ]] || [[ $off != "0x00000000" ]]; then
|
||||||
|
echo "${text}:"
|
||||||
|
xxd -s $((off)) -l $((size)) -p "${input}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function require_command() {
|
||||||
|
local cmd="$1"
|
||||||
|
|
||||||
|
command -v "$cmd" >/dev/null 2>&1 || { echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
require_command xxd
|
||||||
|
require_command awk
|
||||||
|
require_command wc
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "ERROR: Input not set. Use '$(basename "$0") [FILE]' to specify the Input file" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
input="$1"
|
||||||
|
|
||||||
|
[ -e "$input" ] || { echo "ERROR: File '$1' not found" >&2 && exit 1; }
|
||||||
|
check_is_pvattest_binary "$input"
|
||||||
|
|
||||||
|
print_entry 0x38 "Config UID" "$input"
|
||||||
|
print_entry 0x28 "Additional Data" "$input"
|
||||||
+106
-39
@@ -17,7 +17,8 @@ export LC_ALL
|
|||||||
readonly SCRIPTNAME="${0##*/}" # general name of this script
|
readonly SCRIPTNAME="${0##*/}" # general name of this script
|
||||||
#
|
#
|
||||||
readonly DATETIME="$(date +%Y-%m-%d-%H-%M-%S 2>/dev/null)"
|
readonly DATETIME="$(date +%Y-%m-%d-%H-%M-%S 2>/dev/null)"
|
||||||
readonly DOCKER=$(if type -t docker >/dev/null; then echo "YES"; else echo "NO"; fi)
|
readonly DOCKER=$(if type docker >/dev/null 2>&1; then echo "YES"; else echo "NO"; fi)
|
||||||
|
readonly DUMP2TAR_OK=$(if type dump2tar >/dev/null 2>&1; then echo "YES"; else echo "NO"; fi)
|
||||||
readonly HW="$(uname -i 2>/dev/null)"
|
readonly HW="$(uname -i 2>/dev/null)"
|
||||||
# retrieve and split kernel version
|
# retrieve and split kernel version
|
||||||
readonly KERNEL_BASE="$(uname -r 2>/dev/null)"
|
readonly KERNEL_BASE="$(uname -r 2>/dev/null)"
|
||||||
@@ -25,7 +26,9 @@ readonly KERNEL_VERSION=$(echo ${KERNEL_BASE} | cut -d'.' -f1 )
|
|||||||
readonly KERNEL_MAJOR_REVISION=$(echo ${KERNEL_BASE} | cut -d'.' -f2 )
|
readonly KERNEL_MAJOR_REVISION=$(echo ${KERNEL_BASE} | cut -d'.' -f2 )
|
||||||
readonly KERNEL_MINOR_REVISION=$(echo ${KERNEL_BASE} | cut -d'.' -f3 | sed 's/[^0-9].*//g')
|
readonly KERNEL_MINOR_REVISION=$(echo ${KERNEL_BASE} | cut -d'.' -f3 | sed 's/[^0-9].*//g')
|
||||||
readonly KERNEL_INFO=${KERNEL_VERSION}.${KERNEL_MAJOR_REVISION}.${KERNEL_MINOR_REVISION}
|
readonly KERNEL_INFO=${KERNEL_VERSION}.${KERNEL_MAJOR_REVISION}.${KERNEL_MINOR_REVISION}
|
||||||
readonly KVM=$(if type -t virsh >/dev/null; then echo "YES"; else echo "NO"; fi)
|
readonly KUBERNETES=$(if type kubectl >/dev/null 2>&1; then echo "YES"; else echo "NO"; fi)
|
||||||
|
readonly KUBERNETES_LOG_LINES=50
|
||||||
|
readonly KVM=$(if type virsh >/dev/null 2>&1; then echo "YES"; else echo "NO"; fi)
|
||||||
# The file to indicate that another instance of the script is already running
|
# The file to indicate that another instance of the script is already running
|
||||||
readonly LOCKFILE="/tmp/${SCRIPTNAME}.lock"
|
readonly LOCKFILE="/tmp/${SCRIPTNAME}.lock"
|
||||||
# check limits for logfiles like /var/log/messages
|
# check limits for logfiles like /var/log/messages
|
||||||
@@ -43,14 +46,20 @@ readonly PROCESSORVERSION="$(grep -E ".*processor 0:.*" /proc/cpuinfo | \
|
|||||||
sed 's/.*version[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g')"
|
sed 's/.*version[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g')"
|
||||||
if test "x${PROCESSORVERSION}" = "xFF" || test "x${PROCESSORVERSION}" = "xff"; then
|
if test "x${PROCESSORVERSION}" = "xFF" || test "x${PROCESSORVERSION}" = "xff"; then
|
||||||
RUNTIME_ENVIRONMENT=$(grep -E "VM00.*Control Program.*" /proc/sysinfo | \
|
RUNTIME_ENVIRONMENT=$(grep -E "VM00.*Control Program.*" /proc/sysinfo | \
|
||||||
sed 's/.*:[[:space:]]*\([[:graph:]]*\).*/\1/g')
|
sed 's/.*:[[:space:]]*\([[:graph:]]*\).*/\1/g')
|
||||||
else
|
else
|
||||||
RUNTIME_ENVIRONMENT="LPAR"
|
RUNTIME_ENVIRONMENT="LPAR"
|
||||||
fi
|
fi
|
||||||
readonly SYSTEMHOSTNAME="$(hostname -s 2>/dev/null)" # hostname of system being analysed
|
readonly SYSTEMHOSTNAME="$(hostname -s 2>/dev/null)" # hostname of system being analysed
|
||||||
readonly TERMINAL="$(tty 2>/dev/null)"
|
readonly TERMINAL="$(tty 2>/dev/null)"
|
||||||
# The processor version for the first processor and resulting vitrtualization RUNTIME
|
# timeout seconds TOS / kill timeout TOKS
|
||||||
readonly TOS=15 # timeout seconds for command execution
|
readonly TOS=15
|
||||||
|
readonly TOKS=30
|
||||||
|
readonly TIMEOUT=$(if type timeout >/dev/null 2>&1; then echo "YES"; else echo "NO"; fi)
|
||||||
|
readonly TIMEOUT_OK=$(if test "x${TIMEOUT}" = "xYES"; then
|
||||||
|
if test $(timeout -k ${TOKS} ${TOS} uname 2>/dev/null) = $(uname); then
|
||||||
|
echo "YES"; else echo "WRONG_VERSION"; fi
|
||||||
|
else echo "NO"; fi)
|
||||||
readonly ZDEV_CONF=$(lszdev --configured 2>/dev/null | wc -l)
|
readonly ZDEV_CONF=$(lszdev --configured 2>/dev/null | wc -l)
|
||||||
readonly ZDEV_OFF=$(lszdev --offline 2>/dev/null | wc -l)
|
readonly ZDEV_OFF=$(lszdev --offline 2>/dev/null | wc -l)
|
||||||
readonly ZDEV_ONL=$(lszdev --online 2>/dev/null | wc -l)
|
readonly ZDEV_ONL=$(lszdev --online 2>/dev/null | wc -l)
|
||||||
@@ -79,7 +88,7 @@ This script collects runtime, configuration and trace information on
|
|||||||
a Linux on IBM Z installation for debugging purposes.
|
a Linux on IBM Z installation for debugging purposes.
|
||||||
|
|
||||||
It also traces information about z/VM if the Linux runs under z/VM.
|
It also traces information about z/VM if the Linux runs under z/VM.
|
||||||
KVM or DOCKER data ist collected on a host serving this.
|
Virtualization platform data is collected on a host serving this.
|
||||||
|
|
||||||
Default location for data collection and final tar file is "/tmp/".
|
Default location for data collection and final tar file is "/tmp/".
|
||||||
The collected information is written to a TAR archive named
|
The collected information is written to a TAR archive named
|
||||||
@@ -96,7 +105,7 @@ Options:
|
|||||||
stores the temporary data and the final archive.
|
stores the temporary data and the final archive.
|
||||||
-h|--help print this help
|
-h|--help print this help
|
||||||
-v|--version print version information
|
-v|--version print version information
|
||||||
-c|--check online quick check (no data collection)
|
-c|--check online base system information (no data collection)
|
||||||
|
|
||||||
Please report bugs to: linux390@de.ibm.com
|
Please report bugs to: linux390@de.ibm.com
|
||||||
|
|
||||||
@@ -150,7 +159,7 @@ $(cat /proc/sysinfo | grep 'Name')
|
|||||||
Kernel version = ${KERNEL_INFO}
|
Kernel version = ${KERNEL_INFO}
|
||||||
OS version / distro = ${OS_NAME}
|
OS version / distro = ${OS_NAME}
|
||||||
KVM host = ${KVM}
|
KVM host = ${KVM}
|
||||||
DOCKER host = ${DOCKER}
|
container host Kubernetes: ${KUBERNETES} - docker: ${DOCKER}
|
||||||
|
|
||||||
Current user = $(whoami) (must be root for data collection)
|
Current user = $(whoami) (must be root for data collection)
|
||||||
Date and time = $(date)
|
Date and time = $(date)
|
||||||
@@ -162,6 +171,9 @@ Log file check =$(logfile_checker "/var/log*")
|
|||||||
Working directory = $(ls -d ${paramWORKDIR_BASE} 2>&1 && df -k ${paramWORKDIR_BASE})
|
Working directory = $(ls -d ${paramWORKDIR_BASE} 2>&1 && df -k ${paramWORKDIR_BASE})
|
||||||
$(ls -ltr ${paramWORKDIR_BASE}/DBGINFO*tgz 2>/dev/null | tail -2)
|
$(ls -ltr ${paramWORKDIR_BASE}/DBGINFO*tgz 2>/dev/null | tail -2)
|
||||||
$(ls ${LOCKFILE} 2>/dev/null && echo " Warning: dbginfo running since: $(cat ${LOCKFILE})")
|
$(ls ${LOCKFILE} 2>/dev/null && echo " Warning: dbginfo running since: $(cat ${LOCKFILE})")
|
||||||
|
Tool/command dependency check successful:
|
||||||
|
timeout = ${TIMEOUT_OK}
|
||||||
|
dump2tar = ${DUMP2TAR_OK}
|
||||||
|
|
||||||
This is a console output only - no data was saved using option -c !
|
This is a console output only - no data was saved using option -c !
|
||||||
|
|
||||||
@@ -213,7 +225,8 @@ done
|
|||||||
|
|
||||||
# finally verification to run as root
|
# finally verification to run as root
|
||||||
if test "$(/usr/bin/id -u 2>/dev/null)" -ne 0; then
|
if test "$(/usr/bin/id -u 2>/dev/null)" -ne 0; then
|
||||||
echo "${SCRIPTNAME}: Error: You must be user root to run \"${SCRIPTNAME}\"!"
|
echo "${SCRIPTNAME}: Error: You must be user root to run data collection \"${SCRIPTNAME}\"!"
|
||||||
|
echo "${SCRIPTNAME}: Hint: for base system information you may run \"${SCRIPTNAME} -c\""
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -249,6 +262,7 @@ readonly OUTPUT_FILE_ISW="${WORKPATH}installed_sw.out"
|
|||||||
readonly OUTPUT_FILE_TC="${WORKPATH}network.out"
|
readonly OUTPUT_FILE_TC="${WORKPATH}network.out"
|
||||||
readonly OUTPUT_FILE_VMCMD="${WORKPATH}zvm_runtime.out"
|
readonly OUTPUT_FILE_VMCMD="${WORKPATH}zvm_runtime.out"
|
||||||
# Base file names for different output files - no extension !
|
# Base file names for different output files - no extension !
|
||||||
|
readonly OUTPUT_FILE_KUBERNETES="${WORKPATH}kubernetes"
|
||||||
readonly OUTPUT_FILE_OSAOAT="${WORKPATH}network"
|
readonly OUTPUT_FILE_OSAOAT="${WORKPATH}network"
|
||||||
readonly OUTPUT_FILE_SYSFS="${WORKPATH}sysfs"
|
readonly OUTPUT_FILE_SYSFS="${WORKPATH}sysfs"
|
||||||
|
|
||||||
@@ -268,7 +282,7 @@ ALL_STEPS="\
|
|||||||
collect_bridge\
|
collect_bridge\
|
||||||
collect_ovs\
|
collect_ovs\
|
||||||
collect_kvm\
|
collect_kvm\
|
||||||
collect_docker\
|
collect_container\
|
||||||
collect_nvme\
|
collect_nvme\
|
||||||
collect_logfiles\
|
collect_logfiles\
|
||||||
post_processing\
|
post_processing\
|
||||||
@@ -329,14 +343,18 @@ fi
|
|||||||
########################################
|
########################################
|
||||||
|
|
||||||
LOGFILES="\
|
LOGFILES="\
|
||||||
|
/root/anaconda-ks.cfg\
|
||||||
|
/root/original-ks.cfg\
|
||||||
/run/containerd/events.log\
|
/run/containerd/events.log\
|
||||||
/run/docker/libcontainerd/containerd/events.log\
|
/run/docker/libcontainerd/containerd/events.log\
|
||||||
/run/udev/chreiplzfcpmp-[0-9][0-9][a-z][a-z][a-z][a-z]-*\
|
/run/udev/chreiplzfcpmp-[0-9][0-9][a-z][a-z][a-z][a-z]-*\
|
||||||
|
/var/log/anaconda\
|
||||||
/var/log/anaconda.*\
|
/var/log/anaconda.*\
|
||||||
/var/log/audit\
|
/var/log/audit\
|
||||||
/var/log/boot*\
|
/var/log/boot*\
|
||||||
/var/log/cron*\
|
/var/log/cron*\
|
||||||
/var/log/dmesg*\
|
/var/log/dmesg*\
|
||||||
|
/var/log/dnf.*\
|
||||||
/var/log/dracut.log*\
|
/var/log/dracut.log*\
|
||||||
/var/log/IBMtape.trace\
|
/var/log/IBMtape.trace\
|
||||||
/var/log/IBMtape.errorlog\
|
/var/log/IBMtape.errorlog\
|
||||||
@@ -346,9 +364,12 @@ LOGFILES="\
|
|||||||
/var/log/messages*\
|
/var/log/messages*\
|
||||||
/var/log/openvswitch/ovs-vswitchd.log\
|
/var/log/openvswitch/ovs-vswitchd.log\
|
||||||
/var/log/openvswitch/ovsdb-server.log\
|
/var/log/openvswitch/ovsdb-server.log\
|
||||||
|
/var/log/pbl.log\
|
||||||
/var/log/sa\
|
/var/log/sa\
|
||||||
/var/log/syslog*\
|
/var/log/syslog*\
|
||||||
/var/log/yum.log\
|
/var/log/yum.log\
|
||||||
|
/var/log/YaST2\
|
||||||
|
/var/log/zypp*\
|
||||||
"
|
"
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
@@ -368,6 +389,7 @@ CONFIGFILES="\
|
|||||||
/etc/crypttab\
|
/etc/crypttab\
|
||||||
/etc/default\
|
/etc/default\
|
||||||
/etc/depmod.d\
|
/etc/depmod.d\
|
||||||
|
/etc/dnf/dnf.conf\
|
||||||
/etc/docker\
|
/etc/docker\
|
||||||
/etc/dracut.conf.d\
|
/etc/dracut.conf.d\
|
||||||
/etc/exports\
|
/etc/exports\
|
||||||
@@ -450,7 +472,7 @@ CMDS="${CMDS}\
|
|||||||
:lszdev\
|
:lszdev\
|
||||||
:find /dev -print0 | sort -z | xargs -0 -n 10 ls -ld\
|
:find /dev -print0 | sort -z | xargs -0 -n 10 ls -ld\
|
||||||
:lspci -t\
|
:lspci -t\
|
||||||
:lspci -vv\
|
:lspci -vvv\
|
||||||
:lstape\
|
:lstape\
|
||||||
:smc_dbg\
|
:smc_dbg\
|
||||||
"
|
"
|
||||||
@@ -468,6 +490,7 @@ CMDS="${CMDS}\
|
|||||||
:dmsetup table --target multipath\
|
:dmsetup table --target multipath\
|
||||||
:dmsetup status\
|
:dmsetup status\
|
||||||
:multipathd -k'show config'\
|
:multipathd -k'show config'\
|
||||||
|
:multipathd -k'show config local'\
|
||||||
:multipathd -k'show maps'\
|
:multipathd -k'show maps'\
|
||||||
:multipathd -k'show topo'\
|
:multipathd -k'show topo'\
|
||||||
:multipathd -k'show paths'\
|
:multipathd -k'show paths'\
|
||||||
@@ -557,6 +580,18 @@ DOCKER_CMDS="docker version\
|
|||||||
:systemctl status docker.service\
|
:systemctl status docker.service\
|
||||||
"
|
"
|
||||||
|
|
||||||
|
########################################
|
||||||
|
KUBERNETES_CMDS="kubectl version\
|
||||||
|
:oc version # get also OCP version if installed\
|
||||||
|
:kubectl top pod\
|
||||||
|
:kubectl top node\
|
||||||
|
:kubectl describe pod -A\
|
||||||
|
:kubectl describe node -A\
|
||||||
|
:kubectl describe endpoints\
|
||||||
|
:ls -l /var/log/containers # list of logs is sufficent\
|
||||||
|
:kubectl cluster-info dump >>${OUTPUT_FILE_KUBERNETES}.dmp\
|
||||||
|
"
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
VM_CMDS="q userid\
|
VM_CMDS="q userid\
|
||||||
:q users\
|
:q users\
|
||||||
@@ -676,18 +711,18 @@ collect_vmcmdsout() {
|
|||||||
local vm_userid
|
local vm_userid
|
||||||
local module_loaded=1
|
local module_loaded=1
|
||||||
local ifs_orig="${IFS}"
|
local ifs_orig="${IFS}"
|
||||||
local cp_buffer_size=2
|
local cp_buffer_size
|
||||||
local rc_buffer_size=2
|
local rc_buffer_check
|
||||||
|
|
||||||
if echo "${RUNTIME_ENVIRONMENT}" | grep -qi "z/VM" >/dev/null 2>&1; then
|
if echo "${RUNTIME_ENVIRONMENT}" | grep -qi "z/VM" >/dev/null 2>&1; then
|
||||||
pr_collect_output "z/VM"
|
pr_collect_output "z/VM"
|
||||||
|
|
||||||
if type -t vmcp >/dev/null; then
|
if type vmcp >/dev/null; then
|
||||||
cp_command="vmcp"
|
cp_command="vmcp"
|
||||||
if ! lsmod 2>/dev/null | grep -q vmcp && modinfo vmcp >/dev/null 2>&1; then
|
if ! lsmod 2>/dev/null | grep -q vmcp && modinfo vmcp >/dev/null 2>&1; then
|
||||||
modprobe vmcp && module_loaded=0 && sleep 2
|
modprobe vmcp && module_loaded=0 && sleep 2
|
||||||
fi
|
fi
|
||||||
elif type -t hcp >/dev/null; then
|
elif type hcp >/dev/null; then
|
||||||
cp_command="hcp"
|
cp_command="hcp"
|
||||||
if ! lsmod 2>/dev/null | grep -q cpint; then
|
if ! lsmod 2>/dev/null | grep -q cpint; then
|
||||||
modprobe cpint && module_loaded=0 && sleep 2
|
modprobe cpint && module_loaded=0 && sleep 2
|
||||||
@@ -703,11 +738,14 @@ collect_vmcmdsout() {
|
|||||||
IFS=:
|
IFS=:
|
||||||
for vm_command in ${vm_cmds}; do
|
for vm_command in ${vm_cmds}; do
|
||||||
IFS="${ifs_orig}"
|
IFS="${ifs_orig}"
|
||||||
while test ${rc_buffer_size} -eq 2 && test ${cp_buffer_size} -lt 1024; do
|
# initialize buffer values for automatic resizing
|
||||||
|
cp_buffer_size=2
|
||||||
|
rc_buffer_check=2
|
||||||
|
while test ${rc_buffer_check} -eq 2 && test ${cp_buffer_size} -lt 1024; do
|
||||||
cp_buffer_size=$(( cp_buffer_size * 2 ))
|
cp_buffer_size=$(( cp_buffer_size * 2 ))
|
||||||
eval ${cp_command} -b ${cp_buffer_size}k "${vm_command}" \
|
eval ${cp_command} -b ${cp_buffer_size}k "${vm_command}" \
|
||||||
>/dev/null 2>&1
|
>/dev/null 2>&1
|
||||||
rc_buffer_size=$?
|
rc_buffer_check=$?
|
||||||
done
|
done
|
||||||
call_run_command "${cp_command} -b ${cp_buffer_size}k ${vm_command}" \
|
call_run_command "${cp_command} -b ${cp_buffer_size}k ${vm_command}" \
|
||||||
"${OUTPUT_FILE_VMCMD}"
|
"${OUTPUT_FILE_VMCMD}"
|
||||||
@@ -781,11 +819,12 @@ collect_sysfs() {
|
|||||||
# files known to block on read (-x). Stop reading a file that takes
|
# files known to block on read (-x). Stop reading a file that takes
|
||||||
# more than 5 seconds (-T 5) such as an active ftrace buffer.
|
# more than 5 seconds (-T 5) such as an active ftrace buffer.
|
||||||
# error messages are not written to the log
|
# error messages are not written to the log
|
||||||
if type -t dump2tar >/dev/null; then
|
if test "x${DUMP2TAR_OK}" = "xYES"; then
|
||||||
dump2tar /sys -z -o "${OUTPUT_FILE_SYSFS}.tgz" \
|
dump2tar /sys -z -o "${OUTPUT_FILE_SYSFS}.tgz" \
|
||||||
-x '*/tracing/trace_pipe*' \
|
-x '*/tracing/trace_pipe*' \
|
||||||
-x '*/page_idle/bitmap*' \
|
-x '*/page_idle/bitmap*' \
|
||||||
-x '*/tracing/per_cpu/*' \
|
-x '*/tracing/per_cpu/*' \
|
||||||
|
-x '*/tracing/free_buffer' \
|
||||||
--ignore-failed-read -J 1 -T 5 2>>${OUTPUT_FILE_SYSFS}.err
|
--ignore-failed-read -J 1 -T 5 2>>${OUTPUT_FILE_SYSFS}.err
|
||||||
rc=$?
|
rc=$?
|
||||||
else
|
else
|
||||||
@@ -812,6 +851,7 @@ collect_sysfs() {
|
|||||||
-a -not \( -path '*tracing*' -a -name "trace_pipe*" \) \
|
-a -not \( -path '*tracing*' -a -name "trace_pipe*" \) \
|
||||||
-a -not \( -path '*page_idle*' -a -name 'bitmap*' \) \
|
-a -not \( -path '*page_idle*' -a -name 'bitmap*' \) \
|
||||||
-a -not -path '*tracing/per_cpu*' \
|
-a -not -path '*tracing/per_cpu*' \
|
||||||
|
-a -not -path '*/tracing/free_buffer' \
|
||||||
2>/dev/null | while IFS= read -r file_name; do
|
2>/dev/null | while IFS= read -r file_name; do
|
||||||
echo " ${file_name}"
|
echo " ${file_name}"
|
||||||
if ! dd if="${file_name}" status=noxfer iflag=nonblock \
|
if ! dd if="${file_name}" status=noxfer iflag=nonblock \
|
||||||
@@ -857,7 +897,7 @@ collect_osaoat() {
|
|||||||
|
|
||||||
network_devices=$(lsqeth 2>/dev/null | grep "Device name" \
|
network_devices=$(lsqeth 2>/dev/null | grep "Device name" \
|
||||||
| sed 's/D.*:[[:space:]]*\([^[:space:]]*\)[[:space:]]\+/\1/g')
|
| sed 's/D.*:[[:space:]]*\([^[:space:]]*\)[[:space:]]\+/\1/g')
|
||||||
if type -t qethqoat >/dev/null; then
|
if type qethqoat >/dev/null; then
|
||||||
if test -n "${network_devices}"; then
|
if test -n "${network_devices}"; then
|
||||||
pr_collect_output "osa oat"
|
pr_collect_output "osa oat"
|
||||||
for network_device in ${network_devices}; do
|
for network_device in ${network_devices}; do
|
||||||
@@ -880,7 +920,7 @@ collect_ethtool() {
|
|||||||
local network_device
|
local network_device
|
||||||
|
|
||||||
network_devices=$(ls /sys/class/net 2>/dev/null)
|
network_devices=$(ls /sys/class/net 2>/dev/null)
|
||||||
if type -t ethtool >/dev/null; then
|
if type ethtool >/dev/null; then
|
||||||
if test -n "${network_devices}"; then
|
if test -n "${network_devices}"; then
|
||||||
pr_collect_output "ethtool"
|
pr_collect_output "ethtool"
|
||||||
for network_device in ${network_devices}; do
|
for network_device in ${network_devices}; do
|
||||||
@@ -921,7 +961,7 @@ collect_tc() {
|
|||||||
local network_device
|
local network_device
|
||||||
|
|
||||||
network_devices=$(ls /sys/class/net 2>/dev/null)
|
network_devices=$(ls /sys/class/net 2>/dev/null)
|
||||||
if type -t tc >/dev/null; then
|
if type tc >/dev/null; then
|
||||||
if test -n "${network_devices}"; then
|
if test -n "${network_devices}"; then
|
||||||
pr_collect_output "Trafic Control"
|
pr_collect_output "Trafic Control"
|
||||||
for network_device in ${network_devices}; do
|
for network_device in ${network_devices}; do
|
||||||
@@ -942,7 +982,7 @@ collect_bridge() {
|
|||||||
local network_device
|
local network_device
|
||||||
|
|
||||||
network_devices=$(ls /sys/class/net 2>/dev/null)
|
network_devices=$(ls /sys/class/net 2>/dev/null)
|
||||||
if type -t bridge >/dev/null; then
|
if type bridge >/dev/null; then
|
||||||
if test -n "${network_devices}"; then
|
if test -n "${network_devices}"; then
|
||||||
pr_collect_output "bridge"
|
pr_collect_output "bridge"
|
||||||
for network_device in ${network_devices}; do
|
for network_device in ${network_devices}; do
|
||||||
@@ -974,7 +1014,7 @@ collect_ovs() {
|
|||||||
:ovs-vsctl -t 5 show\
|
:ovs-vsctl -t 5 show\
|
||||||
:ovsdb-client dump\
|
:ovsdb-client dump\
|
||||||
"
|
"
|
||||||
if type -t ovs-vsctl >/dev/null; then
|
if type ovs-vsctl >/dev/null; then
|
||||||
pr_collect_output "OpenVSwitch"
|
pr_collect_output "OpenVSwitch"
|
||||||
IFS=:
|
IFS=:
|
||||||
for ovscmd in ${ovscmds}; do
|
for ovscmd in ${ovscmds}; do
|
||||||
@@ -999,14 +1039,21 @@ collect_ovs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
collect_docker() {
|
collect_container() {
|
||||||
local container_list
|
local container_list
|
||||||
local network_list
|
local network_list
|
||||||
local item
|
local item
|
||||||
|
|
||||||
# check if docker command exists
|
# check if container environment exists
|
||||||
|
if test "x${DOCKER}" = "xYES" || test "x${KUBERNETES}" = "xYES"; then
|
||||||
|
pr_collect_output "container host"
|
||||||
|
else
|
||||||
|
pr_skip "container host: not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# for docker command exists
|
||||||
if [ "x${DOCKER}" = "xYES" ]; then
|
if [ "x${DOCKER}" = "xYES" ]; then
|
||||||
pr_collect_output "docker"
|
pr_syslog_stdout " docker ..."
|
||||||
container_list=$(docker ps -qa)
|
container_list=$(docker ps -qa)
|
||||||
network_list=$(docker network ls -q)
|
network_list=$(docker network ls -q)
|
||||||
ifs_orig="${IFS}"
|
ifs_orig="${IFS}"
|
||||||
@@ -1028,8 +1075,25 @@ collect_docker() {
|
|||||||
"${OUTPUT_FILE_DOCKER}"
|
"${OUTPUT_FILE_DOCKER}"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
else
|
fi
|
||||||
pr_skip "docker: not available"
|
|
||||||
|
# for kubectl command exists
|
||||||
|
if [ "x${KUBERNETES}" = "xYES" ]; then
|
||||||
|
pr_syslog_stdout " Kubernetes ..."
|
||||||
|
container_list=$(kubectl top pod | grep -v "MEMORY(bytes)" | cut -d' ' -f1)
|
||||||
|
|
||||||
|
ifs_orig="${IFS}"
|
||||||
|
IFS=:
|
||||||
|
for item in ${KUBERNETES_CMDS}; do
|
||||||
|
IFS=${ifs_orig} call_run_command "${item}" "${OUTPUT_FILE_KUBERNETES}.out"
|
||||||
|
done
|
||||||
|
IFS="${ifs_orig}"
|
||||||
|
if test -n "${container_list}"; then
|
||||||
|
for item in ${container_list}; do
|
||||||
|
call_run_command "kubectl logs --tail=${KUBERNETES_LOG_LINES} ${item}"\
|
||||||
|
"${OUTPUT_FILE_KUBERNETES}.log"
|
||||||
|
done
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1037,7 +1101,7 @@ collect_docker() {
|
|||||||
collect_nvme() {
|
collect_nvme() {
|
||||||
local device
|
local device
|
||||||
|
|
||||||
if type -t nvme >/dev/null; then
|
if type nvme >/dev/null; then
|
||||||
pr_collect_output "NVME storage"
|
pr_collect_output "NVME storage"
|
||||||
call_run_command "nvme list" "${OUTPUT_FILE_NVME}"
|
call_run_command "nvme list" "${OUTPUT_FILE_NVME}"
|
||||||
for device in /dev/nvme[0-9]*; do
|
for device in /dev/nvme[0-9]*; do
|
||||||
@@ -1078,7 +1142,7 @@ collect_kvm() {
|
|||||||
call_run_command "virsh domstats ${domain}" "${OUTPUT_FILE_KVM}"
|
call_run_command "virsh domstats ${domain}" "${OUTPUT_FILE_KVM}"
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
echo "no KVM doamins found" | tee -a ${OUTPUT_FILE_KVM}
|
echo "no KVM domains found" | tee -a ${OUTPUT_FILE_KVM}
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
pr_skip "KVM: no virsh command"
|
pr_skip "KVM: no virsh command"
|
||||||
@@ -1137,23 +1201,23 @@ call_run_command() {
|
|||||||
local rc=0
|
local rc=0
|
||||||
local cmd="${1}"
|
local cmd="${1}"
|
||||||
local logfile="${2}"
|
local logfile="${2}"
|
||||||
# extract the raw_command and set cmd_type
|
# extract the raw_command and set cmd_type, as some shell might split into
|
||||||
local raw_cmd=$(echo "${cmd}" | sed -ne 's/^\([^[:space:]]*\).*$/\1/p')
|
# several lines restrict the cmd echo to the first line only
|
||||||
local cmd_type=$(type -t ${raw_cmd})
|
local raw_cmd=$(echo "${cmd}" | head -1 | sed -ne 's/^\([^[:space:]]*\).*$/\1/p')
|
||||||
# timeout_ok - like a boolean - is not empty if command exists
|
local cmd_type=$(type ${raw_cmd} | cut -d' ' -sf4,5)
|
||||||
local timeout_ok=$(type -t timeout)
|
|
||||||
|
|
||||||
echo "#######################################################" >> "${logfile}"
|
echo "#######################################################" >> "${logfile}"
|
||||||
echo "${USER}@${SYSTEMHOSTNAME:-localhost}> ${cmd}" >> "${logfile}"
|
echo "${USER}@${SYSTEMHOSTNAME:-localhost}> ${cmd}" >> "${logfile}"
|
||||||
|
|
||||||
# check calling command type
|
# check calling command type
|
||||||
if [ "X${cmd_type}" = "Xbuiltin" ]; then
|
if [ "X${cmd_type}" = "Xshell builtin" ]; then
|
||||||
# command is a builtin (no use of timeout possible)
|
# command is a builtin (no use of timeout possible)
|
||||||
eval "${cmd}" >> ${logfile} 2>&1
|
eval "${cmd}" >> ${logfile} 2>&1
|
||||||
rc=$?
|
rc=$?
|
||||||
elif [ "X${cmd_type}" != "X" ]; then
|
elif [ "X${cmd_type}" != "Xnot found" ]; then
|
||||||
if [ "X${timeout_ok}" = "Xfile" ]; then
|
if [ "x${TIMEOUT_OK}" = "xYES" ]; then
|
||||||
eval timeout -k ${TOS} ${TOS} "${cmd}" >> ${logfile} 2>&1
|
eval timeout -k ${TOKS} ${TOS} "${cmd}" >> ${logfile} 2>&1
|
||||||
|
|
||||||
rc=$?
|
rc=$?
|
||||||
else
|
else
|
||||||
# fall back - call all existing commands without timeout
|
# fall back - call all existing commands without timeout
|
||||||
@@ -1345,6 +1409,9 @@ print_version
|
|||||||
# saving stdout/stderr and redirecting stdout/stderr into log file
|
# saving stdout/stderr and redirecting stdout/stderr into log file
|
||||||
exec 8>&1 9>&2 >"${LOGFILE}" 2>&1
|
exec 8>&1 9>&2 >"${LOGFILE}" 2>&1
|
||||||
|
|
||||||
|
# run print_version again to be logged in dbginfo.log
|
||||||
|
print_version
|
||||||
|
|
||||||
# trap on SIGHUP=1 SIGINT=2 SIGTERM=15
|
# trap on SIGHUP=1 SIGINT=2 SIGTERM=15
|
||||||
trap emergency_exit SIGHUP SIGINT SIGTERM
|
trap emergency_exit SIGHUP SIGINT SIGTERM
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.TH DBGINFO.SH 8 "May 2022" "s390-tools"
|
.TH DBGINFO.SH 8 "Sep 2022" "s390-tools"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
dbginfo.sh \- collect runtime, configuration and trace information
|
dbginfo.sh \- collect runtime, configuration and trace information
|
||||||
@@ -8,13 +8,13 @@ for debugging Linux on IBM Z
|
|||||||
.br
|
.br
|
||||||
\fBdbginfo.sh\fP [OPTIONS]
|
\fBdbginfo.sh\fP [OPTIONS]
|
||||||
.br
|
.br
|
||||||
\fBdbginfo.sh\fP {\-h|\-v}
|
\fBdbginfo.sh\fP {\-h|\-c|\-v}
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
This script collects runtime, configuration and trace information that can
|
This script collects runtime, configuration and trace information that can
|
||||||
be used to debug a Linux on IBM Z instance.
|
be used to debug a Linux on IBM Z instance.
|
||||||
For Linux on z/VM, the script also traces information about the z/VM system.
|
For Linux on z/VM, the script also traces information about the z/VM system.
|
||||||
KVM or DOCKER data ist collected on a host serving this.
|
Virtualization platform data is collected on a host serving this.
|
||||||
|
|
||||||
The debug information is written to a file
|
The debug information is written to a file
|
||||||
/<DIRECTORY>/DBGINFO\-<date>\-<time>\-<hostname>\-<processorid>.tgz
|
/<DIRECTORY>/DBGINFO\-<date>\-<time>\-<hostname>\-<processorid>.tgz
|
||||||
@@ -59,7 +59,7 @@ Sample invocation:
|
|||||||
.br
|
.br
|
||||||
dbginfo.sh: Debug information script version %S390_TOOLS_VERSION%
|
dbginfo.sh: Debug information script version %S390_TOOLS_VERSION%
|
||||||
.br
|
.br
|
||||||
Copyright IBM Corp. 2002, 2021
|
Copyright IBM Corp. 2002, 2022
|
||||||
.PP
|
.PP
|
||||||
Hardware platform = s390x
|
Hardware platform = s390x
|
||||||
.br
|
.br
|
||||||
@@ -97,8 +97,10 @@ Date and time of info = 2021-08-26-15-27-58
|
|||||||
.PP
|
.PP
|
||||||
13 of 18: Skip KVM: no virsh command
|
13 of 18: Skip KVM: no virsh command
|
||||||
.PP
|
.PP
|
||||||
14 of 18: Collecting docker output
|
14 of 18: Collecting container host output
|
||||||
.PP
|
.PP
|
||||||
|
Kubernetes ...
|
||||||
|
.br
|
||||||
15 of 18: Collecting NVME storage output
|
15 of 18: Collecting NVME storage output
|
||||||
.PP
|
.PP
|
||||||
16 of 18: Collecting log files
|
16 of 18: Collecting log files
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Configure dump on panic for System z
|
Description=Configure dump on panic for System z
|
||||||
|
ConditionVirtualization=!container
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|||||||
@@ -872,7 +872,7 @@ static void show_devices_argv(char *argv[])
|
|||||||
show_device(rec, card);
|
show_device(rec, card);
|
||||||
free(card);
|
free(card);
|
||||||
}
|
}
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
if (sscanf(argv[i]+1, "%x", &dom) == 1) {
|
if (sscanf(argv[i]+1, "%x", &dom) == 1) {
|
||||||
/* list specific domains of all adapters */
|
/* list specific domains of all adapters */
|
||||||
@@ -897,7 +897,7 @@ static void show_devices_argv(char *argv[])
|
|||||||
}
|
}
|
||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
printf("Invalid adpater id!\n");
|
printf("Invalid adpater id!\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,22 @@ install() {
|
|||||||
chzdev --export - --persistent --by-attrib "zdev:early=1" --quiet \
|
chzdev --export - --persistent --by-attrib "zdev:early=1" --quiet \
|
||||||
--type 2>/dev/null >> "$_tempfile"
|
--type 2>/dev/null >> "$_tempfile"
|
||||||
|
|
||||||
|
# Obtain early device configuration for site-specific settings
|
||||||
|
for (( site=0; site<10; site++ ))
|
||||||
|
do
|
||||||
|
chzdev --export - --persistent --by-attrib "zdev:early=1" --site $site \
|
||||||
|
--quiet 2>/dev/null >> "$_tempfile"
|
||||||
|
done
|
||||||
|
|
||||||
# Apply via --import to prevent other devices from being configured
|
# Apply via --import to prevent other devices from being configured
|
||||||
chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \
|
chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \
|
||||||
--yes --quiet --no-root-update --force >/dev/null
|
--yes --quiet --no-root-update --force >/dev/null
|
||||||
|
# Apply site-specific configurations via --import
|
||||||
|
for (( site=0; site<10; site++ ))
|
||||||
|
do
|
||||||
|
chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \
|
||||||
|
--site $site --yes --quiet --no-root-update --force >/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
rm -f "$_tempfile"
|
rm -f "$_tempfile"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Common definitions
|
# Common definitions
|
||||||
include ../../common.mak
|
include ../../common.mak
|
||||||
|
|
||||||
MODDIR := /usr/lib/dracut/modules.d/
|
|
||||||
ZDEVDIR := 95zdev
|
ZDEVDIR := 95zdev
|
||||||
|
|
||||||
# HAVE_DRACUT
|
# HAVE_DRACUT
|
||||||
@@ -16,9 +15,9 @@ ZDEVDIR := 95zdev
|
|||||||
#
|
#
|
||||||
ifeq ($(HAVE_DRACUT),1)
|
ifeq ($(HAVE_DRACUT),1)
|
||||||
install:
|
install:
|
||||||
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)
|
$(INSTALL) -m 755 -d $(DESTDIR)$(DRACUTMODDIR)/
|
||||||
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)/$(ZDEVDIR)
|
$(INSTALL) -m 755 -d $(DESTDIR)$(DRACUTMODDIR)/$(ZDEVDIR)
|
||||||
$(INSTALL) -m 755 $(ZDEVDIR)/module-setup.sh \
|
$(INSTALL) -m 755 $(ZDEVDIR)/module-setup.sh \
|
||||||
$(ZDEVDIR)/parse-zdev.sh \
|
$(ZDEVDIR)/parse-zdev.sh \
|
||||||
$(DESTDIR)$(MODDIR)/$(ZDEVDIR)/
|
$(DESTDIR)$(DRACUTMODDIR)/$(ZDEVDIR)/
|
||||||
endif
|
endif
|
||||||
|
|||||||
+19
-1
@@ -19,6 +19,20 @@
|
|||||||
struct subtype;
|
struct subtype;
|
||||||
struct setting_list;
|
struct setting_list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently zdev supports 10 sites. Which means, zdev support 10 different
|
||||||
|
* set of attributes which are specific to each site. When the user does
|
||||||
|
* not provide any site information, the common set will be used which is
|
||||||
|
* not specific to any site. So, total we have 11 persistent attribute sets
|
||||||
|
* Where,
|
||||||
|
* 0- 9: Site specific attributes
|
||||||
|
* 10: Common attributes which do not belong to any sites
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NUM_SITES 11
|
||||||
|
#define NUM_USER_SITES (NUM_SITES - 1)
|
||||||
|
#define SITE_FALLBACK NUM_USER_SITES
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct device_state - Represent the state of a device in a configuration
|
* struct device_state - Represent the state of a device in a configuration
|
||||||
* @settings: List of attribute settings
|
* @settings: List of attribute settings
|
||||||
@@ -61,6 +75,7 @@ struct device {
|
|||||||
struct device_state active;
|
struct device_state active;
|
||||||
struct device_state persistent;
|
struct device_state persistent;
|
||||||
struct device_state autoconf;
|
struct device_state autoconf;
|
||||||
|
struct device_state site_specific[NUM_SITES];
|
||||||
|
|
||||||
unsigned int processed:1;
|
unsigned int processed:1;
|
||||||
};
|
};
|
||||||
@@ -97,8 +112,11 @@ struct device *device_list_find(struct device_list *, const char *,
|
|||||||
struct device *);
|
struct device *);
|
||||||
void device_list_print(struct device_list *, int);
|
void device_list_print(struct device_list *, int);
|
||||||
struct setting_list *device_get_setting_list(struct device *dev,
|
struct setting_list *device_get_setting_list(struct device *dev,
|
||||||
config_t config);
|
config_t config,
|
||||||
|
int site_id);
|
||||||
|
|
||||||
config_t device_get_config(struct device *dev);
|
config_t device_get_config(struct device *dev);
|
||||||
|
char *device_get_sites(struct device *dev);
|
||||||
|
bool is_dev_pers(struct device *dev);
|
||||||
|
|
||||||
#endif /* DEVICE_H */
|
#endif /* DEVICE_H */
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ extern struct devtype *devtypes[];
|
|||||||
* devtypes with empty title will not be shown with --list-types.
|
* devtypes with empty title will not be shown with --list-types.
|
||||||
* @devname: Short name for devices of this device type
|
* @devname: Short name for devices of this device type
|
||||||
* @modules: (Optional) Array of kernel modules required for this devtype
|
* @modules: (Optional) Array of kernel modules required for this devtype
|
||||||
|
* @site_support: Support for site-specific configuration for the device-type
|
||||||
* @subtypes: Array of subtypes
|
* @subtypes: Array of subtypes
|
||||||
* @type_attribs: Array of device type attributes (may point to empty array)
|
* @type_attribs: Array of device type attributes (may point to empty array)
|
||||||
* @unknown_type_attribs: Allow specification of unknown device type attributes
|
* @unknown_type_attribs: Allow specification of unknown device type attributes
|
||||||
@@ -59,6 +60,7 @@ struct devtype {
|
|||||||
const char title[DEVTYPE_TITLE_LEN + 1];
|
const char title[DEVTYPE_TITLE_LEN + 1];
|
||||||
const char *devname;
|
const char *devname;
|
||||||
const char **modules;
|
const char **modules;
|
||||||
|
unsigned int site_support:1;
|
||||||
|
|
||||||
struct subtype **subtypes;
|
struct subtype **subtypes;
|
||||||
struct attrib **type_attribs;
|
struct attrib **type_attribs;
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ extern int delayed_warnings;
|
|||||||
extern unsigned long longrun_total;
|
extern unsigned long longrun_total;
|
||||||
extern unsigned long longrun_current;
|
extern unsigned long longrun_current;
|
||||||
|
|
||||||
|
extern int global_site_id;
|
||||||
|
|
||||||
void misc_exit(void);
|
void misc_exit(void);
|
||||||
void indent(unsigned int, const char *, ...);
|
void indent(unsigned int, const char *, ...);
|
||||||
void error(const char *, ...);
|
void error(const char *, ...);
|
||||||
@@ -239,6 +241,7 @@ void longrun_stop(void);
|
|||||||
char *skip_comp(char *);
|
char *skip_comp(char *);
|
||||||
void byte_swap(uint8_t *, unsigned int *, unsigned);
|
void byte_swap(uint8_t *, unsigned int *, unsigned);
|
||||||
bool valid_hex(const char *);
|
bool valid_hex(const char *);
|
||||||
|
bool is_valid_site(const char *);
|
||||||
void debug_init(int, char **);
|
void debug_init(int, char **);
|
||||||
|
|
||||||
#endif /* MISC_H */
|
#endif /* MISC_H */
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#define MODPROBE_PREFIX "s390x"
|
#define MODPROBE_PREFIX "s390x"
|
||||||
#define UDEV_PREFIX "41"
|
#define UDEV_PREFIX "41"
|
||||||
#define UDEV_SUFFIX ".rules"
|
#define UDEV_SUFFIX ".rules"
|
||||||
|
#define ZDEV_PREFIX "40"
|
||||||
|
|
||||||
#define PATH_MODPROBE_CONF "/etc/modprobe.d"
|
#define PATH_MODPROBE_CONF "/etc/modprobe.d"
|
||||||
#define PATH_MODPROBE "/sbin/modprobe"
|
#define PATH_MODPROBE "/sbin/modprobe"
|
||||||
@@ -65,6 +66,7 @@ char *path_get_zfcp_lun_dev(struct zfcp_lun_devid *);
|
|||||||
char *path_get_zfcp_port_dev(struct zfcp_lun_devid *);
|
char *path_get_zfcp_port_dev(struct zfcp_lun_devid *);
|
||||||
char *path_get_scsi_hctl_dev(const char *);
|
char *path_get_scsi_hctl_dev(const char *);
|
||||||
char *path_get_bus_attr(const char *, const char *);
|
char *path_get_bus_attr(const char *, const char *);
|
||||||
|
char *path_get_zdev_rule(const char *name);
|
||||||
|
|
||||||
exit_code_t path_for_each(const char *,
|
exit_code_t path_for_each(const char *,
|
||||||
exit_code_t (*callback)(const char *, const char *,
|
exit_code_t (*callback)(const char *, const char *,
|
||||||
|
|||||||
+1
-1
@@ -12,6 +12,6 @@
|
|||||||
|
|
||||||
#include "exit_code.h"
|
#include "exit_code.h"
|
||||||
|
|
||||||
exit_code_t initrd_check(bool all_pers);
|
exit_code_t initrd_check(bool all_pers, int site_validate);
|
||||||
|
|
||||||
#endif /* ROOT_H */
|
#endif /* ROOT_H */
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ struct setting_list;
|
|||||||
extern int udev_need_settle;
|
extern int udev_need_settle;
|
||||||
extern int udev_no_settle;
|
extern int udev_no_settle;
|
||||||
|
|
||||||
|
#define SITE_BLOCK_START "# site_start"
|
||||||
|
#define SITE_BLOCK_END "# site_end"
|
||||||
|
|
||||||
bool udev_file_is_empty(struct util_udev_file *file);
|
bool udev_file_is_empty(struct util_udev_file *file);
|
||||||
|
|
||||||
void udev_get_device_ids(const char *type, struct util_list *list,
|
void udev_get_device_ids(const char *type, struct util_list *list,
|
||||||
@@ -31,4 +34,7 @@ void udev_add_internal_from_entry(struct setting_list *list,
|
|||||||
struct util_udev_entry_node *entry,
|
struct util_udev_entry_node *entry,
|
||||||
struct attrib **attribs);
|
struct attrib **attribs);
|
||||||
|
|
||||||
|
exit_code_t udev_write_site_rule(void);
|
||||||
|
bool is_legacy_rule(struct util_udev_file *file);
|
||||||
|
|
||||||
#endif /* UDEV_H */
|
#endif /* UDEV_H */
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* zdev - Modify and display the persistent configuration of devices
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZDEV_ID_H
|
||||||
|
#define ZDEV_ID_H
|
||||||
|
|
||||||
|
#define ZDEV_SITE_ID_FILE "/run/zdev_id.env"
|
||||||
|
|
||||||
|
#endif /* ZDEV_ID_H */
|
||||||
@@ -82,6 +82,42 @@ when a device driver is loaded.
|
|||||||
.PP
|
.PP
|
||||||
By default chzdev applies changes to both the active and the persistent
|
By default chzdev applies changes to both the active and the persistent
|
||||||
configuration.
|
configuration.
|
||||||
|
.
|
||||||
|
.SS "Site-specific configurations"
|
||||||
|
In some high-availability setups, root and boot disks of a Linux installation are
|
||||||
|
copied to remote sites that can take over execution of a Linux workload in case of
|
||||||
|
an outage of the original site. A
|
||||||
|
.B site
|
||||||
|
in this context is an execution environment such as an
|
||||||
|
.B LPAR or
|
||||||
|
.B z/VM guest.
|
||||||
|
Each site may provide a different set of devices, or require different parameters to be
|
||||||
|
applied per device.
|
||||||
|
|
||||||
|
chzdev supports site-specific device configuration for up to
|
||||||
|
.B 10
|
||||||
|
sites. Each site is identified by a number in the range 0 to 9. You can provide a separate
|
||||||
|
set of persistent device configuration for each site. The IPL Load Parameter value specified
|
||||||
|
during boot determines the currently active site. Only the device configuration of the active
|
||||||
|
site is applied during boot and when new devices become available. A common configuration can
|
||||||
|
be provided that is applied when no site-specific configuration is available for a device in
|
||||||
|
the active site.
|
||||||
|
|
||||||
|
You can use the
|
||||||
|
.B --site
|
||||||
|
parameter to configure devices for a specific site only. Configuration actions without a site
|
||||||
|
parameter apply to the common configuration.
|
||||||
|
|
||||||
|
Linux supports the following IPL Load Parameter values for selecting the active site:
|
||||||
|
|
||||||
|
.B S<n>
|
||||||
|
Site with number <n> becomes the active site. Example: "S2" specifies site 2 as active site.
|
||||||
|
|
||||||
|
.B SS
|
||||||
|
The Subchannel-Set ID (SSID) of the IPL device specifies the number of the active site.
|
||||||
|
|
||||||
|
If no site is specified in the Load Parameter, only the common configuration is applied.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
.SS "Tool actions"
|
.SS "Tool actions"
|
||||||
@@ -392,6 +428,10 @@ Removes configuration files and settings associated with the
|
|||||||
selected device.
|
selected device.
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
|
.OD disable-all "D" ""
|
||||||
|
Disable device in all configurations.
|
||||||
|
.PP
|
||||||
|
.
|
||||||
.OD enable "e" ""
|
.OD enable "e" ""
|
||||||
Enable device.
|
Enable device.
|
||||||
|
|
||||||
@@ -583,6 +623,34 @@ Apply changes to persistent configuration only.
|
|||||||
|
|
||||||
The persistent configuration is put into effect when the system boots, or
|
The persistent configuration is put into effect when the system boots, or
|
||||||
when a device becomes available, or when a device driver is loaded.
|
when a device becomes available, or when a device driver is loaded.
|
||||||
|
.PP
|
||||||
|
.
|
||||||
|
.OD site "s" "SITE-ID"
|
||||||
|
Apply the persistent configuration to the specified site only.
|
||||||
|
|
||||||
|
This option can be used to configure the device in such a way that, the
|
||||||
|
same configuration can be used on multiple different sites with different
|
||||||
|
device hardwares, without any modification. With the site information, we
|
||||||
|
can add different configurations which are specific to different sites. Where
|
||||||
|
each site represents different systems or different hardware devices which
|
||||||
|
are even located in different locations.
|
||||||
|
For example, having
|
||||||
|
the configuration of main-site or failover-site in the same place, but these
|
||||||
|
configurations used only on the respective sites. Currently a user can define
|
||||||
|
10 different configurations for 10 different sites with
|
||||||
|
.I SITE-ID
|
||||||
|
0 to 9.
|
||||||
|
|
||||||
|
The configuration settings is put into effect only on the system with the
|
||||||
|
site number which is mentioned in
|
||||||
|
.I SITE-ID.
|
||||||
|
|
||||||
|
This parameter is only effective only for persistent configurations and for
|
||||||
|
dasd device-types.
|
||||||
|
|
||||||
|
.B Example:
|
||||||
|
.CL chzdev -ep 0.0.f001 --site 3
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
.OD quiet "q" ""
|
.OD quiet "q" ""
|
||||||
@@ -690,6 +758,29 @@ Answer all confirmation questions with 'yes'.
|
|||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
|
If you intend to assign a cryptographic (AP) adapter or domain to a KVM
|
||||||
|
guest you must first release its usage by the zcrypt driver in the host
|
||||||
|
operating system using chzdev commands similar to the following examples:
|
||||||
|
.
|
||||||
|
.PP
|
||||||
|
.B Remove AP adapters 1 and 20 through 22 from host usage:
|
||||||
|
.RS 4
|
||||||
|
.CL chzdev \-\-type ap apmask=-1,-20-22
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
.
|
||||||
|
.B Return AP domains 5 and 8 through 10 to host usage:
|
||||||
|
.RS 4
|
||||||
|
.CL chzdev \-\-type ap aqmask=+5,+8-10
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
.
|
||||||
|
.B Specify the list of AP adapters and domains available for host usage:
|
||||||
|
.RS 4
|
||||||
|
.CL chzdev \-\-type ap apmask=0-120,129-255 aqmask=0-200,220-255
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
.
|
||||||
.
|
.
|
||||||
.SH "EXIT CODES"
|
.SH "EXIT CODES"
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -74,9 +74,43 @@ of the currently running system, the persistent configuration stored in
|
|||||||
configuration files, and the auto-configuration that is provided by some
|
configuration files, and the auto-configuration that is provided by some
|
||||||
machine types to automatically enable I/O devices.
|
machine types to automatically enable I/O devices.
|
||||||
.PP
|
.PP
|
||||||
|
Persistent configuration data is of two different types. Site-specific configuration
|
||||||
|
and common-configuration. Common configuration refers to the persistent configuration
|
||||||
|
which is not bound to any site. In many use cases, this configuration is being
|
||||||
|
used as a fallback configuration.
|
||||||
|
Refer the
|
||||||
|
.B site
|
||||||
|
section below to learn more about site-specific configuration.
|
||||||
|
.PP
|
||||||
By default lszdev displays information from both the active and the persistent
|
By default lszdev displays information from both the active and the persistent
|
||||||
configuration, and, if available, from the auto-configuration.
|
configuration, and, if available, from the auto-configuration.
|
||||||
.PP
|
.PP
|
||||||
|
.SS Output Format
|
||||||
|
In list format, lszdev uses values with the following meaning for the persistent colums (PERS):
|
||||||
|
|
||||||
|
.B yes
|
||||||
|
.CL A persistent, non-site specific configuration exists; No site specific configurations available.
|
||||||
|
|
||||||
|
.B no
|
||||||
|
.CL No persistent configurations is available.
|
||||||
|
|
||||||
|
.B auto
|
||||||
|
.CL Machine-provided auto-configuration is available.
|
||||||
|
|
||||||
|
.B s<n>
|
||||||
|
.CL A site-specific configuration is available for site-id n.
|
||||||
|
|
||||||
|
.B s+
|
||||||
|
.CL Site specific configurations are available for multiple sites.
|
||||||
|
|
||||||
|
.B Example
|
||||||
|
|
||||||
|
.CL TYPE ID ON PERS NAMES
|
||||||
|
.CL dasd-eckd 0.0.f001 no s+ dasda
|
||||||
|
.CL dasd-eckd 0.0.f002 no s4 dasdb
|
||||||
|
.CL dasd-eckd 0.0.f003 no no
|
||||||
|
.CL qeth 0.0.1200:0.0.1201:0.0.1202 no yes encbdf0
|
||||||
|
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
.SH TYPE
|
.SH TYPE
|
||||||
@@ -123,6 +157,7 @@ comma (,).
|
|||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
|
|
||||||
.SH SELECTION
|
.SH SELECTION
|
||||||
In addition to specifying devices by their ID, you can also select devices by
|
In addition to specifying devices by their ID, you can also select devices by
|
||||||
their state or by the Linux functions they provide.
|
their state or by the Linux functions they provide.
|
||||||
@@ -292,6 +327,7 @@ Display detailed information.
|
|||||||
Displays detailed information about the configuration of the selected device
|
Displays detailed information about the configuration of the selected device
|
||||||
or device type. Specifying \-\-info twice will display additional device
|
or device type. Specifying \-\-info twice will display additional device
|
||||||
information.
|
information.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
.OD list-columns "l" ""
|
.OD list-columns "l" ""
|
||||||
@@ -392,6 +428,25 @@ escaped by placing a slash in front of it.
|
|||||||
List information from the persistent configuration only.
|
List information from the persistent configuration only.
|
||||||
|
|
||||||
Restricts output to information obtained from configuration files.
|
Restricts output to information obtained from configuration files.
|
||||||
|
.PP
|
||||||
|
.
|
||||||
|
.OD site "s" "SITE-ID"
|
||||||
|
List the persistent configuration from the specified site only.
|
||||||
|
|
||||||
|
The resulted persistent configuration details are filtered based on the
|
||||||
|
.ID SITE-ID
|
||||||
|
value. The site specific information can be found in a basic lszdev output.
|
||||||
|
For example, the PERS column may show "s+" which indicates that the device
|
||||||
|
has multiple configurations for multiple sites, and "sn" where 'n' is an
|
||||||
|
number between 0 to 9, which indicates that the persistent configuration
|
||||||
|
for the device is available only for site 'n'.
|
||||||
|
|
||||||
|
.B Example:
|
||||||
|
|
||||||
|
.CL lszdev --site 3
|
||||||
|
.CL lszdev -i --site 2
|
||||||
|
.CL lszdev f001 --site 9
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
.OD quiet "q" ""
|
.OD quiet "q" ""
|
||||||
@@ -429,6 +484,12 @@ Print additional run-time information.
|
|||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
|
.B Display cryptographic (AP) adapter and domain assignments:
|
||||||
|
.RS 4
|
||||||
|
.CL lszdev \-\-type ap
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
.
|
||||||
.SH "EXIT CODES"
|
.SH "EXIT CODES"
|
||||||
lszdev returns a subset of the exit codes returned by the chzdev tool. See
|
lszdev returns a subset of the exit codes returned by the chzdev tool. See
|
||||||
.MP chzdev 8
|
.MP chzdev 8
|
||||||
|
|||||||
@@ -81,9 +81,6 @@ lszdev_objects += generic_ccw.o
|
|||||||
|
|
||||||
all: chzdev lszdev zdev_id
|
all: chzdev lszdev zdev_id
|
||||||
|
|
||||||
ifneq (${HAVE_LOCKFILE}, 0)
|
|
||||||
LDLIBS += -llockfile
|
|
||||||
endif
|
|
||||||
ifneq (${HAVE_JSONC}, 0)
|
ifneq (${HAVE_JSONC}, 0)
|
||||||
LDLIBS += -ljson-c
|
LDLIBS += -ljson-c
|
||||||
endif
|
endif
|
||||||
|
|||||||
+1
-1
@@ -1593,7 +1593,7 @@ static exit_code_t ccw_st_deconfigure_active(struct subtype *st,
|
|||||||
static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st,
|
static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st,
|
||||||
struct device *dev)
|
struct device *dev)
|
||||||
{
|
{
|
||||||
return udev_remove_rule(st->name, dev->id, false);
|
return ccw_st_configure_persistent(st, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+145
-18
@@ -15,6 +15,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
@@ -44,6 +45,12 @@
|
|||||||
#include "udev.h"
|
#include "udev.h"
|
||||||
#include "zfcp_lun.h"
|
#include "zfcp_lun.h"
|
||||||
|
|
||||||
|
/* current site-id in action. By default, operations are always on fallback
|
||||||
|
* site; We need the current site-id as global variable to avoid excessive
|
||||||
|
* diff of simple function parameter modifications to pass this value.
|
||||||
|
*/
|
||||||
|
int global_site_id = SITE_FALLBACK;
|
||||||
|
|
||||||
/* Main program action. */
|
/* Main program action. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ACT_CONFIGURE,
|
ACT_CONFIGURE,
|
||||||
@@ -73,6 +80,7 @@ struct options {
|
|||||||
/* Actions */
|
/* Actions */
|
||||||
unsigned int enable:1;
|
unsigned int enable:1;
|
||||||
unsigned int deconfigure:1;
|
unsigned int deconfigure:1;
|
||||||
|
unsigned int deconfigure_all:1;
|
||||||
unsigned int list_attribs:1;
|
unsigned int list_attribs:1;
|
||||||
unsigned int list_types:1;
|
unsigned int list_types:1;
|
||||||
unsigned int help_attribs:1;
|
unsigned int help_attribs:1;
|
||||||
@@ -97,6 +105,7 @@ struct options {
|
|||||||
unsigned int verbose:1;
|
unsigned int verbose:1;
|
||||||
unsigned int quiet:1;
|
unsigned int quiet:1;
|
||||||
unsigned int no_settle:1;
|
unsigned int no_settle:1;
|
||||||
|
unsigned int site_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Makefile converts chzdev_usage.txt into C file which we include here. */
|
/* Makefile converts chzdev_usage.txt into C file which we include here. */
|
||||||
@@ -119,6 +128,7 @@ enum {
|
|||||||
OPT_TYPE = 't',
|
OPT_TYPE = 't',
|
||||||
OPT_ENABLE = 'e',
|
OPT_ENABLE = 'e',
|
||||||
OPT_DECONFIGURE = 'd',
|
OPT_DECONFIGURE = 'd',
|
||||||
|
OPT_DECONFIGURE_ALL = 'D',
|
||||||
OPT_LIST_ATTRIBS = 'l',
|
OPT_LIST_ATTRIBS = 'l',
|
||||||
OPT_HELP_ATTRIBS = 'H',
|
OPT_HELP_ATTRIBS = 'H',
|
||||||
OPT_LIST_TYPES = 'L',
|
OPT_LIST_TYPES = 'L',
|
||||||
@@ -140,43 +150,52 @@ enum {
|
|||||||
OPT_QUIET = 'q',
|
OPT_QUIET = 'q',
|
||||||
OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
|
OPT_SITE = 's',
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct opts_conflict conflict_list[] = {
|
static struct opts_conflict conflict_list[] = {
|
||||||
OPTS_CONFLICT(OPT_ENABLE,
|
OPTS_CONFLICT(OPT_ENABLE,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES,
|
||||||
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_TYPE, 0),
|
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_TYPE,
|
||||||
|
OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_DECONFIGURE,
|
OPTS_CONFLICT(OPT_DECONFIGURE,
|
||||||
OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS, OPT_LIST_TYPES,
|
OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS, OPT_LIST_TYPES,
|
||||||
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||||
OPT_REMOVE_ALL, OPT_TYPE, 0),
|
OPT_REMOVE_ALL, OPT_TYPE,
|
||||||
|
OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_LIST_ATTRIBS,
|
OPTS_CONFLICT(OPT_LIST_ATTRIBS,
|
||||||
OPT_DECONFIGURE, OPT_HELP_ATTRIBS, OPT_LIST_TYPES,
|
OPT_DECONFIGURE, OPT_HELP_ATTRIBS, OPT_LIST_TYPES,
|
||||||
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED, 0),
|
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||||
|
OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_LIST_TYPES,
|
OPTS_CONFLICT(OPT_LIST_TYPES,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||||
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED, 0),
|
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||||
|
OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_EXPORT,
|
OPTS_CONFLICT(OPT_EXPORT,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||||
OPT_LIST_TYPES, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
OPT_LIST_TYPES, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||||
OPT_REMOVE_ALL, 0),
|
OPT_REMOVE_ALL, OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_IMPORT,
|
OPTS_CONFLICT(OPT_IMPORT,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||||
OPT_LIST_TYPES, OPT_EXPORT, OPT_APPLY, OPT_REMOVE,
|
OPT_LIST_TYPES, OPT_EXPORT, OPT_APPLY, OPT_REMOVE,
|
||||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_BY_PATH,
|
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_BY_PATH,
|
||||||
OPT_BY_ATTRIB, OPT_BY_NODE, OPT_BY_INTERFACE, 0),
|
OPT_BY_ATTRIB, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||||
|
OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_APPLY,
|
OPTS_CONFLICT(OPT_APPLY,
|
||||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||||
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
|
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
|
||||||
OPT_REMOVE_ALL, OPT_ACTIVE, 0),
|
OPT_REMOVE_ALL, OPT_ACTIVE,
|
||||||
|
OPT_DECONFIGURE_ALL, 0),
|
||||||
OPTS_CONFLICT(OPT_ONLINE,
|
OPTS_CONFLICT(OPT_ONLINE,
|
||||||
OPT_OFFLINE),
|
OPT_OFFLINE),
|
||||||
|
OPTS_CONFLICT(OPT_SITE,
|
||||||
|
OPT_TYPE, 0),
|
||||||
OPTS_CONFLICT(OPT_QUIET,
|
OPTS_CONFLICT(OPT_QUIET,
|
||||||
OPT_VERBOSE),
|
OPT_VERBOSE),
|
||||||
OPTS_CONFLICT(OPT_AUTO_CONF,
|
OPTS_CONFLICT(OPT_AUTO_CONF,
|
||||||
@@ -202,6 +221,7 @@ static const struct option opt_list[] = {
|
|||||||
/* Actions. */
|
/* Actions. */
|
||||||
{ "enable", no_argument, NULL, OPT_ENABLE },
|
{ "enable", no_argument, NULL, OPT_ENABLE },
|
||||||
{ "disable", no_argument, NULL, OPT_DECONFIGURE },
|
{ "disable", no_argument, NULL, OPT_DECONFIGURE },
|
||||||
|
{ "disable-all", no_argument, NULL, OPT_DECONFIGURE_ALL },
|
||||||
{ "list-attributes", no_argument, NULL, OPT_LIST_ATTRIBS },
|
{ "list-attributes", no_argument, NULL, OPT_LIST_ATTRIBS },
|
||||||
{ "help-attribute", no_argument, NULL, OPT_HELP_ATTRIBS },
|
{ "help-attribute", no_argument, NULL, OPT_HELP_ATTRIBS },
|
||||||
{ "list-types", no_argument, NULL, OPT_LIST_TYPES },
|
{ "list-types", no_argument, NULL, OPT_LIST_TYPES },
|
||||||
@@ -225,11 +245,12 @@ static const struct option opt_list[] = {
|
|||||||
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
||||||
{ "quiet", no_argument, NULL, OPT_QUIET },
|
{ "quiet", no_argument, NULL, OPT_QUIET },
|
||||||
{ "no-settle", no_argument, NULL, OPT_NO_SETTLE },
|
{ "no-settle", no_argument, NULL, OPT_NO_SETTLE },
|
||||||
|
{ "site", required_argument, NULL, OPT_SITE },
|
||||||
{ NULL, no_argument, NULL, 0 },
|
{ NULL, no_argument, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Command line abbreviations. */
|
/* Command line abbreviations. */
|
||||||
static const char opt_str[] = ":edlHLapr:RfyhvVqt";
|
static const char opt_str[] = ":edlHLapr:RfyhvVqts:D";
|
||||||
|
|
||||||
/* Count of persistently modified devices. */
|
/* Count of persistently modified devices. */
|
||||||
static int pers_mod_devs;
|
static int pers_mod_devs;
|
||||||
@@ -246,6 +267,8 @@ static void init_options(struct options *opts)
|
|||||||
opts->settings = strlist_new();
|
opts->settings = strlist_new();
|
||||||
opts->remove = strlist_new();
|
opts->remove = strlist_new();
|
||||||
opts->base = strlist_new();
|
opts->base = strlist_new();
|
||||||
|
/* Default operations are on fallback site*/
|
||||||
|
opts->site_id = SITE_FALLBACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release memory used in options data structure. */
|
/* Release memory used in options data structure. */
|
||||||
@@ -838,6 +861,12 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
|||||||
opts->deconfigure = 1;
|
opts->deconfigure = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_DECONFIGURE_ALL:
|
||||||
|
/* --disable all the settings*/
|
||||||
|
opts->deconfigure = 1;
|
||||||
|
opts->deconfigure_all = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_LIST_ATTRIBS:
|
case OPT_LIST_ATTRIBS:
|
||||||
/* --list-attributes */
|
/* --list-attributes */
|
||||||
opts->list_attribs = 1;
|
opts->list_attribs = 1;
|
||||||
@@ -955,6 +984,28 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
|||||||
opts->no_settle = 1;
|
opts->no_settle = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_SITE:
|
||||||
|
/* --site */
|
||||||
|
/* 1. User can specify only site-ids from 0 to 9
|
||||||
|
* 2. only one --site parameter is accepted
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!is_valid_site(optarg)) {
|
||||||
|
syntax("Unsupported site ID\n");
|
||||||
|
return EXIT_USAGE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->site_id != SITE_FALLBACK) {
|
||||||
|
syntax("Cannot specify '--site' multiple "
|
||||||
|
"times\n");
|
||||||
|
return EXIT_USAGE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts->site_id = atoi(optarg);
|
||||||
|
global_site_id = opts->site_id;
|
||||||
|
opts->persistent = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
/* Missing option argument. */
|
/* Missing option argument. */
|
||||||
syntax("Option '%s' requires an argument\n",
|
syntax("Option '%s' requires an argument\n",
|
||||||
@@ -987,7 +1038,9 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Determine configuration set. */
|
/* Determine configuration set. */
|
||||||
if (!opts->active && !opts->persistent && !opts->auto_conf) {
|
if (opts->deconfigure_all) {
|
||||||
|
opts->config = config_all;
|
||||||
|
} else if (!opts->active && !opts->persistent && !opts->auto_conf) {
|
||||||
/* Default configuration targets are active + persistent */
|
/* Default configuration targets are active + persistent */
|
||||||
opts->config = config_active | config_persistent;
|
opts->config = config_active | config_persistent;
|
||||||
} else {
|
} else {
|
||||||
@@ -1794,6 +1847,24 @@ static void unblacklist_ranges(struct selected_dev_node *sel,
|
|||||||
*param_ptr = param;
|
*param_ptr = param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Currently the site-specific configurations are supported only
|
||||||
|
* for some device types. Make sure that user get an error message when
|
||||||
|
* try to configure other device-types with site parameter.
|
||||||
|
*/
|
||||||
|
static exit_code_t is_site_supported(struct util_list *selected)
|
||||||
|
{
|
||||||
|
struct selected_dev_node *sel;
|
||||||
|
|
||||||
|
util_list_iterate(selected, sel) {
|
||||||
|
if (sel->dt && !sel->dt->site_support) {
|
||||||
|
error("Site specific configuration is not supported"
|
||||||
|
" for %s devices\n", sel->dt->devname);
|
||||||
|
return EXIT_USAGE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EXIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle device configuration. */
|
/* Handle device configuration. */
|
||||||
static exit_code_t configure_devices(struct options *opts, int specified,
|
static exit_code_t configure_devices(struct options *opts, int specified,
|
||||||
int *found_ptr)
|
int *found_ptr)
|
||||||
@@ -1827,6 +1898,9 @@ static exit_code_t configure_devices(struct options *opts, int specified,
|
|||||||
error("No device was selected!\n");
|
error("No device was selected!\n");
|
||||||
rc = EXIT_EMPTY_SELECTION;
|
rc = EXIT_EMPTY_SELECTION;
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if (opts->site_id != SITE_FALLBACK) {
|
||||||
|
if (is_site_supported(selected))
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Work on selected devices. */
|
/* Work on selected devices. */
|
||||||
@@ -1913,6 +1987,18 @@ static exit_code_t check_in_use(struct device *dev)
|
|||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_site_modified(struct device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++) {
|
||||||
|
if (dev->site_specific[i].modified)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Deconfigure specified device. */
|
/* Deconfigure specified device. */
|
||||||
static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
||||||
struct options *opts, int try,
|
struct options *opts, int try,
|
||||||
@@ -1922,6 +2008,7 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
|||||||
exit_code_t rc;
|
exit_code_t rc;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
config_t config, read_config;
|
config_t config, read_config;
|
||||||
|
int i, site_available = 0;
|
||||||
|
|
||||||
/* Reset processed flag. */
|
/* Reset processed flag. */
|
||||||
if (proc_ptr)
|
if (proc_ptr)
|
||||||
@@ -1954,7 +2041,7 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
|||||||
dev->processed = 1;
|
dev->processed = 1;
|
||||||
|
|
||||||
if (try && !(dev->active.exists || dev->active.definable ||
|
if (try && !(dev->active.exists || dev->active.definable ||
|
||||||
dev->persistent.exists || dev->autoconf.exists)) {
|
is_dev_pers(dev) || dev->autoconf.exists)) {
|
||||||
/* Attempt to deconfigure this device will fail. */
|
/* Attempt to deconfigure this device will fail. */
|
||||||
return EXIT_DEVICE_NOT_FOUND;
|
return EXIT_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
@@ -1964,7 +2051,7 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
|||||||
* dev. */
|
* dev. */
|
||||||
if (SCOPE_ACTIVE(config) &&
|
if (SCOPE_ACTIVE(config) &&
|
||||||
!(dev->active.exists || dev->active.definable)) {
|
!(dev->active.exists || dev->active.definable)) {
|
||||||
if (!((SCOPE_PERSISTENT(config) && dev->persistent.exists) ||
|
if (!((SCOPE_PERSISTENT(config) && is_dev_pers(dev)) ||
|
||||||
(SCOPE_AUTOCONF(config) && dev->autoconf.exists)))
|
(SCOPE_AUTOCONF(config) && dev->autoconf.exists)))
|
||||||
return EXIT_DEVICE_NOT_FOUND;
|
return EXIT_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
@@ -1985,16 +2072,48 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
|||||||
} else if (subtype_online_get(st, dev, config_active) == 1)
|
} else if (subtype_online_get(st, dev, config_active) == 1)
|
||||||
dev->active.modified = 1;
|
dev->active.modified = 1;
|
||||||
}
|
}
|
||||||
if (SCOPE_PERSISTENT(config) && dev->persistent.exists) {
|
if (SCOPE_PERSISTENT(config)) {
|
||||||
dev->persistent.deconfigured = 1;
|
if (dev->persistent.exists) {
|
||||||
dev->persistent.modified = 1;
|
dev->persistent.deconfigured = 1;
|
||||||
|
dev->persistent.modified = 1;
|
||||||
|
} else if (is_dev_pers(dev) && global_site_id != SITE_FALLBACK) {
|
||||||
|
dev->persistent.deconfigured = 1;
|
||||||
|
dev->persistent.modified = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) {
|
if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) {
|
||||||
dev->autoconf.deconfigured = 1;
|
dev->autoconf.deconfigured = 1;
|
||||||
dev->autoconf.modified = 1;
|
dev->autoconf.modified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In case of deconfigure_all command, make sure that site specific
|
||||||
|
* settings are also removed.
|
||||||
|
*/
|
||||||
|
if (opts->deconfigure_all) {
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++) {
|
||||||
|
if (dev->site_specific[i].exists) {
|
||||||
|
site_available++;
|
||||||
|
/* To remove site-specific settings, simply
|
||||||
|
* make the deconfigured = 1
|
||||||
|
*/
|
||||||
|
dev->site_specific[i].deconfigured = 1;
|
||||||
|
dev->site_specific[i].modified = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (site_available) {
|
||||||
|
/* set persistent.exists = 1 to let the
|
||||||
|
* drivers know that we need to modify the
|
||||||
|
* udev-rule
|
||||||
|
*/
|
||||||
|
dev->persistent.exists = 1;
|
||||||
|
dev->persistent.modified = 1;
|
||||||
|
dev->persistent.deconfigured = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dev->active.modified && !dev->persistent.modified &&
|
if (!dev->active.modified && !dev->persistent.modified &&
|
||||||
!dev->autoconf.modified)
|
!dev->autoconf.modified && !is_site_modified(dev))
|
||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
|
|
||||||
/* Pre-write check. */
|
/* Pre-write check. */
|
||||||
@@ -2036,6 +2155,9 @@ static exit_code_t deconfigure_devices(struct options *opts)
|
|||||||
error("No device was selected!\n");
|
error("No device was selected!\n");
|
||||||
rc = EXIT_EMPTY_SELECTION;
|
rc = EXIT_EMPTY_SELECTION;
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if (opts->site_id != SITE_FALLBACK) {
|
||||||
|
if (is_site_supported(selected))
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Work on selected devices. */
|
/* Work on selected devices. */
|
||||||
@@ -2558,8 +2680,13 @@ static void action_note(const char *msg, config_t config)
|
|||||||
{
|
{
|
||||||
if (config == config_active)
|
if (config == config_active)
|
||||||
info("%s the active configuration only\n", msg);
|
info("%s the active configuration only\n", msg);
|
||||||
else if (config == config_persistent)
|
else if (config == config_persistent) {
|
||||||
info("%s the persistent configuration only\n", msg);
|
if (global_site_id == SITE_FALLBACK)
|
||||||
|
info("%s the persistent configuration only\n", msg);
|
||||||
|
else
|
||||||
|
info("%s the site %d configuration only\n", msg,
|
||||||
|
global_site_id);
|
||||||
|
}
|
||||||
else if (config == config_autoconf)
|
else if (config == config_autoconf)
|
||||||
info("%s the auto-configuration only\n", msg);
|
info("%s the auto-configuration only\n", msg);
|
||||||
}
|
}
|
||||||
@@ -3034,7 +3161,7 @@ int main(int argc, char *argv[])
|
|||||||
!dryrun) {
|
!dryrun) {
|
||||||
/* If the root device/device type or early devices have been
|
/* If the root device/device type or early devices have been
|
||||||
* modified, additional work might be necessary. */
|
* modified, additional work might be necessary. */
|
||||||
rc = initrd_check(ZDEV_ALWAYS_UPDATE_INITRD);
|
rc = initrd_check(ZDEV_ALWAYS_UPDATE_INITRD, opts.deconfigure_all);
|
||||||
if (rc && !drc)
|
if (rc && !drc)
|
||||||
drc = rc;
|
drc = rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ SETTINGS
|
|||||||
|
|
||||||
ACTIONS
|
ACTIONS
|
||||||
-e, --enable Enable device
|
-e, --enable Enable device
|
||||||
-d, --disable Disable device
|
-d, --disable Disable specified setting of the device
|
||||||
|
-D, --disable-all Disable all the settings of the device
|
||||||
-l, --list-attributes List attributes
|
-l, --list-attributes List attributes
|
||||||
-L, --list-types List supported device types
|
-L, --list-types List supported device types
|
||||||
-H, --help-attribute Show detailed help on specified attribute
|
-H, --help-attribute Show detailed help on specified attribute
|
||||||
@@ -56,5 +57,6 @@ OPTIONS
|
|||||||
--base PATH Use PATH as base for accessing files
|
--base PATH Use PATH as base for accessing files
|
||||||
--no-settle Do not wait for udev to settle
|
--no-settle Do not wait for udev to settle
|
||||||
--auto-conf Apply changes to auto-configuration only
|
--auto-conf Apply changes to auto-configuration only
|
||||||
|
-s, --site ID Apply changes to the specified site only
|
||||||
-V, --verbose Print additional run-time information
|
-V, --verbose Print additional run-time information
|
||||||
-q, --quiet Print only minimal run-time information
|
-q, --quiet Print only minimal run-time information
|
||||||
|
|||||||
@@ -688,6 +688,7 @@ struct devtype dasd_devtype = {
|
|||||||
"(DASDs)",
|
"(DASDs)",
|
||||||
.devname = "DASD",
|
.devname = "DASD",
|
||||||
.modules = STRING_ARRAY(DASD_MOD_NAME),
|
.modules = STRING_ARRAY(DASD_MOD_NAME),
|
||||||
|
.site_support = 1,
|
||||||
|
|
||||||
.subtypes = SUBTYPE_ARRAY(
|
.subtypes = SUBTYPE_ARRAY(
|
||||||
&dasd_subtype_eckd,
|
&dasd_subtype_eckd,
|
||||||
|
|||||||
+68
-1
@@ -29,6 +29,7 @@ struct device *device_new(struct subtype *st, const char *id)
|
|||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct namespace *ns = st->namespace;
|
struct namespace *ns = st->namespace;
|
||||||
|
int i;
|
||||||
|
|
||||||
dev = misc_malloc(sizeof(struct device));
|
dev = misc_malloc(sizeof(struct device));
|
||||||
dev->subtype = st;
|
dev->subtype = st;
|
||||||
@@ -44,12 +45,17 @@ struct device *device_new(struct subtype *st, const char *id)
|
|||||||
dev->persistent.settings = setting_list_new();
|
dev->persistent.settings = setting_list_new();
|
||||||
dev->autoconf.settings = setting_list_new();
|
dev->autoconf.settings = setting_list_new();
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SITES; i++)
|
||||||
|
dev->site_specific[i].settings = setting_list_new();
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release all resources associated with the specified device. */
|
/* Release all resources associated with the specified device. */
|
||||||
void device_free(struct device *dev)
|
void device_free(struct device *dev)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return;
|
return;
|
||||||
free(dev->id);
|
free(dev->id);
|
||||||
@@ -57,12 +63,18 @@ void device_free(struct device *dev)
|
|||||||
setting_list_free(dev->active.settings);
|
setting_list_free(dev->active.settings);
|
||||||
setting_list_free(dev->persistent.settings);
|
setting_list_free(dev->persistent.settings);
|
||||||
setting_list_free(dev->autoconf.settings);
|
setting_list_free(dev->autoconf.settings);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SITES; i++)
|
||||||
|
setting_list_free(dev->site_specific[i].settings);
|
||||||
|
|
||||||
free(dev);
|
free(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used for debugging. */
|
/* Used for debugging. */
|
||||||
void device_print(struct device *dev, int level)
|
void device_print(struct device *dev, int level)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
printf("%*sdevice at %p:\n", level, "", (void *) dev);
|
printf("%*sdevice at %p:\n", level, "", (void *) dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return;
|
return;
|
||||||
@@ -96,6 +108,36 @@ void device_print(struct device *dev, int level)
|
|||||||
setting_list_print(dev->autoconf.settings, level + 8);
|
setting_list_print(dev->autoconf.settings, level + 8);
|
||||||
else
|
else
|
||||||
printf("%*s<none>\n", level + 8, "");
|
printf("%*s<none>\n", level + 8, "");
|
||||||
|
|
||||||
|
printf("%*spersistent-site-specific:\n", level + 4, "");
|
||||||
|
for (i = 0; i < NUM_SITES; i++) {
|
||||||
|
printf("%*sexists=%d mod=%d deconf=%d\n",
|
||||||
|
level + 8, "", dev->site_specific[i].exists,
|
||||||
|
dev->site_specific[i].modified,
|
||||||
|
dev->site_specific[i].deconfigured);
|
||||||
|
if (dev->site_specific[i].settings)
|
||||||
|
setting_list_print(dev->site_specific[i].settings, level + 8);
|
||||||
|
else
|
||||||
|
printf("%*s<none>\n", level + 8, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *device_get_sites(struct device *dev)
|
||||||
|
{
|
||||||
|
struct util_list *names;
|
||||||
|
char *str;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
names = strlist_new();
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++) {
|
||||||
|
if (dev->site_specific[i].exists)
|
||||||
|
strlist_add(names, "%d", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = strlist_flatten(names, ",");
|
||||||
|
strlist_free(names);
|
||||||
|
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void *device_hash_get_id(void *dev_ptr)
|
static const void *device_hash_get_id(void *dev_ptr)
|
||||||
@@ -627,10 +669,16 @@ exit_code_t device_check_settings(struct device *dev, config_t config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct setting_list *device_get_setting_list(struct device *dev,
|
struct setting_list *device_get_setting_list(struct device *dev,
|
||||||
config_t config)
|
config_t config,
|
||||||
|
int site_id)
|
||||||
{
|
{
|
||||||
struct setting_list *settings = NULL;
|
struct setting_list *settings = NULL;
|
||||||
|
|
||||||
|
if (site_id < SITE_FALLBACK) {
|
||||||
|
settings = dev->site_specific[site_id].settings;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (config == config_active)
|
if (config == config_active)
|
||||||
settings = dev->active.settings;
|
settings = dev->active.settings;
|
||||||
else if (config == config_persistent)
|
else if (config == config_persistent)
|
||||||
@@ -638,6 +686,7 @@ struct setting_list *device_get_setting_list(struct device *dev,
|
|||||||
else if (config == config_autoconf)
|
else if (config == config_autoconf)
|
||||||
settings = dev->autoconf.settings;
|
settings = dev->autoconf.settings;
|
||||||
|
|
||||||
|
out:
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -657,3 +706,21 @@ config_t device_get_config(struct device *dev)
|
|||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine if persistent configuration available for any of the sites*/
|
||||||
|
bool is_dev_pers(struct device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (global_site_id != SITE_FALLBACK &&
|
||||||
|
!dev->site_specific[global_site_id].exists)
|
||||||
|
return false;
|
||||||
|
else if (dev->persistent.exists)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SITES; i++)
|
||||||
|
if (dev->site_specific[i].exists)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
+44
-11
@@ -21,6 +21,8 @@
|
|||||||
#include "setting.h"
|
#include "setting.h"
|
||||||
#include "subtype.h"
|
#include "subtype.h"
|
||||||
|
|
||||||
|
static int import_site_id = SITE_FALLBACK;
|
||||||
|
|
||||||
struct export_header {
|
struct export_header {
|
||||||
export_t type;
|
export_t type;
|
||||||
config_t config;
|
config_t config;
|
||||||
@@ -28,13 +30,28 @@ struct export_header {
|
|||||||
char *id;
|
char *id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool header_str_to_config(const char *config_str, config_t *config)
|
||||||
|
{
|
||||||
|
int site;
|
||||||
|
|
||||||
|
if (strstr(config_str, "site")) {
|
||||||
|
if (sscanf(config_str, "site%d", &site) == 1) {
|
||||||
|
import_site_id = site;
|
||||||
|
*config = config_persistent;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
import_site_id = SITE_FALLBACK;
|
||||||
|
return str_to_config(config_str, config);
|
||||||
|
}
|
||||||
|
|
||||||
static struct export_header *header_new(const char *config_str,
|
static struct export_header *header_new(const char *config_str,
|
||||||
const char *type, const char *id)
|
const char *type, const char *id)
|
||||||
{
|
{
|
||||||
config_t config;
|
config_t config;
|
||||||
struct export_header *hdr;
|
struct export_header *hdr;
|
||||||
|
|
||||||
if (!str_to_config(config_str, &config))
|
if (!header_str_to_config(config_str, &config))
|
||||||
return NULL;
|
return NULL;
|
||||||
hdr = misc_malloc(sizeof(struct export_header));
|
hdr = misc_malloc(sizeof(struct export_header));
|
||||||
if (!id)
|
if (!id)
|
||||||
@@ -130,6 +147,14 @@ static void export_write_comment(FILE *fd)
|
|||||||
fprintf(fd, "# Generated by chzdev\n");
|
fprintf(fd, "# Generated by chzdev\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *site_specific_header(config_t config)
|
||||||
|
{
|
||||||
|
if (global_site_id != SITE_FALLBACK)
|
||||||
|
return misc_asprintf("site%d", global_site_id);
|
||||||
|
else
|
||||||
|
return config_to_str(config);
|
||||||
|
}
|
||||||
|
|
||||||
/* Write an export file header. */
|
/* Write an export file header. */
|
||||||
static void write_header(FILE *fd, config_t config, const char *type,
|
static void write_header(FILE *fd, config_t config, const char *type,
|
||||||
const char *id, int *first_ptr)
|
const char *id, int *first_ptr)
|
||||||
@@ -143,9 +168,9 @@ static void write_header(FILE *fd, config_t config, const char *type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (id)
|
if (id)
|
||||||
fprintf(fd, "[%s %s %s]\n", config_to_str(config), type, id);
|
fprintf(fd, "[%s %s %s]\n", site_specific_header(config), type, id);
|
||||||
else
|
else
|
||||||
fprintf(fd, "[%s %s]\n", config_to_str(config), type);
|
fprintf(fd, "[%s %s]\n", site_specific_header(config), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_exportable(struct device *dev, config_t config)
|
static int count_exportable(struct device *dev, config_t config)
|
||||||
@@ -154,7 +179,7 @@ static int count_exportable(struct device *dev, config_t config)
|
|||||||
struct setting *s;
|
struct setting *s;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
list = device_get_setting_list(dev, config);
|
list = device_get_setting_list(dev, config, global_site_id);
|
||||||
if (!list)
|
if (!list)
|
||||||
return 0;
|
return 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
@@ -408,7 +433,11 @@ static exit_code_t handle_header(const char *filename, int lineno,
|
|||||||
dev->active.exists = 1;
|
dev->active.exists = 1;
|
||||||
}
|
}
|
||||||
if (SCOPE_PERSISTENT(hdr->config)) {
|
if (SCOPE_PERSISTENT(hdr->config)) {
|
||||||
setting_list_clear(dev->persistent.settings);
|
if (import_site_id != SITE_FALLBACK)
|
||||||
|
setting_list_clear(dev->site_specific[import_site_id].settings);
|
||||||
|
else
|
||||||
|
setting_list_clear(dev->persistent.settings);
|
||||||
|
|
||||||
dev->persistent.exists = 1;
|
dev->persistent.exists = 1;
|
||||||
}
|
}
|
||||||
if (SCOPE_AUTOCONF(hdr->config)) {
|
if (SCOPE_AUTOCONF(hdr->config)) {
|
||||||
@@ -462,7 +491,7 @@ static exit_code_t handle_setting(const char *filename, int lineno,
|
|||||||
} else if (dev) {
|
} else if (dev) {
|
||||||
/* We're inside a device section. */
|
/* We're inside a device section. */
|
||||||
attribs = dev->subtype->dev_attribs;
|
attribs = dev->subtype->dev_attribs;
|
||||||
list = device_get_setting_list(dev, config);
|
list = device_get_setting_list(dev, config, SITE_FALLBACK);
|
||||||
} else
|
} else
|
||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
|
|
||||||
@@ -502,7 +531,8 @@ static bool empty_device(struct device *dev)
|
|||||||
return false;
|
return false;
|
||||||
if (util_list_is_empty(&dev->active.settings->list) &&
|
if (util_list_is_empty(&dev->active.settings->list) &&
|
||||||
util_list_is_empty(&dev->persistent.settings->list) &&
|
util_list_is_empty(&dev->persistent.settings->list) &&
|
||||||
util_list_is_empty(&dev->autoconf.settings->list))
|
util_list_is_empty(&dev->autoconf.settings->list) &&
|
||||||
|
import_site_id == SITE_FALLBACK)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -574,8 +604,9 @@ exit_code_t export_read(FILE *fd, const char *filename,
|
|||||||
ptrlist_add(objects, object_new(export_devtype,
|
ptrlist_add(objects, object_new(export_devtype,
|
||||||
dt));
|
dt));
|
||||||
} else if (dev) {
|
} else if (dev) {
|
||||||
ptrlist_add(objects, object_new(export_device,
|
if (global_site_id == import_site_id)
|
||||||
dev));
|
ptrlist_add(objects, object_new(export_device,
|
||||||
|
dev));
|
||||||
}
|
}
|
||||||
} else if (parse_setting(l, &key, &value)) {
|
} else if (parse_setting(l, &key, &value)) {
|
||||||
/* Found <key>=<value>. */
|
/* Found <key>=<value>. */
|
||||||
@@ -584,8 +615,10 @@ exit_code_t export_read(FILE *fd, const char *filename,
|
|||||||
"valid section\n");
|
"valid section\n");
|
||||||
rc = EXIT_FORMAT_ERROR;
|
rc = EXIT_FORMAT_ERROR;
|
||||||
} else {
|
} else {
|
||||||
rc = handle_setting(filename, lineno, key,
|
if (global_site_id == import_site_id ||
|
||||||
value, dt, dev, config);
|
import_site_id == SITE_FALLBACK)
|
||||||
|
rc = handle_setting(filename, lineno, key,
|
||||||
|
value, dt, dev, config);
|
||||||
}
|
}
|
||||||
free(key);
|
free(key);
|
||||||
free(value);
|
free(value);
|
||||||
|
|||||||
+1
-1
@@ -348,7 +348,7 @@ static void _add_setting(const char *filename, struct device *dev,
|
|||||||
struct attrib *a;
|
struct attrib *a;
|
||||||
struct setting_list *list;
|
struct setting_list *list;
|
||||||
|
|
||||||
list = device_get_setting_list(dev, config);
|
list = device_get_setting_list(dev, config, SITE_FALLBACK);
|
||||||
a = attrib_find(dev->subtype->dev_attribs, key);
|
a = attrib_find(dev->subtype->dev_attribs, key);
|
||||||
if (!a) {
|
if (!a) {
|
||||||
warnx("%s: Applying unknown device setting %s=%s", filename,
|
warnx("%s: Applying unknown device setting %s=%s", filename,
|
||||||
|
|||||||
+253
-34
@@ -32,6 +32,12 @@
|
|||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "table_types.h"
|
#include "table_types.h"
|
||||||
|
|
||||||
|
/* current site-id in action. By default, operations are always on fallback
|
||||||
|
* site; We need the current site-id as global variable to avoid excessive
|
||||||
|
* diff of simple function parameter modifications to pass this value.
|
||||||
|
*/
|
||||||
|
int global_site_id = SITE_FALLBACK;
|
||||||
|
|
||||||
/* Main program action. */
|
/* Main program action. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ACT_LIST,
|
ACT_LIST,
|
||||||
@@ -66,6 +72,7 @@ struct options {
|
|||||||
unsigned int pairs:1;
|
unsigned int pairs:1;
|
||||||
unsigned int verbose:1;
|
unsigned int verbose:1;
|
||||||
unsigned int quiet:1;
|
unsigned int quiet:1;
|
||||||
|
unsigned int site_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Makefile converts lszdev_usage.txt into C file which we include here. */
|
/* Makefile converts lszdev_usage.txt into C file which we include here. */
|
||||||
@@ -100,6 +107,7 @@ enum {
|
|||||||
OPT_QUIET = 'q',
|
OPT_QUIET = 'q',
|
||||||
OPT_PAIRS = 'P',
|
OPT_PAIRS = 'P',
|
||||||
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||||
|
OPT_SITE = 's',
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct opts_conflict conflict_list[] = {
|
static struct opts_conflict conflict_list[] = {
|
||||||
@@ -120,6 +128,8 @@ static struct opts_conflict conflict_list[] = {
|
|||||||
OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE, OPT_OFFLINE,
|
OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE, OPT_OFFLINE,
|
||||||
OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE, OPT_FAILED,
|
OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE, OPT_FAILED,
|
||||||
0),
|
0),
|
||||||
|
OPTS_CONFLICT(OPT_SITE,
|
||||||
|
OPT_TYPE),
|
||||||
OPTS_CONFLICT(OPT_ONLINE,
|
OPTS_CONFLICT(OPT_ONLINE,
|
||||||
OPT_OFFLINE),
|
OPT_OFFLINE),
|
||||||
OPTS_CONFLICT(OPT_QUIET,
|
OPTS_CONFLICT(OPT_QUIET,
|
||||||
@@ -159,11 +169,12 @@ static const struct option opt_list[] = {
|
|||||||
{ "pairs", no_argument, NULL, OPT_PAIRS },
|
{ "pairs", no_argument, NULL, OPT_PAIRS },
|
||||||
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
||||||
{ "quiet", no_argument, NULL, OPT_QUIET },
|
{ "quiet", no_argument, NULL, OPT_QUIET },
|
||||||
|
{ "site", required_argument, NULL, OPT_SITE },
|
||||||
{ NULL, no_argument, NULL, 0 },
|
{ NULL, no_argument, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Command line abbreviations. */
|
/* Command line abbreviations. */
|
||||||
static const char opt_str[] = ":tilLhvapPc:nVq";
|
static const char opt_str[] = ":tilLhvapPc:nVqs:";
|
||||||
|
|
||||||
/* Initialize options data structure. */
|
/* Initialize options data structure. */
|
||||||
static void init_options(struct options *opts)
|
static void init_options(struct options *opts)
|
||||||
@@ -172,6 +183,8 @@ static void init_options(struct options *opts)
|
|||||||
opts->select = select_opts_new();
|
opts->select = select_opts_new();
|
||||||
opts->columns = strlist_new();
|
opts->columns = strlist_new();
|
||||||
opts->base = strlist_new();
|
opts->base = strlist_new();
|
||||||
|
/* Default operations are on fallback site*/
|
||||||
|
opts->site_id = SITE_FALLBACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release memory used in options data structure. */
|
/* Release memory used in options data structure. */
|
||||||
@@ -212,6 +225,41 @@ static action_t get_action(struct options *opts)
|
|||||||
return ACT_LIST;
|
return ACT_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine the site information from the device */
|
||||||
|
static char *get_site_from_pers(struct device *dev)
|
||||||
|
{
|
||||||
|
int site, i, num = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SITES; i++) {
|
||||||
|
if (dev->site_specific[i].exists) {
|
||||||
|
site = i;
|
||||||
|
num++;
|
||||||
|
if (site == global_site_id && site != SITE_FALLBACK)
|
||||||
|
return misc_asprintf("s%d", site);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Incase of devices which do not have --site support, all the
|
||||||
|
* read configurations will be in the dev->persistent and not
|
||||||
|
* in dev->site_specific.
|
||||||
|
*/
|
||||||
|
if (num == 0 && dev->persistent.exists == 1 &&
|
||||||
|
global_site_id == SITE_FALLBACK)
|
||||||
|
return misc_asprintf("yes");
|
||||||
|
|
||||||
|
/* Found more site-specific information ? return s+ */
|
||||||
|
if (num > 1)
|
||||||
|
return misc_asprintf("s+");
|
||||||
|
|
||||||
|
if (num == 1)
|
||||||
|
if (site == SITE_FALLBACK)
|
||||||
|
return misc_asprintf("yes");
|
||||||
|
else
|
||||||
|
return misc_asprintf("s%d", site);
|
||||||
|
else
|
||||||
|
return misc_asprintf("no");
|
||||||
|
}
|
||||||
|
|
||||||
/* Check options data structure for syntax errors. */
|
/* Check options data structure for syntax errors. */
|
||||||
static exit_code_t check_options(struct options *opts,
|
static exit_code_t check_options(struct options *opts,
|
||||||
int specified[OPTS_MAX + 1], int op)
|
int specified[OPTS_MAX + 1], int op)
|
||||||
@@ -661,6 +709,27 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
|||||||
opts->quiet = 1;
|
opts->quiet = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_SITE:
|
||||||
|
/* --site */
|
||||||
|
/* User can specify only site-ids from 0 to 9 */
|
||||||
|
if (!is_valid_site(optarg)) {
|
||||||
|
syntax("Unsupported site ID\n");
|
||||||
|
return EXIT_USAGE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->site_id != SITE_FALLBACK) {
|
||||||
|
syntax("Cannot specify '--site' multiple "
|
||||||
|
"times\n");
|
||||||
|
return EXIT_USAGE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* site information is a persistent configuration.
|
||||||
|
* set opts->persistent here.
|
||||||
|
*/
|
||||||
|
opts->persistent = 1;
|
||||||
|
opts->site_id = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
/* Missing option argument. */
|
/* Missing option argument. */
|
||||||
syntax("Option '%s' requires an argument\n",
|
syntax("Option '%s' requires an argument\n",
|
||||||
@@ -718,7 +787,8 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
|||||||
opts->select->all = 1;
|
opts->select->all = 1;
|
||||||
else if (opts->config == config_active)
|
else if (opts->config == config_active)
|
||||||
opts->select->existing = 1;
|
opts->select->existing = 1;
|
||||||
else if (opts->config == config_persistent)
|
else if (opts->config == config_persistent ||
|
||||||
|
opts->site_id != SITE_FALLBACK)
|
||||||
opts->select->configured = 1;
|
opts->select->configured = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -782,34 +852,53 @@ static struct column *dev_table = COLUMN_ARRAY(
|
|||||||
);
|
);
|
||||||
|
|
||||||
static char *merge_str(const char *act, const char *pers, const char *ac,
|
static char *merge_str(const char *act, const char *pers, const char *ac,
|
||||||
config_t config)
|
config_t config, char **site, int max_sites)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
size_t len;
|
int i;
|
||||||
|
struct util_list *str_list;
|
||||||
|
|
||||||
|
str_list = strlist_new();
|
||||||
|
|
||||||
act = act ? act : "-";
|
act = act ? act : "-";
|
||||||
pers = pers ? pers : "-";
|
pers = pers ? pers : "-";
|
||||||
ac = ac ? ac : "-";
|
ac = ac ? ac : "-";
|
||||||
|
|
||||||
if (strcmp(act, pers) == 0 && strcmp(act, ac) == 0)
|
if (strcmp(act, pers) == 0 && strcmp(act, ac) == 0 &&
|
||||||
|
max_sites == 1)
|
||||||
return misc_strdup(act);
|
return misc_strdup(act);
|
||||||
|
|
||||||
len = strlen(act) + strlen(pers) + strlen(ac) + /* 3 * / + NUL */ 4;
|
|
||||||
str = misc_malloc(len);
|
|
||||||
|
|
||||||
if (SCOPE_ACTIVE(config))
|
if (SCOPE_ACTIVE(config))
|
||||||
strcat(str, act);
|
strlist_add(str_list, act);
|
||||||
if (SCOPE_PERSISTENT(config)) {
|
if (SCOPE_PERSISTENT(config)) {
|
||||||
if (*str)
|
if (global_site_id == SITE_FALLBACK) {
|
||||||
strcat(str, "/");
|
strlist_add(str_list, pers);
|
||||||
strcat(str, pers);
|
} else {
|
||||||
|
strlist_add(str_list, site[global_site_id]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (SCOPE_AUTOCONF(config)) {
|
if (SCOPE_AUTOCONF(config)) {
|
||||||
if (*str)
|
strlist_add(str_list, ac);
|
||||||
strcat(str, "/");
|
|
||||||
strcat(str, ac);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do not show site-specific information when user specifically
|
||||||
|
* asked for persistent configuration setting.
|
||||||
|
*/
|
||||||
|
if (SCOPE_PERSISTENT(config) && config != config_persistent) {
|
||||||
|
for (i = 0; i <= max_sites; i++) {
|
||||||
|
if (site[i])
|
||||||
|
strlist_add(str_list, site[i]);
|
||||||
|
else
|
||||||
|
if (str_list)
|
||||||
|
strlist_add(str_list, "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
str = strlist_flatten(str_list, "/");
|
||||||
|
strlist_free(str_list);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,12 +937,13 @@ static char *dev_table_get_modules(struct device *dev)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_attr(struct device *dev, const char *name, config_t config)
|
static char *get_attr(struct device *dev, const char *name, config_t config,
|
||||||
|
int site_id)
|
||||||
{
|
{
|
||||||
struct setting_list *list;
|
struct setting_list *list;
|
||||||
struct setting *s;
|
struct setting *s;
|
||||||
|
|
||||||
list = device_get_setting_list(dev, config);
|
list = device_get_setting_list(dev, config, site_id);
|
||||||
if (!list)
|
if (!list)
|
||||||
return NULL;
|
return NULL;
|
||||||
s = setting_list_find(list, name);
|
s = setting_list_find(list, name);
|
||||||
@@ -868,30 +958,61 @@ static char *get_attr(struct device *dev, const char *name, config_t config)
|
|||||||
return misc_strdup(s->value);
|
return misc_strdup(s->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When lszdev --info, make sure that the output contains only the
|
||||||
|
* valid site information. Check if the site is valid and then add
|
||||||
|
* the new SITEn column. For SITE_FALLBACK, the PERSISTENT column will
|
||||||
|
* be used.
|
||||||
|
*/
|
||||||
|
static bool is_site_show(int site_id, int current_site)
|
||||||
|
{
|
||||||
|
if (site_id == SITE_FALLBACK || site_id == current_site)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return string for attribute with specified @name for device @dev. */
|
/* Return string for attribute with specified @name for device @dev. */
|
||||||
static char *dev_table_get_attr(struct device *dev, const char *attr,
|
static char *dev_table_get_attr(struct device *dev, const char *attr,
|
||||||
config_t config)
|
config_t config)
|
||||||
{
|
{
|
||||||
char *act = NULL, *pers = NULL, *ac = NULL, *str;
|
char *act = NULL, *pers = NULL, *ac = NULL, *str;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
char *site[NUM_USER_SITES];
|
||||||
|
int i;
|
||||||
|
static int max_sites;
|
||||||
|
|
||||||
name = strchr(attr, ':');
|
name = strchr(attr, ':');
|
||||||
if (!name)
|
if (!name)
|
||||||
return NULL;
|
return NULL;
|
||||||
name++;
|
name++;
|
||||||
|
|
||||||
|
/* To get the default settings on any configuration, make sure that
|
||||||
|
* the site_id is specified as SITE_FALLBACK. Any value of site_id
|
||||||
|
* less than SITE_FALLBACK will endup providing site-specific attribute
|
||||||
|
* settings.
|
||||||
|
*/
|
||||||
if (SCOPE_ACTIVE(config))
|
if (SCOPE_ACTIVE(config))
|
||||||
act = get_attr(dev, name, config_active);
|
act = get_attr(dev, name, config_active, SITE_FALLBACK);
|
||||||
if (SCOPE_PERSISTENT(config))
|
if (SCOPE_PERSISTENT(config)) {
|
||||||
pers = get_attr(dev, name, config_persistent);
|
pers = get_attr(dev, name, config_persistent, SITE_FALLBACK);
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++)
|
||||||
|
site[i] = get_attr(dev, name, config, i);
|
||||||
|
}
|
||||||
if (SCOPE_AUTOCONF(config))
|
if (SCOPE_AUTOCONF(config))
|
||||||
ac = get_attr(dev, name, config_autoconf);
|
ac = get_attr(dev, name, config_autoconf, SITE_FALLBACK);
|
||||||
|
|
||||||
str = merge_str(act, pers, ac, config);
|
for (i = 0; i < NUM_USER_SITES; i++)
|
||||||
|
if (dev->site_specific[i].exists)
|
||||||
|
max_sites = (max_sites < i) ? i : max_sites;
|
||||||
|
|
||||||
|
str = merge_str(act, pers, ac, config, site, max_sites);
|
||||||
free(act);
|
free(act);
|
||||||
free(pers);
|
free(pers);
|
||||||
free(ac);
|
free(ac);
|
||||||
|
|
||||||
|
if (SCOPE_PERSISTENT(config))
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++)
|
||||||
|
free(site[i]);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,9 +1059,9 @@ static char *dev_table_get_value(void *item, int id, const char *heading,
|
|||||||
return misc_strdup(YESNO(dev->active.exists ||
|
return misc_strdup(YESNO(dev->active.exists ||
|
||||||
dev->active.definable));
|
dev->active.definable));
|
||||||
case dev_pers:
|
case dev_pers:
|
||||||
if (!dev->persistent.exists && dev->autoconf.exists)
|
if (!is_dev_pers(dev) && dev->autoconf.exists)
|
||||||
return misc_strdup("auto");
|
return misc_strdup("auto");
|
||||||
return misc_strdup(YESNO(dev->persistent.exists));
|
return get_site_from_pers(dev);
|
||||||
case dev_auto:
|
case dev_auto:
|
||||||
return misc_strdup(YESNO(dev->autoconf.exists));
|
return misc_strdup(YESNO(dev->autoconf.exists));
|
||||||
case dev_online:
|
case dev_online:
|
||||||
@@ -1032,11 +1153,17 @@ static struct util_list *dev_table_build(struct options *opts,
|
|||||||
|
|
||||||
/* Only process existing devices. */
|
/* Only process existing devices. */
|
||||||
active = dev->active.exists || dev->active.definable;
|
active = dev->active.exists || dev->active.definable;
|
||||||
persistent = dev->persistent.exists;
|
persistent = (int)is_dev_pers(dev);
|
||||||
autoconf = dev->autoconf.exists;
|
autoconf = dev->autoconf.exists;
|
||||||
if (!active && !persistent && !autoconf)
|
if (!active && !persistent && !autoconf)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* with --site option, we consider only the persistent
|
||||||
|
* configurations available on the specified site-id.
|
||||||
|
* ignore active and autoconf here
|
||||||
|
*/
|
||||||
|
if (!persistent && global_site_id != SITE_FALLBACK)
|
||||||
|
continue;
|
||||||
ptrlist_add(devices, dev);
|
ptrlist_add(devices, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1107,6 +1234,16 @@ enum settings_table_id {
|
|||||||
settings_active,
|
settings_active,
|
||||||
settings_persistent,
|
settings_persistent,
|
||||||
settings_autoconf,
|
settings_autoconf,
|
||||||
|
settings_site0,
|
||||||
|
settings_site1,
|
||||||
|
settings_site2,
|
||||||
|
settings_site3,
|
||||||
|
settings_site4,
|
||||||
|
settings_site5,
|
||||||
|
settings_site6,
|
||||||
|
settings_site7,
|
||||||
|
settings_site8,
|
||||||
|
settings_site9,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct column *settings_table = COLUMN_ARRAY(
|
static struct column *settings_table = COLUMN_ARRAY(
|
||||||
@@ -1114,17 +1251,29 @@ static struct column *settings_table = COLUMN_ARRAY(
|
|||||||
COLUMN("READONLY", align_left, settings_readonly, 1, ""),
|
COLUMN("READONLY", align_left, settings_readonly, 1, ""),
|
||||||
COLUMN("ACTIVE", align_left, settings_active, 1, ""),
|
COLUMN("ACTIVE", align_left, settings_active, 1, ""),
|
||||||
COLUMN("PERSISTENT", align_left, settings_persistent, 1, ""),
|
COLUMN("PERSISTENT", align_left, settings_persistent, 1, ""),
|
||||||
COLUMN("AUTOCONF", align_left, settings_autoconf, 0, "")
|
COLUMN("AUTOCONF", align_left, settings_autoconf, 0, ""),
|
||||||
|
COLUMN("SITE0", align_left, settings_site0, 0, ""),
|
||||||
|
COLUMN("SITE1", align_left, settings_site1, 0, ""),
|
||||||
|
COLUMN("SITE2", align_left, settings_site2, 0, ""),
|
||||||
|
COLUMN("SITE3", align_left, settings_site3, 0, ""),
|
||||||
|
COLUMN("SITE4", align_left, settings_site4, 0, ""),
|
||||||
|
COLUMN("SITE5", align_left, settings_site5, 0, ""),
|
||||||
|
COLUMN("SITE6", align_left, settings_site6, 0, ""),
|
||||||
|
COLUMN("SITE7", align_left, settings_site7, 0, ""),
|
||||||
|
COLUMN("SITE8", align_left, settings_site8, 0, ""),
|
||||||
|
COLUMN("SITE9", align_left, settings_site9, 0, "")
|
||||||
);
|
);
|
||||||
|
|
||||||
static struct util_list *settings_table_build(struct setting_list *active,
|
static struct util_list *settings_table_build(struct setting_list *active,
|
||||||
struct setting_list *persistent,
|
struct setting_list *persistent,
|
||||||
struct setting_list *autoconf,
|
struct setting_list *autoconf,
|
||||||
|
struct device *dev,
|
||||||
bool readonly)
|
bool readonly)
|
||||||
{
|
{
|
||||||
struct util_list *names, *items;
|
struct util_list *names, *items;
|
||||||
struct setting *s;
|
struct setting *s;
|
||||||
struct strlist_node *str;
|
struct strlist_node *str;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Get a list of all configured attributes. */
|
/* Get a list of all configured attributes. */
|
||||||
names = strlist_new();
|
names = strlist_new();
|
||||||
@@ -1139,6 +1288,11 @@ static struct util_list *settings_table_build(struct setting_list *active,
|
|||||||
if (persistent && !readonly) {
|
if (persistent && !readonly) {
|
||||||
util_list_iterate(&persistent->list, s)
|
util_list_iterate(&persistent->list, s)
|
||||||
strlist_add(names, s->name);
|
strlist_add(names, s->name);
|
||||||
|
if (dev) {
|
||||||
|
for (i = 0; i < NUM_SITES; i++)
|
||||||
|
util_list_iterate(&dev->site_specific[i].settings->list, s)
|
||||||
|
strlist_add(names, s->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (autoconf && !readonly) {
|
if (autoconf && !readonly) {
|
||||||
util_list_iterate(&autoconf->list, s)
|
util_list_iterate(&autoconf->list, s)
|
||||||
@@ -1159,6 +1313,7 @@ struct settings_table_data {
|
|||||||
struct setting_list *active;
|
struct setting_list *active;
|
||||||
struct setting_list *persistent;
|
struct setting_list *persistent;
|
||||||
struct setting_list *autoconf;
|
struct setting_list *autoconf;
|
||||||
|
struct setting_list *sites[NUM_SITES];
|
||||||
int pairs;
|
int pairs;
|
||||||
bool readonly;
|
bool readonly;
|
||||||
};
|
};
|
||||||
@@ -1184,6 +1339,37 @@ static char *settings_table_get_value(void *item, int id, const char *heading,
|
|||||||
case settings_autoconf:
|
case settings_autoconf:
|
||||||
list = stdata->autoconf;
|
list = stdata->autoconf;
|
||||||
break;
|
break;
|
||||||
|
case settings_site0:
|
||||||
|
list = stdata->sites[0];
|
||||||
|
break;
|
||||||
|
case settings_site1:
|
||||||
|
list = stdata->sites[1];
|
||||||
|
break;
|
||||||
|
case settings_site2:
|
||||||
|
list = stdata->sites[2];
|
||||||
|
break;
|
||||||
|
case settings_site3:
|
||||||
|
list = stdata->sites[3];
|
||||||
|
break;
|
||||||
|
case settings_site4:
|
||||||
|
list = stdata->sites[4];
|
||||||
|
break;
|
||||||
|
case settings_site5:
|
||||||
|
list = stdata->sites[5];
|
||||||
|
break;
|
||||||
|
case settings_site6:
|
||||||
|
list = stdata->sites[6];
|
||||||
|
break;
|
||||||
|
case settings_site7:
|
||||||
|
list = stdata->sites[7];
|
||||||
|
break;
|
||||||
|
case settings_site8:
|
||||||
|
list = stdata->sites[8];
|
||||||
|
break;
|
||||||
|
case settings_site9:
|
||||||
|
list = stdata->sites[9];
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1208,16 +1394,18 @@ static char *settings_table_get_value(void *item, int id, const char *heading,
|
|||||||
static void settings_table_print(struct setting_list *active,
|
static void settings_table_print(struct setting_list *active,
|
||||||
struct setting_list *persistent,
|
struct setting_list *persistent,
|
||||||
struct setting_list *autoconf,
|
struct setting_list *autoconf,
|
||||||
|
struct device *dev,
|
||||||
struct options *opts, int ind, bool readonly,
|
struct options *opts, int ind, bool readonly,
|
||||||
bool neednl)
|
bool neednl)
|
||||||
{
|
{
|
||||||
struct util_list *items;
|
struct util_list *items;
|
||||||
struct settings_table_data data;
|
struct settings_table_data data;
|
||||||
|
int i;
|
||||||
|
|
||||||
items = settings_table_build(
|
items = settings_table_build(
|
||||||
SCOPE_ACTIVE(opts->config) ? active : NULL,
|
SCOPE_ACTIVE(opts->config) ? active : NULL,
|
||||||
SCOPE_PERSISTENT(opts->config) ? persistent : NULL,
|
SCOPE_PERSISTENT(opts->config) ? persistent : NULL,
|
||||||
autoconf, readonly);
|
autoconf, dev, readonly);
|
||||||
if (util_list_is_empty(items)) {
|
if (util_list_is_empty(items)) {
|
||||||
if (!opts->pairs && !readonly)
|
if (!opts->pairs && !readonly)
|
||||||
indent(ind, "%sNo settings found\n",
|
indent(ind, "%sNo settings found\n",
|
||||||
@@ -1232,14 +1420,28 @@ static void settings_table_print(struct setting_list *active,
|
|||||||
table_set_default(settings_table, settings_active,
|
table_set_default(settings_table, settings_active,
|
||||||
SCOPE_ACTIVE(opts->config));
|
SCOPE_ACTIVE(opts->config));
|
||||||
table_set_default(settings_table, settings_persistent,
|
table_set_default(settings_table, settings_persistent,
|
||||||
|
is_site_show(opts->site_id, SITE_FALLBACK) &&
|
||||||
SCOPE_PERSISTENT(opts->config) && !readonly ? 1 : 0);
|
SCOPE_PERSISTENT(opts->config) && !readonly ? 1 : 0);
|
||||||
table_set_default(settings_table, settings_autoconf,
|
table_set_default(settings_table, settings_autoconf,
|
||||||
(SCOPE_AUTOCONF(opts->config) || autoconf) &&
|
(SCOPE_AUTOCONF(opts->config) || autoconf) &&
|
||||||
!readonly ? 1 : 0);
|
!readonly ? 1 : 0);
|
||||||
|
if (dev) {
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++)
|
||||||
|
table_set_default(settings_table, settings_site0 + i,
|
||||||
|
SCOPE_PERSISTENT(opts->config) &&
|
||||||
|
is_site_show(opts->site_id, i) &&
|
||||||
|
dev->site_specific[i].exists &&
|
||||||
|
!readonly ? 1 : 0);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SITES; i++)
|
||||||
|
data.sites[i] = dev->site_specific[i].settings;
|
||||||
|
}
|
||||||
|
|
||||||
data.active = active;
|
data.active = active;
|
||||||
data.persistent = persistent;
|
data.persistent = persistent;
|
||||||
data.autoconf = autoconf;
|
data.autoconf = autoconf;
|
||||||
data.pairs = opts->pairs;
|
data.pairs = opts->pairs;
|
||||||
|
|
||||||
table_print(settings_table, settings_table_get_value, &data, items,
|
table_print(settings_table, settings_table_get_value, &data, items,
|
||||||
NULL, 1, opts->pairs, ind, 0);
|
NULL, 1, opts->pairs, ind, 0);
|
||||||
|
|
||||||
@@ -1320,7 +1522,7 @@ static exit_code_t do_info_type(struct options *opts)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
settings_table_print(dt->active_settings,
|
settings_table_print(dt->active_settings,
|
||||||
dt->persistent_settings, NULL, opts,
|
dt->persistent_settings, NULL, NULL, opts,
|
||||||
INFO_INDENT, false, false);
|
INFO_INDENT, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1346,7 +1548,7 @@ static void do_list_columns(struct options *opts)
|
|||||||
static void do_info_one_device(struct device *dev, struct options *opts)
|
static void do_info_one_device(struct device *dev, struct options *opts)
|
||||||
{
|
{
|
||||||
struct subtype *st = dev->subtype;
|
struct subtype *st = dev->subtype;
|
||||||
char *names, *bdevs, *cdevs, *ndevs, *modules, *online, *path, *key;
|
char *names, *bdevs, *cdevs, *ndevs, *modules, *online, *path, *key, *sites;
|
||||||
const char *id, *type, *exists, *persist, *ac, *prefix;
|
const char *id, *type, *exists, *persist, *ac, *prefix;
|
||||||
struct util_list *resources, *errors;
|
struct util_list *resources, *errors;
|
||||||
struct strlist_node *s;
|
struct strlist_node *s;
|
||||||
@@ -1367,6 +1569,7 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
|||||||
exists = YESNO(dev->active.exists || dev->active.definable);
|
exists = YESNO(dev->active.exists || dev->active.definable);
|
||||||
persist = YESNO(dev->persistent.exists);
|
persist = YESNO(dev->persistent.exists);
|
||||||
ac = YESNO(dev->autoconf.exists);
|
ac = YESNO(dev->autoconf.exists);
|
||||||
|
sites = device_get_sites(dev);
|
||||||
|
|
||||||
/* Print information. */
|
/* Print information. */
|
||||||
if (opts->pairs) {
|
if (opts->pairs) {
|
||||||
@@ -1384,6 +1587,9 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
|||||||
print_pair("ONLINE", online);
|
print_pair("ONLINE", online);
|
||||||
print_pair("EXISTS", exists);
|
print_pair("EXISTS", exists);
|
||||||
print_pair("PERSISTENT", persist);
|
print_pair("PERSISTENT", persist);
|
||||||
|
if (*sites)
|
||||||
|
print_pair("SITES", sites);
|
||||||
|
|
||||||
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
|
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
|
||||||
print_pair("AUTOCONF", ac);
|
print_pair("AUTOCONF", ac);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
@@ -1413,6 +1619,9 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
|||||||
print_info("Persistent", persist);
|
print_info("Persistent", persist);
|
||||||
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
|
if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
|
||||||
print_info("Auto-configured", ac);
|
print_info("Auto-configured", ac);
|
||||||
|
if (*sites)
|
||||||
|
print_info("Sites", sites);
|
||||||
|
|
||||||
if (errors) {
|
if (errors) {
|
||||||
first = true;
|
first = true;
|
||||||
util_list_iterate(errors, s) {
|
util_list_iterate(errors, s) {
|
||||||
@@ -1453,17 +1662,17 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
|
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
|
||||||
dev->persistent.exists ? dev->persistent.settings :
|
is_dev_pers(dev) ? dev->persistent.settings :
|
||||||
NULL,
|
NULL,
|
||||||
dev->autoconf.exists ? dev->autoconf.settings :
|
dev->autoconf.exists ? dev->autoconf.settings :
|
||||||
NULL,
|
NULL, dev,
|
||||||
opts, INFO_INDENT, false, !opts->pairs);
|
opts, INFO_INDENT, false, !opts->pairs);
|
||||||
|
|
||||||
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
|
settings_table_print(dev->active.exists ? dev->active.settings : NULL,
|
||||||
dev->persistent.exists ? dev->persistent.settings :
|
is_dev_pers(dev) ? dev->persistent.settings :
|
||||||
NULL,
|
NULL,
|
||||||
dev->autoconf.exists ? dev->autoconf.settings :
|
dev->autoconf.exists ? dev->autoconf.settings :
|
||||||
NULL,
|
NULL, dev,
|
||||||
opts, INFO_INDENT, true, !opts->pairs);
|
opts, INFO_INDENT, true, !opts->pairs);
|
||||||
|
|
||||||
strlist_free(errors);
|
strlist_free(errors);
|
||||||
@@ -1474,6 +1683,7 @@ static void do_info_one_device(struct device *dev, struct options *opts)
|
|||||||
free(cdevs);
|
free(cdevs);
|
||||||
free(bdevs);
|
free(bdevs);
|
||||||
free(names);
|
free(names);
|
||||||
|
free(sites);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform --info on devices. */
|
/* Perform --info on devices. */
|
||||||
@@ -1518,10 +1728,18 @@ static exit_code_t do_info_devices(struct options *opts)
|
|||||||
|
|
||||||
/* Only process existing devices. */
|
/* Only process existing devices. */
|
||||||
active = dev->active.exists || dev->active.definable;
|
active = dev->active.exists || dev->active.definable;
|
||||||
persistent = dev->persistent.exists;
|
persistent = (int)is_dev_pers(dev);
|
||||||
autoconf = dev->autoconf.exists;
|
autoconf = dev->autoconf.exists;
|
||||||
if (!active && !persistent && !autoconf)
|
if (!active && !persistent && !autoconf)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* with --site option, we consider only the persistent
|
||||||
|
* configurations available on the specified site-id.
|
||||||
|
* ignore active and autoconf here
|
||||||
|
*/
|
||||||
|
if (!persistent && global_site_id != SITE_FALLBACK)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (found > 0)
|
if (found > 0)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
do_info_one_device(dev, opts);
|
do_info_one_device(dev, opts);
|
||||||
@@ -1558,6 +1776,7 @@ int main(int argc, char *argv[])
|
|||||||
/* Set globals. */
|
/* Set globals. */
|
||||||
verbose = opts.verbose;
|
verbose = opts.verbose;
|
||||||
quiet = opts.quiet;
|
quiet = opts.quiet;
|
||||||
|
global_site_id = opts.site_id;
|
||||||
path_set_base(opts.base);
|
path_set_base(opts.base);
|
||||||
if (opts.pairs)
|
if (opts.pairs)
|
||||||
set_stdout_data();
|
set_stdout_data();
|
||||||
|
|||||||
@@ -42,5 +42,6 @@ OPTIONS
|
|||||||
--base PATH Use PATH as base for accessing files
|
--base PATH Use PATH as base for accessing files
|
||||||
--pairs Produce output in KEY="VALUE" format
|
--pairs Produce output in KEY="VALUE" format
|
||||||
--auto-conf Only show auto-configuration data
|
--auto-conf Only show auto-configuration data
|
||||||
|
-s, --site ID Only show data configured for the specified site
|
||||||
-V, --verbose Print additional run-time information
|
-V, --verbose Print additional run-time information
|
||||||
-q, --quiet Print only minimal run-time information
|
-q, --quiet Print only minimal run-time information
|
||||||
|
|||||||
@@ -1695,3 +1695,20 @@ char *misc_strrstr(const char *haystack, const char *needle)
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if the site mentioned is valid */
|
||||||
|
bool is_valid_site(const char *str)
|
||||||
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
long site_id;
|
||||||
|
|
||||||
|
site_id = strtol(str, &ptr, 10);
|
||||||
|
|
||||||
|
if (*ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (site_id < 0 || site_id >= NUM_USER_SITES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -404,3 +404,13 @@ char *path_get_bus_attr(const char *bus, const char *attr)
|
|||||||
{
|
{
|
||||||
return path_get("/sys/bus/%s/%s", bus, attr);
|
return path_get("/sys/bus/%s/%s", bus, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return path will be with ZDEV_PREFIX oon PATH_UDEV_RULES */
|
||||||
|
char *path_get_zdev_rule(const char *name)
|
||||||
|
{
|
||||||
|
const char *path = PATH_UDEV_RULES;
|
||||||
|
|
||||||
|
/* Create file. */
|
||||||
|
return path_get("%s/%s-%s%s", path,
|
||||||
|
ZDEV_PREFIX, name, UDEV_SUFFIX);
|
||||||
|
}
|
||||||
|
|||||||
+53
-8
@@ -83,23 +83,58 @@ static bool is_zdev_early_0(struct selected_dev_node *sel)
|
|||||||
{
|
{
|
||||||
struct setting *s;
|
struct setting *s;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
dev = device_list_find(sel->st->devices, sel->id, NULL);
|
dev = device_list_find(sel->st->devices, sel->id, NULL);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return false;
|
return false;
|
||||||
s = setting_list_find(dev->persistent.settings,
|
|
||||||
internal_attr_early.name);
|
for (i = 0; i < NUM_SITES; i++) {
|
||||||
if (!s)
|
s = setting_list_find(dev->site_specific[i].settings,
|
||||||
|
internal_attr_early.name);
|
||||||
|
if (!s)
|
||||||
|
return false;
|
||||||
|
if (s->specified && strcmp(s->value, "0") == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When site-specific settings has zdev:early configured, it is not
|
||||||
|
* detected with the --by-attr functionality of select_devices. Instead
|
||||||
|
* we will have to iterate through each configuration and check if there
|
||||||
|
* is a zdev:early set in the device. This is usually applicable only in
|
||||||
|
* the case of deconfigure-all command, because, for all other commands
|
||||||
|
* we copy the settings-in-action to the persistent settings and do the
|
||||||
|
* processing there.
|
||||||
|
*/
|
||||||
|
static bool is_zdev_early_site(struct selected_dev_node *sel)
|
||||||
|
{
|
||||||
|
struct setting *s;
|
||||||
|
struct device *dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (global_site_id != SITE_FALLBACK)
|
||||||
return false;
|
return false;
|
||||||
if (s->specified && strcmp(s->value, "0") == 0)
|
|
||||||
return true;
|
dev = device_list_find(sel->st->devices, sel->id, NULL);
|
||||||
|
if (!dev)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_SITES; i++) {
|
||||||
|
s = setting_list_find(dev->site_specific[i].settings,
|
||||||
|
internal_attr_early.name);
|
||||||
|
if (s)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine if initial RAM-disk needs updating. If so, run the corresponding
|
/* Determine if initial RAM-disk needs updating. If so, run the corresponding
|
||||||
* scripts if available. */
|
* scripts if available. */
|
||||||
exit_code_t initrd_check(bool all_pers)
|
exit_code_t initrd_check(bool all_pers, int site_validate)
|
||||||
{
|
{
|
||||||
struct util_list *selected, *params, *mod = strlist_new();
|
struct util_list *selected, *params, *mod = strlist_new();
|
||||||
struct selected_dev_node *sel;
|
struct selected_dev_node *sel;
|
||||||
@@ -142,7 +177,12 @@ exit_code_t initrd_check(bool all_pers)
|
|||||||
}
|
}
|
||||||
/* Finally add devices with zdev:early=1. */
|
/* Finally add devices with zdev:early=1. */
|
||||||
select = select_opts_new();
|
select = select_opts_new();
|
||||||
strlist_add(&select->by_attr, "%s=1", INTERNAL_ATTR_EARLY);
|
/* If we need information from multiple site, we cannot use the by-attr
|
||||||
|
* functionality of select_devices function. Instead we have to iterate
|
||||||
|
* through individual devices and site settings to find the key.
|
||||||
|
*/
|
||||||
|
if (!site_validate)
|
||||||
|
strlist_add(&select->by_attr, "%s=1", INTERNAL_ATTR_EARLY);
|
||||||
select_devices(select, selected, 1, 0, 0,
|
select_devices(select, selected, 1, 0, 0,
|
||||||
config_active | config_persistent, scope_mandatory,
|
config_active | config_persistent, scope_mandatory,
|
||||||
err_ignore);
|
err_ignore);
|
||||||
@@ -162,7 +202,12 @@ check_mod:
|
|||||||
/* Check devices. */
|
/* Check devices. */
|
||||||
dev = device_list_find(sel->st->devices, sel->id, NULL);
|
dev = device_list_find(sel->st->devices, sel->id, NULL);
|
||||||
if (dev && dev->persistent.exists &&
|
if (dev && dev->persistent.exists &&
|
||||||
(device_needs_writing(dev, config_persistent) || force)) {
|
(device_needs_writing(dev, config_persistent) || force) &&
|
||||||
|
!site_validate) {
|
||||||
|
strlist_add(mod, "%s %s", dev->subtype->devname,
|
||||||
|
dev->id);
|
||||||
|
} else if (site_validate && is_zdev_early_site(sel) &&
|
||||||
|
device_needs_writing(dev, config_persistent)) {
|
||||||
strlist_add(mod, "%s %s", dev->subtype->devname,
|
strlist_add(mod, "%s %s", dev->subtype->devname,
|
||||||
dev->id);
|
dev->id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "setting.h"
|
#include "setting.h"
|
||||||
#include "udev.h"
|
#include "udev.h"
|
||||||
|
#include "zdev_id.h"
|
||||||
|
|
||||||
int udev_need_settle = 0;
|
int udev_need_settle = 0;
|
||||||
int udev_no_settle;
|
int udev_no_settle;
|
||||||
@@ -137,3 +138,61 @@ void udev_add_internal_from_entry(struct setting_list *list,
|
|||||||
out:
|
out:
|
||||||
free(copy);
|
free(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the UDEV rule that determines the active SITE_ID
|
||||||
|
*/
|
||||||
|
exit_code_t udev_write_site_rule(void)
|
||||||
|
{
|
||||||
|
char *path, *name = "zdev-id";
|
||||||
|
exit_code_t rc = EXIT_OK;
|
||||||
|
FILE *fd;
|
||||||
|
|
||||||
|
/* Create file. */
|
||||||
|
path = path_get_zdev_rule(name);
|
||||||
|
|
||||||
|
if (!util_path_exists(path)) {
|
||||||
|
rc = path_create(path);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = misc_fopen(path, "w");
|
||||||
|
if (!fd) {
|
||||||
|
error("Could not write to file %s: %s\n", path,
|
||||||
|
strerror(errno));
|
||||||
|
rc = EXIT_RUNTIME_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
fprintf(fd, "# Generated by chzdev\n");
|
||||||
|
fprintf(fd, "\n");
|
||||||
|
/* We have to make sure that we are not trying to determine the SITE_ID
|
||||||
|
* for all the corresponding uevent. Check if the SITE_ID is already
|
||||||
|
* determined by reading the file /run/zdev_site_id; and if it is not
|
||||||
|
* available, execute the zdev_id program and determine the SITE_ID and
|
||||||
|
* create the new zdev_site_id file for next run.
|
||||||
|
*/
|
||||||
|
fprintf(fd, "TEST!=\"%s\", IMPORT{program}="
|
||||||
|
"\"%s/zdev_id\",GOTO=\"end\"\n", ZDEV_SITE_ID_FILE,
|
||||||
|
TOOLS_LIBDIR);
|
||||||
|
fprintf(fd, "IMPORT{file}=\"%s\"\n", ZDEV_SITE_ID_FILE);
|
||||||
|
fprintf(fd, "LABEL=\"end\"\n");
|
||||||
|
|
||||||
|
if (misc_fclose(fd))
|
||||||
|
warn("Could not close file %s: %s\n", path, strerror(errno));
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(path);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_legacy_rule(struct util_udev_file *file)
|
||||||
|
{
|
||||||
|
struct util_udev_line_node *line;
|
||||||
|
|
||||||
|
util_list_iterate(&file->lines, line)
|
||||||
|
if (starts_with(line->line, SITE_BLOCK_START))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
+254
-31
@@ -26,6 +26,8 @@
|
|||||||
#include "udev.h"
|
#include "udev.h"
|
||||||
#include "udev_ccw.h"
|
#include "udev_ccw.h"
|
||||||
|
|
||||||
|
#define SITE_FALLBACK_SUFFIX "fb"
|
||||||
|
|
||||||
/* Check if a udev rule for the specified ccw device exists. */
|
/* Check if a udev rule for the specified ccw device exists. */
|
||||||
bool udev_ccw_exists(const char *type, const char *id, bool autoconf)
|
bool udev_ccw_exists(const char *type, const char *id, bool autoconf)
|
||||||
{
|
{
|
||||||
@@ -79,10 +81,68 @@ out:
|
|||||||
free(copy);
|
free(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_site_from_line(char *line, int *site, bool *in_site)
|
||||||
|
{
|
||||||
|
char site_str[2];
|
||||||
|
|
||||||
|
if (starts_with(line, SITE_BLOCK_START)) {
|
||||||
|
memcpy(site_str, line + sizeof(SITE_BLOCK_START), 2);
|
||||||
|
if (strcmp(site_str, "fb") != 0)
|
||||||
|
*site = atoi(site_str);
|
||||||
|
else
|
||||||
|
*site = SITE_FALLBACK;
|
||||||
|
*in_site = true;
|
||||||
|
} else if (starts_with(line, SITE_BLOCK_END)) {
|
||||||
|
memcpy(site_str, line + sizeof(SITE_BLOCK_END), 2);
|
||||||
|
if (strcmp(site_str, "fb") != 0)
|
||||||
|
*site = atoi(site_str);
|
||||||
|
else
|
||||||
|
*site = SITE_FALLBACK;
|
||||||
|
*in_site = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_state_copy(struct device_state *dst, struct device_state *src)
|
||||||
|
{
|
||||||
|
setting_list_free(dst->settings);
|
||||||
|
dst->settings = setting_list_copy(src->settings);
|
||||||
|
dst->exists = src->exists;
|
||||||
|
dst->modified = src->modified;
|
||||||
|
dst->deconfigured = src->deconfigured;
|
||||||
|
dst->blacklisted = src->blacklisted;
|
||||||
|
dst->definable = src->definable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract per-site CCW device settings from a CCW device udev rule file. */
|
||||||
|
static void _udev_file_get_settings_new(struct util_udev_file *file,
|
||||||
|
struct attrib **attribs,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
struct util_udev_line_node *line;
|
||||||
|
struct util_udev_entry_node *entry;
|
||||||
|
int site_id = SITE_FALLBACK;
|
||||||
|
struct setting_list *list;
|
||||||
|
bool in_site = false;
|
||||||
|
|
||||||
|
util_list_iterate(&file->lines, line) {
|
||||||
|
get_site_from_line(line->line, &site_id, &in_site);
|
||||||
|
if (!in_site || site_id >= NUM_SITES || site_id < 0)
|
||||||
|
continue;
|
||||||
|
entry = util_list_start(&line->entries);
|
||||||
|
if (!entry)
|
||||||
|
continue;
|
||||||
|
list = dev->site_specific[site_id].settings;
|
||||||
|
add_setting_from_entry(list, entry, attribs);
|
||||||
|
dev->site_specific[site_id].exists = 1;
|
||||||
|
if (site_id == global_site_id)
|
||||||
|
dev_state_copy(&dev->persistent, &dev->site_specific[site_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Extract CCW device settings from a CCW device udev rule file. */
|
/* Extract CCW device settings from a CCW device udev rule file. */
|
||||||
static void udev_file_get_settings(struct util_udev_file *file,
|
static void _udev_file_get_settings_legacy(struct util_udev_file *file,
|
||||||
struct attrib **attribs,
|
struct attrib **attribs,
|
||||||
struct setting_list *list)
|
struct setting_list *list)
|
||||||
{
|
{
|
||||||
struct util_udev_line_node *line;
|
struct util_udev_line_node *line;
|
||||||
struct util_udev_entry_node *entry;
|
struct util_udev_entry_node *entry;
|
||||||
@@ -95,6 +155,22 @@ static void udev_file_get_settings(struct util_udev_file *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void udev_file_get_settings(struct util_udev_file *file,
|
||||||
|
struct attrib **attribs,
|
||||||
|
struct device *dev,
|
||||||
|
bool autoconf)
|
||||||
|
{
|
||||||
|
struct device_state *state = autoconf ? &dev->autoconf :
|
||||||
|
&dev->persistent;
|
||||||
|
|
||||||
|
if (is_legacy_rule(file) || autoconf) {
|
||||||
|
_udev_file_get_settings_legacy(file, attribs, state->settings);
|
||||||
|
state->exists = 1;
|
||||||
|
} else {
|
||||||
|
_udev_file_get_settings_new(file, attribs, dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the persistent configuration of a CCW device from a udev rule. */
|
/* Read the persistent configuration of a CCW device from a udev rule. */
|
||||||
exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf)
|
exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf)
|
||||||
{
|
{
|
||||||
@@ -113,8 +189,7 @@ exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf)
|
|||||||
warn_once("Warning: Invalid udev rule: %s\n", path);
|
warn_once("Warning: Invalid udev rule: %s\n", path);
|
||||||
state->exists = 0;
|
state->exists = 0;
|
||||||
} else {
|
} else {
|
||||||
udev_file_get_settings(file, st->dev_attribs, state->settings);
|
udev_file_get_settings(file, st->dev_attribs, dev, autoconf);
|
||||||
state->exists = 1;
|
|
||||||
}
|
}
|
||||||
util_udev_free_file(file);
|
util_udev_free_file(file);
|
||||||
|
|
||||||
@@ -141,8 +216,32 @@ static char *get_label_id(const char *prefix, const char *type,
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the persistent configuration of a CCW device to a udev rule. */
|
static void write_attr_to_file(FILE *fd, struct device_state *state, const char *id)
|
||||||
exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
|
{
|
||||||
|
struct ptrlist_node *p;
|
||||||
|
struct setting *s;
|
||||||
|
struct util_list *list = NULL;
|
||||||
|
|
||||||
|
/* Apply attributes in correct order. */
|
||||||
|
list = setting_list_get_sorted(state->settings);
|
||||||
|
|
||||||
|
util_list_iterate(list, p) {
|
||||||
|
s = p->ptr;
|
||||||
|
if (s->removed)
|
||||||
|
continue;
|
||||||
|
if ((s->attrib && s->attrib->internal) ||
|
||||||
|
internal_by_name(s->name)) {
|
||||||
|
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
||||||
|
internal_get_name(s->name), s->value);
|
||||||
|
} else {
|
||||||
|
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name,
|
||||||
|
s->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptrlist_free(list, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static exit_code_t udev_ccw_write_device_legacy(struct device *dev, bool autoconf)
|
||||||
{
|
{
|
||||||
struct subtype *st = dev->subtype;
|
struct subtype *st = dev->subtype;
|
||||||
struct ccw_subtype_data *data = st->data;
|
struct ccw_subtype_data *data = st->data;
|
||||||
@@ -150,22 +249,16 @@ exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
|
|||||||
struct device_state *state = autoconf ? &dev->autoconf :
|
struct device_state *state = autoconf ? &dev->autoconf :
|
||||||
&dev->persistent;
|
&dev->persistent;
|
||||||
char *path, *cfg_label = NULL, *end_label = NULL;
|
char *path, *cfg_label = NULL, *end_label = NULL;
|
||||||
struct util_list *list;
|
|
||||||
struct ptrlist_node *p;
|
|
||||||
struct setting *s;
|
|
||||||
exit_code_t rc = EXIT_OK;
|
exit_code_t rc = EXIT_OK;
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
|
|
||||||
if (!state->exists)
|
if (!state->exists)
|
||||||
return udev_remove_rule(type, id, autoconf);
|
return udev_remove_rule(type, id, true);
|
||||||
|
|
||||||
cfg_label = get_label_id("cfg", type, id);
|
cfg_label = get_label_id("cfg", type, id);
|
||||||
end_label = get_label_id("end", type, id);
|
end_label = get_label_id("end", type, id);
|
||||||
|
|
||||||
/* Apply attributes in correct order. */
|
path = path_get_udev_rule(type, id, true);
|
||||||
list = setting_list_get_sorted(state->settings);
|
|
||||||
|
|
||||||
path = path_get_udev_rule(type, id, autoconf);
|
|
||||||
debug("Writing %s udev rule file %s\n", type, path);
|
debug("Writing %s udev rule file %s\n", type, path);
|
||||||
if (!util_path_exists(path)) {
|
if (!util_path_exists(path)) {
|
||||||
rc = path_create(path);
|
rc = path_create(path);
|
||||||
@@ -196,22 +289,8 @@ exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
|
|||||||
}
|
}
|
||||||
fprintf(fd, "GOTO=\"%s\"\n", end_label);
|
fprintf(fd, "GOTO=\"%s\"\n", end_label);
|
||||||
fprintf(fd, "\n");
|
fprintf(fd, "\n");
|
||||||
fprintf(fd, "LABEL=\"%s\"\n", cfg_label);
|
|
||||||
|
|
||||||
/* Write settings. */
|
write_attr_to_file(fd, state, id);
|
||||||
util_list_iterate(list, p) {
|
|
||||||
s = p->ptr;
|
|
||||||
if (s->removed)
|
|
||||||
continue;
|
|
||||||
if ((s->attrib && s->attrib->internal) ||
|
|
||||||
internal_by_name(s->name)) {
|
|
||||||
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
|
||||||
internal_get_name(s->name), s->value);
|
|
||||||
} else {
|
|
||||||
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name,
|
|
||||||
s->value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write udev rule epilog. */
|
/* Write udev rule epilog. */
|
||||||
fprintf(fd, "\n");
|
fprintf(fd, "\n");
|
||||||
@@ -221,7 +300,6 @@ exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
|
|||||||
warn("Could not close file %s: %s\n", path, strerror(errno));
|
warn("Could not close file %s: %s\n", path, strerror(errno));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
ptrlist_free(list, 0);
|
|
||||||
free(end_label);
|
free(end_label);
|
||||||
free(cfg_label);
|
free(cfg_label);
|
||||||
free(path);
|
free(path);
|
||||||
@@ -229,6 +307,150 @@ out:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Write the persistent configuration of a CCW device to a udev rule. */
|
||||||
|
static exit_code_t udev_ccw_write_device_new(struct device *dev)
|
||||||
|
{
|
||||||
|
struct subtype *st = dev->subtype;
|
||||||
|
struct ccw_subtype_data *data = st->data;
|
||||||
|
const char *type = st->name, *drv = data->any_driver ? "*" : data->ccwdrv, *id = dev->id;
|
||||||
|
char *path, *cfg_label = NULL, *end_label = NULL;
|
||||||
|
exit_code_t rc = EXIT_OK;
|
||||||
|
FILE *fd;
|
||||||
|
int i, configured = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the previous file; The new udev rule will be created based on the
|
||||||
|
* current configuration settings
|
||||||
|
*/
|
||||||
|
udev_remove_rule(type, id, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the dev->persistent to the site_specific array; While writing the new
|
||||||
|
* udev-rule we consider the site_specific array only
|
||||||
|
*/
|
||||||
|
|
||||||
|
dev_state_copy(&dev->site_specific[global_site_id], &dev->persistent);
|
||||||
|
for (i = 0; i < NUM_SITES; i++) {
|
||||||
|
configured += dev->site_specific[i].exists;
|
||||||
|
configured -= dev->site_specific[i].deconfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is no configuration settings available, do not create the new
|
||||||
|
* udev-rule file; exit here
|
||||||
|
*/
|
||||||
|
if (!configured)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
cfg_label = get_label_id("cfg", type, id);
|
||||||
|
end_label = get_label_id("end", type, id);
|
||||||
|
|
||||||
|
path = path_get_udev_rule(type, id, false);
|
||||||
|
debug("Writing %s udev rule file %s\n", type, path);
|
||||||
|
if (!util_path_exists(path)) {
|
||||||
|
rc = path_create(path);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = misc_fopen(path, "w");
|
||||||
|
if (!fd) {
|
||||||
|
error("Could not write to file %s: %s\n", path,
|
||||||
|
strerror(errno));
|
||||||
|
rc = EXIT_RUNTIME_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write udev rule prolog. */
|
||||||
|
fprintf(fd, "# Generated by chzdev\n");
|
||||||
|
|
||||||
|
if (drv) {
|
||||||
|
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"ccw\", "
|
||||||
|
"KERNEL==\"%s\", DRIVER==\"%s\", GOTO=\"%s\"\n", id,
|
||||||
|
drv, cfg_label);
|
||||||
|
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"drivers\", "
|
||||||
|
"KERNEL==\"%s\", TEST==\"[ccw/%s]\", "
|
||||||
|
"GOTO=\"%s\"\n", drv, id, cfg_label);
|
||||||
|
} else {
|
||||||
|
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"ccw\", "
|
||||||
|
"KERNEL==\"%s\", GOTO=\"%s\"\n", id, cfg_label);
|
||||||
|
}
|
||||||
|
fprintf(fd, "GOTO=\"%s\"\n", end_label);
|
||||||
|
fprintf(fd, "\n");
|
||||||
|
|
||||||
|
fprintf(fd, "LABEL=\"%s\"\n", cfg_label);
|
||||||
|
/* site comparison block */
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++) {
|
||||||
|
if (dev->site_specific[i].exists &&
|
||||||
|
!dev->site_specific[i].deconfigured) {
|
||||||
|
fprintf(fd, "ENV{ZDEV_SITE_ID}==\"%d\",GOTO=\"%s_site%d\"\n", i,
|
||||||
|
cfg_label, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a generic configuration available, then use that setting as a
|
||||||
|
* fail-over incase of no site-id information in LOADPARM
|
||||||
|
*/
|
||||||
|
if (dev->site_specific[SITE_FALLBACK].exists &&
|
||||||
|
!dev->site_specific[SITE_FALLBACK].deconfigured)
|
||||||
|
fprintf(fd, "GOTO=\"%s_site_fb\"\n", cfg_label);
|
||||||
|
else
|
||||||
|
fprintf(fd, "GOTO=\"%s\"\n", end_label);
|
||||||
|
fprintf(fd, "\n");
|
||||||
|
|
||||||
|
/* Write the site blocks for all the available configurations */
|
||||||
|
for (i = 0; i < NUM_USER_SITES; i++) {
|
||||||
|
if (dev->site_specific[i].exists &&
|
||||||
|
!dev->site_specific[i].deconfigured) {
|
||||||
|
fprintf(fd, "# site_start_%d\n", i);
|
||||||
|
fprintf(fd, "LABEL=\"%s_site%d\"\n", cfg_label, i);
|
||||||
|
|
||||||
|
write_attr_to_file(fd, &dev->site_specific[i], id);
|
||||||
|
/* Write udev rule epilog. */
|
||||||
|
fprintf(fd, "GOTO=\"%s\"\n", end_label);
|
||||||
|
fprintf(fd, "# site_end_%d\n", i);
|
||||||
|
fprintf(fd, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dev->site_specific[SITE_FALLBACK].exists &&
|
||||||
|
!dev->site_specific[SITE_FALLBACK].deconfigured) {
|
||||||
|
fprintf(fd, "# site_start_fb\n");
|
||||||
|
fprintf(fd, "LABEL=\"%s_site_fb\"\n", cfg_label);
|
||||||
|
|
||||||
|
write_attr_to_file(fd, &dev->site_specific[i], id);
|
||||||
|
/* Write udev rule epilog. */
|
||||||
|
fprintf(fd, "GOTO=\"%s\"\n", end_label);
|
||||||
|
fprintf(fd, "# site_end_fb\n");
|
||||||
|
fprintf(fd, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write udev rule epilog. */
|
||||||
|
fprintf(fd, "\n");
|
||||||
|
fprintf(fd, "LABEL=\"%s\"\n", end_label);
|
||||||
|
|
||||||
|
if (misc_fclose(fd))
|
||||||
|
warn("Could not close file %s: %s\n", path, strerror(errno));
|
||||||
|
|
||||||
|
rc = udev_write_site_rule();
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
out:
|
||||||
|
free(end_label);
|
||||||
|
free(cfg_label);
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
|
||||||
|
{
|
||||||
|
if (autoconf)
|
||||||
|
return udev_ccw_write_device_legacy(dev, autoconf);
|
||||||
|
else
|
||||||
|
return udev_ccw_write_device_new(dev);
|
||||||
|
}
|
||||||
|
|
||||||
#define MARKER "echo free "
|
#define MARKER "echo free "
|
||||||
|
|
||||||
static char *read_cio_ignore(const char *path)
|
static char *read_cio_ignore(const char *path)
|
||||||
@@ -300,6 +522,7 @@ exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf)
|
|||||||
|
|
||||||
/* Write udev rule. */
|
/* Write udev rule. */
|
||||||
fprintf(fd, "# Generated by chzdev\n");
|
fprintf(fd, "# Generated by chzdev\n");
|
||||||
|
|
||||||
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"subsystem\", "
|
fprintf(fd, "ACTION==\"add\", SUBSYSTEM==\"subsystem\", "
|
||||||
"KERNEL==\"ccw\", RUN{program}+=\"/bin/sh -c "
|
"KERNEL==\"ccw\", RUN{program}+=\"/bin/sh -c "
|
||||||
"'echo free %s > /proc/cio_ignore'\"\n", id_list);
|
"'echo free %s > /proc/cio_ignore'\"\n", id_list);
|
||||||
|
|||||||
+133
-1
@@ -11,9 +11,17 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "zdev_id.h"
|
||||||
|
|
||||||
#define SYSINFO "/proc/sysinfo"
|
#define SYSINFO "/proc/sysinfo"
|
||||||
#define CMDLINE "/proc/cmdline"
|
#define CMDLINE "/proc/cmdline"
|
||||||
|
#define LOADPARM "/sys/firmware/ipl/loadparm"
|
||||||
|
#define IPL_DEV_ID "/sys/firmware/ipl/device"
|
||||||
|
#define IPL_DEV_TYPE "/sys/firmware/ipl/ipl_type"
|
||||||
|
#define SITE_FALLBACK 10
|
||||||
|
|
||||||
#define WHITESPACE " \t\n"
|
#define WHITESPACE " \t\n"
|
||||||
|
|
||||||
static void array_add(char ***array_p, int *num_p, const char *str)
|
static void array_add(char ***array_p, int *num_p, const char *str)
|
||||||
@@ -140,15 +148,139 @@ out:
|
|||||||
printf("ZDEV_NO_AUTO=%d\n", no_auto);
|
printf("ZDEV_NO_AUTO=%d\n", no_auto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the erraneous loadparm provides a site_id which is not valid,
|
||||||
|
* default it to the common-site id.
|
||||||
|
*/
|
||||||
|
static int validate_site(int site_id)
|
||||||
|
{
|
||||||
|
if (site_id < SITE_FALLBACK)
|
||||||
|
return site_id;
|
||||||
|
return SITE_FALLBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the ipl device and extract the SSID */
|
||||||
|
static int get_site_id(void)
|
||||||
|
{
|
||||||
|
FILE *fd;
|
||||||
|
char *line;
|
||||||
|
size_t n;
|
||||||
|
int site_id = SITE_FALLBACK, ssid;
|
||||||
|
|
||||||
|
fd = fopen(IPL_DEV_ID, "r");
|
||||||
|
if (!fd)
|
||||||
|
goto fail_safe;
|
||||||
|
|
||||||
|
if (getline(&line, &n, fd) == -1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (sscanf(line, "%*d.%d.%*d", &ssid) == 1)
|
||||||
|
site_id = validate_site(ssid);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(line);
|
||||||
|
fclose(fd);
|
||||||
|
fail_safe:
|
||||||
|
return site_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the ipl type and see if it belongs to ccw or zfcp, if different,
|
||||||
|
* default it to common-site.
|
||||||
|
*/
|
||||||
|
static int read_ssid(void)
|
||||||
|
{
|
||||||
|
FILE *fd;
|
||||||
|
char *line = NULL;
|
||||||
|
size_t n;
|
||||||
|
int site_id = SITE_FALLBACK;
|
||||||
|
|
||||||
|
fd = fopen(IPL_DEV_TYPE, "r");
|
||||||
|
if (!fd)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (getline(&line, &n, fd) != -1) {
|
||||||
|
if (strcmp(line, "ccw") == 0 || strcmp(line, "zfcp"))
|
||||||
|
site_id = get_site_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(fd);
|
||||||
|
out:
|
||||||
|
return site_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_zdev_site_id(int site_id)
|
||||||
|
{
|
||||||
|
FILE *fd;
|
||||||
|
|
||||||
|
fd = fopen(ZDEV_SITE_ID_FILE, "w");
|
||||||
|
if (!fd)
|
||||||
|
err(1, "Could not write to zdev_site_id file");
|
||||||
|
if (site_id == SITE_FALLBACK)
|
||||||
|
fprintf(fd, "ZDEV_SITE_ID=\n");
|
||||||
|
else
|
||||||
|
fprintf(fd, "ZDEV_SITE_ID=%d\n", site_id);
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the loadparm and extract the current site_id.
|
||||||
|
* loadparm can contains either Sn or "Ss". Sn indicate the site_id, where
|
||||||
|
* 'n' is the integer which could be one of the valid site_ids from 0 to 9.
|
||||||
|
* When loadparm value is "Ss", zdev_id extracts the site_id from the SSID
|
||||||
|
* of the current ipl device. For ccw and zfcp devices, the current ipl
|
||||||
|
* device-id can be found at /sys/firmware/ipl/device.
|
||||||
|
* For all other invalid cases, set ZDEV_SITE_ID to NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void process_loadparm(const char *filename)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
FILE *fd;
|
||||||
|
char *line = NULL, *substr;
|
||||||
|
int site_id = SITE_FALLBACK;
|
||||||
|
|
||||||
|
fd = fopen(filename, "r");
|
||||||
|
if (!fd)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We expect the value here to be either SX, where X is the site-id
|
||||||
|
* or SS,in which case, the site-id will be derived from the SSID
|
||||||
|
*/
|
||||||
|
if ((getline(&line, &n, fd)) != -1) {
|
||||||
|
substr = strchr(line, 'S');
|
||||||
|
if (!substr)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (isdigit(substr[1]))
|
||||||
|
site_id = validate_site(atoi(&substr[1]));
|
||||||
|
else if (substr[1] == 'S')
|
||||||
|
site_id = read_ssid();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(fd);
|
||||||
|
out:
|
||||||
|
write_zdev_site_id(site_id);
|
||||||
|
if (site_id == SITE_FALLBACK)
|
||||||
|
printf("ZDEV_SITE_ID=\n");
|
||||||
|
else
|
||||||
|
printf("ZDEV_SITE_ID=%d\n", site_id);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *sysinfo, *cmdline;
|
char *sysinfo, *cmdline, *loadparm;
|
||||||
|
|
||||||
sysinfo = argc < 2 ? SYSINFO : argv[1];
|
sysinfo = argc < 2 ? SYSINFO : argv[1];
|
||||||
cmdline = argc < 3 ? CMDLINE : argv[2];
|
cmdline = argc < 3 ? CMDLINE : argv[2];
|
||||||
|
loadparm = argc < 4 ? LOADPARM : argv[3];
|
||||||
|
|
||||||
process_sysinfo(sysinfo);
|
process_sysinfo(sysinfo);
|
||||||
process_cmdline(cmdline);
|
process_cmdline(cmdline);
|
||||||
|
process_loadparm(loadparm);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
# Common definitions
|
# Common definitions
|
||||||
include ../../common.mak
|
include ../../common.mak
|
||||||
|
|
||||||
UDEVDIR := /usr/lib/udev/rules.d/
|
|
||||||
RULES := 81-dpm.rules
|
RULES := 81-dpm.rules
|
||||||
|
|
||||||
install:
|
install:
|
||||||
$(INSTALL) -m 755 -d $(DESTDIR)$(UDEVDIR)
|
$(INSTALL) -m 755 -d $(DESTDIR)$(UDEVRULESDIR)
|
||||||
$(INSTALL) -m 644 $(RULES) $(DESTDIR)$(UDEVDIR)/
|
$(INSTALL) -m 644 $(RULES) $(DESTDIR)$(UDEVRULESDIR)/
|
||||||
|
|||||||
+77
-29
@@ -20,31 +20,52 @@ check_dep_fuse:
|
|||||||
"-DFUSE_USE_VERSION=30")
|
"-DFUSE_USE_VERSION=30")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
.detect_openssl.dep.c:
|
||||||
# HAVE_ZLIB: Allow skip zgetdump build, when no zlib-devel is available
|
echo "#include <openssl/evp.h>" > $@
|
||||||
#
|
echo "#if OPENSSL_VERSION_NUMBER < 0x10100000L" >> $@
|
||||||
ifeq (${HAVE_ZLIB},0)
|
echo " #error At least OpenSSL version 1.1.0 is required" >> $@
|
||||||
|
echo "#endif" >> $@
|
||||||
|
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||||
|
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||||
|
echo " EVP_MD_CTX_free(ctx);" >> $@
|
||||||
|
echo "}" >> $@
|
||||||
|
|
||||||
all:
|
.check_dep_zgetdump: .detect_openssl.dep.c check_dep_fuse
|
||||||
$(SKIP) HAVE_ZLIB=0
|
|
||||||
|
|
||||||
install:
|
|
||||||
$(SKIP) HAVE_ZLIB=0
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
check_dep_zlib:
|
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"zgetdump", \
|
"zgetdump", \
|
||||||
"zlib.h", \
|
"zlib.h", \
|
||||||
"zlib-devel or libz-dev", \
|
"zlib-devel or libz-dev", \
|
||||||
"HAVE_ZLIB=0")
|
"HAVE_ZLIB=0")
|
||||||
|
$(call check_dep, \
|
||||||
|
"zgetdump", \
|
||||||
|
"glib.h", \
|
||||||
|
"glib2-devel / libglib2.0-dev", \
|
||||||
|
"HAVE_GLIB2=0")
|
||||||
|
$(call check_dep, \
|
||||||
|
"zgetdump", \
|
||||||
|
$<, \
|
||||||
|
"openssl-devel / libssl-dev version >= 1.1.0", \
|
||||||
|
"HAVE_OPENSSL=0", \
|
||||||
|
"-I.")
|
||||||
|
touch $@
|
||||||
|
|
||||||
all: check_dep_fuse check_dep_zlib zgetdump
|
#
|
||||||
|
# Allow skip of zgetdump build, when no zlib-devel, openssl-devel, glib2-devel is available
|
||||||
|
#
|
||||||
|
BUILD_TARGETS :=skip-zgetdump
|
||||||
|
INSTALL_TARGETS := skip-zgetdump
|
||||||
|
ifneq (${HAVE_ZLIB},0)
|
||||||
|
ifneq (${HAVE_OPENSSL},0)
|
||||||
|
ifneq (${HAVE_GLIB2},0)
|
||||||
|
BUILD_TARGETS := zgetdump
|
||||||
|
INSTALL_TARGETS := install-zgetdump
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
OBJECTS = zgetdump.o opts.o zg.o zg_error.o zg_print.o \
|
OBJECTS = zgetdump.o opts.o zg.o zg_error.o zg_print.o \
|
||||||
dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \
|
dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \
|
||||||
dfi_lkcd.o dfi_elf.o \
|
dfi_lkcd.o dfi_elf.o dfi_elf_common.o dfi_pv_elf.o \
|
||||||
dfi_s390.o dfi_s390_ext.o\
|
dfi_s390.o dfi_s390_ext.o\
|
||||||
dfi_s390mv.o dfi_s390mv_ext.o \
|
dfi_s390mv.o dfi_s390mv_ext.o \
|
||||||
dfi_s390tape.o dfi_kdump.o \
|
dfi_s390tape.o dfi_kdump.o \
|
||||||
@@ -54,7 +75,27 @@ OBJECTS = zgetdump.o opts.o zg.o zg_error.o zg_print.o \
|
|||||||
dt.o dt_s390sv.o dt_s390sv_ext.o \
|
dt.o dt_s390sv.o dt_s390sv_ext.o \
|
||||||
dt_s390mv.o dt_s390mv_ext.o \
|
dt_s390mv.o dt_s390mv_ext.o \
|
||||||
dt_scsi.o output.o \
|
dt_scsi.o output.o \
|
||||||
ngdump.o dt_ngdump.o dfi_ngdump.o
|
ngdump.o dt_ngdump.o dfi_ngdump.o \
|
||||||
|
pv_utils.o
|
||||||
|
|
||||||
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
|
GLIB2_CFLAGS := $(shell pkg-config --silence-errors --cflags glib-2.0)
|
||||||
|
GLIB2_LIBS := $(shell pkg-config --silence-errors --libs glib-2.0)
|
||||||
|
LIBCRYPTO_CFLAGS := $(shell pkg-config --silence-errors --cflags libcrypto)
|
||||||
|
LIBCRYPTO_LIBS := $(shell pkg-config --silence-errors --libs libcrypto)
|
||||||
|
else
|
||||||
|
GLIB2_CFLAGS := -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
|
||||||
|
GLIB2_LIBS := -lglib-2.0
|
||||||
|
LIBCRYPTO_CFLAGS :=
|
||||||
|
LIBCRYPTO_LIBS := -lcrypto
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIBPV = $(rootdir)/libpv/libpv.a
|
||||||
|
LIBPV_CFLAGS := -DOPENSSL_API_COMPAT=0x10100000L \
|
||||||
|
$(GLIB2_CFLAGS) \
|
||||||
|
$(LIBCRYPTO_CFLAGS) \
|
||||||
|
$(NULL)
|
||||||
|
LIBPV_LIBS := $(GLIB2_LIBS) $(LIBCRYPTO_LIBS)
|
||||||
|
|
||||||
ifeq ("$(HAVE_FUSE)","0")
|
ifeq ("$(HAVE_FUSE)","0")
|
||||||
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
|
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
|
||||||
@@ -66,23 +107,30 @@ else
|
|||||||
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse3
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
LDLIBS += -lz $(FUSE_LDLIBS)
|
LDLIBS += -lz $(FUSE_LDLIBS) $(LIBPV_LIBS)
|
||||||
ALL_CFLAGS += $(FUSE_CFLAGS)
|
ALL_CFLAGS += $(FUSE_CFLAGS) $(LIBPV_CFLAGS)
|
||||||
|
|
||||||
ifneq ("$(HAVE_FUSE)","0")
|
ifneq ("$(HAVE_FUSE)","0")
|
||||||
OBJECTS += zfuse.o
|
OBJECTS += zfuse.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libs = $(rootdir)/libutil/libutil.a
|
libs = $(rootdir)/libutil/libutil.a $(LIBPV)
|
||||||
zgetdump: $(OBJECTS) $(libs)
|
|
||||||
|
|
||||||
install: all
|
all: $(BUILD_TARGETS)
|
||||||
|
|
||||||
|
zgetdump: .check_dep_zgetdump $(OBJECTS) $(libs)
|
||||||
|
|
||||||
|
skip-zgetdump:
|
||||||
|
echo " SKIP zgetdump due to unresolved dependencies"
|
||||||
|
|
||||||
|
install-zgetdump: zgetdump
|
||||||
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8 $(DESTDIR)$(BINDIR)
|
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8 $(DESTDIR)$(BINDIR)
|
||||||
$(INSTALL) -m 755 zgetdump $(DESTDIR)$(BINDIR)
|
$(INSTALL) -m 755 zgetdump $(DESTDIR)$(BINDIR)
|
||||||
$(INSTALL) -m 644 zgetdump.8 $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -m 644 zgetdump.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
|
|
||||||
clean:
|
install: $(INSTALL_TARGETS)
|
||||||
rm -f *.o *~ zgetdump core.*
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: all install clean check_dep_fuse check_dep_zlib
|
clean:
|
||||||
|
rm -f -- *.o *~ zgetdump core.* .detect_openssl.dep.c .check_dep_zgetdump
|
||||||
|
|
||||||
|
.PHONY: all install clean check_dep_fuse check_dep_zlib skip-zgetdump install-zgetdump
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user