Why did we get the issues
One great security action on our systems last year was to delete and optimize hundreds of old and unsecure programs. But after that huge clean-up campaign we sometimes got shortdumps of type LOAD_PROGRAM_NOT_FOUND on our production system.
The reason was, that someone had called an existing transaction, where the assigned report has been deleted. This happens, because you can delete reports in SE38/SE80 that are assigned to a tcode in table TSTC. There is no check like a where-used list for that.
So I designed a report to list and optionally delete custom tcodes from tstc, where an assigned type 1 executable report is missing.
1. Get tcodes from database with missing type 1 reports
* Left outer JOIN get TCODE/REPORT couples
SELECT t~tcode t~pgmna p~progname FROM tstc AS t
LEFT OUTER JOIN reposrc AS p
ON p~progname = t~pgmna
INTO CORRESPONDING FIELDS OF TABLE xt_tc
WHERE t~pgmna NE space
AND t~cinfo EQ xk_cinfo_80. "Type 1 only
* Delete entries for existing reports
DELETE xt_tc WHERE progname NE space.
First all couples of tcodes and report names are merged in a left outer join of tables TSTC and REPOSRC. We nned those entries, where the join doesn't find entries in tables REPOSRC. Therefore all entries, where the program name is filled from table REPOSRC, are not of interest, In our internal table we now have all tcode entries with missing type 1 reports.
2. List all custom tcodes with missing type 1 reports
CLEAR xv_count.
* Sorted list of tcodes without existing reports
SORT xt_tc.
LOOP AT xt_tc ASSIGNING <x_tc>.
CHECK <x_tc>-tcode(1) CA 'YZ' "Custom namespace
OR <x_tc>-tcode(5) EQ '/OWN/'. "Own namespace
ADD 1 TO xv_count.
WRITE: /1 <x_tc>-tcode COLOR COL_KEY,
<x_tc>-pgmna.
xv_tcode = <x_tc>-tcode.
HIDE xv_tcode.
CLEAR xv_tcode.
ENDLOOP.
IF xv_count EQ 0.
WRITE: /1 text-ndt COLOR COL_TOTAL."No transaction to delete can be found
ENDIF.
AT LINE-SELECTION.
IF NOT xv_tcode IS INITIAL.
CALL FUNCTION 'RS_TOOL_ACCESS'
EXPORTING
operation = 'CROSSREF'
object_name = xv_tcode
object_type = 'TRAN'.
ENDIF.
For we only want to delete custom tcodes or tcodes of our own namespace, we can list all found tcodes in a loop and check for the right prefix.The purple marked lines have to be adjusted in other systems. At line selection the where-used list of each tcode can be called.
3. Option to delete tcodes via SE80 and transport request (with break option)
PARAMETERS: xp_del TYPE flag AS CHECKBOX DEFAULT space."delete option
* Delete TCODE via SE80
IF xp_del EQ 'X'.
CALL FUNCTION 'RS_TOOL_ACCESS'
EXPORTING
operation = 'DELETE'
object_name = <x_tc>-tcode
object_type = 'TRAN'
with_objectlist = 'X'.
* continue?
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
titlebar = text-h01 "Tcode deletion process
text_question = text-q01 "Continue with next tcode?
display_cancel_button = space
IMPORTING
answer = xv_answer
EXCEPTIONS
OTHERS = 0.
IF xv_answer NE '1'.
EXIT.
ENDIF.
ENDIF.
Normally we will run this programm in list mode without update first to see the result. If the result seems okay, whe can start it with the delete option. This is within the list loop. To delete the tcode function RS_TOOL_ACCESS (behaves like SE80) is called. This deletion will be added to a transport request. After each deletion there is the posibility to leave the loop,
4. The complete report
REPORT zs_check_tcode_prog.
TYPES: BEGIN OF x_tc,
tcode TYPE tcode,
pgmna TYPE program_id,
progname TYPE progname,
END OF x_tc.
DATA: xv_answer TYPE string.
DATA: xv_count TYPE i.
DATA: xv_tcode TYPE tcode.
DATA: xt_tc TYPE TABLE OF x_tc.
CONSTANTS: xk_cinfo_80 TYPE syhex01 VALUE '80'.
FIELD-SYMBOLS <x_tc> TYPE x_tc.
PARAMETERS: xp_del TYPE flag AS CHECKBOX DEFAULT space."delete option
START-OF-SELECTION.
CLEAR xv_count.
* Left outer JOIN get TCODE/REPORT couples
SELECT t~tcode t~pgmna p~progname FROM tstc AS t
LEFT OUTER JOIN reposrc AS p
ON p~progname = t~pgmna
INTO CORRESPONDING FIELDS OF TABLE xt_tc
WHERE t~pgmna NE space
AND t~cinfo EQ xk_cinfo_80.
* Delete entries for existing reports
DELETE xt_tc WHERE progname NE space.
* Sorted list of tcodes without existing reports
SORT xt_tc.
LOOP AT xt_tc ASSIGNING <x_tc>.
CHECK <x_tc>-tcode(1) CA 'YZ' "Custom namespace
OR <x_tc>-tcode(5) EQ '/OWN/'. "Own namespace
ADD 1 TO xv_count.
WRITE: /1 <x_tc>-tcode COLOR COL_KEY,
<x_tc>-pgmna.
xv_tcode = <x_tc>-tcode.
HIDE xv_tcode.
CLEAR xv_tcode.
* Delete TCODE via SE80
IF xp_del EQ 'X'.
CALL FUNCTION 'RS_TOOL_ACCESS'
EXPORTING
operation = 'DELETE'
object_name = <x_tc>-tcode
object_type = 'TRAN'
with_objectlist = 'X'.
* continue?
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
titlebar = text-h01 "Tcode deletion process
text_question = text-q01 "Continue with next tcode?
display_cancel_button = space
IMPORTING
answer = xv_answer
EXCEPTIONS
OTHERS = 0.
IF xv_answer NE '1'.
EXIT.
ENDIF.
ENDIF.
ENDLOOP.
IF xv_count EQ 0.
WRITE: /1 text-ndt COLOR COL_TOTAL."No transaction to delete can be found
ENDIF.
AT LINE-SELECTION.
IF NOT xv_tcode IS INITIAL.
CALL FUNCTION 'RS_TOOL_ACCESS'
EXPORTING
operation = 'CROSSREF'
object_name = xv_tcode
object_type = 'TRAN'.
ENDIF.
We have deleted nearly 150 custom tcodes in this way.
5. Possible Enhancements
For this sample program is for type 1 executable reports only, you also may have to find tcodes for module pools and function groups. Then you need to change the selection on field TSTCT-CINFO (remove the X80 limitation).
6. Further remaining issues
After deletion of the tcode the transaction can't be called anymore. But it may be still assigned to some menus or in the favourites. For this may be different between DEV and PROD systems I still have no solution for it.