Определить среду, z/OS UNIX против JCL или TSO
Какую функцию я могу вызвать изнутри программы C, чтобы узнать, в какой среде z/OS выполняется программа, например, это z/OS UNIX (также известный как USS) или это из TSO, скажем, через JCL?
1 ответ
Есть два подхода: CEE3INF и поиск в областях данных z/OS.
CEE3INF имеет то преимущество, что он документирован и переносится в любую среду LE, а также предоставляет информацию о PIPI, которую нелегко найти в структурах z/OS.
В качестве альтернативы CEE3INF в областях системных данных есть много информации, если вам просто нужно различать Batch, TSO, CICS и то, были ли вы дублированы как процесс USS. Альтернатива проста, и она особенно полезна за пределами среды LE... хотя это даже легко сделать на C, просто загрузив некоторые указатели, которые вы можете получить с помощью утилиты преобразования XLC DSECT в C-структуру.
Адресное пространство TSO - это пространство, в котором ASCBTSB не равно нулю (PSAAOLD->ASCBTSB). Пакетное задание - это задание, в котором заполняется ASCBJBNI (PSAAOLD->ASCBJBNI). В адресном пространстве CICS значение TCBCAUF не равно нулю (PSATOLD->TCBCAUF).
В любом из вышеперечисленных вы также можете проверить, была ли ваша задача дублирована как процесс UNIX, выбрав TCB->STCB->STCBOTCB. Если не ноль, значит, вы были дублированы и можете использовать службы UNIX. Поле OTCBPRLI содержит информацию о процессе, такую как PID, а THLI содержит информацию на уровне потока.
Обратите внимание, что данная задача может иметь право использовать функции USS, но это еще не так. Функция querydub() может помочь вам отличить задачу, которая уже была дублирована, от задачи, которая может быть дублирована, но еще не была.
Если вы используете CEE3INF, то были некоторые комментарии о том, что он не работает должным образом вне функции 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"). Были комментарии о том, что CEE3INF не работает при вызове вне main(), но я думаю, что проблема просто в ошибке в примере выше.
Для проверки я компилирую приведенный выше код в оболочке служб UNIX с помощью этой команды:
xlc -o testinf testinf.c
Затем я запускаю исполняемый файл из сеанса оболочки z/OS:
> ./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 Services"?
Легко понять, как пакетные задания отличаются от сеансов TSO и запущенных задач, но что означает "выполнение в среде z/OS UNIX Services"? В таких подсистемах, как 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 Services" или нет.
Вот три очень разных определения "работы в z/OS UNIX Services":
- Была ли единица работы "дублирована" как процесс служб UNIX и, следовательно, готова и способна запрашивать функции ядра служб UNIX.
- Работает ли единица работы под оболочкой UNIX, например /bin/sh.
- Выполняется ли программа LE с параметром времени выполнения POSIX(ON).
Почему это должно иметь значение? Что ж, некоторое программное обеспечение - особенно такие вещи, как функции библиотеки времени выполнения, вызываемые другими приложениями, - ведет себя по-разному в зависимости от того, является ли вызывающий процессом процессом UNIX или нет.
Представьте, что вы пишете функцию "OPEN", которой в качестве аргумента передается имя файла. Если ваш вызывающий процесс является процессом UNIX, вы можете интерпретировать имя файла как фактическое имя файла...OPEN(XYZ) интерпретируется как "проверить текущий рабочий каталог на наличие файла с именем 'XYZ'". Но если вызывающий объект не дублируется как процесс UNIX, то OPEN(XYZ) может означать открытие оператора DD 'XYZ'. Вы можете сделать это определение, используя подход, который я описал выше, поскольку он говорит вам, что ваша задача фактически дублируется как процесс UNIX.
Хорошо, но в чем разница между этим и #2 выше (работа под оболочкой)?
Вот один пример. Предположим, у вас есть вызываемая процедура, которая хочет записать сообщение в выходной файл. Большинство приложений UNIX, не относящихся к мэйнфрейму, будут просто писать в STDOUT или STDERR, но это не всегда работает в z/OS, потому что многие приложения являются процессами UNIX, но они не работают под оболочкой - и без оболочки, STDOUT и STDERR может не существовать.
Вот сценарий...
Вы запускаете обычную программу, которая не имеет ничего общего со службами UNIX, но что-то делает, чтобы ее окрестили процессом UNIX. В качестве примера, возможно, кто-то поместит "DD PATH=/some/unix/file" в JCL устаревшей программы на COBOL... чудесным образом, когда это пакетное задание COBOL запускается, это процесс UNIX, потому что он использует файловая система служб UNIX. Есть много вещей, которые могут назвать вашу задачу процессом UNIX...DD PATH - один из них, но даже вызов функции, которая открывает сокет TCP/IP или что-то подобное, может помочь. Может быть, вы пишете продукт поставщика, который представляет собой просто программу пакетного ассемблера, но он открывает сокет TCP/IP... это еще один распространенный пример процессов UNIX, которые работают без оболочки.
Так почему это проблема? Хорошо, подумайте, что произойдет, если эта вызываемая функция решит записать свои сообщения в STDERR. Возможно, он проверяет, работает ли он как процесс служб UNIX, и если да, он записывает в STDERR, в противном случае он динамически выделяет и записывает в файл SYSOUT. Звучит просто, но это не сработает для моего примера приложения с DD PATH.
Откуда взялся STDERR? Обычно это настраивает программа оболочки UNIX - когда вы запускаете программу под оболочкой, оболочка обычно передает вашей программе три предварительно открытых дескриптора файлов для STDIN, STDOUT и STDERR. Поскольку в моем примере сценария оболочки нет, эти дескрипторы файлов не были переданы приложению, поэтому запись в STDERR не удастся. Фактически, оболочка передает дочернему процессу много вещей, помимо STDIN/STDOUT/STDERR, таких как переменные среды, обработка сигналов и так далее. (Конечно, пользователь может вручную выделить STDIN / STDOUT / STDERR в своем JCL... Я не говорю об этом здесь).
Если вы хотите иметь программное обеспечение, которое может работать как под оболочкой, так и не под оболочкой, у вас есть больше работы, чем просто посмотреть, было ли ваше приложение дублировано как процесс UNIX:
- Проверьте, являетесь ли вы процессом UNIX... в противном случае вы не можете работать под оболочкой.
- Убедитесь, что оболочка запустила вас. Есть множество способов сделать это, но обычно вы проверяете свой "родительский процесс" или что-то вроде переданных вам переменных среды. Это не всегда легко сделать, так как на самом деле в z/OS много разных оболочек, так что вы не можете найти "легитимные" оболочки. Один из наиболее надежных подходов - получить оболочку входа для пользователя и проверить ее.
- В качестве альтернативы проверке родительского процесса вы можете напрямую проверить нужный вам ресурс, например, вызвав ioctl() для дескриптора файла STDERR, как в моем примере. Это, конечно, может быть опасно... представьте себе случай, когда приложение открывает несколько сокетов и вызывает вашу функцию... то, что вы думаете на самом деле STDIN/STDOUT/STDERR, на самом деле может быть дескрипторами открытых файлов, установленными вашим вызывающим, и то, что вы пишете, может легко сбить его данные.
Что касается моего третьего примера - программы LE, работающие с POSIX(ON) - это в значительной степени проблема для разработчиков, пишущих на языках высокого уровня, основанных на среде выполнения LE, поскольку поведение некоторых функций времени выполнения отличается от POSIX(ON) или POSIX. (ВЫКЛ).
Примером может служить программист на C, пишущий функцию, которая может вызываться вызывающими абонентами POSIX(ON) и POSIX(OFF). Допустим, функция хочет выполнить некоторую фоновую обработку в отдельном потоке... в приложениях POSIX(ON) разработчик может использовать pthread_create(), но это не будет работать в POSIX(OFF). На самом деле в среде выполнения IBM LE есть много вещей, которые ведут себя по-разному в зависимости от настройки POSIX: потоки, обработка сигналов и т. Д. И т. Д. И т. Д. И т. Д. И т. Д. И т. Д. настройки POSIX во время выполнения и использовать разные пути в зависимости от того, как он установлен.
Надеюсь, это проливает свет на сложность, скрывающуюся за этим вопросом... три разных определения "работы в среде z/OS UNIX" и три разных сценария использования, иллюстрирующие важность каждого из них.