24
Tue, Dec
1 New Articles

The CL Corner: Overriding Commands and Their Parameter Values

CL
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Learn how to use the Command Analyzer Change exit point.

By Bruce Vining

In the last column, we saw how proxy commands can be used to provide aliases for commands such as ENDJOB and SIGNOFF. Today, we'll look at how the Command Analyzer Change exit point can be used to conditionally alter the command string that is actually processed when using the KILL proxy command.

 

The Command Analyzer Change exit point is documented here. The exit point passes to the exit program three parameters:

 

Required Parameter Group

 

 

1

Change command exit information

Input

Char(*)

2

Replacement command

Output

Char(*)

3

Length of replacement command string

Output

Binary(4)

 

  

The first parameter, Change command exit information, is a structure providing information about the command being processed. This structure is defined in the exit point documentation this way:

 

Format CHGC0100

 

 

Offset

Type

Field

Dec

Hex

0

0

CHAR(20)

Exit point name

20

14

CHAR(8)

Exit point format name

28

1C

CHAR(10)

Command name

38

26

CHAR(10)

Library name

48

30

CHAR(1)

Change allowed indicator

49

31

CHAR(1)

Prompt indicator

50

32

CHAR(2)

Reserved

52

34

BINARY(4)

Offset to command string

56

38

BINARY(4)

Length of command string

60

3C

BINARY(4)

Offset to proxy chain

64

41

BINARY(4)

Number of entries in proxy chain

 

 

CHAR(*)

Command string

Proxy commands and libraries. These fields repeat in the order listed.

CHAR(10)

Proxy command name

CHAR(10)

Proxy command library name

 

 

The first two fields, Exit point name and Exit point format name, are passed to the exit program so that the program can know the format of the information being passed. The Exit point name, QIBM_QCA_CHG_COMMAND, indicates that the exit program is being called by the Command Analyzer Change exit point. The Exit point format name, CHGC0100, indicates that the structure being passed is defined as shown above. Currently, the Command Analyzer Change exit point supports only one format, so this field may not appear to be necessary. But in the future, other formats could be added to provide additional (or at least different) information. On your system, you may have a combination of user exit programs, some using the initial format and some using the new format. As you will see later, you tell the system which format you want used when the exit program is called. This format flexibility is done so that user exit programs written to this format do not have to be changed as new formats are added. If the system is accidently told to call with a new format CHGCxxxx, and the exit program is written only expecting to use format CHGC0100, then the exit program can use the Exit point format name field to verify that it has been called correctly--prior to processing the remaining fields in the structure.

 

The next two fields, Command name and Library name, identify what command is being processed. In the case of proxy commands, this command name is the actual target command to be run. So if we used the proxy command KILL, which has a target command of ENDJOB, we would find ENDJOB as the Command name.

 

Following these fields, the Change allowed indicator field informs the exit program if it can actually change the command to be run. In certain cases, the exit program cannot modify the command string (these are documented in the exit point documentation). If this field is '1', indicating that the exit program can modify the command to be run, then the program can add parameters, remove parameters, and even change the command to be run. The exit program does this by returning the "new" command string in the second parameter passed to the exit program, Replacement command, and returning the length of the "new" command string in the third parameter, Length of replacement command string.

 

The next field, Prompt indicator, tells the exit program if prompting has been requested for the command. Note that the exit program is called by the system prior to any prompting.

 

Later in this structure are the Offset to command string and Length of command string fields. Since the system cannot know in advance what parameters the user might specify at run time, the command string is not defined with a fixed location or length. These fields, which are at a fixed location, tell the exit program where to find the start of the command string and how long the command string is.

 

Similar to how the system does not know in advance how long the command string will be, the system also does not know how many proxy commands might be linked together in order to access the actual target command. In our case, we have the proxy command KILL with the target command ENDJOB. But you could also have the proxy command DIE with the target command of KILL, where KILL is another proxy command with the target command of ENDJOB. This chain of proxy commands used to finally find ENDJOB is passed to the exit program. Due to the variable-length nature of the proxy chain, the proxy chain is accessed by the fields Offset to proxy chain and Number of entries in proxy chain. Each entry in the proxy chain is 20 bytes in length--the proxy command name and the library where the proxy command was located.

 

