This commit is contained in:
SJLennon
2021-07-09 11:34:44 -04:00
parent 3ec2c08be1
commit 0cc0c22864
13 changed files with 1212 additions and 6 deletions
+175
View File
@@ -0,0 +1,175 @@
**FREE
/TITLE GETJOBTR Get Active Job Type: Interactive, Batch, whatever
// -------------------------------------------------------------------
// This program is passed job name, user and job number and if the
// job is active, it returns the job type, otherwise returns ' '.
// Initially written to be called from GETOBJUR.
//=== Parameters =================================================
// Input Parm:
// Job name - 10 char job name + 10 char user + 6 char job number,
// or * for job program is running in.
// Out Parm:
// Type - 1 character as returned by the QUSLJOB API.
// I=Interactive, B=Batch, blank is job not active.
// A=Autostart, M=subsystem monitor, R=spooled reader,
// S=system job, W=spooled writer, X=SCPF system job.
//Compile: CRTBNDRPG PGM(GETJOBTR) SRCFILE(...) DBGVIEW(*LIST)
// -------------------------------------------------------------------
// 12/00/97 LENNON Original Writing
// 07/--/2021 Lennon Converted to **FREE and Linear module.
// It was origially a standalone program. Perhaps it should
// be a service program and perhaps some of the diract API
// call should be in a service program.
// -------------------------------------------------------------------
ctl-opt debug option(*nodebugio: *srcstmt)
dftactgrp(*no) actgrp(*caller)
main(Main);
/copy USPHDR
//=== CRTUSRSPC (QUSCTRUS) Parameters ================================
dcl-s CusName char(20) inz('GETJOBTR QTEMP');
dcl-s CusAttr char(10) inz('GETJOBTR ');
dcl-s CusIntSize bindec(9);
dcl-s CusIntVal char(1) inz(x'00');
dcl-s CusAut char(10) inz('*CHANGE');
dcl-s CusText char(50) inz('GETJOBTR ');
dcl-s CusReplace char(10) inz('*NO');
dcl-s CusDomain char(10) inz('*DEFAULT');
//=== List Job (QUSLJOB) Parameters ==================================
dcl-s LJBFormat char(8) inz('JOBL0100');
dcl-s LJBQJobName char(26);
dcl-s LJBStatus char(10) inz('*ACTIVE');
//=== List Job Entry Layout ==========================================
dcl-ds LJLEntry based(ljptr);
LJJobName char(10);
LJJobUser char(10);
LJJobNum char(6);
LJJobIdent char(16);
LJJobStus char(10);
LJJobType char(1);
LJJobSubT char(1);
LJReserved char(2);
end-ds;
dcl-s LJPtr pointer inz(*null);
//=== Send Pgm Message (QMHSNDPM) Parameters =========================
dcl-s MSNMsgId char(7);
dcl-s MSNFile char(20) inz('QCPFMSG *LIBL ');
dcl-s MSNData char(1);
dcl-s MSNLength bindec(9);
dcl-s MSNType char(10) inz('*ESCAPE');
dcl-s MSNStackE char(10) inz('*CTLBDY');
dcl-s MSNStackC bindec(9) inz(1);
dcl-s MSNMsgKey char(4);
//=== API Error Code Structure =======================================
dcl-ds APIError len(272);
APIEProv int(10) inz(0) pos(1);
APIEAvail int(10) inz(0) pos(5);
APIErrId char(7) pos(9);
APIErrRsv char(1);
APIEData char(256);
end-ds;
dcl-pr p_qusdltus extpgm('QUSDLTUS');
*n char(20); // CusName
*n char(272); // APIError
end-pr;
//------------------------------------------------------
dcl-pr p_qmhsndpm extpgm('QMHSNDPM');
*n char(7); // MSNMsgId
*n char(20); // MSNFile
*n char(256); // APIEData
*n bindec(9); // MSNLength
*n char(10); // MSNType
*n char(10); // MSNStackE
*n bindec(9); // MSNStackC
*n char(4); // MSNMsgKey
*n char(272); // APIError
end-pr;
//------------------------------------------------------
dcl-pr p_quscrtus extpgm('QUSCRTUS');
*n char(20); // CusName
*n char(10); // CusAttr
*n bindec(9); // CusIntSize
*n char(1); // CusIntVal
*n char(10); // CusAut
*n char(50); // Custext
*n char(10); // CusReplace
*n char(272); // APIError
*n char(10); // CusDomain
end-pr;
//------------------------------------------------------
dcl-pr p_qusptrus extpgm('QUSPTRUS');
*n char(20); // CusName
*n pointer; // UspPtr
end-pr;
//------------------------------------------------------
dcl-pr p_qusljob extpgm('QUSLJOB');
*n char(20); // CusName
*n char(8); // LJBFormat
*n char(26); // LJBQJobName
*n char(10); // LJBStatus
end-pr;
//=== Main ===========================================================
dcl-proc Main;
// -----------------------------------
dcl-pi *n extpgm('GETJOBTR');
pQJob char(26);
pType char(1);
end-pi;
//=== Delete the User Space ======================================
APIEProv=%LEN(APIError);
p_QUSDLTUS(
CusName:
APIError);
// If user space doesn't exist, accept message CPF2105, else
// something nasty wrong - pass errors back
if APIEAvail <> 0 and APIErrId <> 'CPF2105';
APIEProv=0;
MSNMsgId=APIErrId;
MSNLength=APIEAvail-16;
p_QMHSNDPM(
MSNMsgId:
MSNFile:
APIEData:
MSNLength:
MSNType:
MSNStackE:
MSNStackC:
MSNMsgKey:
APIError);
endif;
// === Create User Space =========================================
// We only expect one entry back since job is fully qualified, but
// allocate enough for 10 entries in case entry size expands.
CusIntSize=%size(UspHdr) + (%size(LJLentry)*10);
LJBQJobname=pQJob;
// === Create the User Space =====================================
APIEProv = 0;
p_QUSCRTUS(
CusName:
CusAttr:
CusIntSize:
CusIntVal:
CusAut:
Custext:
CusReplace:
APIError:
CusDomain);
// === Get Pointer to User Space =================================
p_QUSPTRUS(CusName: UspPtr);
// === Get Job Info ==============================================
p_QUSLJOB(
CusName:
LJBFormat:
LJBQJobName:
LJBStatus);
if UspLst#Ent>0;
LJPtr=UspPtr+UspLstOfs;
// All that code just to execute this one instruction...
pType=LJJobType;
else;
pType=' ';
endif;
// === Return to Caller ==========================================
// Leave LR Off - this isn't very big.
return;
//
end-proc;
+86
View File
@@ -0,0 +1,86 @@
GETOBJUC: +
PGM PARM(&OBJECT &TYPE &MEMBER &RETMSG &RETMSGFLD &RETFILE)
/* -----------------------------------------------------------------*/
/* This program finds all the jobs which are using an object. */
/* It returns a message suitable for display to the operator */
/* and/or file QTEMP/GETOBJUP listing all jobs. This file */
/* could be used to send a message to all users of the object. */
/* -----------------------------------------------------------------*/
/* Use the GETOBJUSR command to invoke this program */
/* -----------------------------------------------------------------*/
/* 11/24/97 LENNON Original writing */
/* -----------------------------------------------------------------*/
/* 10/05/2001 Sam Lennon. If a non file object is locked *EXCL then */
/* RTVOBJD to get real library name to put in the */
/* message fails. If this occurs, just continue and */
/* *LIBL may appear in the message. */
/* -----------------------------------------------------------------*/
/* Input parameters */
DCL VAR(&OBJECT) TYPE(*CHAR) LEN(20) /* Obj & lib */
DCL VAR(&TYPE) TYPE(*CHAR) LEN(10) /* Obj type */
DCL VAR(&MEMBER) TYPE(*CHAR) LEN(10) /* if *FILE */
DCL VAR(&RETMSG) TYPE(*CHAR) LEN(4) /* Return a msg? */
DCL VAR(&RETMSGFLD) TYPE(*CHAR) LEN(200) /* Fld for msg */
DCL VAR(&RETFILE) TYPE(*CHAR) LEN(4) /* Return a file? */
/* Variables used in this program */
DCL VAR(&OBJNAM) TYPE(*CHAR) LEN(10) /* Obj name */
DCL VAR(&OBJLIB) TYPE(*CHAR) LEN(10) /* Obj lib */
DCL VAR(&FRMOBJLIB) TYPE(*CHAR) LEN(10) /* For duping file */
DCL VAR(&FAKMSGFLD) TYPE(*CHAR) LEN(1) /* No msg fld passed */
/* Error Handling Variables */
DCL VAR(&E_MSGID) TYPE(*CHAR) LEN(7)
DCL VAR(&E_MSGF) TYPE(*CHAR) LEN(10)
DCL VAR(&E_MSGFLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&E_MSGDTA) TYPE(*CHAR) LEN(100)
/* Catch unmonitored errors */
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
/* Convert *LIBL/*CURLIB into a real name, if possible */
CHGVAR VAR(&OBJNAM) VALUE(%SST(&OBJECT 1 10))
CHGVAR VAR(&OBJLIB) VALUE(%SST(&OBJECT 11 10))
RTVOBJD OBJ(&OBJLIB/&OBJNAM) OBJTYPE(&TYPE) RTNLIB(&OBJLIB)
MONMSG MSGID(CPF9803) EXEC(DO) /*Cannot Allocate*/
GOTO CMDLBL(PASTLIBGET)
ENDDO
CHGVAR VAR(%SST(&OBJECT 11 10)) VALUE(&OBJLIB)
PASTLIBGET: +
/* If output file requested, create empty file in QTEMP */
IF COND(&RETFILE = '*YES') THEN(DO)
DLTF FILE(QTEMP/GETOBJUP)
MONMSG MSGID(CPF2105) /* not found */
RTVOBJD OBJ(*LIBL/GETOBJUP) OBJTYPE(*FILE) RTNLIB(&FRMOBJLIB)
CRTDUPOBJ OBJ(GETOBJUP) FROMLIB(&FRMOBJLIB) OBJTYPE(*FILE) +
TOLIB(QTEMP)
ADDPFM FILE(QTEMP/GETOBJUP) MBR(GETOBJUP)
OVRDBF FILE(GETOBJUP) TOFILE(QTEMP/GETOBJUP) SECURE(*YES)
ENDDO
/* Call RPG program to find the users */
IF COND(&RETMSG = '*YES') THEN(DO)
CALL PGM(GETOBJUR) PARM(&OBJECT &TYPE &MEMBER &RETMSG +
&RETMSGFLD &RETFILE)
ENDDO
ELSE CMD(DO)
CALL PGM(GETOBJUR) PARM(&OBJECT &TYPE &MEMBER &RETMSG +
&FAKMSGFLD &RETFILE)
ENDDO
/* End of program */
GOTO CMDLBL(ENDPGM)
/* Error handler - resend any trapped escape message */
ERROR: +
RCVMSG MSGTYPE(*LAST) MSGDTA(&E_MSGDTA) MSGID(&E_MSGID) +
MSGF(&E_MSGF) MSGFLIB(&E_MSGFLIB)
MONMSG MSGID(CPF0000) /* Just in case */
SNDPGMMSG MSGID(&E_MSGID) MSGF(&E_MSGFLIB/&E_MSGF) +
MSGDTA(&E_MSGDTA) MSGTYPE(*ESCAPE)
MONMSG MSGID(CPF0000) /* Just in case */
ENDPGM: +
ENDPGM
+17
View File
@@ -0,0 +1,17 @@
*================================================================
* File of Jobs using an object, returned by GETOBJUSR Command.
*
* =====> Create with MBR(*NONE). Dupe into QTEMP to use.
*
* 12/00/97 LENNON Initial Coding
*================================================================
A R GETOBJU
A OUJOBNAME 10 TEXT('Job Name')
A COLHDG('Job' 'Name')
A OUJOBUSER 10A TEXT('Job User')
A COLHDG('Job' 'User')
A OUJOBNUM 6A TEXT('Job Number')
A COLHDG('Job' 'Number')
A OUJOBTYPE 1A TEXT('I=interact, other=non inter')
A COLHDG('Type')
+369
View File
@@ -0,0 +1,369 @@
**FREE
/TITLE GETOBJUR - Get users of an object
//--------------------------------------------------------------------
// Given an object and type, this program finds all jobs that have
// locks on the object. It returns a message suitable for sending
// to the system operator and/or a file, QTEMP/GETOBJUP, which
// could be used to send messages to all interactive users of the
// object, or for some other use.
// This program is called from CL program GETOBJUC.
// It calls the QWCLOBJL (List Object Locks) API.
// Message looks like this:
// QIWS/QCUSTCDT *FILE is in use by QPAD165916/LENNONS/167740.
// Or this:
// QIWS/QCUSTCDT *FILE is in use by CUSTLST/LENNONS/167922,
// DAILYORD/LENNONS/167924, INV_UPD/LENNONS/167923,
// QPAD165916/LENNONS/167740 plus 1 more.
// Compile: CRTBNDRPG PGM(GETOBJUR) SRCFILE(...) DBGVIEW(*LIST)
//--------------------------------------------------------------------
// 12/00/97 LENNON Original Writing
// 07/--/2021 Converted to **FREE and Linear module.
// There are SQL services now that can provide similar
// infomations, but as far as I know there is no SQL
// interface to QWCLOBJL. And there certainly was not in
// 1997. This code probably performs better than existing
// SQL interfaces. For most use cases performance may not
// be a consideration.
//--------------------------------------------------------------------
ctl-opt debug option(*nodebugio: *srcstmt)
dftactgrp(*no) actgrp(*caller)
main(Main);
dcl-f GETOBJUP usage(*output) usropn block(*yes);
/copy USPHDR
//=== CRTUSRSPC (QUSCTRUS) Parameters ================================
dcl-ds *n;
CusQName char(20);
CusName char(10) overlay(cusqname) inz('GETOBJUSR');
CusLib char(10) overlay(cusqname:11) inz('QTEMP');
end-ds;
dcl-s CusAttr char(10) inz('GETOBJUSR ');
dcl-s CusIntSize int(10);
dcl-s CusIntVal char(1) inz(x'00');
dcl-s CusAut char(10) inz('*CHANGE');
dcl-s CusText char(50) inz('GETOBJUSR Command');
//=== Send Pgm Message (QMHSNDPM) Parameters =========================
dcl-s MSNMsgId char(7);
dcl-s MSNFile char(20) inz('QCPFMSG *LIBL ');
dcl-s MSNData char(1);
dcl-s MSNLength int(10);
dcl-s MSNType char(10) inz('*ESCAPE');
dcl-s MSNStackE char(10) inz('*CTLBDY');
dcl-s MSNStackC int(10) inz(1);
dcl-s MSNMsgKey char(4);
//=== List Object Locks List Entry Layout ============================
dcl-ds LOLEntry based(loptr);
LOJobName char(10);
LOJobUser char(10);
LOJobNum char(6);
LOLckState char(10);
LOLckStus int(10);
LOLckType int(10);
LOMemName char(10);
LOShare char(1);
LOReserved char(1);
end-ds;
dcl-s LOPtr pointer inz(*null);
dcl-s LOEndPtr pointer inz(*null);
//=== API Error Code Structure =======================================
dcl-ds APIError len(272);
APIEProv int(10) inz(216) pos(1);
APIEAvail int(10) inz(0) pos(5);
APIErrID char(7) pos(9);
APIErrRsv char(1);
APIEData char(256);
end-ds;
//=== Misc Field Definitions =========================================
dcl-s LolFmt char(8) inz('OBJL0100');
dcl-s ObjMEM char(10);
dcl-s NumJobs packed(5);
dcl-c MaxJobs const(4); //Maximum jobs for detailed reporting.
// If you increase MaxJobs, increase the message parameter by 30 bytes
// for each additional job.
dcl-ds JobName26;
SavJobName like(lojobname);
SavJobUser like(lojobuser);
SavJobNum like(lojobnum);
end-ds;
dcl-s Jobname28 char(28);
dcl-s JobType char(1);
//=== Parameters for SRTUSRSPC =======================================
// SKeyStart - Array of key starting positions
// SKeyLgth - Array of key lengths
// SKeyAorD - Array of ascending/descending sequences
// SKeyType - Array of key field data types.
dcl-s SKeyStart packed(5) dim(10); // start position
dcl-s SKeyLgth packed(5) dim(10); // lengths
dcl-s SKeyAorD char(1) dim(10); // ascend/descend
dcl-s SKeyType char(1) dim(10); // data type
dcl-s S#Keys packed(3) inz(3);
dcl-s SError char(1);
//=== Program Entry and Parameters ===================================
dcl-proc Main ;
// Input Parameters
// pObject is object name (10c) + object library (10c)
// pObjType is *FILE, *DTAARA, etc., standard OS/400 type
// pObjMem is the member for files, or *NONE if just want users
// of the file.
// pMsgYN is *YES to create a message.
// pFileYN is *YES if file GETOBJUP is to be created in QTEMP
// Output Parameter
// PMsgFld is where the message gets created.
// ---------------------------------------------------------
dcl-pi *n extpgm('GETOBJUR');
pObject char(20);
pObjType char(10);
pObjMem char(10);
pMsgYN char(4);
pMsgFld char(200);
pFileYN char(4);
end-pi;
//------------------------------------------------------
dcl-pr ListObjLck extpgm('QWCLOBJL');
*n char(20); // CusQName
*n char(8); // LolFmt
*n char(20); // pObject
*n char(10); // pObjType
*n char(10); // ObjMem
*n char(272); // APIError
end-pr;
//------------------------------------------------------
// Gets job type entry for this job.
// Returns: JobType has the job type. I=interactive, B=batch, etc.
dcl-pr GetJobType extpgm('GETJOBTR');
*n char(26); // JobName26
*n char(1); // JobType
end-pr;
//------------------------------------------------------
dcl-pr p_srtusrspc extpgm('SRTUSRSPC');
*n char(10); // CusName
*n char(10); // CusLib
*n packed(3); // S#keys
*n packed(5) dim(10); // KeyStart
*n packed(5) dim(10); // KeyLgth
*n char(1) dim(10); // Key A or D
*n char(1) dim(10); // SKeyType
*n char(1); // SError
end-pr;
//------------------------------------------------------
dcl-pr SendMsg extpgm('QMHSNDPM');
*n char(7); // MSNMsgId
*n char(20); // MSNFile
*n char(256); // APIEData
*n int(10); // MSNLength
*n char(10); // MSNType
*n char(10); // MSNStackE
*n int(10); // MSNStackC
*n char(4); // MSNMsgKey
*n char(272); // APIError
end-pr;
//------------------------------------------------------
dcl-pr UsrSpcCrt extpgm('QUSCRTUS');
*n char(20); // CusQName
*n char(10); // CusAttr
*n int(10); // CusIntSize
*n char(1); // CusIntVal
*n char(10); // CusAut
*n char(50); // Custext
end-pr;
//------------------------------------------------------
dcl-pr UsrSpcDlt extpgm('QUSDLTUS');
*n char(20); // CusQName
*n char(272); // APIError
end-pr;
//------------------------------------------------------
dcl-pr UsrSpcPointer extpgm('QUSPTRUS');
*n char(20); // CusQName
*n pointer; // UspPtr
end-pr;
//=== Code starts here ===========================================
exsr Initialize;
//=== List the Object Locks ======================================
// Object type should be *NONE if not a file.
if pObjType='*FILE';
ObjMem=pObjMem;
else;
ObjMem='*NONE';
endif;
APIEProv=0;
ListObjLck(
CusQName:
LolFmt:
pObject:
pObjType:
ObjMem:
APIError);
exsr srtusrspc;
// === Main Program Loop =========================================
// Loop through the entries in the list
exsr NxtJob;
dow LOPtr <> *NULL;
if pFileYN='*YES';
GetJobType(JobName26: JobType);
exsr WriteRec;
endif;
if pMsgYN='*YES';
exsr BldMsg;
endif;
exsr NxtJob;
enddo;
// === End of Program ============================================
if pFileYN='*YES';
close GETOBJUP;
endif;
if pMsgYN='*YES';
select;
when NumJobs >= 1 and NumJobs <=MaxJobs;
pMsgfld=%trimr(pMsgFld) + '.';
when NumJobs > MaxJobs;
pMsgfld=%trimr(pMsgFld) + ' plus ' +
%trim(%editc(NumJobs-MaxJobs:'J')) +
' more.';
other;
endsl;
endif;
*inlr=*on;
// === NxtJob ====================================================
// A job can have more than one lock on an object. We just want a
// job once.
// Sets LOPtr to the first entry, or to the next different entry.
// LOPtr assumed to be *NULL on first call.
// Returns: LOPtr=*NULL if no more entries.
// NumJobs=number of unique jobs so far
begsr NxtJob;
select;
when LOPtr=*NULL;
if UspLst#Ent > 0;
LOPtr=UspPtr+UspLstOfs;
LOEndPtr=LOPtr+(UspLst#Ent*UspLstEntSz);
NumJobs=0;
exsr SavJobInf;
endif;
other;
LOPtr=LOPtr+UspLstEntSz;
dow LOPtr < LOEndPtr
and SavJobName=LOJobName
and SavJobUser=LOJobUser
and SavJobNum=LOJobNum ;
LOPtr=LOPtr+UspLstEntSz;
enddo;
if LOPtr < LOEndPtr;
exsr SavJobInf;
else;
LOPtr=*NULL;
endif;
endsl;
endsr;
// === BldMsg ====================================================
// Adds current job to the message until MaxJobs have been added.
begsr BldMsg;
JobName28=%trimr(SavJobName) + '/' +
%trimr(SavJobUser) + '/' +
SavJobNum;
select;
when NumJobs=1;
pMsgFld=
%trimr(%subst(pObject:11:10)) +'/' +
%trimr(%subst(pObject:1:10)) + ' ' +
%trimr(pObjType) +
' is in use by ' +
JobName28;
when NumJobs >= 2 and NumJobs <=MaxJobs;
pMsgFld=%trimr(pMsgfld) + ', ' +
JobName28;
endsl;
endsr;
// === SavJobInf =================================================
// Saves current job indentification information and counts
// number of unique jobs found.
// LOPtr must be initialized.
begsr SavJobInf;
NumJobs=NumJobs+1;
SavJobName=LOJobName;
SavJobUser=LOJobUser;
SavJobNum=LOJobNum;
endsr;
// === WriteRec ==================================================
// Builds and writes a record to the file GETOBJUP
// LOPtr must be initialized.
begsr WriteRec;
OUJOBNAME=LOJobname;
OUJOBUSER=LOJobUser;
OUJOBNUM=LOJobNum;
OUJOBTYPE=JobType;
write GETOBJU;
endsr;
// === Sort User Space ===========================================
begsr SrtUsrSpc;
p_SRTUSRSPC(
CusName:
CusLib:
S#keys:
SKeyStart:
SKeyLgth:
SKeyAorD:
SKeyType:
SError);
endsr;
// ===============================================================
// === Initialization ============================================
begsr Initialize;
// === Delete the User Space =================================
APIEProv=%LEN(APIError);
UsrSpcDlt(CusQName: APIError);
// If user space doesn't exist, accept message CPF2105, else
// something nasty is wrong - pass escape message back.
if APIEAvail <> 0
and APIErrId <> 'CPF2105';
APIEProv=0;
MSNMsgId=APIErrId;
MSNLength=APIEAvail-16;
SendMsg(
MSNMsgId:
MSNFile:
APIEData:
MSNLength:
MSNType:
MSNStackE:
MSNStackC:
MSNMsgKey:
APIError);
endif;
// === Create User Space =====================================
// Allow for 100,000 entries, which should be more than enough
APIEProv = 0;
CusIntSize=%size(UspHdr) + (%size(LOLentry)*100000);
UsrSpcCrt(
CusQName:
CusAttr:
CusIntSize:
CusIntVal:
CusAut:
Custext);
// === Get Pointer to User Space =============================
UsrSpcPointer(CusQName: UspPtr);
// === Initialize requested outputs ==========================
if pFileYN='*YES';
open GETOBJUP;
endif;
if pMsgYN='*YES';
clear pMsgFld;
endif;
// === Set SRTUSRSPC paremeters ==============================
SKeyStart(1)=1;
SKeyStart(2)=11;
SKeyStart(3)=21;
SKeyLgth(1)=10;
SKeyLgth(2)=10;
SKeyLgth(3)=6;
SKeyAorD(1)='A';
SKeyAorD(2)='A';
SKeyAorD(3)='A';
SKeyType(1)='C';
SKeyType(2)='C';
SKeyType(3)='C';
endsr;
end-proc;
+50
View File
@@ -0,0 +1,50 @@
GETOBJUSR: CMD PROMPT('Get Users of an Object')
/*-----------------------------------------------------------------*/
/* CPP is GETOBJUC */
/* Compile: */
/* CRTCMD CMD(GETOBJUSR) PGM(GETOBJUC) */
/* ALLOW(*BPGM *IPGM *BMOD *IMOD) */
/*-----------------------------------------------------------------*/
/* 12/00/97 LENNON Original writting */
/*-----------------------------------------------------------------*/
PARM KWD(OBJECT) TYPE(Q1) MIN(1) PROMPT('Object +
Name')
PARM KWD(TYPE) TYPE(*CHAR) LEN(10) RSTD(*YES) +
VALUES(*ALRTBL *AUTL *BNDDIR *CFGL +
*CHTFMT *CLD *CLS *CMD *CNNL *COSD *CRQD +
*CSI *CSPMAP *CSPTBL *CTLD *DEVD *DOC +
*DTAARA *DTADCT *DTAQ *EDTD *EXITRG *FCT +
*FILE *FLR *FNTRSC *FNTTBL *FORMDF *FTR +
*GSS *IPXD *JOBD *JOBQ *JOBSCD *JRN +
*JRNRCV *LIB *LIND *LOCALE *MENU *MODD +
*MODULE *MSGF *MSGQ *M36 *M36CFG *NODL +
*NTBD *NWID *NWSD *OUTQ *OVL *PAGDFN +
*PAGSEG *PDG *PGM *PNLGRP *PRDAVL *PRDDFN +
*PRDLOD *PSFCFG *QMFORM *QMQRY *QRYDFN +
*SBSD *SCHIDX *SPADCT *SQLPKG *SRVPGM +
*SSND *S36 *TBL *USRIDX *USRPRF *USRQ +
*USRSPC *WSCST) MIN(1) PROMPT('Object Type')
PARM KWD(MEMBER) TYPE(*NAME) LEN(10) DFT(*ALL) +
SPCVAL((*ALL) (*FIRST) (*NONE)) +
PMTCTL(ISFILE) PROMPT('Member')
PARM KWD(RETMSG) TYPE(*CHAR) LEN(4) RSTD(*YES) +
DFT(*YES) VALUES(*YES *NO) PROMPT('Return +
a message?')
PARM KWD(MSGFLD) TYPE(*CHAR) LEN(200) +
RTNVAL(*YES) PMTCTL(RETMSGY) +
PROMPT('Return Message Field')
PARM KWD(RETFILE) TYPE(*CHAR) LEN(4) RSTD(*YES) +
DFT(*NO) VALUES(*YES *NO) PROMPT('Return +
file QTEMP/GETOBJUSRP?')
Q1: QUAL TYPE(*NAME) LEN(10) MIN(1)
QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) +
SPCVAL((*LIBL) (*CURLIB)) PROMPT('Library')
RETMSGY: PMTCTL CTL(RETMSG) COND((*EQ *YES))
ISFILE: PMTCTL CTL(TYPE) COND((*EQ *FILE))
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+75
View File
@@ -0,0 +1,75 @@
# APIs, including QWCLOBJL (List Object Locks), QUSLJOB(List Job) QUSCRTUS, QUSDLTUS, QUSPTRUS (User Spaces)
User commands that use RPG and CL to call IBM i APIs.
## QWCLOBJL (List Object Locks) API
In the late 90s the Fortune 500 company where I worked had contending overnight batch jobs from different project teams that required exclusive control of some files. Jobs kept breaking to the operator console when more than one tried running simultaneously. The night shift operator then had to do a WRKOBJLCK command to attempt to resolve the contention.
The code provided here is a command we could put in the driving CL program and when the ALCOBJ command failed it provided information on who had the object locked.
The company is long gone, but I recently found the code on my PC and resurrected it.
Now (2021) you can get similar information with SQL - see [Work Management Services](https://www.ibm.com/docs/en/i/7.4?topic=services-work-management) on the IBM site. However, I have not found an SQL interface to QWCLOBJL. I also suspect that this code if faster than SQL, but probably in most use cases speed may not be a factor.
### GETOBJUSR Command
This is the top level interface. Prompted, it looks like this:
![GetObjUsr Prompt](Images/GetObjUsr_1.jpg)
You specify the object and type and the command returns information on the locks on the object. You can return a file of objects and/or a message.
The file would be GETOBJUP in QTEMP.
The message would be suitable for sending to the operator and look something like one of these:
![GetObjUsr Message](Images/GetObjUsr_2.jpg)
![GetObjUsr Message](Images/GetObjUsr_3.jpg)
It shows the details of up to 4 jobs and lists how many additional jobs, if any, have locks.
### GETOBJUC
This the command processing program for the GETOBJUSR command. It calls GETOBJUR to get the lock information.
### GETOBJUR
This RPG program creates a user space in QTEMP, then calls the QWCLOBJL (List Object Locks) API to populate the user spaces, calls SRTUSRSPC to sort by job, returns the requested message and/or file, then deletes the user space.
The code was originally in fexed form RPG/400, but I converted it to **FREE (using [Craig Rutledge's JCRCMDS](https://www.jcrcmds.com/)).
## GETOBJUP
DDS for the file created, if requested, in QTEMP. Resulting file contents look something like this:
![GetObjup Sample](Images/GetObjUsr_4.jpg)
### SRTUSRSPC
This program sorts a user space. I believe I downloaded the code from the Old News 3X/400 site. It is fixed form RPG/400 that I haven't bothered to convert. Old, educational, and it works.
## QUSLJOB (List Job) API
### GETJOBTR
This is a standalone program that returns the job type. GETOBJUR needed it, but I coded it separately in case it was useful elsewhere.
You pass it two parameters:
1. Input: The 26 char job name, user name and job number (or * for the current job)
2. Output: 1-character field to return the job type, as below.
Type|Description
----|-----------------------------------
A|The job is an autostart job.
B|The job is a batch job.
I|The job is an interactive job.
M|he job is a subsystem monitor job.
R|The job is a spooled reader job.
S|he job is a system job.
W|The job is a spooled writer job.
X|The job is the SCPF system job.
Notes:
1. The code was originally fixed format but I converted it to **FREE (using [Craig Rutledge's JCRCMDS](https://www.jcrcmds.com/)). If needed for general use it should probably be a service program. I'm not sure service programs were a thing in 1997, but if they were I was not familar with them then.
2. On more current OS releases you can get similar information in SQL with the [GET_JOB_INFO table function](https://www.ibm.com/docs/en/i/7.4?topic=services-get-job-info-table-function).
+405
View File
@@ -0,0 +1,405 @@
*******************************************************************
* From "Sort Those API Lists," NEWS/400, May 1996.
* Author: Greg LaForge
* COPYRIGHT (c) 1996 Duke Communications International,
* ALL RIGHTS RESERVED.
*
*
* Program: SRTUSRSPC
* Description: This program sorts in a user space lists
* created by system API commands.
*
**************************************************************************
* Indicators used.
*
* 01 - Error on CALLs. Triggers abnormal termination of program and
* sets return parameter EXITER to *ON.
*
**************************************************************************
* Arrays.
*
* AD - Array of ascending/descending sequences (passed in).
* DT - Array of key fields' data types.
* KY - Array to pass info to the sort routine.
* LN - Array of key lengths (passed in).
* ST - Array of key starting positions (passed in).
*
D ad s 1 dim(10) ascend/descend
D dt s 1 dim(10) data type
D ln s 5 0 dim(10) lengths
D st s 5 0 dim(10) start positions
* ************************************************************************
* Data structures.
*
* BINALP - Converts binary to alpha field.
* ERROR - Formats error fields for sort APIs.
* INDTA - Creates a 9,000-byte field.
* MISC - Defines some binary fields.
* OUTDTA - Creates a 9,000-byte field.
* RCVVAR - Defines some binary fields for user space lists.
* SORT - Formats sort control block for QLGSORT API.
* SORTIN - Formats input fields for QLGSRTIO API.
* SORTOU - Formats output fields for QLGSRTIO API.
*
*-----------------------------------------------------------------------
* Converts binary to alpha field.
*
D binalp ds
D alpha 4
D binary 9b 0 overlay(alpha)
*-----------------------------------------------------------------------
* Formats error fields for sort APIs.
*
D error ds
D errlen 9b 0
D erravl 9b 0
D errid 7
D errdta 17 272
*-----------------------------------------------------------------------
* Creates a 9,000-byte field.
*
D indta ds 9000
D hold 9000 9000
*-----------------------------------------------------------------------
* Defines some binary fields.
*
D misc ds
D lendta 9b 0
D strpos 9b 0
D lenspc 9b 0
D lenvar 9b 0
D parm3 9b 0
D parm4 9b 0
D outlen 9b 0
*-----------------------------------------------------------------------
* Creates a 9,000-byte field.
*
D outdta ds 9000
D holda 9000 9000
*-----------------------------------------------------------------------
* Defines some binary fields for user space lists.
*
D rcvvar ds
D offset 9b 0
D nbrent 9 12b 0
D sizent 9b 0
*-----------------------------------------------------------------------
* Formats sort control block for QLGSORT API.
*
D sort ds
D blklen 1 4b 0
D reqtyp 5 8b 0
D fill01 9 12b 0
D option 13 16b 0
D rcdlen 17 20b 0
D rcdcnt 21 24b 0
D keyoff 25 28b 0
D keys 29 32b 0
D lanoff 33 36b 0
D inoff 37 40b 0
D #infil 41 44b 0
D outoff 45 48b 0
D #outfi 49 52b 0
D fill02 53 56b 0
D ky 57 216
D dim(40) key fields
*-----------------------------------------------------------------------
* Formats input fields for QLGSRTIO API.
*
D sortin ds
D intype 9b 0
D infil1 9b 0
D inlen 9b 0
D inrecs 9b 0
*-----------------------------------------------------------------------
* Formats output fields for QLGSRTIO API.
*
D sortou ds
D ourprc 9b 0
D ouravl 9b 0
D oufil1 9b 0
D oufil2 9b 0
*---------------------------------------------------------------------
* BEGIN of work fields added by CONNECTIONS 2000's CVTILERPG utility
*---------------------------------------------------------------------
D #keys s like(dec003 )
D #recs s like(int )
D byte s 1
D chr032 s 32
D dec003 s 3 0
D exiter s like(byte )
D force s like(byte )
D i s like(int )
D inbuff s like(chr032 )
D int s 9 0
D i1 s like(int )
D i2 s like(int )
D i3 s like(int )
D i4 s like(int )
D lib s like(name )
D name s 10
D oubuff s like(chr032 )
D qname s 20
D spacer s like(qname )
D tmp50 s like(int )
D totrec s like(int )
D usrspc s like(name )
*---------------------------------------------------------------------
* END of work fields added by CONNECTIONS 2000's CVTILERPG utility
*---------------------------------------------------------------------
**************************************************************************
*
* Mainline.
*
C exsr inzpgm
C exsr prcpgm
C exsr trmpgm
*
C return
*-----------------------------------------------------------------------
* CHK4ER: Look to see whether error has occurred; if so, exit.
*
C chk4er begsr
*
B001 C if *in01 = *on error in call
001 C or errid <> *blanks returned error
001 C exsr *pssr
E001 C endif
*
C endsr
*-----------------------------------------------------------------------
* DCLVAR: Declare program variables.
* This subroutine is never executed.
*
C dclvar begsr
* Declare data types.
C eval byte = *blank
C eval chr032 = *blank
C eval dec003 = 0
C eval int = 0
C eval name = *blank
C eval qname = *blank
*
* Declare variables based on data types.
*
C endsr
*-----------------------------------------------------------------------
* INZPGM: Initialize program.
*
C inzpgm begsr
*
C *entry plist
C parm usrspc user space
C parm lib user space lib
C parm #keys nbr of keys
C parm st start positions
C parm ln lengths
C parm ad ascend/descend
C parm dt data types
C parm exiter *ON=error
*
* Clear error flag.
C move *off exiter
*
* Get some info in the user space header.
C movel usrspc spacer
C move lib spacer
*
C call 'QUSRTVUS' 01
C parm spacer
C parm 125 strpos
C parm 16 lendta
C parm rcvvar
*
C exsr chk4er
*
* Determine starting position of list in the user space.
C eval strpos = offset
C eval strpos = strpos + 1
*
* Initialize the sort function.
C eval blklen = #keys length of
C eval blklen = blklen * 16 sort control
C eval blklen = blklen + 56 block
C eval reqtyp = 8 sort type
C eval fill01 = 0 filler
C eval option = 0 no options
C eval rcdlen = sizent rec size
C eval rcdcnt = 0 no rec count
C eval keyoff = 56 offset to keys
C eval keys = #keys # of keys
C eval lanoff = 0 language offset
C eval inoff = 0 no input files
C eval #infil = 0 no input files
C eval outoff = 0 no out files
C eval #outfi = 0 no out files
C eval fill02 = 0
*
* Fill the key field area.
B001 C 1 do #keys i
001 C eval i1 = i - 1
001 C eval i1 = i1 * 4
001 C eval i1 = i1 + 1
001 C eval i2 = i1 + 1
001 C eval i3 = i2 + 1
001 C eval i4 = i3 + 1
001 *
001 * Convert start position to binary and place into array.
001 C eval binary = st(i)
001 C movel alpha ky(i1)
001 *
001 * Convert key length to binary and place into array.
001 C eval binary = ln(i)
001 C movel alpha ky(i2)
001 *
001 * Convert data type to binary and place into array.
B002 C select
002 C when dt(i) = 'Z' zoned decimal
002 C eval binary = 2
002 C when dt(i) = 'B' binary
002 C eval binary = 0
002 C when dt(i) = 'P' packed decimal
002 C eval binary = 3
002 C other all else
002 C eval binary = 6
E002 C endsl
001 *
001 C movel alpha ky(i3)
001 *
001 * Convert the sort order to binary and place into array.
B002 C if ad(i) = 'D' descend
002 C eval binary = 2
X002 C else
002 C eval binary = 1
E002 C endif
001 *
001 C movel alpha ky(i4)
E001 C enddo
*
C endsr
*-----------------------------------------------------------------------
* PRCPGM: Process program.
*
C prcpgm begsr
*
* Now that the sort control block is built, initialize
* the sort routine and get it ready to accept records.
*
C eval errlen = 272 avail space
*
C call 'QLGSORT' 01
C parm sort control block
C parm inbuff input buffer
C parm oubuff output buffer
C parm 0 parm3 not used
C parm 0 parm4 not used
C parm error error ds
*
C exsr chk4er
*
* Pass a block of records to the sort routine. The block
* can contain up to 9,000 bytes.
*
C eval #recs = 9000 / rcdlen number of recs
C eval intype = 1 put records
C eval infil1 = 0 not used
C eval inlen = rcdlen rec len
C eval inrecs = #recs
C eval totrec = 0
* Do for blocks of records:
B001 C dow totrec < nbrent
001 C eval totrec = totrec + #recs
B002 C if totrec > nbrent
002 C eval tmp50 = totrec - nbrent
002 C eval inrecs = inrecs - tmp50
E002 C endif
001 C eval lendta = rcdlen * inrecs
001 * Retrieve a block of records.
001 C call 'QUSRTVUS' 01
001 C parm spacer
001 C parm strpos
001 C parm lendta
001 C parm indta
001 *
001 C exsr chk4er
001 * Send them to the sort routine.
001 C call 'QLGSRTIO' 01
001 C parm sortin
001 C parm indta
001 C parm outdta
001 C parm outlen
001 C parm sortou
001 C parm error
001 *
001 C exsr chk4er
001 *
001 C eval strpos = strpos + lendta
E001 C enddo
*
* Tell the sort routine we are all done.
C eval intype = 2 end put
C call 'QLGSRTIO' 01
C parm sortin
C parm indta
C parm outdta
C parm outlen
C parm sortou
C parm error
*
C exsr chk4er
*
* Retrieve records from the sort and place back into user space.
C eval intype = 3 get records
C eval strpos = offset
C eval strpos = strpos + 1
C eval inrecs = #recs
C eval totrec = 0
*
* Do for blocks of records:
B001 C dow totrec < nbrent
001 C eval totrec = totrec + #recs
B002 C if totrec > nbrent
002 C eval tmp50 = totrec - nbrent
002 C eval inrecs = inrecs - tmp50
E002 C endif
001 C eval lendta = rcdlen * inrecs
001 * Retrieve a block of records.
001 C call 'QLGSRTIO' 01
001 C parm sortin
001 C parm indta
001 C parm outdta
001 C parm outlen
001 C parm sortou
001 C parm error
001 *
001 C exsr chk4er
001 * Place them back into user space.
001 C call 'QUSCHGUS' 01
001 C parm spacer
001 C parm strpos
001 C parm lendta
001 C parm outdta
001 C parm '2' force
001 *
001 C exsr chk4er
001 *
001 C eval strpos = strpos + lendta
E001 C enddo
*
C endsr
*-----------------------------------------------------------------------
* *PSSR: Error handling subroutine.
*
C *pssr begsr
C move *on exiter
C move *on *inlr
C return
C endsr
*-----------------------------------------------------------------------
* TRMPGM: Terminate program.
*
C trmpgm begsr
* All done.
C move *on *inlr
*
C endsr
+25
View File
@@ -0,0 +1,25 @@
//=== USPHDR Description =============================================
// The list APIs which return data in a user space put a standard
// header at the start of the user space. This descibes the header.
//=== Basing Pointer for Header ======================================
D UspPtr s * inz(*Null)
//=== User Space Header Layout =======================================
D UspHdr ds based(UspPtr)
D UspH 192a
D UspUser 64a overlay(UspH:1)
D UspSize 10i 0 overlay(UspH:65)
D UspInfSts 1a overlay(UspH:104)
D UspICmpl c const('C')
D UspIPrtl c const('P')
D UspIIncp c const('I')
D UspSpSize 10i 0 overlay(UspH:105)
D UspInOff 10i 0 overlay(UspH:109)
D UspInSize 10i 0 overlay(UspH:113)
D UspHdrOfs 10i 0 overlay(UspH:117)
D UspHdrSize 10i 0 overlay(UspH:121)
D UspLstOfs 10i 0 overlay(UspH:125)
D UspLstSize 10i 0 overlay(UspH:129)
D UspLst#Ent 10i 0 overlay(UspH:133)
D UspLstEntSz 10i 0 overlay(UspH:137)
+10 -6
View File
@@ -1,15 +1,15 @@
# RPGLE free format, SQL and CLP Code for the IBM i
This repository contains *working* example code, using RPGLE free-format, enbedded SQL and CLP for the IBM i
More developers are learning about the **IBM i** as a wonderful business platform. (It was formerly known as the **AS/400**.)
My intent is to provide real programs that help you learn, or improve your current understanding, and which you can adapt to you needs.
This repository contains *working* example code, using RPGLE free-format, enbedded SQL and CLP for the IBM i.
More developers are learning about the **IBM i** as a wonderful business platform. ( It was formerly known as the **AS/400**.)
Feel free to provide comments and feedback as issues.
My intent is to provide real programs that help you learn and/or improve your current understanding. Explore and adapt the code to your needs. Some of the code may be of use "as is" but no guarantee is provided.
**Each folder has its own ReadMe with additional infomation/documentation.**
Feel free to provide comments and feedback as issues.
## Copy_Mbrs
Code to be copied into other programs.
@@ -38,6 +38,10 @@ SQL User Defined Functions to convert legacy dates to true dates. Written in RP
A standardized way to handle locked records in an interactive program, and display information about who is holding the lock. For programs that use native IO.
## APIs
Commands, with CLP and RPG programs, calling IBM i APis.
## GRP_JOB
Sets up group jobs suitable for an IBM i developer.
@@ -48,4 +52,4 @@ Developer Utilities.
QRY - Qry (List) Contents of a file
RC - Display File Record count
RC - Display File Record count