Sup­pri­mer des fichiers dans l’IFS sans se brû­ler les doigts

Sup­pri­mer des fichiers dans l’IFS sans se brû­ler les doigts

lun 24 juin 2019 0 Par Ibmiiste

Contexte et principe

Cet article est ins­pi­ré de « Use Qshell Tools to Clean Up Your IFS Auto­ma­ti­cal­ly » publié sur MC Press Online, qui montre com­ment encap­su­ler la com­mande Unix find dans une pro­cé­dure RPG pour auto­ma­ti­ser le net­toyage de l’IFS.
L’idée est de construire dyna­mi­que­ment une com­mande find … -exec rm exé­cu­tée via QShell, en fonc­tion de cri­tères pas­sés en para­mètres (che­min, nombre de jours, récur­si­vi­té, filtre de nom, type de date).

La com­mande find per­met de recher­cher des fichiers selon dif­fé­rents cri­tères (nom, dates, type, etc.).
L’option -exec exé­cute une com­mande pour chaque fichier trou­vé, et ici cette com­mande est rm, qui sup­prime le fichier cor­res­pon­dant.
En résu­mé, la com­mande com­plète dit au sys­tème : « sup­prime les fichiers qui cor­res­pondent aux cri­tères fournis ».

Para­mètres de la procédure

La pro­cé­dure RPG Suppression_ifs encap­sule cette logique et expose une inter­face générique :

Dcl-proc Suppression_ifs export;
  dcl-pi Suppression_ifs ind;
    p_chemin      varchar(2000) const;
    p_Jours       Int(5)        const;
    P_Recursivite ind           const options(*nopass:*omit);
    p_Filtre      varchar(128)  const options(*nopass:*omit);
    p_Type_date   char(1)       const options(*nopass:*omit);
  end-pi;

Rôle de chaque paramètre :

  • p_chemin : che­min IFS où se trouvent les fichiers à traiter.
  • p_Jours : nombre de jours uti­li­sé pour le cri­tère de date.
  • p_Recursivite : indi­ca­teur qui, s’il est à VRAI, auto­rise la des­cente dans les sous‑répertoires.
  • p_Filtre : modèle de nom de fichier (avec jokers * et ?) trans­mis à find via -name.
  • p_Type_date : type de date prise en compte pour la com­pa­rai­son avec p_Jours :
    • M → -mtime (date de der­nière modification),
    • C → -ctime (date de création),
    • A → -atime (date de der­nier accès).

p_Jours est inter­pré­té comme un déca­lage en jours entre la date du jour et la date carac­té­ris­tique du fichier : la com­mande find com­pare donc « main­te­nant moins p_Jours » avec la date choi­sie, en uti­li­sant un signe + ou - (stric­te­ment plus vieux que N jours, ou moins vieux que N jours).

Sécu­ri­té : limi­ter la zone de purge

Pour limi­ter les risques de sup­pres­sion acci­den­telle d’objets sys­tème, la pro­cé­dure intègre un garde‑fou simple : elle n’autorise que les che­mins situés sous /home.

//---------------------------------------------------------
// Mécanisme optionnel de protection, autorisation uniquement
// dans le répertoire /home afin d'éviter de supprimer des
// objets systèmes
//---------------------------------------------------------
if (%subst(p_chemin:1:6) <> '/home/');
  return *ON;
endif;

C’est une pro­tec­tion volon­tai­re­ment stricte, pen­sée pour des réper­toires appli­ca­tifs ou uti­li­sa­teurs.
À adap­ter en fonc­tion de votre orga­ni­sa­tion (par exemple /home/data/logs, etc.) et de votre poli­tique de sécu­ri­té interne.

Ges­tion des para­mètres optionnels

Le début du trai­te­ment consiste à véri­fier quels para­mètres ont réel­le­ment été pas­sés et à gérer les para­mètres omis, via *NOPASS / *OMIT.

//----------------------------------------------------------
// Initialisation des variables avec les paramètres si applicable
//----------------------------------------------------------
if %parms > 2;
  if %addr(p_Recursivite) <> *NULL;
    l_Recursivite = p_Recursivite;
  endif;
endif;

if %parms > 3;
  if %addr(p_Filtre) <> *NULL;
    l_Filtre = %trim(p_Filtre);
  endif;
endif;

if %parms > 4;
  if %addr(p_Type_date) <> *NULL;
    l_type_date = p_Type_date;
  endif;
endif;

On tra­vaille ain­si avec des variables locales (l_Recursivitel_Filtrel_type_date) ini­tia­li­sées par défaut, puis sur­char­gées si les para­mètres cor­res­pon­dants sont présents.

Construc­tion pro­gres­sive de la com­mande find

1. Ini­tia­li­sa­tion

On com­mence par construire le début de la com­mande QShell :

//-------------------------------------------------------------
// Départ de la construction de la chaîne de commande QSH
l_commande_qsh = 'STRQSH CMD(''find '
                  + %trim(p_chemin)
                  + ' -type f ';

On indique le réper­toire de base et on limite la recherche aux fichiers (-type f).

2. Récur­si­vi­té

Par défaut, la com­mande est non récur­sive si p_Recursivite n’est pas four­ni ou vaut OFF.
On uti­lise -prune pour empê­cher find de des­cendre dans les sous‑répertoires.

dcl-s l_Recursivite ind inz(*off);

// ...

//-------------------------------------------------------------
// Voie sécurisée, par défaut non récursif
// -prune empêche de descendre dans les sous-répertoires
if not l_Recursivite;
  l_commande_qsh = %trim(l_commande_qsh)
              + ' -path '''''
              + %trim(p_chemin)
              + '/*'''''
              + ' -prune';
endif;

3. Filtre sur le nom

Si un filtre est four­ni, on ajoute une clause -name à find.
Les jokers Unix clas­siques sont uti­li­sables : * (plu­sieurs carac­tères) et ? (un caractère).

//-------------------------------------------------------------
// Plus sécurisé, on filtre sur un modèle de nom
if l_Filtre <> *BLANKS;
  l_commande_qsh = %trim(l_commande_qsh)
              + ' -name '''''
              + %trim(l_Filtre)
              + '''''';
endif;

Exemples de filtres pos­sibles : *.pdf*.logREP_??.csv, etc.

4. Filtre sur les dates

La com­mande peut ensuite fil­trer sur une des dates carac­té­ris­tiques du fichier.

//-------------------------------------------------------------
// Time: M, C or A = -mtime, -ctime, -atime
// M : Date de modification
// C : Date de création
// A : Date de dernier accès
l_type_date = %xlate('MCA':'mca':l_type_date);
l_commande_qsh = %trim(l_commande_qsh) + ' -'
                 + l_type_date + 'time';

On force la lettre en minus­cule, puis on ajoute -mtime-ctime ou -atime sui­vant le cas.

On gère ensuite le signe et la valeur asso­ciée au nombre de jours :

//-------------------------------------------------------------
// +/- Nombre de jours
if (l_Jours >= 0);
  l_commande_qsh = %trim(l_commande_qsh) + ' +';
else;
  l_commande_qsh = %trim(l_commande_qsh) + ' -';
endif;

l_commande_qsh = %trim(l_commande_qsh)
                       + %trim(%editc(%abs(p_Jours):'J'));
  • +N signi­fie « stric­te­ment plus de N jours ».
  • -N signi­fie « stric­te­ment moins de N jours ».
  • N (sans signe) signi­fie « exac­te­ment N jours ».

5. Fina­li­sa­tion et exécution

Enfin, on com­plète la com­mande avec l’exécution de rm et on appelle l’API QCMDEXC via une pro­cé­dure Cmd_exec.

//-------------------------------------------------------------
// -exec rm = Remove en QSH
l_commande_qsh = %trim(l_commande_qsh)
                       + ' -exec rm {} \\;'')';

//-------------------------------------------------------------
Cmd_exec(%trim(l_commande_qsh));

Le couple -exec rm {} \; indique à find d’exécuter rm pour chaque fichier trou­vé, en rem­pla­çant {} par le che­min com­plet du fichier.


Recom­man­da­tions d’usage

  • Tou­jours com­men­cer par tes­ter la com­mande en mode « liste » plu­tôt qu’en mode « sup­pres­sion » (par exemple en rem­pla­çant rm par ls ou echo) pour véri­fier le péri­mètre exact des fichiers ciblés.
  • Vali­der le com­por­te­ment sur un envi­ron­ne­ment de test avant de déployer en production.
  • Véri­fier les droits d’accès IFS et la poli­tique interne de purge, notam­ment sur les réper­toires autorisés.
**FREE

//******************************************************************************
// MODULE : DLTIFS010R DATE CREATION : 12/04/2019
// AUTEUR : O.DRUBIGNY CC BY SA Olivier DRUBIGNY
// Ce(tte) œuvre est mise à disposition selon le s termes de la Licence
// Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0
// International.
//------------------------------------------------------------------------------
// DESCRIPTION : Suppression de répertoire/fichier de l'ifs récursif ou non
// Grâce à l'utilisation de QSH
//******************************************************************************
// Option de compilation et de programme
/Copy Qcpysrc,Cpyctlstm


// External subprocedures prototypes globales
// prototype sous-procédures externes
/Copy Qcpysrc,Utiproc


// Program status data structure
// Data Structure d'information programme
/copy qcpysrc,psds


// Définition de l'Interface de la procédure
// Paramètres d'appel
// Procedure-Interface definition
// --------------------------------------------------
// Procedure name: Suppression_ifs
// Purpose: Supprimer un fichier ou un répertoire de l'ifs
// de façon récursive ou non
// Returns:
// Parameter: p_chemin => Contient le chemin de l'objet à supprim...
// er dans l'ifs
// p_Jours => Nombre de jours
// p_Recursivite => Récursif ou non
// p_Filtre => Filtre
// p_Type_date => date à comparer par rapport à p_Jours
// --------------------------------------------------

Dcl-proc Suppression_ifs export;


dcl-pi Suppression_ifs ind;
p_chemin varchar(2000) const;
p_Jours Int(5) const;
P_Recursivite ind const options(*nopass:*omit);
p_Filtre varchar(128) const options(*nopass:*omit);
p_Type_date char(1) const options(*nopass:*omit);
end-pi;


// Variables locales / local variables
dcl-s l_Retour ind;
dcl-s l_Recursivite ind inz(*off);
dcl-s l_Filtre char(128);
dcl-s l_type_date char(1) Inz('m');
dcl-s l_commande_qsh char(512);
Dcl-s l_Jours Int(5);

// constants
// constantes
// dcl-c constante1 'CONSTANTE';

monitor;
l_Retour = *OFF;
//---------------------------------------------------------
// Méchanisme optionnelde protection, autorisation uniquement dans le
// répertoire /home afin d'éviter de supprimer des objets systèmes
//---------------------------------------------------------

if (%subst(p_chemin:1:6) <> '/home/');
return *ON;
endif;

//----------------------------------------------------------
// Initialisation des variables avec les paramètres si applicable
//----------------------------------------------------------

if %parms > 2;
if %addr(p_Recursivite) <> *NULL;
l_Recursivite = p_Recursivite;
endif;
endif;

if %parms > 3;
if %addr(p_Filtre) <> *NULL;
l_Filtre = %trim(p_Filtre);
endif;
endif;

if %parms > 4;
if %addr(p_Type_date) <> *NULL;
l_type_date = p_Type_date;
endif;
endif;

//-------------------------------------------------------------
// Départ de la construction de la chaîne de commande QSH

l_commande_qsh = 'STRQSH CMD(''find '
+ %trim(p_chemin)
+ ' -type f ';

//-------------------------------------------------------------
// Voie sécurisée, par défaut non récursif
// -prune empêche de descendre dans les sous-répertoires
if not l_Recursivite;
l_commande_qsh = %trim(l_commande_qsh)
+ ' -path '''''
+ %trim(p_chemin)
+ '/*'''''
+ ' -prune';
endif;

//-------------------------------------------------------------
// Plus sécurisé, on filtre sur un modèle de nom

if l_Filtre <> *BLANKS;
l_commande_qsh = %trim(l_commande_qsh)
+ ' -name '''''
+ %trim(l_Filtre)
+ '''''';
endif;

//-------------------------------------------------------------
// Time: M, C or A = -mtime, -ctime, -atime
// M : Date de modification
// C : Date de création
// A : Date de dernier accès
l_type_date = %xlate('MCA':'mca':l_type_date);
l_commande_qsh = %trim(l_commande_qsh) + ' -'
+ l_type_date + 'time';

//-------------------------------------------------------------
// +/- Nombre de jours

if (l_Jours >= 0);
l_commande_qsh = %trim(l_commande_qsh) + ' +';
else;
l_commande_qsh = %trim(l_commande_qsh) + ' -';
endif;

l_commande_qsh = %trim(l_commande_qsh)
+ %trim(%editc(%abs(p_Jours):'J'));

//-------------------------------------------------------------
// -exec rm = Remove en QSH

l_commande_qsh = %trim(l_commande_qsh)
+ ' -exec rm {} \;'')';

//-------------------------------------------------------------
Cmd_exec(%trim(l_commande_qsh));

on-error;
l_Retour = *ON;
dump(a);
gest_erreur();
endmon;

return l_Retour;

END-PROC ;