29
Fri, Nov
0 New Articles

TechTip: Take Advantage of the SU CL Command

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

Switch to and back from different user profiles within the same job with ease.

 

In UNIX or Linux, users switch to the super user (aka root) or another user via the su shell command (in a new shell, actually). With proper options, a su command can even preserve the original environment in the newly started shell sessionfor example, the -m option (do not reset environment variables) of the su command of GNU Linux. For an IBM i developer or operator, a CL command with function similar to the UNIX/Linux su shell command would be very handy.

 

In this article, I'll show you a practical utility, the SU CL command, which allows you to switch to and back from different user profiles within the same job. The SU command changes the USRPRF under which the current thread/job runs so that the new USRPRF (replacing the previous USRPRF) becomes one of the sources of authority of the current thread/job. While no other job resources are changed due to a SU command, you can for example still retrieve previously entered commands with function key F9 in the command environment.

How Does the Su Command Work?

The SU command allows an operator or a program to switch to another user profile in a single job. When switching to another user profile, you should pass a user profile (*USRPRF) name and the password of the USRPRF (or optionally one of the following accepted special values: *NOPWD, *NOPWDCHK, or *NOPWDSTS). For example: SU USER(USER_A) PASSWORD(******). When switching back to the previous USRPRF, you can simply issue SU USER(*EXIT).

 

The SU command allows an operator or a program to switch to multiple users one by one and then switch back in the reverse order. To preserve the USRPRF handles, the SU command uses data queue (*DTAQ) object QTEMP/@SUDTAQ of type *LIFO (queue entries are received in a last-in first-out order). In other words, @SUDTAQ works as a "USRPRF handle stack." Figure 1 illustrates the working mechanism of the SU command in brief.

 

 02-1513Junleiflow-small                     

Figure 1: This is how the SU command works.

 

[1], [2] When an operator or a program issues a SU USER(USER_NAME) PASSWORD(******) command, SU saves the current USRPRF handle by first retrieving a USRPRF handle (PH_A) of the current user (USER_A) via the Get Profile Handle (QSYGETPH) API and then pushing PH_A on the USRPRF handle stack), @SUDTAQ, via the Send Data Queue (QSNDDTAQ) API.

[3] Get the USRPRF handle (PH_B) of the target user (USER_B) by invoking the QSYGETPH API with the input user name and password parameters.

[4] Switch to the USER_B by invoking the Set Profile (QWTSETP) API, passing the USRPRF handle PH_B. After QWTSEPT returns successfully, the current job is running under the user profile USER_B -- PH_B.

[5] Release PH_B via the Release Profile Handle (QSYRLSPH) API.

[6] Work under user profile USER_B.

[7] When a SU USER(*EXIT) command is issued, SU pops the user profile handle of USER_A (PH_A) out of the "USRPRF handle stack" via the Receive Data Queue (QRCVDTAQ) API and then invokes QWTSETP to switch back USER_A.

[8] After QWTSEPT returns successfully, the current thread runs under the user profile USER_A again. SU then releases PH_A.

 

Note that the SU command accepts either a password or one of the following special values:

  • *NOPWDThe user requesting the profile handle must have *USE authority to the user profile. A profile handle does not get created for a disabled user profile. A profile handle does not get created for a user profile with an expired password.
  • *NOPWDCHKThe user requesting the profile handle must have *USE authority to the user profile. If the profile is disabled, the user requesting the profile handle must have *ALLOBJ and *SECADM special authorities to get a handle. If the password is expired, the user requesting the profile handle must have *ALLOBJ and *SECADM special authorities to get a handle.
  • *NOPWDSTSThe user requesting the profile handle must have *USE authority to the user profile. A profile handle does not get created for a disabled user profile. If the password is expired, the user requesting the profile handle must have *ALLOBJ and *SECADM special authorities to get a handle.

Source Code of the SU Command

The following is the source of command definition of the SU command su.cl-cmd.

 

             CMD       PROMPT('su')

             PARM       KWD(USER) TYPE(*NAME) LEN(10)   SPCVAL((*EXIT +

                         *EXIT)) MIN(1)   CASE(*MONO) PROMPT('User +

                         name')

             PARM       KWD(PASSWORD) TYPE(*CHAR) LEN(128) +

                         DFT(*NOPWDCHK)   SPCVAL((*NOPWD *NOPWD) +

                         (*NOPWDCHK   *NOPWDCHK) (*NOPWDSTS +

                         *NOPWDSTS)) MIN(0)   CASE(*MIXED) +

                         DSPINPUT(*NO)   INLPMTLEN(10) +

                         PROMPT('Password')

 

The CL version of the CPP of the SU command su.clle is shown as follows:

 

/********************************************************************/

/* @file su.clle                                                  */

/* CL version of the CPP of   the SU command.                           */

/********************************************************************/

 

             PGM       PARM(&TGTUSR &PWD)

 

             DCL       VAR(&TGTUSR) TYPE(*CHAR) LEN(10)

             DCL       VAR(&PWD) TYPE(*CHAR) LEN(128)

             DCL       VAR(&ORG_PH) TYPE(*CHAR) LEN(12)

             DCL       VAR(&TGT_PH) TYPE(*CHAR) LEN(12)

             DCL       VAR(&QNAM) TYPE(*CHAR) LEN(10)   VALUE(@SUDTAQ)

             DCL       VAR(&QLIB) TYPE(*CHAR) LEN(10)   VALUE(QTEMP)

             DCL       VAR(&ENT_LEN) TYPE(*DEC) LEN(5 0)   VALUE(12)

             DCL       VAR(&TIMEOUT) TYPE(*DEC) LEN(5 0)   VALUE(0)

             DCL       VAR(&PWD_LEN) TYPE(*INT) LEN(4)   VALUE(128)

             DCL       VAR(&OFF1) TYPE(*INT) LEN(4)

             DCL       VAR(&OFF2) TYPE(*INT) LEN(4)

             DCL       VAR(&CCSID) TYPE(*INT) LEN(4)   VALUE(0)

             DCL       VAR(&WHERE) TYPE(*PTR)

             DCL       VAR(&PWD_PTR) TYPE(*PTR)

             DCL       VAR(&NULL) TYPE(*PTR)

             DCL       VAR(&EC) TYPE(*CHAR) LEN(16) +

                           VALUE(X'00000000000000000000000000000000')

 

             IF         COND(&TGTUSR *NE '*EXIT') THEN(GOTO   +

                         CMDLBL(SWAP_TO))

             ELSE       CMD(GOTO CMDLBL(SWAP_BACK))

 

SWAP_TO:     CHKOBJ       OBJ(&QLIB/&QNAM) OBJTYPE(*DTAQ)

             MONMSG     MSGID(CPF9801) EXEC(DO)

             CRTDTAQ   DTAQ(QTEMP/@SUDTAQ) MAXLEN(12) SEQ(*LIFO)   +

                         AUT(*CHANGE)

             ENDDO     /* Create the PH stack in case it isn't   +

                         already exists */

 

             CALL       PGM(QSYGETPH) PARM('*CURRENT ' ' ' &ORG_PH)

             CALL       PGM(QSNDDTAQ) PARM(&QNAM &QLIB   &ENT_LEN +

                         &ORG_PH) /*   Save current PH */

 

             /* Get the PH of target user */

             IF         COND(%SST(&PWD 1 6) *EQ   '*NOPWD') THEN(CALL +

                         PGM(QSYGETPH)   PARM(&TGTUSR &PWD &TGT_PH))

             ELSE       CMD(DO)

             CALLPRC   PRC('_MEMCHR') PARM((&PWD *BYREF) ('   ' +

                         *BYVAL)   (&PWD_LEN *BYVAL)) RTNVAL(&WHERE)

             IF         COND(&WHERE *NE &NULL)   THEN(DO)

             CHGVAR     VAR(&PWD_PTR) VALUE(%ADDR(&PWD))

             CHGVAR     VAR(&OFF2) VALUE(%OFS(&WHERE))

             CHGVAR     VAR(&OFF1) VALUE(%OFS(&PWD_PTR))

             CHGVAR     VAR(&PWD_LEN) VALUE(&OFF2 -   &OFF1)

             ENDDO     /* If &where == *NULL */

             CALL       PGM(QSYGETPH) PARM(&TGTUSR   &PWD &TGT_PH &EC +

                         &PWD_LEN   &CCSID)

             ENDDO     /* Else block         */

 

             CALL       PGM(QWTSETP) PARM(&TGT_PH) /*   Switch to +

                          target user */

             CALL       PGM(QSYRLSPH) PARM(&TGT_PH) /*   Release PH */

             GOTO       CMDLBL(BYE)

 

SWAP_BACK:   CALL       PGM(QRCVDTAQ)   PARM(&QNAM &QLIB &ENT_LEN +

                         &ORG_PH   &TIMEOUT) /* Pop previous PH out +

                         of the PH stack */

             IF         COND(&ENT_LEN *EQ 0)   THEN(SNDPGMMSG +

                         MSGID(CPF9898)   MSGF(QSYS/QCPFMSG) +

                         MSGDTA('Exit to   where? :p') MSGTYPE(*ESCAPE))

             ELSE       CMD(DO)

             CALL       PGM(QWTSETP) PARM(&ORG_PH) /*   Switch back to +

                         original user */

             CALL       PGM(QSYRLSPH) PARM(&ORG_PH) /*   Release PH */

             ENDDO

 

BYE:         ENDPGM

 

The following is the OPM MI version of the CPP of the SU command su.emi (needs to be compiled via mic).

 

/**

* @file su.emi

*

* CPP of the SU command.

*/

 

dcl spcptr @tgt-user   parm       ;

dcl dd tgt-user char(10)   bas(@tgt-user) ;

dcl spcptr @pwd parm           ;

dcl dd pwd char(128)   bas(@pwd) ;

 

dcl ol pl-main(

      @tgt-user, @pwd

) parm ext                     ;

entry *(pl-main) ext           ;

brk   "MORNING"                   ;

       /* Check target USRPRF parameter */

       cmpbla(b) tgt-user, *EXIT / eq(=+3) ;

       calli swap-to, *, @swap-to         ;

       b =+2                               ;

:

       calli swap-back, *, @swap-back ; /* SU USER(*EXIT) */

:      

brk "SEEU"                     ;

       rtx *                   ;

 

/* Routine: swap-to */

dcl insptr @swap-to   auto       ;

entry swap-to int               ;

dcl sysptr @sudtaq   auto         ;

dcl dd rt char(34)   auto         ;

       dcl dd * char(2) def(rt) pos(1)   init(x"0A01")   ;

       dcl dd * char(30) def(rt) pos(3)   init(" ")   ;

       dcl dd * char(2) def(rt) pos(33)   init(x"0000")   ;

 

       /* Resolve QTEMP/@SUDTAQ */

       cpybla rt(3:30), qrcvdtaq?q       ;

       setip @on-2201, crt-su-dtaq       ;

       rslvsp @sudtaq, rt, @pco?qtemp, * ;

       b so-boring                       ;

crt-su-dtaq:

       cpyblap cl-cmd,

         "CRTDTAQ DTAQ(QTEMP/@SUDTAQ)   MAXLEN(12) SEQ(*LIFO) AUT(*CHANGE)",

         " "                   ;

       triml pkd-cmd-len, cl-cmd, "   " ;

       callx pco?sept(qcmdexc-entry),

         al-qcmdexc, *         ;

so-boring:

       /* Save current profile handle for   swapping back */

       cpybla user, cur-user   ;

       setspp @ph, org-ph     ;

       callx pco?sept(qsygetph-entry),

         al-qsygetph-short, * ; /* When   specify *CURRENT for parm user, */

                               /* QSYGETPH expects 3-4 parms           */

       cpynv qrcvdtaq?len, 12 ;

       setspp @qrcvdtaq?msg, org-ph ;

       callx pco?sept(qsnddtaq-entry),

         al-qsnddtaq, *       ;

brk "MEMO"                           ;

       /* Get the profile handle of the   target USRPRF */

       cpybla user, tgt-user   ;

       setspp @ph, ph         ;

       cmpbla(b) pwd, "*NOPWD" /   eq(spec-pwd-value) ;

       triml pwd-len, pwd, " " ;

       callx pco?sept(qsygetph-entry),

         al-qsygetph, *      ;

       b =+2                   ;

spec-pwd-value:

       callx pco?sept(qsygetph-entry),

         al-qsygetph-short, * ; /* When   specify a special value for parm */

                                 /* PASSWORD,   QSYGETPH expects 3-4 parms */

:

        /* Swap to target USRPRF */

       callx pco?sept(qwtsetp-entry),

         al-qwtsetp, *         ;

       callx pco?sept(qsyrlsph-entry),

         al-qsyrlsph, *       ; /* Release profile handle of   tgt-user */

end-swap-to:  

brk "TO"                      ;

       b @swap-to             ;

 

/* Routine: swap-back */

dcl insptr @swap-back   auto     ;

entry swap-back int             ;

       /* Resolve QTEMP/@SUDTAQ */

       cpybla rt(3:10), qrcvdtaq?q       ;

       setip @on-2201, end-swap-back     ;

       rslvsp @sudtaq, rt, @pco?qtemp, * ;

 

       /* Dequeue previous profile handle   from @SUDTAQ */

       setspp @qrcvdtaq?msg, org-ph ;

       callx pco?sept(qrcvdtaq-entry),

         al-qrcvdtaq, *       ;

       cmpnv(b) qrcvdtaq?len, 0 /   neq(end-deq) ;

       cpybla msg,

         "Exit to where? :p"   ;

       setspp @sndimdmsg?text,

         msg                   ;

       triml sndimdmsg?textl,

         msg, " "             ;

       cpybla sndimdmsg?msgtype,

         "*ESCAPE"             ;

       calli sndimdmsg, *, @sndimdmsg ;

       b end-swap-back                     ;

end-deq:

       /* Set profile handle to previous PH   */

       setspp @ph, org-ph     ;

       callx pco?sept(qwtsetp-entry),

         al-qwtsetp, *         ;

       callx pco?sept(qsyrlsph-entry),

         al-qsyrlsph, *       ;

 

end-swap-back:

       b @swap-back           ;

 

/* Exception handlers */

dcl excm excd-2201   excid(h'2201') bp(on-2201) imd ;

dcl insptr @on-2201   auto                ;

on-2201:

       cpybla msg,

         "Data queue @sudtaq does not   exist" ;

       cpybla msg(12:7), qrcvdtaq?q         ;

       setspp @sndimdmsg?text,

         msg                   ;

       triml sndimdmsg?textl,

         msg, " "              ;

       cpybla sndimdmsg?msgtype,

         "*DIAG"                     ;

       calli sndimdmsg, *, @sndimdmsg ;

brk "2201"                     ;

       b @on-2201             ;

 

/* QCMDEXC */

dcl con qcmdexc-entry   bin(2) unsgnd init(h'7C5')   ;

dcl dd pkd-cmd-len   pkd(15,5) auto               ;

dcl spcptr @pkd-cmd-len   auto init(pkd-cmd-len)   ;

dcl dd cl-cmd char(64)   auto                     ;

dcl spcptr @cmd-str auto   init(cl-cmd)           ;

dcl ol al-qcmdexc   (@cmd-str, @pkd-cmd-len) arg   ;

 

/* QSYGETPH */

dcl con qsygetph-entry   bin(2) unsgnd init(h'1305') ;

dcl dd user char(10)   auto                         ;

dcl spcptr @user auto   init(user)                   ;

dcl dd ph char(12)   auto                           ;

dcl dd org-ph char(12)   auto                        ;

       /* Profile handle of original USRPRF   */

dcl spcptr @ph auto                               ;

dcl dd ec-size bin(4) auto   init(0)                 ;

dcl spcptr @ec auto   init(ec-size)                 ;

dcl dd pwd-len bin(4) auto                         ;

dcl spcptr @pwd-len auto   init(pwd-len)             ;

dcl dd ccsid bin(4) auto   init(-1)                 ;

       /* determine CCSID according to the   current password level (QPWDLVL) */

dcl spcptr @ccsid auto   init(ccsid)                ;

dcl ol al-qsygetph (

       @user, @pwd, @ph, @ec, @pwd-len,   @ccsid

) arg                                     ;

dcl ol al-qsygetph-short (

       @user, @pwd, @ph

) arg                                     ;

dcl con cur-user char(10)   init("*CURRENT")         ;

 

/* QSYRLSPH */

dcl con qsyrlsph-entry   bin(2) unsgnd init(h'130B') ;

dcl ol al-qsyrlsph (@ph)   arg                       ;

 

/* QWTSETP */

dcl con qwtsetp-entry   bin(2) unsgnd init(h'1350') ;

dcl ol al-qwtsetp (@ph)   arg                     ;

 

/* QRCVDTAQ */

dcl con qrcvdtaq-entry   bin(2) unsgnd init(h'B51') ;

dcl dd qrcvdtaq?q char(10)   auto init("@SUDTAQ")   ;

dcl spcptr @qrcvdtaq?q auto   init(qrcvdtaq?q)     ;

dcl dd qrcvdtaq?lib   char(10) auto init("QTEMP")     ;

dcl spcptr @qrcvdtaq?lib   auto init(qrcvdtaq?lib) ;

dcl dd qrcvdtaq?len   pkd(5,0) auto init(p'12')     ;

dcl spcptr @qrcvdtaq?len   auto init(qrcvdtaq?len) ;

dcl spcptr @qrcvdtaq?msg   auto                     ;

dcl dd qrcvdtaq?waittime   pkd(5,0) auto init(p'0') ;

       /* Dequeue @SUDTAQ without waiting */

dcl spcptr   @qrcvdtaq?waittime auto init(qrcvdtaq?waittime) ;

dcl ol al-qrcvdtaq(

       @qrcvdtaq?q,

       @qrcvdtaq?lib,

       @qrcvdtaq?len,

       @qrcvdtaq?msg,

       @qrcvdtaq?waittime

) arg                           ;

 

/* QSNDDTAQ */

dcl con qsnddtaq-entry   bin(2) unsgnd init(h'B52') ;

dcl ol al-qsnddtaq(

       @qrcvdtaq?q,

       @qrcvdtaq?lib,

       @qrcvdtaq?len,

       @qrcvdtaq?msg

) arg                           ;

 

 

dcl con *EXIT char(10)   init("*EXIT") ;

dcl dd msg char(64) auto   init(" ")   ;

dcl dd flag bin(2) auto   init(0) ;

 

/* Includes */

/include   "sept.emi"             ;

/include   "sndimdmsg.emi"       ;

 

pend                           ;

 

Source files included by su.emi are available here: sept.emi, sndimdmsg.emi.

 

For your convenience, the C version of the CPP of SU is available here: su.c.

Let's Try It!

Imagine that you're developing a defect-tracking application. A physical file called BUGS is expected to store all reported defects. Three kinds of users of this defect-tracking application have different authorities to PF BUGS:

  • The administrator (identified by USRPRF ADMIN)User profile ADMIN owns the PF BUGS and hence has full authorities to BUGS.
  • Testers whose group profile is TESTERTesters are responsible for reporting defects to managers and programmers, who are expected to solve all detected defects. USRPRF TESTER has add and read authorities to PF BUGS but is prohibited from modifying or deleting BUGS records.
  • Programmers whose group profile is PGMRUSRPRF PGM has read and update authorities to PF BUGS.

 

The public and private authorities to different users are set by ADMIN as shown:

 

GRTOBJAUT OBJ(BUGS)   OBJTYPE(*FILE) USER(*PUBLIC) AUT(*EXCLUDE)

/* Revoke *PUBLIC authorities to BUGS */

 

GRTOBJAUT OBJ(BUGS)   OBJTYPE(*FILE) USER(TESTER) AUT(*USE)

GRTOBJAUT OBJ(BUGS)   OBJTYPE(*FILE) USER(TESTER) AUT(*ADD)

/* Allow TESETER to read BUGS or add   records to it */

 

GRTOBJAUT OBJ(BUGS)   OBJTYPE(*FILE) USER(PGMR) AUT(*CHANGE)

RVKOBJAUT OBJ(BUGS)   OBJTYPE(*FILE) USER(PGMR) AUT(*DLT)

/* Allow PGMR to read BUGS or update   records in it */

 

The following example steps demonstrate operations on PF BUGS under three different USRPRFs within a single job:

 

CLRPFM BUGS /* Under USRPRF ADMIN */

SU TESTER.

   STRQSH CMD('db2 "INSERT INTO BUGS   (DID, DDATE, DDESC)

     VALUES(''A01'', ''2013-01-01'',   ''Today is too cold.'')"')

     /* Under USRPRF TESTER */

   SU PGMR

   STRQSH CMD('db2 "UPDATE BUGS SET   DDESC=TRIM(DDESC) CONCAT ' - Solved'"')

       /* Under USRPRF PGMR */

   SU *EXIT

RUNQRY *N BUGS /* Under USRPRF TESTER */

SU *EXIT

 

Note that a DSPJOB OPTION(*STSA) can be used to check the current user profile of the job.

Junlei Li

Junlei Li is a programmer from Tianjin, China, with 10 years of experience in software design and programming. Junlei Li began programming under i5/OS (formerly known as AS/400, iSeries) in late 2005. He is familiar with most programming languages available on i5/OS—from special-purpose languages such as OPM/ILE RPG to CL to general-purpose languages such as C, C++, Java; from strong-typed languages to script languages such as QShell and REXX. One of his favorite programming languages on i5/OS is machine interface (MI) instructions, through which one can discover some of the internal behaviors of i5/OS and some of the highlights of i5/OS in terms of operating system design.

 

Junlei Li's Web site is http://i5toolkit.sourceforge.net/, where his open-source project i5/OS Programmer's Toolkit (https://sourceforge.net/projects/i5toolkit/) is documented.

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: