SAP on IBM i: Download the most current PTF lists automatically

As you know, IBM is maintaining lists of program temporary fixes (PTFs) that are required to run SAP on IBM i smoothly. These PTF lists are updated from time to time, as new PTFs are created and found to be useful for SAP users. SAP has provided tools to compare the contents of those lists with the PTFs that are actually installed on the host where the SAP system is running, among them the kernel command CHKR3PTF and the function DiagnosticsPTF Check in SAP transaction DBACockpit. Some SAP installation tools execute the PTF check before they perform the requested installation. For each of these, the PTF list must be stored in subdirectory config of the SAP transport directory. The PTF list file is named infoapar.<vrm>, where <vrm> is replaced with the version, release and modification number of the operating system. A typical name in IBM i 7.4 would be /usr/sap/trans/config/infoapar.740. By default, the file is being shipped with SAP kernel patches and copied into the directory when a new SAP kernel is installed.

Obviously, the method of shipping the PTF list with the kernel can result in quite outdated lists. Wouldn’t it be nice to download that list immediately from the IBM web page after it has been published without waiting for the next SAP kernel update? At the end of this article, you will find the source code of an ABAP program named ZIBMGETPTFLIST4I that you can copy into your system and execute. The program has been tested in SAP NetWeaver releases 7.02 and higher. If you like, you can schedule the program to be executed once every night so that you have a very short delay when the PTF lists got updated by IBM. This provides you with a reliable status indicator in transaction DBACockpit and other SAP PTF check tools.

To run the program successfully, your system must be enabled to access the internet through the HTTPS protocol. If your system is configured to download SAP Notes from SAP or use APAP open source projects through abapGit, you probably don’t have to do much. If this is the first time you are trying to access the internet from your SAP application server, you need to check the following settings:

  1. Start transaction SMICM and verify through menu path GotoServices that the HTTPS service has been started:

    Transaction%20SMICM%20-%20Services

  2. Execute transaction STRUST and check if certificates for the areas System PSE and SSL client SSL Client (Standard) exist. A folder symbol indicates that certificates exist, a red X indicates that no certificate has been defined:

    STRUST%20Certificate%20List

  3. For the section SSL client SSL Client (Standard), the certificate DigiCert Global Root CA needs to be installed. If you don’t have it installed yet, you can download the file DigiCertGlobalRootCA.crt from https://www.digicert.com/kb/digicert-root-certificates.htm to your local workstation and import it from there into your SAP system with transaction STRUST.
  4. If you needed to make any changes in the previous steps, you need to restart the Internet Communication Manager so that the changes become active. This can be done in transaction SMICM through menu path AdministrationICMExit SoftLocal.
  5. In SAP releases 7.3x and earlier, it may be necessary to specify the following profile parameter (see SAP Note 510007):

    ssl/client_ciphersuites = 150:PFS:HIGH::EC_X25519:EC_P256:EC_HIGH

Source of program ZIBMGETPTFLIST4I

Below you can find the source of the program to download the IBM PTF lists to your local SAP host. SAP or IBM do not offer support for this program, and there is no guarantee that the program does not cause damage or fulfills a specific purpose. You can use it on an as-is basis and modify it according to your needs.

*&---------------------------------------------------------------------*
*& Report ZIBMGETPTFLIST4I
*&---------------------------------------------------------------------*
*&
*& Download IBM maintained list of required PTFs for SAP on IBM i
*& to a streamfile, so that it can be used by SAP tools like CHKR3PTF
*& or transaction DB4PTFCHK to check the currency of the code level.
*&
*& Prerequisites:
*& - SAP NetWeaver 7.02 or higher
*& - If necessary, activate service HTTPS in ICM, e.g. by profile parameter
*& icm/server_port_<n> = PROT=HTTPS,PORT=443$$,PROCTIMEOUT=600,TIMEOUT=600
*& - A certificate must be created in transaction STRUST for System PSE
*& - A certificate must be created in transaction STRUST for SSL client
*& SSL Client Standard)
*& - A certificate "DigiCert Global Root CA" must be downloaded from
*& https://www.digicert.com/digicert-root-certificates.htm
*& - The "DigiCert Global Root CA" must be uploaded for SSL client (Standard)
*& SSL Client (Standard).
*& - Up to and includung SAP NetWeaver release 7.3x, the following profile
*& parameter must be specified:
*& ssl/client_ciphersuites = 150:PFS:HIGH::EC_X25519:EC_P256:EC_HIGH
*&
*& Input parameters:
*& - Release: Operating system release, for which the PTF list is
*& to be obtained. Currently supported values are V7R2M0,
*& V7R3M0, V7R4M0 and V7R5M0. Default is the operating system
*& release level of the application server.
*& - Outfile: Path to the output file as seen from the application
*& server, e.g. /usr/sap/trans/config/infoapar.740
*& Default: $(DIR_TRANS)/config/infoapar.<vrm>
*& - Pattern: Pattern that identifies the text file version of the
*& PTF list within the HTML document. Default is "*/INFOAPAR.*"
*&
*& Error information:
*& - Check transaction SMICM -> Goto -> Trace File -> Display All
*&
*&---------------------------------------------------------------------*
REPORT ZIBMGETPTFLIST4I. data: lv_os_release_short type string, lv_os_release_long type string, lv_local_filename type string, lv_trans_dir type aparpath, lv_ptf_document_url type string, lv_ptf_document_contents type string, lv_ptf_list_url type string, lt_embedded_urls type standard table of string, lv_selected_url type string, lv_ptf_list_text type string, lv_ptf_list_text_clean type string, lv_abap_codepage type tcp00-cpcodepage, lv_replacement_char_x type xstring, lv_replacement_char type string, lv_url_end type i, lv_error_message type string, lo_http_client type ref to if_http_client, l_as4_api_exception type ref to cx_as4_api_exception. parameters: Release type string default ' ', Outfile type string lower case default ' ', Pattern type string lower case default '*/INFOAPAR.*'. if Release is initial. try. call method cl_as4_api=>call_api_getsysval exporting hostname = sy-host receiving value = lv_os_release_long. catch cx_as4_api_exception into l_as4_api_exception. call method cl_as4_api=>handle_api_exception exporting error_code = l_as4_api_exception->api_rc error_text = l_as4_api_exception->error_text. endtry. else. lv_os_release_long = Release. endif. lv_os_release_short = lv_os_release_long. translate lv_os_release_short using 'V R M '. condense lv_os_release_short no-gaps. if ( lv_os_release_short = '720' ). lv_ptf_document_url = 'https://www.ibm.com/support/pages/sap-support-required-ptf-list-ibm-i-72'. elseif ( lv_os_release_short = '730'). lv_ptf_document_url = 'https://www.ibm.com/support/pages/sap-support-required-ptf-list-ibm-i-73'. elseif ( lv_os_release_short = '740' ). lv_ptf_document_url = 'https://www.ibm.com/support/pages/sap-support-required-ptf-list-ibm-i-74'. elseif ( lv_os_release_short = '750' ). lv_ptf_document_url = 'https://www.ibm.com/support/pages/sap-support-required-ptf-list-ibm-i-75'. else. write: / 'Local release', lv_os_release_long, 'is not supported by this program.'. return. endif. cl_http_client=>create_by_url( exporting url = lv_ptf_document_url importing client = lo_http_client exceptions argument_not_found = 1 plugin_not_active = 2 internal_error = 3 others = 4 ). if sy-subrc <> 0. write: / 'Unable to access url', lv_ptf_document_url. write: / 'sy-subrc =', sy-subrc. return. endif. lo_http_client->send( exceptions http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3 others = 4 ). if sy-subrc <> 0. write: / 'Failure sending http request to url', lv_ptf_document_url. write: / 'sy-subrc =', sy-subrc. return. endif. call method lo_http_client->receive exceptions http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3 others = 4. if sy-subrc <> 0. write: / 'Unable to receiv data from', lv_ptf_document_url. write: / 'sy-subrc =', sy-subrc. return. endif. lv_ptf_document_contents = lo_http_client->response->get_cdata( ). split lv_ptf_document_contents at 'href=' into table lt_embedded_urls. loop at lt_embedded_urls into lv_selected_url. if lv_selected_url cp pattern. shift lv_selected_url by 1 places. find '"' in lv_selected_url match offset lv_url_end. lv_selected_url = substring( val = lv_selected_url len = lv_url_end ). concatenate 'https://www.ibm.com' lv_selected_url into lv_selected_url. exit. else. clear lv_selected_url. endif. endloop. if lv_selected_url is initial. write: / 'Document at', lv_ptf_document_url, 'did not contain a PTF list.'. return. endif. call method lo_http_client->close( ). cl_http_client=>create_by_url( exporting url = lv_selected_url importing client = lo_http_client exceptions argument_not_found = 1 plugin_not_active = 2 internal_error = 3 others = 4 ). if sy-subrc <> 0. write: / 'Unable to access url', lv_selected_url. write: / 'sy-subrc =', sy-subrc. return. endif. lo_http_client->send( exceptions http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3 others = 4 ). if sy-subrc <> 0. write: / 'Failure sending http request to url', lv_selected_url. write: / 'sy-subrc =', sy-subrc. return. endif. call method lo_http_client->receive exceptions http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3 others = 4. if sy-subrc <> 0. write: / 'Unable to receiv data from', lv_selected_url. write: / 'sy-subrc =', sy-subrc. return. endif. lv_ptf_list_text = lo_http_client->response->get_cdata( ). if Outfile is initial.
* build up as4_filename like '/usr/sap/trans/config/infoapar.xxx call 'C_SAPGPARAM' id 'NAME' field 'DIR_TRANS' id 'VALUE' field lv_trans_dir. "#EC CI_CCALL concatenate lv_trans_dir '/config/infoapar.' lv_os_release_short into lv_local_filename. else. lv_local_filename = Outfile. endif. call function 'SCP_GET_CODEPAGE_NUMBER' EXPORTING database_also = space IMPORTING appl_codepage = lv_abap_codepage EXCEPTIONS others = 1. if sy-subrc <> 0. write: / 'Function SCP_GET_CODEPAGE_NUMBER could not retrieve code page, sy-subrc =', sy-subrc. return. endif. if lv_abap_codepage = '4102'. lv_replacement_char_x = 'FFFD'. lv_replacement_char = cl_abap_codepage=>convert_from( source = lv_replacement_char_x codepage = 'UTF-16' ). lv_ptf_list_text = condense( val = lv_ptf_list_text from = lv_replacement_char ). endif. lv_replacement_char_x = '0D'. lv_replacement_char = cl_abap_codepage=>convert_from( source = lv_replacement_char_x codepage = 'UTF-8' ). lv_ptf_list_text_clean = condense( val = lv_ptf_list_text from = lv_replacement_char ). open dataset lv_local_filename for output in text mode encoding non-unicode message lv_error_message. if sy-subrc <> 0. write: / 'Open dataset', lv_local_filename, 'failed with sy-subrc =', sy-subrc. write: / lv_error_message. return. endif. transfer lv_ptf_list_text_clean to lv_local_filename. close dataset lv_local_filename. write: / 'Contents of', lv_selected_url, 'where written to', lv_local_filename. call method lo_http_client->close( ).