To define this structure in CL, we have a few choices. We could define the first parameter, Change command exit information, as a large *CHAR field and then use built-ins such as %SST and %BIN to extract the information we need. Historically, this is how CL programs generally supported a structure being passed as a parameter. A major drawback to this approach is that this structure is, as we saw earlier, variable length. With the limited number of parameters supported with the ENDJOB command, we could safely (at least for this release) guess a maximum length of 1000 bytes and be confident that this would be sufficient for our purposes. But another command, such as Start Journal (STRJRN), could easily have a command string much longer, and who knows what ENDJOB will even look like in 10 years. By using this approach, we need to guess and specify a maximum length as built-ins such as %SST will check to make sure the program is not trying to access data beyond the declared length of the variable.

 

A much better approach would be to use the V5R4 CL enhancements related to pointer support, based storage support, and defined storage support. Using these capabilities, we can eliminate guesswork as to the size of the Change command exit information parameter and at the same time improve performance. One possible definition of the Change command exit information parameter, utilizing these V5R4 features, is provided here:

 

             Dcl        Var(&Chg_Info) Type(*Char) Len(68)             

              Dcl        Var(&EP_Name)    Type(*Char)  Stg(*Defined) + 

                           Len(20)        DefVar(&Chg_Info 1)          

              Dcl        Var(&EP_Format)  Type(*Char)  Stg(*Defined) + 

                           Len(8)         DefVar(&Chg_Info 21)         

              Dcl        Var(&Cmd_Name)   Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&Chg_Info 29)         

              Dcl        Var(&Cmd_Lib)    Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&Chg_Info 39)         

              Dcl        Var(&Alw_Chg)    Type(*Char)  Stg(*Defined) + 

                           Len(1)         DefVar(&Chg_Info 49)         

              Dcl        Var(&Prompt)     Type(*Char)  Stg(*Defined) + 

                           Len(1)         DefVar(&Chg_Info 50)         

              Dcl        Var(&Off_InlCmd) Type(*Int)   Stg(*Defined) + 

                                          DefVar(&CHG_INFO 53)         

              Dcl        Var(&Len_InlCmd) TYPE(*Int)   Stg(*Defined) + 

                                          DefVar(&Chg_Info 57)         

              Dcl        Var(&Off_Prx)    TYPE(*Int)   Stg(*Defined) + 

                                          DefVar(&Chg_Info 61)         

              Dcl        Var(&Nbr_Prx)    TYPE(*Int)   Stg(*Defined) + 

                                          DefVar(&Chg_Info 65)

 

             Dcl        Var(&Ptr_InlCmd)  Type(*Ptr)                  

             Dcl        Var(&Inl_Cmd)     Type(*Char)  Stg(*Based) +  

                          Len(32767)      BasPtr(&Ptr_InlCmd)         

                                                                       

             Dcl        Var(&Ptr_Prx)     Type(*Ptr)                  

             Dcl        Var(&Prx_Struct)  Type(*Char)  Stg(*Based) +  

                          Len(20)         BasPtr(&Ptr_Prx)            

              Dcl        Var(&Prx_Name)   Type(*Char)  Stg(*Defined) +

                           Len(10)        DefVar(&Prx_Struct 1)       

              Dcl        Var(&Prx_Lib)    TYPE(*Char)  Stg(*Defined) +

                           Len(10)        DefVar(&Prx_Struct 11)                 

 

The structure, as passed by the exit point, is actually much larger than the declared 68-byte length declared above, but we only need to define the fixed portion of the structure. The remaining information--the command to be run and the proxy commands used to reach the command to be run--will be accessed later by way of pointers (&Ptr_InlCmd and &Ptr_Prx, respectively) and based variables (&Inl_Cmd and &Prx_Struct, respectively). Pointer offsets are not checked at run time in the same way substring operations are checked (though the system still performs some checks that we will not get into at this time). The use of *defined fields also means that you do not have to physically copy data from the structure to individual fields with operations such as the %SST built-in. You can simply reference the data as it exists within the structure. This elimination of copying the data provides a small performance improvement.

 

The other two parameters passed to the exit program are simple character variables and integer variables. As such they can be defined this way:

 

             Dcl        Var(&New_Cmd)     Type(*Char)  Len(32000) 

                                                                  

             Dcl        Var(&Len_NewCmd)  Type(*Int)               

 

Using the exit point documentation and the definitions shown above, the following user exit program, CHKKILL (Check for KILL), will conditionally add OPTION(*IMMED) to an ENDJOB command if the command was run due to the proxy command KILL.

 

This source should be stored in a source member named CHKKILL. If you encounter an error associated with the Retrieve Variable Size (RTVVARSIZ) command not being found, you need to refer to the earlier article "Just How Big Is That Variable?" The source for this command and the command processing program can be found there.

 

             Pgm        Parm(&Chg_Info &New_Cmd &Len_NewCmd)           

                                                                       

             Dcl        Var(&Chg_Info) Type(*Char) Len(68)             

              Dcl        Var(&EP_Name)    Type(*Char)  Stg(*Defined) + 

                           Len(20)        DefVar(&Chg_Info 1)          

              Dcl        Var(&EP_Format)  Type(*Char)  Stg(*Defined) + 

                           Len(8)         DefVar(&Chg_Info 21)         

              Dcl        Var(&Cmd_Name)   Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&Chg_Info 29)         

              Dcl        Var(&Cmd_Lib)    Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&Chg_Info 39)         

              Dcl        Var(&Alw_Chg)    Type(*Char)  Stg(*Defined) + 

                           Len(1)         DefVar(&Chg_Info 49)         

              Dcl        Var(&Prompt)     Type(*Char)  Stg(*Defined) + 

                           Len(1)         DefVar(&Chg_Info 50)         

              Dcl        Var(&Off_InlCmd) Type(*Int)   Stg(*Defined) + 

                                          DefVar(&CHG_INFO 53)         

              Dcl        Var(&Len_InlCmd) TYPE(*Int)   Stg(*Defined) + 

                                          DefVar(&Chg_Info 57)         

              Dcl        Var(&Off_Prx)    TYPE(*Int)   Stg(*Defined) + 

                                          DefVar(&Chg_Info 61)         

              Dcl        Var(&Nbr_Prx)    TYPE(*Int)   Stg(*Defined) + 

                                          DefVar(&Chg_Info 65)         

                                                                       

             Dcl        Var(&New_Cmd)     Type(*Char)  Len(32000)      

                                                                        

             Dcl        Var(&Len_NewCmd)  Type(*Int)                   

                                                                       

             Dcl        Var(&Ptr_InlCmd)  Type(*Ptr)                    

             Dcl        Var(&Inl_Cmd)     Type(*Char)  Stg(*Based) +   

                          Len(32767)      BasPtr(&Ptr_InlCmd)          

                                                                       

             Dcl        Var(&Ptr_Prx)     Type(*Ptr)                   

             Dcl        Var(&Prx_Struct)  Type(*Char)  Stg(*Based) +   

                          Len(20)         BasPtr(&Ptr_Prx)             

              Dcl        Var(&Prx_Name)   Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&Prx_Struct 1)        

              Dcl        Var(&Prx_Lib)    TYPE(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&Prx_Struct 11)       

                                                                        

             Dcl        Var(&Limit)       Type(*Int)                   

             Dcl        Var(&Size_PrxID)  Type(*Int)                   

             Dcl        Var(&Size_MatPG)  Type(*Int)                    

             Dcl        Var(&Pkd_InlCmd)  Type(*Dec)   Len(3 0)        

             Dcl        Var(&StrPos)      Type(*Dec)   Len(3 0) +      

                          Value(1)                                     

             Dcl        Var(&Len_Option)  Type(*Dec)   Len(3 0) +      

                          Value(7)                                     

             Dcl        Var(&Result)      Type(*Dec)   Len(3 0)        

             Dcl        Var(&MsgID)       Type(*Char)  Len(7)           

                                                                       

             Dcl        Var(&ErrMsgDta)   Type(*Char)  Len(40)         

              Dcl        Var(&PgmName)    Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&ErrMsgDta 1)         

              Dcl        Var(&LibName)    Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&ErrMsgDta 11)        

              Dcl        Var(&ErrEP_Name) Type(*Char)  Stg(*Defined) + 

                           Len(20)        DefVar(&ErrMsgDta 21)        

              Dcl        Var(&ErrEP_Fmt)  Type(*Char)  Stg(*Defined) + 

                           Len(8)         DefVar(&ErrMsgDta 21)        

              Dcl        Var(&Err_CmdNam) Type(*Char)  Stg(*Defined) + 

                           Len(10)        DefVar(&ErrMsgDta 21)        

              Dcl        Var(&Err_InlLen) Type(*Int)   Stg(*Defined) + 

                                          DefVar(&ErrMsgDta 21)         

              Dcl        Var(&Err_Scan)   Type(*Dec)   Stg(*Defined) + 

                           Len(3 0)       DefVar(&ErrMsgDta 21)        

                                                                       

             Dcl        Var(&Pgm_Struct)  Type(*Char)  Len(80)        

              Dcl        Var(&BytPrv)     Type(*Int)   Stg(*Defined) +

                                          DefVar(&Pgm_Struct 1)       

              Dcl        Var(&BytAvl)     Type(*Int)   Stg(*Defined) +

                                          DefVar(&Pgm_Struct 5)       

              Dcl        Var(&PgmFmt)     Type(*Int)   Stg(*Defined) +

                                          DefVar(&Pgm_Struct 9)       

              Dcl        Var(&Lib)        Type(*Char)  Stg(*Defined) +

                           Len(30)        DefVar(&Pgm_Struct 19)      

              Dcl        Var(&Pgm)        Type(*Char)  Stg(*Defined) +

                           Len(30)        DefVar(&Pgm_Struct 51)      

                                                                       

             MonMsg     MsgID(CPF0000 MCH0000) +                      

                          Exec(GoTo CmdLbl(CatchAll))                 

                                                                       

             If         Cond(&EP_Name *NE 'QIBM_QCA_CHG_COMMAND') +   

                          Then(Do)                                    

                        Chgvar Var(&MsgID) Value('PRX1001')           

                        ChgVar Var(&ErrEP_Name) Value(&EP_Name)       

                        CallSubr Subr(SndErrMsg)                      

                        EndDo                                         

                                                                       

             If         Cond(&EP_Format *NE 'CHGC0100') Then(Do)      

                        Chgvar Var(&MsgID) Value('PRX1002')           

                        ChgVar Var(&ErrEP_Fmt) Value(&EP_Format)      

                        CallSubr Subr(SndErrMsg)                      

                        EndDo                                         

                                                                      

             If         Cond(&Cmd_Name *NE 'ENDJOB') Then(Do)         

                        Chgvar Var(&MsgID) Value('PRX1003')           

                        ChgVar Var(&Err_CmdNam) Value(&Cmd_Name)      

                        CallSubr Subr(SndErrMsg)                      

                        EndDo

 

             If         Cond(&Nbr_Prx *EQ 0) Then(Return)     

                                                                                                         

                                                                      

             ChgVar     Var(&Ptr_Prx) Value(%Addr(&Chg_Info))         

             ChgVar     Var(%OffSet(&Ptr_Prx)) +                      

                          Value(%OffSet(&Ptr_Prx) + &Off_Prx)         

             RtvVarSiz  Var(&Prx_Struct) Size(&Size_PrxID)            

             DoFor      Var(&Limit) From(1) To(&Nbr_Prx)              

                        If Cond(&Prx_Name = 'KILL') Then(Do)          

                           If Cond(&Len_InlCmd *GT 999) Then(Do)      

                              ChgVar Var(&MsgID) Value('PRX1004')     

                              ChgVar Var(&Err_InlLen) +               

                                Value(&Len_InlCmd)                    

                              CallSubr Subr(SndErrMsg)                 

                              EndDo                                   

                           ChgVar Var(&Ptr_InlCmd) +                  

                             Value(%Addr(&Chg_Info))                  

                           ChgVar Var(%OffSet(&Ptr_InlCmd)) +         

                             Value(%OffSet(&Ptr_InlCmd) + &Off_InlCmd)

                           ChgVar Var(&Pkd_InlCmd) Value(&Len_InlCmd) 

                           Call Pgm(QCLScan) Parm(&Inl_Cmd +          

                             &Pkd_InlCmd &StrPos 'OPTION(' +         

                             &Len_Option '0' '0' ' ' &Result)        

                           Select                                    

                             When Cond(&Result *GT 0) Then(Return)

                             When Cond((&Result *EQ 0) *OR +      

                                  (&Result *EQ -1)) Then(Do)           

                               If Cond(&Alw_Chg *EQ '0') Then(Do)    

                                  ChgVar Var(&MsgID) Value('PRX1005')

                                  CallSubr Subr(SndErrMsg)           

                                  EndDo                              

                               Else Cmd(Do)                           

                                  ChgVar Var(&New_Cmd) +             

                                    Value(%SST(&Inl_Cmd 1 +          

                                      &Len_InlCmd) *BCat +           

                                      'OPTION(*IMMED)')              

                                  ChgVar Var(&Len_NewCmd) +          

                                    Value(&Len_InlCmd + 15)          

                                  EndDo                              

                               Return                                

                               EndDo                                 

                             When Cond(&Result *LT 0) Then(Do)       

                               ChgVar Var(&MsgID) Value('PRX1006')   

                               ChgVar Var(&Err_Scan) Value(&Result)  

                               CallSubr Subr(SndErrMsg)              

                               EndDo                                 

                             EndSelect                               

                           EndDo                                     

                        ChgVar Var(%OffSet(&Ptr_Prx)) +              

                          Value(%OffSet(&Ptr_Prx) + &Size_PrxID)     

                        EndDo                                        

                                                                     

             Return                                                  

                                                                      

CatchAll:    ChgVar Var(&MsgID) Value('PRX1099')                     

             CallSubr Subr(SndErrMsg)                                

                                                                     

             Subr       Subr(SndErrMsg)                              

             RtvVarSiz  Var(&Pgm_Struct) Size(&Size_MatPG)           

             CallPrc    Prc('_PROPB') Parm((&Pgm_Struct) +           

                          (x'00' *ByVal) (&Size_MatPG *ByVal))       

             ChgVar     Var(&BytPrv) Value(&Size_MatPG)              

             CallPrc    Prc('_MATPGMNM') Parm((&Pgm_Struct))         

             ChgVar     Var(&PgmName) Value(%SST(&Pgm 1 10))         

             ChgVar     Var(&LibName) Value(%SSt(&Lib 1 10))         

             SndPgmMsg  MsgID(&MsgID) MsgF(VINING/USERMSGF) +        

                          MsgDta(&ErrMsgDta) MsgType(*Escape)        

             EndSubr                                                  

                                                                     

             EndPgm                                                  

 

To compile the CHKKILL program, you could use this command:

 

CRTBNDCL PGM(CHKKILL) TEXT('Check for KILL Proxy')

 

If you look at the CHKKILL program, you will see that it sends various escape messages for errors that are encountered. To create these messages, use the following commands:

 

CRTMSGF MSGF(VINING/USERMSGF)

ADDMSGD MSGID(PRX1001) MSGF(VINING/USERMSGF)

     MSG('Exit program &2/&1 was incorrectly called by exit point &3.')

     FMT((*CHAR 10) (*CHAR 10) (*CHAR 20))

ADDMSGD MSGID(PRX1002) MSGF(VINING/USERMSGF)

     MSG('Exit program &2/&1 was incorrectly called with format &3.')

     FMT((*CHAR 10) (*CHAR 10) (*CHAR 8))

ADDMSGD MSGID(PRX1003) MSGF(VINING/USERMSGF)

     MSG('Exit program &2/&1 was incorrectly called for command &3.')

     FMT((*CHAR 10) (*CHAR 10) (*CHAR 10))

ADDMSGD MSGID(PRX1005) MSGF(VINING/USERMSGF)

     MSG('Exit program &2/&1 was not able to change OPTION default.')

     FMT((*CHAR 10) (*CHAR 10))

ADDMSGD MSGID(PRX1006) MSGF(VINING/USERMSGF)

     MSG('Exit program &2/&1 encountered return code &3 on scan.')

     FMT((*CHAR 10) (*CHAR 10) (*DEC 3 0))

ADDMSGD MSGID(PRX1099) MSGF(VINING/USERMSGF)

     MSG('Exit program &2/&1 ended unexpectedly. See previous messages.')

     FMT((*CHAR 10) (*CHAR 10))

 

We have run out of room for this month's article, but next month we will look at the initial flow of the CHKKILL program. We will also see how to activate CHKKILL so that it is called by the system whenever the ENDJOB command is run (either directly as ENDJOB or indirectly through a proxy such as KILL). In the meantime, feel free to review the CHKKILL source to determine how it works. Hopefully, you will learn, or at least confirm, a few approaches on how to get the most out of CL!

Program Puzzler 

Using the above program, CHKKILL will add the literal 'OPTION(*IMMED)' when processing a KILL proxy command that has not already specified the OPTION keyword. Related to this behavior, I have intentionally included one statement in the program that I consider to be a poor programming practice:

 

                                  ChgVar Var(&Len_NewCmd) +          

                                    Value(&Len_InlCmd + 15)          

 

The problem I have with this statement is that I have to count the number of characters being concatenated to the initial command string, &Inl_Cmd, in order to set the length of the new command string, &Len_NewCmd. In this case the hardcoded "15" represents the 14 characters found in the literal value 'OPTION(*IMMED)' plus one character for the blank separating this literal value from the initial command string. Can you determine a way to eliminate the need to count the 15 characters? Your answer should also provide for a developer in the future adding additional keywords such as 'LOGLMT(0)' to the above 'OPTION(*IMMED)' literal without the developer needing to change how the &Len_NewCmd variable is set (in this case changing the "15" to "25"). The one hint I will give is that the answer is in the article "Just How Big Is That Variable?" The answer I'm thinking of can be found here under The CL Corner: Program Puzzler, though other solutions do exist.

More CL Questions?              

Wondering how to accomplish a function in CL? Send your CL-related questions to me at This email address is being protected from spambots. You need JavaScript enabled to view it.. I'll try to answer your burning questions in future columns.

 

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: