IBM-i Control Language – Check Subsystem Status

  • Home
  • /
  • Blog
  • /
  • IBM-i Control Language – Check Subsystem Status

January 9, 2026

How to Check Whether a Subsystem Is Active in IBM i Using CL

If you’ve spent any time automating operations on IBM i, you’ve probably bumped into this classic requirement: “Before I run this job, I need to know whether a subsystem is active.”

It sounds simple, but depending on your tooling and IBM i version, there are several ways to approach it. Some are modern and elegant. Others are… let’s say “heritage techniques.” In this post, we’ll walk through the three most common methods so you can choose the one that fits your environment.

Option 1: The Funky Way Query SUBSYSTEM_INFO with SQL

If your system is reasonably up to date, IBM has gifted us a clean solution: the QSYS2.SUBSYSTEM_INFO view. It tells you exactly what you want to know, including whether a subsystem is ACTIVE, INACTIVE, ENDING, or RESTRICTED.

You can call it directly from CL using RUNSQL.

“But RUNSQL does not output to an outfile!” I can hear you exclaim!

Don’t worry, we will simply do a little SQL CREATE TABLE trick. Here I am using QTEMP but you can use any library you like:

PGM                                                    
        DCLF       FILE(QTEMP/CHKSBSTMP) ALWVARLEN(*YES)
                                                                          
        RUNSQL     SQL('CREATE TABLE QTEMP/CHKSBSTMP AS (SELECT +    
                        STATUS FROM QSYS2/SUBSYSTEM_INFO WHERE +        
                        SUBSYSTEM_DESCRIPTION = ''QINTER'' AND +        
                        SUBSYSTEM_DESCRIPTION_LIBRARY = ''QSYS'') +     
                        WITH DATA') COMMIT(*NONE) NAMING(*SYS)          

        RCVF       RCDFMT(*FILE)                                       
        MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(FAIL))              

        SNDPGMMSG  MSG('Subsystem QINTER is Active')                                                  

        RETURN                                                       

FAIL:   SNDPGMMSG MSG('* Unable to retrieve subsystem status!') 
ENDPGM

That’s the simple skeleton of what we want to do. Now, let write this with a little bit more sparkle:

/******************************************************************************/
/* Program: CHKSBSACT - Check if Subsystem is Active                                                             */
/* Purpose: Determines if a specified subsystem is currently active                                                 */
/* Parameters:                                                                                                                                    */
/*   &SBS    - Subsystem name (10 chars)                                                                                        */
/*   &LIB    - Subsystem library (10 chars)                                                                                       */
/*   &RESULT - Return value: 'YES' if active, 'NO' if inactive, 'ERR' error                                    */
/* https://www.nicklitten.com/ibm-i-control-language-check-subsystem-status                              */
/******************************************************************************/

PGM        PARM(&SBS &LIB &RESULT)

DCLPRCOPT  LOG(*NO) DFTACTGRP(*NO) ACTGRP(*CALLER)

COPYRIGHT  TEXT('CHKSBSACT Ver:001 Check if Subsystem is Active')
DCL        VAR(&COPYRIGHT) TYPE(*CHAR) LEN(256) +
              VALUE('Nick Litten © 2025 | IBM i V7.5 https://www.nicklitten.com')
DCL        VAR(&COPYRIGHTP) TYPE(*PTR) STG(*DEFINED) DEFVAR(&COPYRIGHT)

DCL        VAR(&SBS) TYPE(*CHAR) LEN(10)
DCL        VAR(&LIB) TYPE(*CHAR) LEN(10)
DCL        VAR(&RESULT) TYPE(*CHAR) LEN(3)
DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)
DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(512)
DCL        VAR(&SQLSTMT) TYPE(*CHAR) LEN(512)

/* File declaration for SQL result */
DCLF       FILE(CHKSBSTMP) ALWVARLEN(*YES)

/* Initialize result to error state */
CHGVAR     VAR(&RESULT) VALUE('ERR')

/* Clean up any existing temp file */
DLTF       FILE(QTEMP/CHKSBSTMP)
MONMSG     MSGID(CPF2105 CPF2110) /* File not found errors */

/* Build dynamic SQL statement using actual parameters */
CHGVAR     VAR(&SQLSTMT) VALUE('CREATE TABLE +
                 QTEMP.CHKSBSTMP AS (SELECT STATUS FROM +
                 QSYS2.SUBSYSTEM_INFO WHERE +
                 SUBSYSTEM_DESCRIPTION = ''' *CAT %TRIM(&SBS) +
                 *CAT ''' AND SUBSYSTEM_DESCRIPTION_LIBRARY = +
                 ''' *CAT %TRIM(&LIB) *CAT ''') WITH DATA')

/* Execute SQL to retrieve subsystem status */
RUNSQL     SQL(&SQLSTMT) COMMIT(*NONE) NAMING(*SQL)
MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(SQL_ERROR))

/* Read the status from temp file */
RCVF       RCDFMT(*FILE)
MONMSG     MSGID(CPF0864) EXEC(GOTO CMDLBL(NO_DATA)) /* EOF */
MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(READ_ERROR))

/* Check if subsystem is active */
IF         COND(%TRIM(&STATUS) *EQ 'ACTIVE') THEN(DO)
   CHGVAR     VAR(&RESULT) VALUE('YES')
ENDDO
ELSE       CMD(DO)
   CHGVAR     VAR(&RESULT) VALUE('NO')
ENDDO

/* Clean up and return */
GOTO       CMDLBL(CLEANUP)

/*---------------------------------------------------------------------------*/
/* Error handling routines                                                   */
/*---------------------------------------------------------------------------*/

/* No data found - subsystem doesn't exist or no match */
NO_DATA:
CHGVAR     VAR(&RESULT) VALUE('NO')
SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) +
              MSGDTA('Subsystem' *BCAT %TRIM(&SBS) *BCAT +
              'not found in library' *BCAT %TRIM(&LIB)) +
              MSGTYPE(*DIAG)
GOTO       CMDLBL(CLEANUP)

/* SQL execution error */
SQL_ERROR:
RCVMSG     MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID)
SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) +
              MSGDTA('SQL error' *BCAT &MSGID *BCAT '-' +
              *BCAT %SST(&MSGDTA 1 100)) MSGTYPE(*DIAG)
GOTO       CMDLBL(CLEANUP)

/* File read error */
READ_ERROR:
RCVMSG     MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID)
SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) +
              MSGDTA('Read error' *BCAT &MSGID *BCAT '-' +
              *BCAT %SST(&MSGDTA 1 100)) MSGTYPE(*DIAG)
GOTO       CMDLBL(CLEANUP)

/* Cleanup routine */
CLEANUP:
DLTF       FILE(QTEMP/CHKSBSTMP)
MONMSG     MSGID(CPF2105 CPF2110) /* Ignore if not found */

RETURN

ENDPGM

The main drawback to this technique is that it needs the file QTEMP/CHKSBSTMP to exist so you can compile the code in the first place. You can do this from a command line by entering STRSQL and:

CREATE TABLE QTEMP/CHKSBSTMP AS (SELECT +    
                        STATUS FROM QSYS2/SUBSYSTEM_INFO WHERE +        
                        SUBSYSTEM_DESCRIPTION = ''QINTER'' AND +        
                        SUBSYSTEM_DESCRIPTION_LIBRARY = ''QSYS'') +     
                        WITH DATA

Of course – once you need to compile this code using offline tools like VS-Code it will always fail because the file doesn’t exist for each new compile session. Clonky right!

Pros and cons

  • ✔ Simple code
  • ✔ Brief calls to SQL function
  • ✘ Doesn’t work on older releases of IBM-i
  • ✘ Depends on file existing to compile, which is never ideal

If IBM gave us an OUTPUT(&VARIABLE) option on the RUNSQL command this technique would be the bomb. But until that time, I am stick with a good old API call from my CL program. QWDRSBSD to the rescue!

Option 2: The Classic Way Use the QWDRSBSD API

Before SQL views existed, the standard way to check subsystem status was the QWDRSBSD API. It’s still fully supported and works on every IBM i release you’re likely to encounter.

/******************************************************************************/
/* Program: CHKQINACT - Check if Subsystem is Active                                                             */
/* Purpose: Determines if a specified subsystem is currently active                                                 */
/* https://www.nicklitten.com/ibm-i-control-language-check-subsystem-status                               */
/******************************************************************************/

PGM

DCLPRCOPT  LOG(*NO) DFTACTGRP(*NO) ACTGRP(*CALLER)

COPYRIGHT  TEXT('CHKSBSACT Ver:001 Check if Subsystem is Active')
DCL        VAR(&COPYRIGHT) TYPE(*CHAR) LEN(256) +
              VALUE('Nick Litten © 2025 | IBM i V7.5 https://www.nicklitten.com')
DCL        VAR(&COPYRIGHTP) TYPE(*PTR) STG(*DEFINED) DEFVAR(&COPYRIGHT)

DCL        VAR(&SBSNAME) TYPE(*CHAR) LEN(10) VALUE(QINTER)
DCL        VAR(&SBSLIB) TYPE(*CHAR) LEN(10) VALUE(QSYS)
DCL        VAR(&QUALNAME) TYPE(*CHAR) LEN(20)
DCL        VAR(&RCVVAR) TYPE(*CHAR) LEN(512)
DCL        VAR(&RCVLEN) TYPE(*INT) LEN(4) VALUE(512)
DCL        VAR(&FORMAT) TYPE(*CHAR) LEN(8) VALUE('SBSI0100')
DCL        VAR(&ERRCODE) TYPE(*CHAR) LEN(16) VALUE(X'00000000')
DCL        VAR(&STATUS) TYPE(*CHAR) LEN(10)

CHGVAR     VAR(&QUALNAME) VALUE(&SBSNAME *CAT &SBSLIB)

CALL       PGM(QWDRSBSD) PARM((&RCVVAR) (&RCVLEN) +
                              (&FORMAT) (&QUALNAME) (&ERRCODE))
MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(FAIL))

/* Extract subsystem status (positions 29-38 in SBSI0100) */
CHGVAR     VAR(&STATUS) VALUE(%SST(&RCVVAR 29 10))

SNDPGMMSG  MSG('Subsystem QINTER is' *BCAT &STATUS)

RETURN

FAIL:
SNDPGMMSG  MSG('* Unable to retrieve subsystem status!')

ENDPGM

Why you might choose this method

  • ✔ Works everywhere
  • ✔ No SQL required
  • ✔ Reliable and battle tested

If you’re maintaining older systems or writing code that must run across mixed environments, this is a safe choice.

Option 3: The Quick and Dirty Way WRKSBS + MONMSG

Sometimes you just need a fast check and you don’t care about elegance. In that case, you can rely on the fact that WRKSBS fails if the subsystem isn’t active.

PGM

   QSYS/WRKSBSJOB SBS(QINTER) OUTPUT(*PRINT)    
   MONMSG MSGID(CPF0000) EXEC(DO)
      SNDPGMMSG  MSG('Subsystem QINTER is NOT active')
      RETURN
   ENDDO

   SNDPGMMSG  MSG('Subsystem QINTER is active')

ENDPGM

Pros and cons

  • ✔ Very simple
  • ✔ Works on any release
  • ✘ Not precise
  • ✘ Depends on command failure, which is never ideal

Use this only when you need a quick‑and‑dirty solution.

So, Which Method Should You Use?

If your system supports it, SQL SUBSYSTEM_INFO is the clear winner. It’s clean, modern, and gives you the exact subsystem state without any fuss.

If you’re working on older systems or writing code that must run everywhere, the QWDRSBSD API is your dependable workhorse.

And if you’re in a hurry, well… the WRKSBS trick will get the job done.

Do you want to see a reusable CL command (CHKSBSACT), complete with return variables and message handling? Then jump over to my CL Programming Course lesson here

What is IBM CL?

IBM i Control Language (CL) is a powerful scripting language for the IBM AS/400, IBM iSeries and IBM i Systems. It’s got roots in the older IBM Job Control Language, and it works as a simple way to script commands, instructions and other functions into an easy-to-understand programs.

NickLitten


IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Shameless Trekkie, Belligerent Nerd, Englishman Abroad and Passionate Eater of Cheese and Biscuits.

Nick Litten Dot Com is a mixture of blog posts that can be sometimes serious, frequently playful and probably down-right pointless all in the space of a day.

Enjoy your stay, feel free to comment and remember: If at first you don't succeed then skydiving probably isn't a hobby you should look into.

Nick Litten

related posts:

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

Subscribe NOW
7-day free trial

Take This Course with ALL ACCESS

Unlock your Learning Potential with instant access to every course and all new courses as they are released.
 [ For Serious Software Developers only ]

Online Learning for IBM i Software Technology Professionals

“The more that you read, the more things you will know. The more that you learn, the more places you’ll go.” – Dr. Seuss

>