识别环境、z/OS UNIX 与 JCL 或 TSO
Posted
技术标签:
【中文标题】识别环境、z/OS UNIX 与 JCL 或 TSO【英文标题】:Identify environment, z/OS UNIX vs JCL or TSO 【发布时间】:2020-03-29 09:09:08 【问题描述】:我可以从 C 程序内部调用什么函数,以发现程序正在哪个 z/OS 环境中运行,例如它是 z/OS UNIX(又名 USS)还是来自 TSO,比如通过 JCL?
【问题讨论】:
使用 LE 可调用服务CEE3INF。 完美!谢谢。 @cschneid CEE3INF 有什么特别之处,它不能在 C 中的 main 函数以外的任何地方运行?如果我尝试将代码放入函数中,它会异常结束。 我知道没有什么特别的。我无法访问 z/OS 机器,所以我现在无法进行实验,抱歉。 @cschneid,文档的使用说明中有一行写着“z/OS UNIX 的注意事项——CEE3INF 只允许在线程中使用”——这感觉像是一个不完整的句子,但我想知道是否它试图说“仅在主要方面”。无论如何,感谢您指向此功能的指针。即使有这个明显的限制,它也正是我所需要的。真遗憾,您不能将您的评论写成答案! 【参考方案1】:有两种方法:CEE3INF,以及翻阅 z/OS 数据区。
CEE3INF 的优点是可记录在案并可移植到任何 LE 环境,并提供您在 z/OS 结构中不容易找到的有关 PIPI 的信息。
作为 CEE3INF 的替代方案,如果您只需要区分 Batch、TSO、CICS 以及您是否被称为 USS 流程,系统数据区域中有大量信息。替代方法很简单,并且在 LE 环境之外特别有用……尽管在 C 中甚至可以很容易地通过加载一些指针来实现,这些指针可以通过使用 XLC DSECT 到 C 结构的转换实用程序获得。
TSO 地址空间是 ASCBTSB 非零 (PSAAOLD->ASCBTSB) 的地址空间。批处理作业是填写 ASCBJBNI (PSAAOLD->ASCBJBNI) 的作业。 CICS 地址空间的 TCBCAUF 设置为非零 (PSATOLD->TCBCAUF)。
在上述任何一项中,您还可以通过检查 TCB->STCB->STCBOTCB 来检查您的任务是否被称为 UNIX 进程。如果非零,则您已被配音并且可以使用 UNIX 服务。 OTCBPRLI字段有PID等进程信息,THLI有线程级信息。
请注意,给定任务可能有资格使用 USS 功能,但目前还没有。 “querydub()”函数可以帮助您区分已配音的任务与可以配音但尚未配音的任务。
如果您使用 CEE3INF,有一些 cmets 关于它在 main() 函数之外无法正常工作,但我认为问题是 IBM 在其文档中提供的示例中的一个小错误。此示例在我的 z/OS 2.3 和 2.4 系统上运行良好:
#include <leawi.h>
#include <string.h>
#include <ceeedcct.h>
int do_call(void)
_INT4 sys_subsys,env_info,member_id,gpid;
_FEEDBACK fc;
CEE3INF(&sys_subsys,&env_info,&member_id,&gpid,&fc);
if ( _FBCHECK(fc,CEE000) != 0 )
printf("CEE3INF failed with message number %d\n", fc.tok_msgno);
printf("System/Subsystem in hex %08x \n",sys_subsys);
printf("Enviornment info in hex %08x \n",env_info);
printf("Member languages in hex %08x \n",member_id);
printf("GPID information in hex %08x \n",gpid);
printf("\n");
int main(void)
do_call();
这是来自 IBM 手册的示例代码,除了在 CEE3INF 调用中的通知外,IBM 文档有一个错误(“...fc”而不是“...&fc”)。如果在 main() 之外调用 CEE3INF 有一些 cmets 不起作用,但我认为问题只是上面示例中的错误。
为了测试,我使用以下命令在 UNIX Services shell 下编译上面的代码:
xlc -o testinf testinf.c
然后我从 z/OS shell 会话运行可执行文件:
> ./testinf
System/Subsystem in hex 02000002
Enviornment info in hex 00540000
Member languages in hex 10000000
GPID information in hex 04020300
这是一个 z/OS 2.3 系统 - 我在 2.4 上得到了相同的结果。
更新:“在 z/OS UNIX 服务环境中运行”是什么意思?
很容易理解批处理作业、TSO 会话和已启动的任务,但“在 z/OS UNIX 服务环境中运行”是什么意思?在 CICS、IMS 或 WebSphere 等子系统中,“在 xxx 下运行”很容易定义,因为事务在特殊类型的服务地址空间内运行……但不幸的是,UNIX 服务并非如此。
确实,几乎任何在 z/OS 上运行的任务都可以使用 z/OS UNIX 服务,因此实际上没有您可以以传统方式定义的“z/OS UNIX 服务环境”。并行将是 VSAM ...是一个打开 VSAM 文件的程序“在 VSAM 中运行?”。我们可能关心运行 IDCAMS 的程序、打开 VSAM 文件的程序、使用 CICS/VSAM 的程序——但如果没有进一步的限定,“在 VSAM 中运行”并不是特别有意义。此外,“在 VSAM 中运行”并非以批处理、STC 或 TSO 用户身份运行 - 它与 z/OS UNIX 服务相同 - 您可以是批处理作业、已启动任务或 TSO 用户,您还可以是否“在 z/OS UNIX 服务中运行”。
以下是“在 z/OS UNIX 服务中运行”的三个截然不同的定义:
-
工作单元是否已被“配音”为 UNIX 服务进程,因此是否已准备好并能够请求 UNIX 服务内核功能。
工作单元是否在 UNIX shell 下运行,例如 /bin/sh。
LE 程序是否使用 POSIX(ON) 运行时选项运行。
为什么会有这些问题?嗯,一些软件——尤其是像其他应用程序调用的运行时库函数——根据调用者是否是 UNIX 进程而表现不同。
想象一下编写一个“OPEN”函数,将文件名作为参数传递。如果您的调用者是 UNIX 进程,您可能会将文件名解释为实际文件名...OPEN(XYZ) 被解释为“检查当前工作目录中是否有名为 'XYZ' 的文件”。但是如果调用者不被称为 UNIX 进程,那么 OPEN(XYZ) 可能意味着打开 'XYZ' DD 语句。您可以使用我上面概述的方法来确定,因为它告诉您您的任务实际上被称为 UNIX 进程。
好的,但是这和上面的#2 有什么不同(在 shell 下运行)?
这是一个例子。假设您有一个可调用例程,想要将消息写入输出文件。大多数非大型机 UNIX 应用程序会简单地写入 STDOUT 或 STDERR,但这并不总是适用于 z/OS,因为许多应用程序是 UNIX 进程,但它们不在 shell 下运行 - 并且没有 shell、STDOUT 和 STDERR可能不存在。
这是场景...
您运行一个与 UNIX 服务无关的常规程序,但它会做一些事情以使自己被称为 UNIX 进程。举个例子,也许有人将“DD PATH=/some/unix/file”放在一个古老的 COBOL 程序的 JCL 中......奇迹般地,当这个 COBOL 批处理作业运行时,它是一个 UNIX 进程,因为它利用UNIX 服务文件系统。 有很多事情可以让您的任务被称为 UNIX 进程...DD PATH 就是其中之一,但即使调用打开 TCP/IP 套接字或类似良性的函数也可以解决问题。也许您正在编写一个供应商产品,它只是一个批处理汇编程序,但它打开了一个 TCP/IP 套接字……这是 UNIX 进程在没有 shell 的情况下运行的另一个常见示例。
那么为什么这是一个问题?好吧,想想如果该可调用函数决定将它的消息写入 STDERR 会发生什么。也许它会测试它是否作为 UNIX 服务进程运行,如果是,它会写入 STDERR,否则它会动态分配并写入 SYSOUT 文件。听起来很简单,但它不适用于我的具有 DD PATH 的应用程序示例。
STDERR 从何而来?通常,UNIX shell 程序会设置它——当您在 shell 下运行程序时,shell 通常会向您的程序传递三个预先打开的文件句柄,即 STDIN、STDOUT 和 STDERR。由于在我的示例场景中没有 shell,这些文件句柄没有传递给应用程序,因此对 STDERR 的写入将失败。实际上,除了STDIN/STDOUT/STDERR,shell 传递给子进程的东西还有很多,比如环境变量、信号处理等等。 (当然,用户可以在他的 JCL 中手动分配 STDIN/STDOUT/STDERR ......我不是在这里谈论)。
如果您想拥有既可以在 shell 下运行又可以在 shell 下不运行的软件,您需要做的不仅仅是查看您的应用程序是否被称为 UNIX 进程:
检查您是否是 UNIX 进程...如果不是,则无法在 shell 下运行。 检查您是否由 shell 启动。有多种方法可以做到这一点,但通常您正在检查您的“父进程”或您传递的环境变量之类的东西。这并不总是容易做到的,因为在 z/OS 上实际上有许多不同的 shell,所以你没有太多可以继续发现“合法”的 shell。更防弹的方法之一是为用户获取登录 shell 并检查它。 作为检查父进程的替代方法,您可以直接检查您需要的资源,例如在我的示例中针对 STDERR 文件句柄调用 ioctl()。当然,这可能很危险...想象一下应用程序打开几个套接字并调用您的函数的情况...您认为真正的 STDIN/STDOUT/STDERR 实际上可能是您的调用者设置的打开文件句柄,你写的东西很容易破坏他的数据。至于我的第三个示例 - 使用 POSIX(ON) 运行的 LE 程序 - 对于使用基于 LE 运行时的高级语言编写的开发人员来说,这在很大程度上是一个问题,因为某些运行时函数的行为与 POSIX(ON) 不同) 或 POSIX(OFF)。
一个例子是 C 程序员编写了一个可以被 POSIX(ON) 和 POSIX(OFF) 调用者调用的函数。假设该函数想要在单独的线程下进行一些后台处理……在 POSIX(ON) 应用程序中,开发人员可能会使用 pthread_create(),但这在 POSIX(OFF) 中不起作用。实际上,IBM 的 LE 运行时中有很多东西会根据 POSIX 设置表现不同:线程、信号处理等。如果您希望编写“通用”代码并且需要这些功能,那么您肯定需要查询执行时的 POSIX 设置,并根据其设置方式采用不同的路径。
希望这能阐明隐藏在这个问题背后的复杂性...“在 z/OS UNIX 环境中运行”的三个不同定义,以及三个不同的用例说明了每个用例为何如此重要。
【讨论】:
如果这对@MoragHughson 有效,我建议您将两个答案结合起来,(如果 Morag 可以接受)她可以接受该答案,我可以删除我的答案。 感谢您的关注!是的,确实是这样。我已经纠正了同样的问题,果然现在它在函数内部工作得很好。非常感谢。如果您想按照@cschneid 的建议进行组合,我很乐意接受您的回答。 好的 - 结合我的两个答案并删除另一个...很高兴听到它对你有用。 您好! :-) 如果我正在编译 LP64,我该如何调用 CEE3INF? KC 中的章节说“列出的可调用服务仅适用于 AMODE 31” 我一直在尝试您提到的控制块爬行,不幸的是,批处理作业不是填写 ASCBJBNI (PSAAOLD->ASCBJBNI) 的作业。在USS中运行时,我也有一个job名,所以这无助于检测USS、TSO和Batch的区别。以上是关于识别环境、z/OS UNIX 与 JCL 或 TSO的主要内容,如果未能解决你的问题,请参考以下文章
在 z/OS Assembler 中,我可以读取 JCL 输入流两次吗?
如何通过 Java Web 应用在 IBM z OS 中提交 JCL?