diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..f870fed90 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,45 @@ +--- +name: Bug report +about: Create a report to help us improve. +title: '' +labels: bug, new +--- + + + +**Describe the bug** + +**Steps to Reproduce** + +1. +2. + +**Expected behavior** + +**Screenshots (if needed)** + +**Logs** + + + + + + + + + + +**Describe your environment** + + +- Zowe version number (Check the Desktop login screen, or manifest.json in the Zowe install folder): +- Install method (pax, smpe, kubernetes, github clone): +- Operating system (z/OS, kubernetes, etc) and OS version: +- Node.js version number (Shown in logs, or via `node --version`): +- Java version number (Shown in logs, or via `java -version`): +- z/OSMF version: +- What is the output of log message ZWES1014I: +- Environment variables in use: + + +**Additional context** diff --git a/.github/ISSUE_TEMPLATE/bug_report_high.md b/.github/ISSUE_TEMPLATE/bug_report_high.md new file mode 100644 index 000000000..2a055864e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report_high.md @@ -0,0 +1,45 @@ +--- +name: High-severity bug report +about: Create a report on a high-severity bug. High severity is when there is an issue that has a major impact on usage of Zowe. +title: '' +labels: bug, new, severity-high +--- + + + +**Describe the bug** + +**Steps to Reproduce** + +1. +2. + +**Expected behavior** + +**Screenshots (if needed)** + +**Logs** + + + + + + + + + + +**Describe your environment** + + +- Zowe version number (Check the Desktop login screen, or manifest.json in the Zowe install folder): +- Install method (pax, smpe, kubernetes, github clone): +- Operating system (z/OS, kubernetes, etc) and OS version: +- Node.js version number (Shown in logs, or via `node --version`): +- Java version number (Shown in logs, or via `java -version`): +- z/OSMF version: +- What is the output of log message ZWES1014I: +- Environment variables in use: + + +**Additional context** diff --git a/.github/ISSUE_TEMPLATE/bug_report_low.md b/.github/ISSUE_TEMPLATE/bug_report_low.md new file mode 100644 index 000000000..e47807673 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report_low.md @@ -0,0 +1,45 @@ +--- +name: Low-severity bug report +about: Create a report on a low-severity bug. Low severity is when there is an issue that is inconvenient but doesn't impact key use cases. +title: '' +labels: bug, new, severity-low +--- + + + +**Describe the bug** + +**Steps to Reproduce** + +1. +2. + +**Expected behavior** + +**Screenshots (if needed)** + +**Logs** + + + + + + + + + + +**Describe your environment** + + +- Zowe version number (Check the Desktop login screen, or manifest.json in the Zowe install folder): +- Install method (pax, smpe, kubernetes, github clone): +- Operating system (z/OS, kubernetes, etc) and OS version: +- Node.js version number (Shown in logs, or via `node --version`): +- Java version number (Shown in logs, or via `java -version`): +- z/OSMF version: +- What is the output of log message ZWES1014I: +- Environment variables in use: + + +**Additional context** diff --git a/.github/ISSUE_TEMPLATE/bug_report_medium.md b/.github/ISSUE_TEMPLATE/bug_report_medium.md new file mode 100644 index 000000000..86e45dc95 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report_medium.md @@ -0,0 +1,45 @@ +--- +name: Medium-severity bug report +about: Create a report on a medium-severity bug. Medium severity is when there is an issue that makes the use of Zowe difficult, but has a workaround or doesn't prevent the use of Zowe. +title: '' +labels: bug, new, severity-medium +--- + + + +**Describe the bug** + +**Steps to Reproduce** + +1. +2. + +**Expected behavior** + +**Screenshots (if needed)** + +**Logs** + + + + + + + + + + +**Describe your environment** + + +- Zowe version number (Check the Desktop login screen, or manifest.json in the Zowe install folder): +- Install method (pax, smpe, kubernetes, github clone): +- Operating system (z/OS, kubernetes, etc) and OS version: +- Node.js version number (Shown in logs, or via `node --version`): +- Java version number (Shown in logs, or via `java -version`): +- z/OSMF version: +- What is the output of log message ZWES1014I: +- Environment variables in use: + + +**Additional context** diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..842a135fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,25 @@ +--- +name: Feature request +about: Suggest an idea for ZSS +labels: enhancement, new +--- + + + +**Is your feature or enhancement request related to a problem or limitation? Please describe** + + + +**Describe your enhancement idea** + + + + +**Describe alternatives you've considered** + + + +**Provide any additional context** + + + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 5cac6ad55..031980ccc 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,7 +3,7 @@ ## Proposed changes -This PR addresses Issue: [*Link to Github issue within https://github.com/zowe/zlux/issues* if any] +This PR addresses Issue: [*Link to Github issue within https://github.com/zowe/zss/issues* if any] This PR depends upon the following PRs: @@ -19,7 +19,7 @@ Please delete options that are not relevant. ## PR Checklist Please delete options that are not relevant. - [ ] If the changes in this PR are meant for the next release / mainline, this PR targets the "staging" branch. -- [ ] My code follows the style guidelines of this project (see: [Contributing guideline](https://github.com/zowe/zlux/blob/master/CONTRIBUTING.md)) +- [ ] My code follows the style guidelines of this project (see: [Contributing guideline](https://github.com/zowe/zss/blob/v2.x/master/CONTRIBUTING.md)) - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] New and existing unit tests pass locally with my changes diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..bb9de01ab --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,30 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '0 */6 * * *' + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v5 + with: + close-issue-message: > + This issue has been automatically closed due to lack of activity. + If this issue is still valid and important to you, it can be reopened. + days-before-close: 90 + days-before-stale: 180 + exempt-all-assignees: true + exempt-all-milestones: true + exempt-issue-labels: "community-upvoted, dependency, for-review, keep, security, high-severity, critical-severity, help-wanted, good-first-issue" + stale-issue-label: "stale-reopen-if-needed" + stale-issue-message: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs, + but can be reopened if needed. Thank you for your contributions. + stale-pr-label: "stale-reopen-if-needed" + start-date: "2022-05-30T00:00:00Z" diff --git a/CHANGELOG.md b/CHANGELOG.md index fa08c220f..2ca6c819b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to the ZSS package will be documented in this file. ## Recent Changes +## `2.5.0` + +- Bugfix: In 2.3 and 2.4, 'safkeyring://' syntax stopped working, only allowing 'safkeyring:////'. Now, support for both is restored. +- Support ZIS runtime version check +- Update the dynamic linkage stub vector to include new functions +- Add ZIS plugin development documentation and samples + ## `2.4.0` - Enhancement: ZSS /datasetContents now has a PUT API for creating datasets. diff --git a/c/zis/server-api.c b/c/zis/server-api.c index 3b4fe0745..a8d59223f 100644 --- a/c/zis/server-api.c +++ b/c/zis/server-api.c @@ -32,9 +32,34 @@ _Bool zisIsLPADevModeOn(const ZISContext *context) { } void zisGetServerVersion(int *major, int *minor, int *revision) { - *major = ZIS_MAJOR_VERSION; - *minor = ZIS_MINOR_VERSION; - *revision = ZIS_REVISION; + *major = -1; + *minor = -1; + *revision = -1; + CAA *caa = (CAA *)getCAA(); + if (caa == NULL) { + return; + } + RLETask *task = caa->rleTask; + if (task == NULL) { + return; + } + RLEAnchor *rleAnchor = task->anchor; + if (rleAnchor == NULL) { + return; + } + ZISContext *context = NULL; + if (getRLEApplicationAnchor(rleAnchor, (void **)&context)) { + return; + } + if (!(context->zisAnchor->flags & ZIS_SERVER_ANCHOR_VERSIONED_CONTEXT)) { + return; + } + if (context->version < ZIS_CONTEXT_VERSION_ZIS_VERSION_SUPPORT) { + return; + } + *major = context->zisVersion.major; + *minor = context->zisVersion.minor; + *revision = context->zisVersion.revision; } /* diff --git a/c/zis/server.c b/c/zis/server.c index 51a1f100a..31744d26e 100644 --- a/c/zis/server.c +++ b/c/zis/server.c @@ -1109,6 +1109,7 @@ ZISServerAnchor *createZISServerAnchor() { /* new feature bit for dynamic linking - Fall 2021 */ anchor->flags |= ZIS_SERVER_ANCHOR_FLAG_DYNLINK; + anchor->flags |= ZIS_SERVER_ANCHOR_VERSIONED_CONTEXT; return anchor; } @@ -1118,6 +1119,10 @@ static void enableDynLink(ZISServerAnchor *anchor) { anchor->flags |= ZIS_SERVER_ANCHOR_FLAG_DYNLINK; } +static void enableVersionedContext(ZISServerAnchor *anchor) { + anchor->flags |= ZIS_SERVER_ANCHOR_VERSIONED_CONTEXT; +} + static void removeZISServerAnchor(ZISServerAnchor **anchor) { unsigned int size = sizeof(ZISServerAnchor); @@ -1143,6 +1148,8 @@ static int initGlobalResources(ZISContext *context) { } else { // make sure any existing anchors supports dynamic linkage now enableDynLink(anchor); + // make sure it also supports a versioned ZIS context + enableVersionedContext(anchor); } context->zisAnchor = anchor; @@ -1158,6 +1165,11 @@ static ZISContext makeContext(STCBase *base) { ZISContext cntx = { .eyecatcher = ZIS_CONTEXT_EYECATCHER, + .version = ZIS_CONTEXT_VERSION, + .size = sizeof(ZISContext), + .zisVersion.major = ZIS_MAJOR_VERSION, + .zisVersion.minor = ZIS_MINOR_VERSION, + .zisVersion.revision = ZIS_REVISION, .stcBase = base, .parms = NULL, .cmServer = NULL, @@ -1370,6 +1382,8 @@ static int initContext(ZISContext *context) { memcpy(context->dynlinkModuleNameNullTerm, context->zisModuleName.text, 4); strcat(context->dynlinkModuleNameNullTerm, ZIS_DYN_LINKAGE_PLUGIN_MOD_SUFFIX); + setRLEApplicationAnchor(context->stcBase->rleAnchor, context); + return RC_ZIS_OK; } diff --git a/c/zis/stubinit.c b/c/zis/stubinit.c index 0d0327d07..63a2eca3b 100644 --- a/c/zis/stubinit.c +++ b/c/zis/stubinit.c @@ -273,6 +273,8 @@ stubVector[ZIS_STUB_LETMRLEE] = (void*)termRLEEnvironment; stubVector[ZIS_STUB_LEMKFCAA] = (void*)makeFakeCAA; stubVector[ZIS_STUB_LEARTCAA] = (void*)abortIfUnsupportedCAA; + stubVector[ZIS_STUB_LESETANC] = (void*)setRLEApplicationAnchor; + stubVector[ZIS_STUB_LEGETANC] = (void*)getRLEApplicationAnchor; stubVector[ZIS_STUB_MKLOGCTX] = (void*)makeLoggingContext; stubVector[ZIS_STUB_MKLLGCTX] = (void*)makeLocalLoggingContext; stubVector[ZIS_STUB_RMLOGCTX] = (void*)removeLoggingContext; diff --git a/c/zis/zisdynamic.c b/c/zis/zisdynamic.c index 95195bede..da78dec56 100644 --- a/c/zis/zisdynamic.c +++ b/c/zis/zisdynamic.c @@ -90,6 +90,10 @@ ZOWE_PRAGMA_PACK +#define ZIS_MIN_MAJOR_VERSION ZIS_MAJOR_VERSION +#define ZIS_MIN_MINOR_VERSION ZIS_MINOR_VERSION +#define ZIS_MIN_REVISION ZIS_REVISION + typedef struct ZISDynStubVector_tag { #define ZISDYN_STUB_VEC_EYECATCHER "ZWESISSV" @@ -386,8 +390,44 @@ void zisdynGetPluginVersion(int *major, int *minor, int *revision) { *revision = ZISDYN_REVISION; } +static int verifyZISVersion(void) { + + int zisMajor = 0; + int zisMinor = 0; + int zisRev = 0; + zisGetServerVersion(&zisMajor, &zisMinor, &zisRev); + zowelog(NULL, LOG_COMP_ID_CMS, ZOWE_LOG_DEBUG, + "ZIS major=%d, minor=%d, rev=%d\n", zisMajor, zisMinor, zisRev); + + if (zisMajor != ZISDYN_MAJOR_VERSION) { + goto out_bad_version; + } + if (zisMinor < ZISDYN_MINOR_VERSION) { + goto out_bad_version; + } + if (zisMinor == ZISDYN_MINOR_VERSION && zisRev < ZISDYN_REVISION) { + goto out_bad_version; + } + + return 0; + + out_bad_version: + zowelog(NULL, LOG_COMP_ID_CMS, ZOWE_LOG_SEVERE, + ZISDYN_LOG_BAD_ZIS_VERSION_MSG, + ZIS_MIN_MAJOR_VERSION, + ZIS_MIN_MINOR_VERSION, + ZIS_MIN_REVISION, + ZIS_MIN_MAJOR_VERSION + 1, + zisMajor, zisMinor, zisRev); + return -1; +} + ZISPlugin *getPluginDescriptor(void) { + if (verifyZISVersion() != 0) { + return NULL; + } + ZISPluginName pluginName = {.text = ZISDYN_PLUGIN_NAME}; ZISPluginNickname pluginNickname = {.text = ZISDYN_PLUGIN_NICKNAME}; diff --git a/defaults.yaml b/defaults.yaml index 8d51ca126..c3d872d34 100644 --- a/defaults.yaml +++ b/defaults.yaml @@ -14,7 +14,7 @@ components: fallback: true retryIntervalSeconds: 10 https: - keyring: ${{ ()=> { if (components.zss.tls) { if (zowe.certificate.keystore.type == "JCERACFKS") { return zowe.certificate.keystore.file.substring(15) } else { return zowe.certificate.keystore.file } } else { return null } }() }} + keyring: ${{ ()=> { if (components.zss.tls) { if (zowe.certificate.keystore.type == "JCERACFKS") { return zowe.certificate.keystore.file.replace(/safkeyring:\/+/,"") } else { return zowe.certificate.keystore.file } } else { return null } }() }} password: ${{ ()=> { if (components.zss.tls) { if (zowe.certificate.keystore.type == "JCERACFKS") { return null } else { return zowe.certificate.keystore.password } } else { return null } }() }} label: ${{ ()=> { if (components.zss.tls) { return zowe.certificate.keystore.alias } else { return null } }() }} port: ${{ ()=> { if (components.zss.tls) { return components.zss.port } else { return null } }() }} diff --git a/deps/zowe-common-c b/deps/zowe-common-c index f1bcf35a3..4f2732d0e 160000 --- a/deps/zowe-common-c +++ b/deps/zowe-common-c @@ -1 +1 @@ -Subproject commit f1bcf35a37772e4d17886547393955dbf414ed3c +Subproject commit 4f2732d0e781aec89b39f862262d5014a97c09b7 diff --git a/h/zis/message.h b/h/zis/message.h index fead6486b..202350676 100644 --- a/h/zis/message.h +++ b/h/zis/message.h @@ -272,7 +272,7 @@ #define ZISDYN_LOG_TERM_MSG_TEXT "ZIS Dynamic Base plugin terminating" #define ZISDYN_LOG_TERM_MSG ZISDYN_LOG_TERM_MSG_ID" "ZISDYN_LOG_TERM_MSG_TEXT -#define ZISDYN_LOG_TERMED_MSG_ID ZIS_MSG_PRFX"02045" +#define ZISDYN_LOG_TERMED_MSG_ID ZIS_MSG_PRFX"0205I" #define ZISDYN_LOG_TERMED_MSG_TEXT "ZIS Dynamic Base plugin successfully terminated" #define ZISDYN_LOG_TERMED_MSG ZISDYN_LOG_TERMED_MSG_ID" "ZISDYN_LOG_TERMED_MSG_TEXT @@ -304,6 +304,10 @@ #define ZISDYN_LOG_DEV_MODE_MSG_TEXT "ZIS Dynamic base plugin development mode is enabled" #define ZISDYN_LOG_DEV_MODE_MSG ZISDYN_LOG_DEV_MODE_MSG_ID" "ZISDYN_LOG_DEV_MODE_MSG_TEXT +#define ZISDYN_LOG_BAD_ZIS_VERSION_MSG_ID ZIS_MSG_PRFX"0214E" +#define ZISDYN_LOG_BAD_ZIS_VERSION_MSG_TEXT "Bad cross-memory server version: expected [%d.%d.%d, %d.0.0), found %d.%d.%d" +#define ZISDYN_LOG_BAD_ZIS_VERSION_MSG ZISDYN_LOG_BAD_ZIS_VERSION_MSG_ID" "ZISDYN_LOG_BAD_ZIS_VERSION_MSG_TEXT + #endif /* ZIS_MSG_H_ */ diff --git a/h/zis/plugin.h b/h/zis/plugin.h index 76cb341ea..fd192e5ab 100644 --- a/h/zis/plugin.h +++ b/h/zis/plugin.h @@ -86,7 +86,8 @@ struct ZISPlugin_tag { #define ZIS_PLUGIN_VERSION 1 unsigned int size; int flags; -#define ZIS_PLUGIN_FLAG_LPA 0x00000001 +#define ZIS_PLUGIN_FLAG_NONE 0x00000000 +#define ZIS_PLUGIN_FLAG_LPA 0x00000001 unsigned int maxServiceCount; /* These are used by the server */ @@ -120,6 +121,21 @@ typedef ZISPlugin *(ZISPluginDescriptorFunction)(); #pragma map(zisCreatePluginAnchor, "ZISPLGCA") #pragma map(zisRemovePluginAnchor, "ZISPLGRM") +/** + * @brief Create a plugin descriptor. + * @param[in] name The plugin name (unique within ZIS). + * @param[in] nickname The plugin nickname unique within ZIS. + * @param[in] initFunction The init callback function invoked at ZIS startup. + * @param[in] termFunction The term callback function invoked at ZIS termination. + * @param[in] commandFunction The command handler function invoked when a user + * issues a modify command using the plugin's nickname as target. + * @param[in] version The plugin version (when bumped forces ZIS to load the new + * version of the plugin module to LPA if it's an LPA plugin). + * @param[in] serviceCount The number of services in this plugin. + * @param[in] flags Various flags (use the @c ZIS_PLUGIN_FLAG_xxxx values). + * @return The descriptor address if success, @c NULL in case of an allocation + * error. + */ ZISPlugin *zisCreatePlugin(ZISPluginName name, ZISPluginNickname nickname, ZISPuginInitFunction *initFunction, @@ -129,8 +145,22 @@ ZISPlugin *zisCreatePlugin(ZISPluginName name, unsigned int serviceCount, int flags); +/** + * @brief Remove the plugin descriptor (releases its memory). + * @param[in,out] plugin The plugin descriptor to be removed. + */ void zisDestroyPlugin(ZISPlugin *plugin); +/** + * @brief Add a service to a plugin. + * @param[in,out] plugin The plugin descriptor to be used. + * @param[in] service The service to be added. + * @return + * - @c RC_ZIS_PLUGIN_OK in case of success
+ * - @c RC_ZIS_PLUGIN_INCOMPATIBLE_SEVICE if a PC-cp service is used with + * a non-LPA plugin
+ * - @c RC_ZIS_PLUGIN_BAD_SERVICE_NAME if the service name is invalid
+ */ int zisPluginAddService(ZISPlugin *plugin, ZISService service); ZISPluginAnchor *zisCreatePluginAnchor(); diff --git a/h/zis/server-api.h b/h/zis/server-api.h index 70db7d160..d0fb07496 100644 --- a/h/zis/server-api.h +++ b/h/zis/server-api.h @@ -20,7 +20,7 @@ #pragma map(zisIsLPADevModeOn, "ZISLPADV") /** - * Get the version of ZIS. + * Get the version of ZIS. In case of failure, all the results are set to -1. * @param[out] major The major ZIS version. * @param[out] minor The minor ZIS version. * @param[out] revision The revision of ZIS (aka the patch version). diff --git a/h/zis/server.h b/h/zis/server.h index b49cd45da..84aa4e45e 100644 --- a/h/zis/server.h +++ b/h/zis/server.h @@ -33,9 +33,23 @@ typedef struct ZISContext_tag { int cmsFlags; EightCharString zisModuleName; char dynlinkModuleNameNullTerm[9]; + char reserved0[3]; + + int16_t version; +#define ZIS_CONTEXT_VERSION 2 +#define ZIS_CONTEXT_VERSION_ZIS_VERSION_SUPPORT 2 + uint16_t size; + uint32_t flags; + struct { + int32_t major; + int32_t minor; + int32_t revision; + } zisVersion; + } ZISContext; #define ZIS_SERVER_ANCHOR_FLAG_DYNLINK 0x0001 /* supports dynamic linkage */ +#define ZIS_SERVER_ANCHOR_VERSIONED_CONTEXT 0x0002 typedef struct ZISServerAnchor_tag { char eyecatcher[8]; diff --git a/h/zis/service.h b/h/zis/service.h index a0651adfc..aa97efd31 100644 --- a/h/zis/service.h +++ b/h/zis/service.h @@ -123,12 +123,33 @@ ZOWE_PRAGMA_PACK_RESET #pragma map(zisUpdateServiceAnchor, "ZISUSVCA") #pragma map(zisServiceUseSpecificAuth, "ZISUSAUT") +/** + * @brief Create a service descriptor. + * @param[in] name The service name (unique within the plugin). + * @param[in] flags Various flags (use the @c ZIS_SERVICE_FLAG_xxxx values). + * @param[in] initFunction The init callback function invoked at ZIS startup. + * @param[in] termFunction The term callback function invoked at ZIS termination. + * @param[in] serveFunction The serve callback function invoked when the service + * is called. + * @param[in] version The version of the service. + * @return The result service descriptor. + */ ZISService zisCreateService(ZISServiceName name, int flags, ZISServiceInitFunction *initFunction, ZISServiceTermFunction *termFunction, ZISServiceServeFunction *serveFunction, unsigned int version); +/** + * @brief Create service descriptor for a space-switch service. + * @param[in] name The service name (unique within the plugin). + * @param[in] initFunction The init callback function invoked at ZIS startup. + * @param[in] termFunction The term callback function invoked at ZIS termination. + * @param[in] serveFunction The serve callback function invoked when the service + * is called. + * @param[in] version The version of the service. + * @return The result service descriptor. + */ ZISService zisCreateSpaceSwitchService( ZISServiceName name, ZISServiceInitFunction *initFunction, @@ -137,6 +158,16 @@ ZISService zisCreateSpaceSwitchService( unsigned int version ); +/** + * @brief Create service descriptor for a current-primary service. + * @param[in] name The service name (unique within the plugin). + * @param[in] initFunction The init callback function invoked at ZIS startup. + * @param[in] termFunction The term callback function invoked at ZIS termination. + * @param[in] serveFunction The serve callback function invoked when the service + * is called. + * @param[in] version The version of the service. + * @return The result service descriptor. + */ ZISService zisCreateCurrentPrimaryService( ZISServiceName name, ZISServiceInitFunction *initFunction, @@ -148,9 +179,9 @@ ZISService zisCreateCurrentPrimaryService( /** * Adds class and entity names to a service. * - * @param service The service to be used with the class and entity. - * @param className The class name to be used. - * @param entityName The entity name to be used. + * @param[in,out] service The service to be used with the class and entity. + * @param[in] className The class name to be used. + * @param[in] entityName The entity name to be used. * @return 0 in case of success, -1 if the class or entity name is too long. */ int zisServiceUseSpecificAuth(ZISService *service, diff --git a/h/zis/zisstubs.h b/h/zis/zisstubs.h index 06ad5201a..13a0a66e2 100644 --- a/h/zis/zisstubs.h +++ b/h/zis/zisstubs.h @@ -20,7 +20,7 @@ FULL BACKWARD COMPATIBILITY MUST BE MAINTAINED */ -#define ZIS_STUBS_VERSION 2 +#define ZIS_STUBS_VERSION 3 /* How does a user check for compatibility? @@ -362,6 +362,8 @@ #define ZIS_STUB_LETMRLEE 457 /* termRLEEnvironment */ #define ZIS_STUB_LEMKFCAA 458 /* makeFakeCAA */ #define ZIS_STUB_LEARTCAA 459 /* abortIfUnsupportedCAA */ +#define ZIS_STUB_LESETANC 460 /* setRLEApplicationAnchor */ +#define ZIS_STUB_LEGETANC 461 /* getRLEApplicationAnchor */ /* logging, 470-499 */ #define ZIS_STUB_MKLOGCTX 470 /* makeLoggingContext */ diff --git a/plugins/zis/README.md b/plugins/zis/README.md new file mode 100644 index 000000000..f00153be4 --- /dev/null +++ b/plugins/zis/README.md @@ -0,0 +1,592 @@ +This program and the accompanying materials are +made available under the terms of the Eclipse Public License v2.0 which accompanies +this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + +SPDX-License-Identifier: EPL-2.0 + +Copyright Contributors to the Zowe Project. +___ + +# ZIS plugin development + + +* [ZIS plugin development](#zis-plugin-development) + * [Preface](#preface) + * [Terminology](#terminology) + * [Overview](#overview) + * [What is Zowe Cross-Memory Server?](#what-is-zowe-cross-memory-server) + * [When do I need ZIS?](#when-do-i-need-zis) + * [Extending ZIS](#extending-zis) + * [Plugin structure](#plugin-structure) + * [Module](#module) + * [Services](#services) + * [Callbacks](#callbacks) + * [Plugin lifecycle](#plugin-lifecycle) + * [ZIS startup](#zis-startup) + * [ZIS termination](#zis-termination) + * [Service call](#service-call) + * [z/OS operator modify command invocation](#zos-operator-modify-command-invocation) + * [Making a plugin](#making-a-plugin) + * [Plugin descriptor](#plugin-descriptor) + * [Plugin name](#plugin-name) + * [Plugin nickname](#plugin-nickname) + * [Plugin flags](#plugin-flags) + * [Plugin version](#plugin-version) + * [Plugin services](#plugin-services) + * [Service name](#service-name) + * [Service flags](#service-flags) + * [Service serve function](#service-serve-function) + * [Putting it all together](#putting-it-all-together) + * [Building a plugin](#building-a-plugin) + * [Compilation](#compilation) + * [Compiler requirements](#compiler-requirements) + * [Assembly](#assembly) + * [Assembler requirements](#assembler-requirements) + * [Recommended options](#recommended-options) + * [Linking](#linking) + * [Linker requirement](#linker-requirement) + * [Dynamic linkage stub](#dynamic-linkage-stub) + * [Deploying a plugin](#deploying-a-plugin) + * [Dynamic linkage considerations](#dynamic-linkage-considerations) + * [Plugin details](#plugin-details) + * [Serve function environment](#serve-function-environment) + * [Other callbacks' environment](#other-callbacks-environment) + * [User parameter list](#user-parameter-list) + * [Accessing caller's data](#accessing-callers-data) + * [Function return codes](#function-return-codes) + * [PC-ss vs PC-cp service](#pc-ss-vs-pc-cp-service) + * [Notes](#notes) + * [Plugin security](#plugin-security) + * [Dev mode](#dev-mode) + * [General ZIS dev mode](#general-zis-dev-mode) + * [LPA dev mode](#lpa-dev-mode) + + +## Preface + +**IMPORTANT:** Zowe Cross-Memory Server plugins execute with elevated +privileges, writing code for plugins requires you to be familiar with the +operating system, principles of cross memory communication and implications of +running your code in an authorized environment. + +Before making a new plugin, we recommend that extenders read the following +sources: +* [Synchronous cross memory communication](https://www.ibm.com/docs/en/zos/2.5.0?topic=guide-synchronous-cross-memory-communication) + +## Terminology + +Before we start, we need to clarify some abbreviations and terminology. +* A/S - address space +* HASN/PASN/SASN - the home/primary/secondary address space +* HLASM - High Level Assembler +* LPA - the link pack area +* PC - program call + * PC-ss - space-switch PC + * PC-cp - current-primary PC +* ZIS - Zowe Cross-Memory Server + +## Overview + +### What is Zowe Cross-Memory Server? +* Zowe Cross-Memory Server (also known as ZIS) is an authorized server +application that provides both privileged services and cross-memory services to unprivileged +applications on z/OS in a secure manner. +* Each ZIS instance is identified by a unique 16-character name (LPAR wide) +* ZIS runs as a started task + +### When do I need ZIS? +* Your service code requires a system key, supervisor state and/or +APF-authorization +* You want to provide services to applications that can’t use HTTP or the +standard IPC mechanisms + +### Extending ZIS +ZIS has the ability to be extended with third-party plugins. Usually, a plugin +consists of a single load module and a line of configuration. This document +will specifically go into details on how to develop and use ZIS plugins. + +Throughout this document we'll use snippets from the sample plugin code in [zss/plugins/zis/sample/](https://github.com/zowe/zss/tree/82c6f2d30951d64fb1bb6487c2dde92700b91552/plugins/zis/sample). +Refer to that source for the full plugin sample. + +## Plugin structure + +### Module +A ZIS plugin is a load module with the following characteristics: +* AMODE 64 +* Reentrant +* The result of call a ZIS plugin lod module is a plugin descriptor data +structure mapped by the C struct [`ZISPlugin`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L81-L112) + +### Services +Each plugin consists of 0 or more services which are invoked via the PC +instruction (program call). + +### Callbacks + +There are several callbacks plugin developers can set to better control +the lifecycle of plugins and services. All the callbacks except for the "serve" +service callback are invoked inside the ZIS address space. Depending on the +service configuration the "serve" callback is invoked in either the caller's +address space or the ZIS address space + +Plugin callbacks: +* **init**: invoked upon ZIS startup +* **term**: invoked upon ZIS termination +* **command handler**: invoked when a ZIS modify command uses the plugin as its +target + +Service callbacks: +* **init**: invoked upon ZIS startup +* **term**: invoked upon ZIS termination +* **serve**: invoked when the service is called + +## Plugin lifecycle + +### ZIS startup +For each plugin: +* Load the plugin module into the ZIS A/S private storage +* Call the entry point +* Process the result `ZISPlugin` struct and relocate the plugin module to LPA if +required (controlled by plugin parameters) +* Call the plugin "init" function +* For each plugin service, call the service "init" function + +When done ZIS sets the "ready" flag and accepts requests + +### ZIS termination +First, ZIS unsets the "ready" flag and stops accepting requests. +Then, for each plugin: +* For each service, call the service "term" function +* Call the plugin "term" function + +Any plugin module that has been loaded to LPA will remain in LPA. + +### Service call +* ZIS looks up the service using the caller-specified plugin and service name +* In the corresponding program call handler ZIS invokes the "serve" function of +the service + +### z/OS operator modify command invocation +* ZIS looks up the plugin using the modify command target, which is a plugin +nickname +* Call the command handler of the target plugin + +There are additional steps in dev mode which are described in the +[Dev mode](#dev-mode) section. + +## Making a plugin + +This section will describe how to create a ZIS plugin using snippets from +the sample plugin as examples. The sample plugin has a single service that +returns the content of the control registers to a problem state caller (a simple +LE client application). The register content is read using the `STCTG` HLASM +instruction, which is a privileged operation and cannot be performed inside +problem state applications. + +### Plugin descriptor + +A valid plugin must return the address of the [`ZISPlugin`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L81-L112) +struct describing the plugin itself and its services. That struct is created +using the [`zisCreatePlugin`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L139) +function. + +Here's an example of how to use it: +```c +ZISPlugin *plugin = zisCreatePlugin( + (ZISPluginName) {SAMPLE_PLUGIN_NAME}, + (ZISPluginNickname) {SAMPLE_PLUGIN_NICKNAME}, + NULL, // plugin "init" function + NULL, // plugin "term" function + NULL, // plugin "modify command" handler + 1, // plugin version + 1, // number of services + ZIS_PLUGIN_FLAG_NONE // plugin flags +); +``` + +For now the most important parameters are the plugin name, nickname, flags and +version. + +##### Plugin name +* Mapped by the [`ZISPluginName`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L40) +struct +* A 16-character printable EBCDIC string +* Uniquely identifies a plugin within ZIS +##### Plugin nickname +* Mapped by the [`ZISPluginNickname`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L45) +struct +* A 4-character printable EBCDIC string +* Uniquely identifies a plugin for modify commands within ZIS +##### Plugin flags +* Control various aspects of a plugin +* By default, plugin modules are only loaded into the private ZIS storage, but +when the [`ZIS_PLUGIN_FLAG_LPA`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L63) +flag is set, the module will be loaded to LPA +##### Plugin version +* ZIS uses the plugin version value to refresh the plugin module in LPA if +needed, i.e. when a different version is detected, the current LPA module is +discarded and the new version is loaded + +**IMPORTANT:** when any changes to a plugin or its service are made, the version +must be incremented, so that the LPA module gets refreshed. During development +process that can be avoided, see [LPA dev mode](#lpa-dev-mode). + +Please refer to the [`zisCreatePlugin` doc](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L124-L138) +for more details. + +### Plugin services + +Once we have our plugin descriptor, we can start creating and adding services to +the plugin. + +A service can be created with the [`zisCreateService`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L137) +function. + +```c +ZISService service = zisCreateService( + (ZISServiceName) {GETCR_SERVICE_NAME}, + ZIS_SERVICE_FLAG_SPACE_SWITCH, // service flags + NULL, // service "init" function + NULL, // service "term" function + serveControlRegisters, // service "serve" function + 1 // service version +); +``` + +The parameters we're interested in at the moment are the service name, flags +and the "serve" function (see more details in [`zisCreateService` doc](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L126-L136) +). + +##### Service name +* Mapped by the [`ZISServiceName`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L42) +struct +* A 16-character printable EBCDIC string +* Uniquely identifies a service within its plugin +##### Service flags +* Control various aspects of a service +* By default, services are invoked in the PC-cp handler, to make a service +space-switch, use `ZIS_SERVICE_FLAG_SPACE_SWITCH` (see details in [this](#pc-ss-vs-pc-cp-service) +section) +* You can also protect a service with an additional SAF check by setting the +`ZIS_SERVICE_FLAG_SPECIFIC_AUTH` flag (see details in [this](#plugin-security) +section) +##### Service serve function +* Invoked when a service is called +* Depending on the type of the service, it's either invoked in the PC-ss or +PC-cp ZIS handler (i.e. either the ZIS A/S or caller's primary A/S) + +After a service has been created, it should be added to the plugin descriptor +using the [`zisPluginAddService`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L164) +function. + +### Putting it all together + +When you have finished building the plugin descriptor and added all the +services, the descriptor should be returned from the entry point function of +your plugin. Below is a full example of such an entry point. + +```c +ZISPlugin *getPluginDescriptor(void) { + + // this call will create a plugin data structure with the provided plugin + // name and nickname + ZISPlugin *plugin = zisCreatePlugin( + (ZISPluginName) {SAMPLE_PLUGIN_NAME}, + (ZISPluginNickname) {SAMPLE_PLUGIN_NICKNAME}, + NULL, // plugin "init" function + NULL, // plugin "term" function + NULL, // plugin "modify command" handler + 1, // plugin version + 1, // number of services + ZIS_PLUGIN_FLAG_NONE // plugin flags + ); + if (plugin == NULL) { + return NULL; + } + + // add a single service to our plugin + ZISService service = zisCreateService( + (ZISServiceName) {GETCR_SERVICE_NAME}, + ZIS_SERVICE_FLAG_SPACE_SWITCH, // service flags + NULL, // service "init" function + NULL, // service "term" function + serveControlRegisters, // service "serve" function + 1 // service version + ); + int addRC = zisPluginAddService(plugin, service); + if (addRC != RC_ZIS_PLUGIN_OK) { + zisDestroyPlugin(plugin); + return NULL; + } + + return plugin; +} +``` + +## Building a plugin + +To build your plugin only the plugin sources will need to be compiled and +assembled. Considering the [dynamic linkage](#dynamic-linkage-stub) is used, all +the [zss](https://github.com/zowe/zss) and [zowe-common-c](https://github.com/zowe/zowe-common-c) +functionality will be available dynamically and only the corresponding headers +will be needed. + +### Compilation + +Plugin sources are compiler using the XL C/C++ compiler. + +#### Compiler requirements +* Metal C (`-S -qmetal -DMETTLE=1`) +* 64-bit (`-q64`) +* Reserved GPR12 (`-qreserved_reg=r12`) +* Read-only constants (`-qroconst`) +* Long names (`-qlongname`) + +### Assembly + +Plugin objects are built using the `as` tool. + +#### Assembler requirements +* GOFF (`-mgoff`) +* Produce object (`-mobject`) + +#### Recommended options +* Check reenterability (`--RENT`) + +### Linking + +Plugin modules are linked using the `ld` linker. + +#### Linker requirement +* Reenterable (`-b reus=rent`) +* Mixed case (`-b case=mixed`) + +**There is no requirement to link-edit plugin load modules with AC(1).** + +You can find the complete build script with all the options in the sample plugin +(see [`zss/plugins/zis/sample/build.sh`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/plugins/zis/sample/build.sh) +). + +### Dynamic linkage stub + +Starting from Zowe v2.4 ZIS plugins can use dynamic linkage. That is achieved +by linking plugin modules with a special HLASM-based stub. The stub is +generated using the tools in [`zss/tools/dynzis`](https://github.com/zowe/zss/tree/82c6f2d30951d64fb1bb6487c2dde92700b91552/tools/dynzis). + +An example of how to generate the stub. +```shell +# build the tool +javac -encoding iso8859-1 zss/tools/dynzis/org/zowe/zis/ZISStubGenerator.java +# generate the stub HLASM +java -cp zss/tools/dynzis org.zowe.zis.ZISStubGenerator asm zss/h/zis/zisstubs.h > dynzis.s +``` + +Once the stub has been generated, assemble and link it with your plugin objects. + +See [zss/tools/dynzis/README.md](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/tools/dynzis/README.md) +for more details. + +## Deploying a plugin + +Put the plugin module in a data set in the ZIS STEPLIB concatenation and add +the following line to the ZIS PARMLIB member: +``` +ZWES.PLUGIN.id=module_name +``` + +Where +* `id` is a string with no blanks, which is unique within the `ZWES.PLUGIN` +scope in your config member +* `module_name` is the module name of your plugin + +### Dynamic linkage considerations + +If your plugin utilizes the dynamic linkage, the dynamic linkage plugin must +also be added to the config. + +Add the following line to the config member to enable the dynamic linkage +plugin: +``` +ZWES.PLUGIN.DYNL=ZWESISDL +``` + +## Plugin details + +### Serve function environment + +Depending on the caller, the "serve" function is invoked in the following +environment: +* Authorization: key 4 and supervisor state +* Dispatchable unit mode: task or SRB +* Cross memory mode: + * If PC-ss, PASN will point to ZIS A/S and SASN will point to the caller's A/S + * If PC-cp, both PASN and SASN will point to the caller's A/S +* AMODE: 64-bit +* ASC mode: primary +* Interrupt status: enabled or disabled for I/O and external interrupts +* Locks: any lock except CMS or no locks held +* Active RLE environment + * Recovery context is established (either ESTAE or FRR depending on the + environment) and recovery functionality is available using [`recoveryPush`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/recovery.h#L487) + and [`recoveryPop`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/recovery.h#L503) + * No logging context is created but logging is available using [`cmsPrintf`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/crossmemory.h#L517) + +### Other callbacks' environment + +The plugin and service "init", "term" functions and the plugin +"command handler" function are invoked in the following environment: +* Authorization: APF-authorized, key 4 and problem state +* Dispatchable unit mode: task +* Cross memory mode: HASN=PASN=SASN +* AMODE: 64-bit +* ASC mode: primary +* Interrupt status: enabled for I/O and external interrupts +* Locks: no locks held +* Active RLE environment + * Recovery context is established (ESTAE) and recovery functionality is + available using [`recoveryPush`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/recovery.h#L487) + and [`recoveryPop`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/recovery.h#L503) + * Logging context is created and logging is available using [`zowelog`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/logging.h#L337) + +#### User parameter list + +ZIS will pass the address of the caller's parameter list in the caller's primary +address space to the service "serve" function. However, it will be opaque. The +plugin developer and the client need to agree of the parameter list format. + +Here are some guidelines: +* Include an eye-catcher field which can be later validated by the service +* Include a version field for compatibility +* Make sure the parameter list has the same layout and size in Metal C 31-bit, +Metal C 64-bit, LE 31-bit, etc. That can be done using `__packed` or the [`ZOWE_PARGMA_PACK`/`ZOWE_PRAGMA_PACK_RESET` macros](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/zowetypes.h#L178-L179). + +The following is an example of a parameter list taken from the sample: +```c +typedef __packed struct GetCRServiceParm_tag { +#define GETCR_SERVICE_PARM_EYECATCHER "GETCRPRM" +#define GETCR_SERVICE_PARM_VERSION 1 + char eyecatcher[8]; + uint8_t version; + ControlRegisters result; +} GetCRServiceParm; +``` + +#### Accessing caller's data + +All the virtual storage from the caller's address space, including the parameter +list, must be read using the [`cmCopyFromSecondaryWithCallerKey`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/cmutils.h#L104) +function and written to using the [`cmCopyToSecondaryWithCallerKey`](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/cmutils.h#L92) +function. Among other things, this will ensure that a malicious caller will not +use ZIS to access storage using ZIS'es privileged key. + +An example of how to copy a parameter list and return results: +```c + +void *serviceParmList = ...; // parameter list in the caller's A/S +GetCRServiceParm localParmList; // parameter list in the primary A/S + +cmCopyFromSecondaryWithCallerKey(&localParmList, serviceParmList, + sizeof(localParmList));sa +. . . +cmCopyToSecondaryWithCallerKey(serviceParmList, &localParmList, + sizeof(localParmList)); +``` + +#### Function return codes + +Your "serve" function must return [`RC_ZIS_SRVC_OK`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L201) +in case of success and for any other return values the value larger than +[`ZIS_MAX_GEN_SRVC_RC`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L215) +must be used. + +For example: +```c +#define RC_GETCR_OK RC_ZIS_SRVC_OK +#define RC_GETCR_BAD_EYECATCHER (ZIS_MAX_GEN_SRVC_RC + 1) +#define RC_GETCR_BAD_VERSION (ZIS_MAX_GEN_SRVC_RC + 2) +``` + +The values in the range (`RC_ZIS_SRVC_OK`, `ZIS_MAX_GEN_SRVC_RC`] are reserved. + +### PC-ss vs PC-cp service + +Depending on the nature of your service, set the [`ZIS_SERVICE_FLAG_SPACE_SWITCH`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L96) +flag so that the service is invoked in either the PC-ss or PC-cp ZIS program +call handler. The main differences between PC-ss and PC-cp are described below. + +| Feature | PC-ss | PC-cp | Examples | +|---------------------------------------------------------------|-------|-------|---------------------------------------| +| Access to resources inside or owned by ZIS A/S | Yes | No | Allocating storage inside the ZIS A/S | +| Code isolation | Yes | No | | +| Service code in private storage 1 | Yes | No | | +| Execute services that are not supported in cross-memory mode | No | Yes | Calling an SVC, performing basic I/O | + +##### Notes +1. The code used by a PC-cp service must be in commonly addressable storage +(to facilitate that ZIS can automatically place the plugin module in LPA, see +[`ZIS_PLUGIN_FLAG_LPA`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/plugin.h#L90)) + +### Plugin security + +Every ZIS caller must have READ access to the "ZWES.IS" profile in the "FACILITY" +class. In addition to that, plugin developers can add another SAF check via +the [`zisServiceUseSpecificAuth`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L187) function. + +First, set the [`ZIS_SERVICE_FLAG_SPECIFIC_AUTH`](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/service.h#L97) +flag when creating a service, then call `zisServiceUseSpecificAuth` to set the +SAF profile to which you wish the callers' READ access to be checked +when calling the service. + +The SAF profile must be in a RACLISTed class, that is, be present in virtual +storage as opposed to just being in the RACF database on disk. + +## Dev mode + +When loading a new version of a plugin ZIS discards the previous version of +the plugin module and never deletes it from LPA. This is done for security and +integrity reasons. However, during development process you usually rebuild your +plugin multiple times and that would be wasteful to always leave the old version +in LPA, because LPA is a very limited resource. To prevent LPA exhaustion and +avoid wasting some other common resources ZIS has introduced various development +modes. + +**IMPORTANT:** never use the development modes in production as they might lead +to system integrity exposures. + +### General ZIS dev mode + +This is a dev mode which when enabled will include the following modes: +* [LPA dev mode](#lpa-dev-mode) + +To enable the general ZIS dev mode, add the following line to the config member: +``` +ZWES.DEV_MODE=YES +``` + +### LPA dev mode + +When the LPA dev mode is on, at startup and termination ZIS will remove the old +version of the ZIS load module and any plugin modules from LPA. + +To enable the LPA dev mode, add the following line to the config member: +``` +ZWES.DEV_MODE.LPA=YES +``` + +You should see the following messages IDs when the dev mode is on: +* [ZWES0247W](https://github.com/zowe/zowe-common-c/blob/4f2732d0e781aec89b39f862262d5014a97c09b7/h/crossmemory.h#L1043-L1047) +* [ZWES0213W](https://github.com/zowe/zss/blob/82c6f2d30951d64fb1bb6487c2dde92700b91552/h/zis/message.h#L303-L305) +(if the dynamic linkage plugin is used) + +Additionally, the dynamic linkage plugin will remove its old stub vector from +common storage, since it can no longer reference the old LPA plugin module. + +___ + +This program and the accompanying materials are +made available under the terms of the Eclipse Public License v2.0 which accompanies +this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + +SPDX-License-Identifier: EPL-2.0 + +Copyright Contributors to the Zowe Project. diff --git a/plugins/zis/sample/README.md b/plugins/zis/sample/README.md new file mode 100644 index 000000000..48f57955e --- /dev/null +++ b/plugins/zis/sample/README.md @@ -0,0 +1,50 @@ +This program and the accompanying materials are +made available under the terms of the Eclipse Public License v2.0 which accompanies +this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + +SPDX-License-Identifier: EPL-2.0 + +Copyright Contributors to the Zowe Project. +___ + +# ZIS sample plugin + +## Build + +Run the following command to build both the plugin and the client application: +```shell +> ./build.sh +``` + +The plugin module `ZISSAMPL` will be placed into the `user_name.DEV.LOADLIB` +data set and the client binary will be stored in `./bin`. + +## Deploy + +* Make sure the plugin module is in a data sets which is part of the STEPLIB +concatenation of your ZIS. +* Add the following line to your ZIS PARMLIB config member: +``` +ZWES.PLUGIN.SMPL=ZISSAMPL +``` +* Additionally, make sure you have the dynamic linkage plugin in your config: +``` +ZWES.PLUGIN.DYNL=ZWESISDL +``` + +## Run + +* Restart your ZIS +* Run the client with the ZIS name as the argument +```shell +> ./bin/sample_client +``` +___ + +This program and the accompanying materials are +made available under the terms of the Eclipse Public License v2.0 which accompanies +this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + +SPDX-License-Identifier: EPL-2.0 + +Copyright Contributors to the Zowe Project. diff --git a/plugins/zis/sample/build.sh b/plugins/zis/sample/build.sh new file mode 100755 index 000000000..18edf62c2 --- /dev/null +++ b/plugins/zis/sample/build.sh @@ -0,0 +1,67 @@ +#!/bin/sh +set -e + +# This program and the accompanying materials are +# made available under the terms of the Eclipse Public License v2.0 which accompanies +# this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html +# +# SPDX-License-Identifier: EPL-2.0 +# +# Copyright Contributors to the Zowe Project. + +ZSS=../../../../../zss +COMMON=$ZSS/deps/zowe-common-c + +# compile, assembler and linker flags for the sample plugin +CFLAGS="-S -qmetal -DMETTLE=1 -q64 -qreserved_reg=r12 -qroconst -qlongname" +ASFLAGS="-mgoff -mobject --RENT" +LDFLAGS="-b reus=rent -b case=mixed" +CFLAGS_INFO="-qlist= -qaggregate -qexpmac -qsource -qoffset -qxref" +LDFLAGS_INFO="-V -b map -b xref" + +PLUGIN_INCLUDES="-I ${COMMON}/h -I ${ZSS}/h -I ." + +# build the sample plugin +# - build the java generator tool and generate the HLASM stubs for dynamic linkage +# - build the plugin itself +mkdir -p tmp_plugin +cd tmp_plugin + +javac -encoding iso8859-1 ${ZSS}/tools/dynzis/org/zowe/zis/ZISStubGenerator.java +java -cp ${ZSS}/tools/dynzis org.zowe.zis.ZISStubGenerator asm \ + ${ZSS}/h/zis/zisstubs.h > dynzis.s + +xlc ${CFLAGS} ${CFLAGS_INFO} ${PLUGIN_INCLUDES} \ + $ZSS/plugins/zis/sample/sample_plugin.c +as ${ASFLAGS} -aegimrsx=sample_plugin.asm sample_plugin.s +as ${ASFLAGS} -aegimrsx=dynzis.asm dynzis.s +ld ${LDFLAGS} ${LDFLAGS_INFO} -e getPluginDescriptor \ +-o "//'$USER.DEV.LOADLIB(ZISSAMPL)'" \ +sample_plugin.o dynzis.o > sample_plugin.link +cd .. + +# build the sample client +mkdir -p tmp_client +mkdir -p bin +cd tmp_client +xlc "-Wa,goff" \ +"-Wc,langlvl(extc99),asm,asmlib('SYS1.MACLIB'),lp64,xplink" \ +-DCMS_CLIENT -D_OPEN_THREADS=1 -I $COMMON/h -I $ZSS/h \ +${COMMON}/c/alloc.c \ +${COMMON}/c/cmutils.c \ +${COMMON}/c/crossmemory.c \ +${COMMON}/c/timeutls.c \ +${COMMON}/c/utils.c \ +${COMMON}/c/zos.c \ +${COMMON}/c/zvt.c \ +${ZSS}/c/zis/client.c \ +-o ../bin/sample_client ../sample_client.c +cd .. + +# This program and the accompanying materials are +# made available under the terms of the Eclipse Public License v2.0 which accompanies +# this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html +# +# SPDX-License-Identifier: EPL-2.0 +# +# Copyright Contributors to the Zowe Project. diff --git a/plugins/zis/sample/sample_client.c b/plugins/zis/sample/sample_client.c new file mode 100644 index 000000000..58b3b5878 --- /dev/null +++ b/plugins/zis/sample/sample_client.c @@ -0,0 +1,64 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#include +#include + +#include "zis/client.h" + +#include "sample_plugin.h" + +int main(int argc, char **argv) { + + if (argc < 2) { + printf("error: too few parameters\n"); + printf("usage: > sample_client \n"); + exit(EXIT_FAILURE); + } + + GetCRServiceParm parmList = { + .eyecatcher = GETCR_SERVICE_PARM_EYECATCHER, + .version = GETCR_SERVICE_PARM_VERSION, + }; + + CrossMemoryServerName xmemName = cmsMakeServerName(argv[1]); + ZISServicePath servicePath = { + .pluginName = SAMPLE_PLUGIN_NAME, + .serviceName = GETCR_SERVICE_NAME, + }; + ZISServiceStatus status; + + int callRC = zisCallService(&xmemName, &servicePath, &parmList, &status); + if (callRC == RC_GETCR_OK) { + printf("info: successfully called the \'%s\' service:\n", + GETCR_SERVICE_NAME); + size_t crCount = sizeof(parmList.result.reg) / sizeof(parmList.result.reg[0]); + for (size_t regIdx = 0; regIdx < crCount; regIdx++) { + printf(" CR%-2zu = 0x%016llX\n", regIdx, parmList.result.reg[regIdx]); + } + exit(EXIT_SUCCESS); + } else { + printf("error: service call failed - call RC = %d, " + "service RC = %d, CMS RC = %d\n", callRC, + status.serviceRC, status.cmsRC); + exit(EXIT_FAILURE); + } + +} + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ \ No newline at end of file diff --git a/plugins/zis/sample/sample_plugin.c b/plugins/zis/sample/sample_plugin.c new file mode 100644 index 000000000..e2067f8f7 --- /dev/null +++ b/plugins/zis/sample/sample_plugin.c @@ -0,0 +1,145 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#include +#include +#include + +#include "zowetypes.h" +#include "cmutils.h" +#include "zis/plugin.h" + +#include "sample_plugin.h" + +// forward declaration of the "serve" function +static int serveControlRegisters(const CrossMemoryServerGlobalArea *ga, + ZISServiceAnchor *anchor, + ZISServiceData *data, + void *serviceParmList); + +ZISPlugin *getPluginDescriptor(void) { + + // this call will create a plugin data structure with the provided plugin + // name and nickname + ZISPlugin *plugin = zisCreatePlugin( + (ZISPluginName) {SAMPLE_PLUGIN_NAME}, + (ZISPluginNickname) {SAMPLE_PLUGIN_NICKNAME}, + NULL, // plugin "init" function + NULL, // plugin "term" function + NULL, // plugin "modify command" handler + 1, // plugin version + 1, // number of services + ZIS_PLUGIN_FLAG_NONE // plugin flags + ); + if (plugin == NULL) { + return NULL; + } + + // add a single service to our plugin + ZISService service = zisCreateService( + (ZISServiceName) {GETCR_SERVICE_NAME}, + ZIS_SERVICE_FLAG_SPACE_SWITCH, // service flags + NULL, // service "init" function + NULL, // service "term" function + serveControlRegisters, // service "serve" function + 1 // service version + ); + int addRC = zisPluginAddService(plugin, service); + if (addRC != RC_ZIS_PLUGIN_OK) { + zisDestroyPlugin(plugin); + return NULL; + } + + return plugin; +} + +// forward declaration of the helper functions +static int verifyGetCRServiceParmList(const GetCRServiceParm *parmList); +void getControlRegisters(ControlRegisters *result); + +/** + * This is the "serve" function of the "get CR" service. It will be invoked by + * the cross-memory server once the respective service is called. + * @param[in] ga the cross-memory server's global area. + * @param[in,out] anchor the ZIS anchor provided by the cross-memory server. + * @param[in,out] data the service data provided by the cross-memory server. + * @param[in,out] serviceParmList the parameter list from the caller. + * @return the service's return code. + */ +static int serveControlRegisters(const CrossMemoryServerGlobalArea *ga, + ZISServiceAnchor *anchor, + ZISServiceData *data, + void *serviceParmList) { + + // since the caller's parameter list is in a different address space, we + // have to copy it to a local variable using a special copy function + GetCRServiceParm localParmList; + cmCopyFromSecondaryWithCallerKey(&localParmList, serviceParmList, + sizeof(localParmList)); + + // it's good practice to validate the parameter list + // see all the details in the helper function + int verifyRC = verifyGetCRServiceParmList(&localParmList); + if (verifyRC != RC_GETCR_OK) { + return verifyRC; + } + + // now, let's perform a privileged operation and extract the control registers + getControlRegisters(&localParmList.result); + + // finally, we need to return the result to the caller by copying the updated + // parameter list to the caller's address space + cmCopyToSecondaryWithCallerKey(serviceParmList, &localParmList, + sizeof(localParmList)); + + return RC_GETCR_OK; +} + +/** + * Verify the "get CR" service's parameter list. + * @param parmList the parameter list to be verified. + * @return @c RC_GETCR_OK in case of success and the corresponding + * RC_GETCR_XXXX value in case of failure. + */ +static int verifyGetCRServiceParmList(const GetCRServiceParm *parmList) { + if (memcmp(parmList->eyecatcher, GETCR_SERVICE_PARM_EYECATCHER, + sizeof(parmList->eyecatcher))) { + return RC_GETCR_BAD_EYECATCHER; + } + if (parmList->version != GETCR_SERVICE_PARM_VERSION) { + return RC_GETCR_BAD_VERSION; + } + return RC_GETCR_OK; +} + +/** + * Extract the content of the control registers. + * @param[out] result the 64-bit value from CR. + */ +void getControlRegisters(ControlRegisters *resultRegisters) { + ControlRegisters regs __attribute__((aligned(8))) = {0}; + __asm( + " STCTG 0,15,%[result] \n" + : [result]"=m"(regs) + : + : + ); + *resultRegisters = regs; +} + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ \ No newline at end of file diff --git a/plugins/zis/sample/sample_plugin.h b/plugins/zis/sample/sample_plugin.h new file mode 100644 index 000000000..b40da0298 --- /dev/null +++ b/plugins/zis/sample/sample_plugin.h @@ -0,0 +1,49 @@ +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + + SPDX-License-Identifier: EPL-2.0 + + Copyright Contributors to the Zowe Project. +*/ + +#ifndef PLUGINS_ZIS_SAMPLE_PLUGIN_H +#define PLUGINS_ZIS_SAMPLE_PLUGIN_H + +// these are the codes returned by the "get CR" service +// the success return code must be equal to @c RC_ZIS_SRVC_OK and any other +// return codes must have values larger than @c ZIS_MAX_GEN_SRVC_RC +#define RC_GETCR_OK RC_ZIS_SRVC_OK +#define RC_GETCR_BAD_EYECATCHER (ZIS_MAX_GEN_SRVC_RC + 1) +#define RC_GETCR_BAD_VERSION (ZIS_MAX_GEN_SRVC_RC + 2) + +#define SAMPLE_PLUGIN_NAME "SAMPLE " +#define SAMPLE_PLUGIN_NICKNAME "SMPL" + +#define GETCR_SERVICE_NAME "GET_CTRL_REGS " + +typedef __packed struct ControlRegisters_tag { + uint64_t reg[16]; +} ControlRegisters; + +/** + * This struct describes the parameter list of the "get CR" service. + */ +typedef __packed struct GetCRServiceParm_tag { +#define GETCR_SERVICE_PARM_EYECATCHER "GETCRPRM" +#define GETCR_SERVICE_PARM_VERSION 1 + char eyecatcher[8]; + uint8_t version; + ControlRegisters result; +} GetCRServiceParm; + +#endif //PLUGINS_ZIS_SAMPLE_PLUGIN_H + +/* + This program and the accompanying materials are + made available under the terms of the Eclipse Public License v2.0 which accompanies + this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + SPDX-License-Identifier: EPL-2.0 + Copyright Contributors to the Zowe Project. +*/ diff --git a/tests/build_zisdl.sh b/tests/build_zisdl.sh old mode 100644 new mode 100755 index 29882af48..4264eabf1 --- a/tests/build_zisdl.sh +++ b/tests/build_zisdl.sh @@ -1,11 +1,4 @@ #!/bin/sh -# -# OMEGAMON Open Data -# V1R1M0 -# 5698-B6603 © Copyright Rocket Software, Inc. or its affiliates. 2021. -# All rights reserved. -# - set -e ################################################################################ @@ -25,15 +18,18 @@ COMMON="../../deps/zowe-common-c" echo "********************************************************************************" echo "Building ZIS Dynamic Linkage test..." -mkdir -p "${WORKING_DIR}/tmp-zisdl" && cd "$_" +mkdir -p "${WORKING_DIR}/tmp-zisdl" +cd ${WORKING_DIR}/tmp-zisdl + +javac -encoding iso8859-1 ${ZSS}/tools/dynzis/org/zowe/zis/ZISStubGenerator.java +java -cp ${ZSS}/tools/dynzis org.zowe.zis.ZISStubGenerator asm \ + ${ZSS}/h/zis/zisstubs.h > stubs.s xlc -S -M -qmetal -q64 -DMETTLE=1 \ -qreserved_reg=r12 \ -Wc,arch\(8\),agg,exp,list\(\),so\(\),off,xref,roconst,longname,lp64 \ -I ${COMMON}/h -I ${ZSS}/h ../zisdl.c -cp ${ZSS}/c/zis/stubs.s . - for file in \ zisdl stubs do diff --git a/version.txt b/version.txt index 197c4d5c2..437459cd9 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.4.0 +2.5.0