From 43e6f0ee891e06240c007d47918b7f6498a12720 Mon Sep 17 00:00:00 2001 From: smas Date: Mon, 31 Jul 2000 13:15:35 +0000 Subject: [PATCH] =?UTF-8?q?Premi=C3=A8re=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/liblog.3 | 638 ++++++ lib/liblog.c | 4725 ++++++++++++++++++++++++++++++++++++++++++ lib/liblog.doc | Bin 0 -> 111616 bytes lib/liblog.h | 179 ++ lib/libtool.3 | 424 ++++ lib/libtool.doc | Bin 0 -> 47104 bytes lib/libtool.h | 49 + lib/libtool.pc | 1369 ++++++++++++ lib/log.h | 516 +++++ lib/tool.h | 68 + util/logadmin.c | 426 ++++ util/logagent.c | 504 +++++ util/logagent.h | 24 + util/logbench.c | 150 ++ util/logresolve.c | 187 ++ util/logsupervisor.c | 1246 +++++++++++ 16 files changed, 10505 insertions(+) create mode 100644 lib/liblog.3 create mode 100644 lib/liblog.c create mode 100644 lib/liblog.doc create mode 100644 lib/liblog.h create mode 100644 lib/libtool.3 create mode 100644 lib/libtool.doc create mode 100644 lib/libtool.h create mode 100644 lib/libtool.pc create mode 100644 lib/log.h create mode 100644 lib/tool.h create mode 100644 util/logadmin.c create mode 100644 util/logagent.c create mode 100644 util/logagent.h create mode 100644 util/logbench.c create mode 100644 util/logresolve.c create mode 100644 util/logsupervisor.c diff --git a/lib/liblog.3 b/lib/liblog.3 new file mode 100644 index 0000000..91172b5 --- /dev/null +++ b/lib/liblog.3 @@ -0,0 +1,638 @@ +'\" t +.\" @(#)LIBLOG.3 1.0 00/07/04 SMA; +.TH LIBLOG 3 "07 Apr 2000" +.SH NOM +LIBLOG (librairie d'interface avec le systeme de suivi et de pilotage) +.SH SYNOPSIS +.LP +.BI "cc [flag ...] file ... -lver -ldl -lnode -lshmem -ldatastr -lmsg -ladm -lgen -llog [library ...]" +.LP +.BI "#include " +.LP +.BI "LOGT_Status LOG_Library_Open ( int " Instance ", LOGT_Flags " Open_Mode ");" +.LP +.BI "LOGT_Status LOG_Library_Close ( LOGT_Flags " Close_Mode ");" +.LP +.BI "LOGT_Status LOG_Library_Stderr_Set ( FILE * " Out ");" +.LP +.BI "LOGT_Status LOG_Channel_Open ( LOGT_Channel ** " Channel ", int " Pid ", int " Channel_Id ", char * " Module_Name ", char * " Master_Module_Name ");" +.LP +.BI "LOGT_Status LOG_Channel_Enter ( LOGT_Channel * " Channel ", char * " Sub_Module_Name ");" +.LP +.BI "LOGT_Status LOG_Channel_Leave ( LOGT_Channel * " Channel ", char * " Sub_Module_Name ");" +.LP +.BI "LOGT_Status LOG_Channel_Close ( LOGT_Channel * " Channel ");" +.LP +.BI "LOGT_Status LOG_RTab_Alloc ( LOGT_RTab ** " Rtab ", char * " Name " );" +.LP +.BI "LOGT_Status LOG_RTab_Setup ( LOGT_RTab * " RTab ", LOGT_RuleClass " Rule_Class ", LOGT_Rule " Rule ", LOGT_Rooting " Value ");" +.LP +.BI "LOGT_Status LOG_RTab_Add ( LOGT_Channel * " Channel ", LOGT_RTab * " RTab ");" +.LP +.BI "LOGT_Status LOG_RTab_Remove ( LOGT_Channel * " Channel ", LOGT_RTab * " RTab ");" +.LP +.BI "LOGT_Status LOG_RTab_Free ( LOGT_RTab * " RTab ");" +.LP +.BI "LOGT_Status LOG_Trigger_Add ( LOGT_Trigger ** " Trigger ", LOGT_Channel * " Channel ", LOGT_RTab * " RTab ", char * " Event_Type ", LOGT_Flags " Trigger_Mode ");" +.LP +.BI "LOGT_Status LOG_Trigger_Remove ( LOGT_Trigger * " Trigger ");" +.LP +.BI "LOGT_Status LOG_Event_Send ( LOGT_Channel * " Channel ", LOGT_RC * " Return_Code ", char * " Cd_Support ", va_list " Data ");" +.LP +.BI "LOGT_RC LOG_Event_External_Send ( LOGT_Channel * " Channel ", char * " Cd_Support ", char * " Data ");" +.LP +.BI "LOGT_Status LOG_Event_Info_Get ( LOGT_Channel * " Channel ", LOGT_Info * " Info ", va_list " Data ");" +.LP +.BI "LOGT_Status LOG_Event_Cpt_Get ( LOGT_Channel * " Channel ", int * " Cpt "[LOGD_RC_SIZE], char * " Reg_Expr ");" +.LP +.SH FONCTIONS +.LP +.BI "LOGT_Status LOG_Library_Open ( int " Instance ", LOGT_Flags " Open_Mode ");" +.LP +.RS 3 +La librairie LIBLOG met en place des ressources partagees par tous les traitements qui utilise la meme instance de la librairie LIBLOG : +.LP +.RS 3 +- les tables de routage systeme (GMRT et GDRT) +.LP +- le cache des modules +.LP +- le cache des formats d'evenement +.LP +- la queue de messages pour inserer les evenements en base +.RS -3 +.LP +Cette fonction permet d'acceder a ces ressources partagees pour une instance particuliere de la librairie: +.LP +.RS 3 +- en creation si +.I Open_Mode +vaut +.B LOGD_CREATE +.LP +- en ouverture simple si +.I Open_Mode +vaut +.B LOGD_OPEN +.RS -3 +.LP +.I NB +: l'indicateur d'ouverture +.I Open_Mode +pourra etre combinee avec un mode de debugging ( +.B MSGD_DEBUG_NONE +: aucun message d'erreur n'est affiche +.LP +.B MSGD_DEBUG +: les messages d'erreur generes par la librairie LIBMSG sont affiches sur la sortie standard d'erreur +.LP +.B MSGD_DEBUG_ALL +: les messages d'erreur generes par toutes les librairies sous-jacentes a la LIBMSG sont affiches sur la sortie standard d'erreur +.LP +.I NB +: l'appel a cette fonction est obligatoire avant d'utiliser toute autre fonction de la librairie LIBLOG. +.LP +Le mode +.B LOGD_CREATE +est exclusivement reserve aux administrateurs ! +.LP +.RS -3 +.BI "LOGT_Status LOG_Library_Close ( LOGT_Flags " Close_Mode " );" +.LP +.RS 3 +Cette fonction permet de fermer ou de supprimer les ressources partagees de l'instance qu a ete ouverte : +.LP +.RS 3 +- Suppression si +.I Close_Mode +vaut +.B LOGD_DESTROY +.LP +- Fermeture simple si +.I Close_Mode +vaut +.B LOGD_CLOSE +.RS -3 +.LP +.I NB +: la fermeture de la librairie est absolument necessaire une fois qu'un traitement a fini de l'utiliser. +.LP +Le mode +.B LOGD_DESTROY +est exclusivement reserve aux administrateurs ! +.LP +.RS -3 +.BI "LOGT_Status LOG_Library_Stderr_Set ( FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet de definir +.I Out +comme la sortie standard des messages d'erreur de la librarie. +.RS -3 +.LP +.BI "LOGT_Status LOG_Channel_Open ( LOGT_Channel ** " Channel ", int " Pid ", int " Channel_Id ", char * " Module_Name ", char * " Master_Module_Name ");" +.LP +.RS 3 +Cette fonction permet de creer un channel a travers lequel des evenements seront envoyes au systeme de suivi. +Elle requiert les arguments suivants : +.RS 3 +.LP +* (Out) +.I Channel +: l'adresse du pointeur sur le channel a creer +.LP +* (In) +.I Pid +: l'identifiant du processus proprietaire du channel +.LP +* (In) +.I Channel_Id +: l'identifiant du channel +.LP +* (In) +.I Module_Name +: le nom du module proprietaire du channel +.LP +* (In) +.I Master_Module_Name +: le nom du module maitre (facultatif) +.RS -3 +.LP +.I Pour info +: +Le nom du module proprietaire du channel permet de connaitre le traitement qui est a l'origine des evenements qui sont envoyes au suivi. Le nom du module maitre permet de connaitre le contexte de lancement de ce traitement. +.LP +Le numero du processus permet de distinguer differents processus realisant un meme traitement. +.LP +L'identifiant du channel permet de distinguer les differents channels d'un meme processus. +.LP +.I NB +: si le numero de processus passe en parametre vaut 0, alors c'est le processus courant qui sera considere comme processus proprietaire. +Ce parametre doit surtout etre renseigne pour les programmes shell, afin que ce ne soit pas le numero de processus demon qui soit pris en compte. +.LP +Par convention, en fonctionnement mono-thread, l'identifiant du channel sera fixe a 0. En fonctionnement multi-thread, l'utilisateur est libre de fixer ce parametre comme il le veut. +.LP +.I NB +: si le nom du module maitre vaut NULL, alors il sera renseigne avec le nom du module proprietaire du channel. +.LP +.RS -3 +.BI "LOGT_Status LOG_Channel_Enter ( LOGT_Channel * " Channel ", char * " Sub_Module_Name " );" +.LP +.RS 3 +Cette fonction permet d'affecter un sous-module a un channel. +Un sous-module correspond en general au nom d'une fonction du traitement. Il permet de mieux identifier la partie du traitement qui genere les evenements. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (In) +.I Channel +: le pointeur sur le channel de communication +.LP +* (In) +.I Sub_Module_Name +: le nom du sous-module a attacher au channel +.RS -3 +.LP +.RS -3 +.BI "LOGT_Status LOG_Channel_Leave ( LOGT_Channel * " Channel ", char * " Sub_Module_Name " );" +.LP +.RS 3 +Cette fonction permet de supprimer un sous-module d'un channel. +Le sous-module qui lui avait ete precedemment affecte est devient alors le sous-module actif. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (In) +.I Channel +: le pointeur sur le channel de communication +.LP +* (In) +.I Sub_Module_Name +: le nom du sous-module a supprimer du channel +.RS -3 +.LP +.RS -3 +.BI "LOGT_Status LOG_Channel_Close ( LOGT_Channel * " Channel " );" +.LP +.RS 3 +Cette fonction permet de fermer un channel. +.LP +.I Channel +est un pointeur sur le channel a fermer +.LP +.RS -3 +.BI "LOGT_Status LOG_RTab_Alloc ( LOGT_RTab ** " Rtab ", char * " Name " );" +.LP +.RS 3 +Cette fonction permet de creer une table de routage utilisateur. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (Out) RTab +: adresse d'un pointeur sur la table de routage a creer. +.LP +* (In) Name +: nom de la table de routage. +.RS -3 +.LP +.RS -3 +.BI "LOGT_Status LOG_RTab_Setup ( LOGT_RTab * " RTab ", LOGT_RuleClass " Rule_Class ", LOGT_Rule " Rule ", LOGT_Rooting " Value " );" +.LP +.RS 3 +Cette fonction permet de parametrer une table de routage utilisateur, par ajout d'une regle de routage. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I RTab +: un pointeur sur la table de routage +.LP +* (In) +.I Rule_Class +: la classe de la nouvelle regle +.LP +* (In) +.I Rule +: la nouvelle regle +.LP +* (In) +.I Value +: la valeur de la nouvelle regle +.RS -3 +.LP +La classe de regle designe la maniere de selectionner les types d'evenement concernes par la nouvelle regle : +.LP +.RS 3 +- +.B LOGD_SELECT_ALL +: selection de tous les types d'evenements +.LP +- +.B LOGD_SELECT_GRV +: selection des types d'evenement selon leur gravite +.LP +- +.B LOGD_SELECT_RC +: selection des types d'evenement selon le code retour qui y est associe +.LP +- +.B LOGD_SELECT_TYPE +: selection des types d'evenement selon leur nom +.RS -3 +.LP +La regle depend de la classe de regle choisie: +.LP +.RS 3 +- NULL pour la classe +.B LOGD_SELECT_ALL +.LP +- code gravite pour la classe +.B LOGD_SELECT_GRV +.LP +- code retour pour la classe +.B LOGD_SELECT_RC +.LP +- nom du type d'evenement (expression reguliere) pour la classe +.B LOGD_SELECT_TYPE +.RS -3 +.LP +La valeur de la regle est le type de routage a appliquer aux types d'evenement concernes par la regle : +.RS 3 +.LP +- +.B LOGD_NULL +: routage vers /dev/null (aucun traitement de l'evenement) +.LP +- +.B LOGD_STDERR +: affichage de l'evenement sur la sortie standard d'erreur +.LP +- +.B LOGD_DATABASE +: insertion de l'evenement dans la base de donnees du suivi +.LP +- +.B LOGD_DEFAULT +: routage par defaut +.LP +- +.B LOGD_PREVIOUS +: routage defini dans la table de routage precedente +.RS -3 +.LP +Pour parametrer une table de routage utilisateur, on commencera par definir les regles les plus generales (LOGD_ALL) et finir avec les regles les plus specifiques. +.LP +.RS -3 +.BI "LOGT_Status LOG_RTab_Add ( LOGT_Channel * " Channel ", LOGT_RTab * " RTab " );" +.LP +.RS 3 +Cette fonction permet d'affecter une nouvelle table de routage utilisateur a un channel. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (In) +.I RTab +: un pointeur sur la table de routage +.RS -3 +.LP +.RS -3 +.BI "LOGT_Status LOG_RTab_Remove ( LOGT_Channel * " Channel ", LOGT_RTab * " RTab " );" +.LP +.RS 3 +Cette fonction permet de supprimer l'association d'une table de routage utilisateur a un channel. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (In) +.I RTab +: un pointeur sur la table de routage +.RS -3 +.LP +L'utilisateur pourra utiliser la constante LOGD_TOP_RTAB comme deuxieme argument, pour supprimer la table de routage de tete (la plus recemment associee au channel). +.LP +.RS -3 +.BI "LOGT_Status LOG_RTab_Free ( LOGT_RTab * " RTab " );" +.LP +.RS 3 +Cette fonction permet de supprimer une table de routage utilisateur. +.LP +.I RTab +est un pointeur sur la table de routage a supprimer. +.LP +NB : avant de supprimer une table de routage, on verifiera qu'elle n'est attachee a aucun channel. +.LP +.RS -3 +.BI "LOGT_Status LOG_Trigger_Add ( LOGT_Trigger ** " Trigger ", LOGT_Channel * " Channel ", LOGT_RTab * "RTab ", char * " Event_Type ", LOGT_Flags " Trigger_Mode " );" +.LP +.RS 3 +Cette fonction permet d'ajouter un trigger a un channel. +.LP +Elle requiert les arguments suivants : +.RS 3 +.LP +* (Out) +.I Trigger +: l'adresse du pointeur sur le nouveau trigger +.LP +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (In) +.I RTab +: un pointeur sur la table de routage concernee +.LP +* (In) +.I Event_Type +: le type d'evenement declencheur (expression reguliere) +.LP +* (In) +.I Trigger_Mode +: le mode de fonctionnement du trigger +.RS -3 +.LP +.I Rappel +: +.LP +Si un trigger fonctionne sur le mode +.B LOGD_ONESHOT +, il est automatiquement supprime des lors qu'il a ete active. En mode +.B LOGD_PERMANENT +, le trigger reste active en permanence. +.LP +Si un trigger fonctionne sur le mode +.B LOGD_ADD +, l'activation du trigger provoque l'association de la table de routage avec le channel. Avec le mode +.B LOGD_REMOVE +, l'activation du trigger correspond a leur dissociation. +.LP +Les differents modes de fonctionnement peuvent etre combines par addition binaire. +.LP +.I NB +: plusieurs triggers peuvent etre poses sur un meme channel. +.LP +.RS -3 +.BI "LOGT_Status LOG_Trigger_Remove ( LOGT_Trigger * " Trigger " );" +.LP +.RS 3 +Cette fonction permet de supprimer un trigger positionne sur un channel. +.LP +.I Trigger +est un pointeur sur le trigger a supprimer. +.LP +.RS -3 +.BI "LOGT_Status LOG_Event_Send ( LOGT_Channel * " Channel ", LOGT_RC * " Return_Code ", char * " Cd_Support ", va_list " Data ");" +.LP +.RS 3 +Cette fonction permet d'envoyer un evenement a travers un channel et de recuperer le code retour associe au type d'evenement (pilotage). +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (Out) +.I RC +: un pointeur sur le code retour +.LP +* (In) +.I Cd_Support +: le code du support source +.LP +* (In) +.I Data +: une liste d'arguments contenant les donnees de l'evenement +.RS -3 +.LP +.RS -3 +.BI "LOGT_RC LOG_Event_External_Send ( LOGT_Channel * " Channel ", char * " Cd_Support ", char * " Data ");" +.LP +.RS 3 +Cette fonction est definie pour tous les appels a partir de programmes ecrits en PL/SQL. +Elle permet d'envoyer un evenement a travers un channel et de recuperer le code retour associe au type d'evenement (pilotage). +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (In) +.I Cd_Support +: le code du support source +.LP +* (In) +.I Data +: une chaine de caracteres contenant les donnees de l'evenement +.RS -3 +.LP +.I NB +: la fonction retourne le code retour associe au type d'evenement. +.LP +.RS -3 +.BI "LOGT_Status LOG_Event_Info_Get ( LOGT_Channel * " Channel ", LOGT_Info * " Info ", va_list " Data " );" +.LP +.RS 3 +Cette fonction permet de simuler l'envoi d'un evenement et de recuperer toutes les informations concernant le type par lequel il a ete resolu. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (Out) +.I Info +: un pointeur sur les informations a recuperer +.LP +* (In) +.I Data +: une liste d'arguments contenant les donnees de l'evenement a tester +.RS -3 +.LP +.I NB +: le type LOGT_Info est une structure qui contient les informations suivantes : +.LP +.RS 3 +- +.B EvtType +(type d'evenement par lequel l'evenement est resolu) de type char * +.LP +- +.B RC +(code retour associe) de type +.B LOGT_RC +.LP +- +.B Gravite +(code gravite associe) de type +.B LOGT_Gravite +.LP +- +.B Rooting +(routage associe) de type +.B LOGT_Rooting +.RS -3 +.LP +.RS -3 +.BI "LOGT_Status LOG_Event_Info_External_Get ( LOGT_Channel * " Channel ", LOGT_Info * " Info ", char * " Event_Name " );" +.LP +.RS 3 +Cette fonction permet de simuler l'envoi d'un evenement et de recuperer toutes les informations concernant le type par lequel il a ete resolu. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (Out) +.I Info +: un pointeur sur les informations a recuperer +.LP +* (In) +.I Event_Name +: le nom de l'evenement a tester +.RS -3 +.LP +.RS -3 +.BI "LOGT_Status LOG_Event_Cpt_Get ( LOGT_Channel * " Channel ", int * " Cpt " [LOGD_RC_SIZE], char * " Reg_Expr " );" +.LP +.RS 3 +Cette fonction permet de recuperer les compteurs d'evenements dont le nom correspond a une expression reguliere. +.LP +Elle requiert les arguments suivants : +.LP +.RS 3 +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (Out) +.I Cpt +: un pointeur sur un tableau de compteurs +.LP +* (In) +.I Reg_Expr +: une expression reguliere +.RS -3 +.LP +.I NB +: le tableau de compteurs doit etre alloue par l'utilisateur. +.LP +La fonction retourne dans ce tableau le nombre d'evenements correspondant a l'expression reguliere ayant ete envoyes via le channel pour chacun des codes retour. +.LP +.I Exemple +: Cpt[LOGD_RC_OK] contiendra le nombre d'evenements envoyes ayant retourne le code LOGD_RC_OK. +.SH CODES RETOUR +.LP +Toutes les fonctions constituant l'API de la librairie LIBLOG retournent un code de type +.B LOGT_Status +: +.LP +.RS 3 +- +.B LOGS_OK +: la fonction s'est correctement executee et a produit un resultat +.LP +- +.B LOGS_KO +: la fonction s'est correctement executee mais n'a pas produit de resultat +.LP +- +.B LOGS_ERRAPI +: la fonction a ete appelee avec des arguments de valeur incorrecte +.LP +- +.B LOGS_ERRMEM +: la fonction ne s'est pas correctement executee pour un probleme d'allocation memoire +.LP +- +.B LOGS_ERRSHM +: la fonction ne s'est pas correctement executee pour un probleme relatif a la memoire partagee +.LP +- +.B LOGS_ERRSIG +: une operation sur semaphore a ete interrompue par un signal +.LP +- +.B LOGS_ERRSEM +: la fonction ne s'est pas correctement executee pour un probleme relatif a l'utilisation des semaphores +.LP +- +.B DSS_ERRDLL +: la fonction ne s'est pas correctement executee pour un probleme de chargement dynamique d'objet +.LP +.RS -3 +.I NB +: la macro +.B LOG_ERROR() +permet de tester si un code retour correspond a une erreur. +.LP +En cas d'erreur, la variable +.B LOG_Error_Msg +contient un message du type : +.LP +.RS 3 +Error : +.RS -3 +.LP diff --git a/lib/liblog.c b/lib/liblog.c new file mode 100644 index 0000000..d267bf0 --- /dev/null +++ b/lib/liblog.c @@ -0,0 +1,4725 @@ +/* Utilisation des API sans vérification des arguments */ + +#define ND_MODE 1 +#define SM_MODE 1 +#define DS_MODE 1 +#define MSG_MODE 1 + +#include + +VER_INFO_EXPORT (liblog,"$Revision: 1.1 $", "$Name: $",__FILE__,"$Author: smas $") + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PUBLIQUES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS OPTIMISEES (LOG_MODE = 1) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro de l'instance à ouvrir */ +/* (I) Context : contexte d'utilisation de la librairie */ +/* (I) Open_Mode : mode d'ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Open_I ( int Instance, const char * Context, LOGT_Flags Open_Mode ) +{ + LOGT_Status rc; + int Locked; + int MSG_Debug_Mode = MSGD_DEBUG_NONE; + + /* Définition du mode debug */ + + if (Open_Mode & LOGD_DEBUG) + { + LOG_stderr = stderr; + MSG_Debug_Mode = MSGD_DEBUG; + } + else if (Open_Mode & LOGD_DEBUG_ALL) + { + LOG_stderr = stderr; + MSG_Debug_Mode = MSGD_DEBUG_ALL; + } + + /* Ouverture de la librairie LIBMSG */ + + rc = MSG_Library_Open (Instance, Context, MSGD_OPEN | MSG_Debug_Mode); + if (rc != MSGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the LIBMSG library"); + LOG_Error_Print (); + return rc; + } + + /* Accès aux ressources partagées de la librairie */ + + if (Open_Mode & LOGD_CREATE) + { + /* On vérifie que le processus courant n'a pas déjà ouvert la librairie */ + + if (LOG_Open_Counter > 0) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : the current process has already opened the LIBLOG library"); + LOG_Error_Print (); + MSG_Library_Close (MSGD_CLOSE); + return LOGS_ERRAPI; + } + + /* Création de la base LIBLOG */ + + rc = SM_Heap_Open (LOG_Name_Prefix (LOGD_BASE_HEAP_NAME), &LOG_Base_Heap, LOGD_BASE_HEAP_SEGMENT_SIZE, SMD_CREATE | SMD_WRITE, &Locked); + if (rc != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the heap for the LIBLOG base"); + LOG_Error_Print (); + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + rc = SM_Chunk_Alloc (LOG_Base_Heap, sizeof (LOGT_Base), (void **)&LOG_Base); + if (rc != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to allocate memory for the LIBLOG base structure"); + LOG_Error_Print (); + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Création du cache des modules */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_KMOD_NAME), &(LOG_Base->KMOD), NDD_DS_TREE | NDD_MN_AUTO_EQU, LOG_FILE_MANAGER, LOGD_KMOD_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the KMOD data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->KMOD->Manager, "LOG_KMOD_Manager"); + + /* Création du cache des formats d'événement */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_KFORMAT_NAME), &(LOG_Base->KFORMAT), NDD_DS_TREE | NDD_MN_AUTO_EQU, LOG_FILE_MANAGER, LOGD_KFORMAT_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the KFORMAT data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->KFORMAT->Manager, "LOG_KFORMAT_Manager"); + + /* Création de la table de routage globale par défaut (GDRT) */ + + rc = SM_Chunk_Alloc (LOG_Base_Heap, sizeof (LOGT_RTab) + strlen (LOGD_GDRT_NAME) + 1, (void **)(&LOG_Base->GDRT)); + if (rc != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to allocate memory for the GDRT rooting table"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else + { + LOG_Base->GDRT->Name = (char *)((size_t)(LOG_Base->GDRT) + sizeof (LOGT_RTab)); + strcpy (LOG_Base->GDRT->Name, LOGD_GDRT_NAME); + LOG_Base->GDRT->Type = LOGD_GDRT; + } + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_GDRT_NAME), &(LOG_Base->GDRT->Root), NDD_DS_TREE | NDD_MN_AUTO_EQU, LOG_FILE_MANAGER, LOGD_GDRT_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the GDRT data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->GDRT->Root->Manager, "LOG_GDRT_Manager"); + + /* Création de la table de routage globale maître (GMRT) */ + + rc = SM_Chunk_Alloc (LOG_Base_Heap, sizeof (LOGT_RTab) + strlen (LOGD_GMRT_NAME) + 1, (void **)(&LOG_Base->GMRT)); + if (rc != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to allocate memory for the GMRT rooting table"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else + { + LOG_Base->GMRT->Name = (char *)((size_t)(LOG_Base->GMRT) + sizeof (LOGT_RTab)); + strcpy (LOG_Base->GMRT->Name, LOGD_GMRT_NAME); + LOG_Base->GMRT->Type = LOGD_GMRT; + } + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_GMRT_NAME), &(LOG_Base->GMRT->Root), NDD_DS_TREE | NDD_MN_AUTO_EQU, LOG_FILE_MANAGER, LOGD_EMPTY_RTAB_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the GMRT data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->GMRT->Root->Manager, "LOG_RTab_Manager"); + + /* Création de la liste des tables de routage locales maître (LMRT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_LMRT_LIST_NAME), &(LOG_Base->LMRT_List), NDD_DS_LIST | NDD_MN_ORDERED, LOG_FILE_MANAGER, LOGD_RTAB_LIST_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the LMRT list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->LMRT_List->Manager, "LOG_Base_RTabList_Manager"); + + /* Création de la liste des tables de routage locale par défaut (LDRT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_LDRT_LIST_NAME), &(LOG_Base->LDRT_List), NDD_DS_LIST | NDD_MN_ORDERED, LOG_FILE_MANAGER, LOGD_RTAB_LIST_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the LDRT list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->LDRT_List->Manager, "LOG_Base_RTabList_Manager"); + + /* Création de la liste des tables de routage utilisateur (URT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_URT_LIST_NAME), &(LOG_Base->URT_List), NDD_DS_LIST | NDD_MN_ORDERED, LOG_FILE_MANAGER, LOGD_RTAB_LIST_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the URT list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->URT_List->Manager, "LOG_Base_RTabList_Manager"); + + /* Création de la liste des channels */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_CHANNEL_LIST_NAME), &(LOG_Base->Channel_List), NDD_DS_LIST | NDD_MN_ORDERED, LOG_FILE_MANAGER, LOGD_RTAB_LIST_SEGMENT_SIZE, DSD_CREATE, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the channel list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + else strcpy (LOG_Base->Channel_List->Manager, "LOG_Base_ChannelList_Manager"); + + /* Création du port de messages des événements */ + + rc = MSG_Port_Open (LOGD_EVENT_PORT_NAME, &Send_Port, MSGD_CREATE); + if (rc != MSGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to create the event port list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Verrouillage de la base LIBLOG en lecture */ + + rc = SM_Heap_Unlock (LOG_Base_Heap); + if (rc != SMS_OK && SM_Heap_Lock (LOG_Base_Heap, SMD_READ, &Locked) != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to lock the LIBLOG base for reading"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + } + else + { + SMT_DSH * DSH; + NDT_Root * Root; + + /* Ouverture de la base LIBLOG */ + + rc = SM_Heap_Open (LOG_Name_Prefix (LOGD_BASE_HEAP_NAME), &LOG_Base_Heap, 0, SMD_OPEN | SMD_READ, &Locked); + if (rc != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the heap for the LIBLOG base"); + LOG_Error_Print (); + return rc; + } + + DSH = LOG_Base_Heap->MHH->DSR->Head->Value; + + /* La structure de la base se trouve dans le premier chunk du premier segment du heap */ + + LOG_Base = (LOGT_Base *)((size_t)(DSH->Start) + sizeof (NDT_Node) + sizeof (SMT_Chunk)); + + /* Ouverture du cache des modules */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_KMOD_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the KMOD data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture du cache des formats d'événement */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_KFORMAT_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the KFORMAT data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture de la table de routage globale par défaut (GDRT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_GDRT_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the GDRT data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture de la table de routage globale maître (GMRT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_GMRT_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the GMRT data structure"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture de la liste des tables de routage locales maître (LMRT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_LMRT_LIST_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the LMRT list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture de la liste des tables de routage locale par défaut (LDRT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_LDRT_LIST_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the LDRT list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture de la liste des tables de routage utilisateur (URT) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_URT_LIST_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the URT list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture de la liste des channels */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_CHANNEL_LIST_NAME), &Root, NULL, NULL, 0, DSD_OPEN, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the channel list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + + /* Ouverture du port de messages des événements */ + + rc = MSG_Port_Open (LOGD_EVENT_PORT_NAME, &Send_Port, MSGD_OPEN); + if (rc != MSGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Open : unable to open the event port list"); + LOG_Error_Print (); + LOG_Base = NULL; + MSG_Library_Close (MSGD_CLOSE); + return rc; + } + } + + /* Mise à jour du compteur d'ouverture */ + + LOG_Open_Counter++; + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Close_I ( LOGT_Flags Close_Mode ) +{ + LOGT_Status rc; + + if (Close_Mode == LOGD_DESTROY) + { + /* Suppression du port de messages des événements */ + + MSG_Port_Close (Send_Port, MSGD_DESTROY); + + /* Déverrouillage de la base LIBLOG */ + + rc = SM_Heap_Unlock (LOG_Base_Heap); + if (rc != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to unlock the LIBLOG base"); + LOG_Error_Print (); + return rc; + } + + /* Destruction de la liste des channels */ + + rc = DS_DataStruct_Close (LOG_Base->Channel_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the channel list"); + LOG_Error_Print (); + return rc; + } + + /* Destruction du cache des modules */ + + rc = DS_DataStruct_Close (LOG_Base->KMOD, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the KMOD data structure"); + LOG_Error_Print (); + return rc; + } + + /* Destruction du cache des formats d'événement */ + + rc = DS_DataStruct_Close (LOG_Base->KFORMAT, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the KFORMAT data structure"); + LOG_Error_Print (); + return rc; + } + + /* Destruction de la table de routage globale par défaut (GDRT) */ + + rc = DS_DataStruct_Close (LOG_Base->GDRT->Root, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the GDRT data structure"); + LOG_Error_Print (); + return rc; + } + + /* Destruction de la table de routage globale maître (GMRT) */ + + rc = DS_DataStruct_Close (LOG_Base->GMRT->Root, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the GMRT data structure"); + LOG_Error_Print (); + return rc; + } + + /* Destruction de la liste des tables de routage locale maître (LMRT) */ + + rc = DS_DataStruct_Close (LOG_Base->LMRT_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the LMRT list"); + LOG_Error_Print (); + return rc; + } + + /* Destruction de la liste des tables de routage locale maître (LMRT) */ + + rc = DS_DataStruct_Close (LOG_Base->LDRT_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the LDRT list"); + LOG_Error_Print (); + return rc; + } + + /* Destruction de la liste des tables de routage utilisateur (URT) */ + + rc = DS_DataStruct_Close (LOG_Base->URT_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the URT list"); + LOG_Error_Print (); + return rc; + } + + /* Destruction du heap contenant la structure de base */ + + rc = SM_Heap_End (LOG_Name_Prefix (LOGD_BASE_HEAP_NAME)); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to destroy the heap of the base structure"); + LOG_Error_Print (); + return rc; + } + + /* Réinitialisation du compteur d'ouverture */ + + LOG_Open_Counter = 0; + } + else + { + /* On ne libère les ressources que lors de la dernière fermeture */ + + if (LOG_Open_Counter == 1) + { + pid_t Pid = getpid (); + NDT_Node * Node, * Next_Node; + + /* Fermeture du port de messages des événements */ + + MSG_Port_Close (Send_Port, MSGD_CLOSE); + + /* Ménage des channels du processus courant qui n'auraient pas été fermés */ + + DS_Node_First_Get (LOG_Base->Channel_List, &Node); + while (Node) + { + LOGT_Channel * Channel = (LOGT_Channel *)(Node->Value); + + DS_Node_Next_Get (Node, &Next_Node); + + if (Channel->Pid == Pid) + { + rc = LOG_Channel_Close (Channel); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close a channel which belongs to the current process"); + LOG_Error_Print (); + } + else + { + /* + Petit message d'alerte à l'encontre de l'utilisateur de la librairie + pour lui préciser qu'il a oublié de fermer l'un de ses channels. + */ + + sprintf (LOG_Error_Msg, "Warning LOG_Library_Close : a channel which belongs to the current process has not been closed. The garbage collector has done the work for you !"); + LOG_Error_Print (); + } + } + + Node = Next_Node; + } + + /* Ménage des tables de routage utilisateur du processus courant qui n'auraient pas été supprimées */ + + DS_Node_First_Get (LOG_Base->URT_List, &Node); + + while (Node) + { + LOGT_RTab * RTab = (LOGT_RTab *)(Node->Value); + + DS_Node_Next_Get (Node, &Next_Node); + + if (RTab->Pid == Pid) + { + rc = LOG_RTab_Free (RTab); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close a user rooting table which belongs to the current process"); + LOG_Error_Print (); + } + else + { + /* + Ici, on n'affiche pas de message d'alerte car ce cas peut ne pas être du fait de l'utilisateur + (notamment si une table de routage est supprimée d'un channel sur trigger, l'utilisateur + ne sait pas forcément qu'elle l'a été et ne peut donc pas savoir qu'il faut la supprimer). + */ + } + } + + Node = Next_Node; + } + + /* Fermeture du cache des modules */ + + rc = DS_DataStruct_Close (LOG_Base->KMOD, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the KMOD data structure"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture du cache des formats d'événement */ + + rc = DS_DataStruct_Close (LOG_Base->KFORMAT, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the KFORMAT data structure"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture de la table de routage globale par défaut (GDRT) */ + + rc = DS_DataStruct_Close (LOG_Base->GDRT->Root, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the GDRT data structure"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture de la table de routage globale maître (GMRT) */ + + rc = DS_DataStruct_Close (LOG_Base->GMRT->Root, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the GMRT data structure"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture de la liste des tables de routage locale maître (LMRT) */ + + rc = DS_DataStruct_Close (LOG_Base->LMRT_List, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the LMRT list"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture de la liste des tables de routage locale maître (LDRT) */ + + rc = DS_DataStruct_Close (LOG_Base->LDRT_List, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the LDRT list"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture de la liste des tables de routage utilisateur (URT) */ + + rc = DS_DataStruct_Close (LOG_Base->URT_List, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the URT list"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture de la liste des channels */ + + rc = DS_DataStruct_Close (LOG_Base->Channel_List, DSD_CLOSE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the channel list"); + LOG_Error_Print (); + return rc; + } + + /* Fermeture du heap contenant la structure de base */ + + rc = SM_Heap_Close (LOG_Base_Heap); + if (rc != SMS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Library_Close : unable to close the heap of the base structure"); + LOG_Error_Print (); + return rc; + } + + LOG_Base = NULL; + + /* Mise à jour du compteur d'ouverture */ + + LOG_Open_Counter--; + } + } + + /* Fermeture de la librairie LIBDATASTR */ + + rc = DS_Library_Close (); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Stderr_Set_I ( FILE * Out ) +{ + LOG_stderr = Out; + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Création d'un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (O) Channel : adresse du pointeur sur le canal créé */ +/* (I) Pid : numéro du processus propriétaire du canal */ +/* (I) Channel_Id : identifiant du canal au sein du processus */ +/* (I) Module_Name : nom du module propriétaire du canal */ +/* (I) Master_Module_Name : nom du module primaire */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Open_I ( LOGT_Channel ** Channel, int Pid, int Channel_Id, const char * Module_Name, const char * Master_Module_Name ) +{ + LOGT_Status rc; + NDT_Node * Node; + LOGT_RTab * LMRT, * LDRT; + char DS_Name [100]; + LOGT_Module To_Find; + +/************************ VERSION AVEC LA LIBRAIRIE LOGEVT ********************** + Id Id_Module; + + Id_Module = logevt_get_id_module (Module_Name); + + if (Id_Module < 0) + { + fprintf (stderr, "Error LOG_Channel_Open : logevt_get_id_module a retourn\351 %d", (int)Id_Module); + return rc; + } + + *Channel = (LOGT_Channel *) malloc (sizeof (LOGT_Channel)); + + (*Channel)->Id = logevt_open_channel (Id_Module, 0, 0); + + if ((int)(*Channel)->Id < 0 ) + { + fprintf (stderr, "Error LOG_Channel_Open : logevt_open_channel a retourn\351 %d", (int)(*Channel)); + return rc; + } +*********************************************************************************/ + + *Channel = NULL; + + /* Recherche de l'identifiant du module envoyeur */ + + To_Find.Name = Module_Name; + + rc = DS_Node_Find (LOG_Base->KMOD, &Node, &To_Find, NULL); + if (DS_ERROR(rc)) return rc; + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to find module \"%s\"", Module_Name); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + /* Création du channel */ + + rc = DS_Value_Alloc (LOG_Base->Channel_List, (void **)Channel); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to create a channel"); + LOG_Error_Print (); + return rc; + } + + if (!Pid) (*Channel)->Pid = (int)getpid (); + else (*Channel)->Pid = Pid; + (*Channel)->Id = Channel_Id; + (*Channel)->ModuleId = ((LOGT_Module *)(Node->Value))->Id; + (*Channel)->Master_ModuleId = 0; + (*Channel)->RTab_List = NULL; + (*Channel)->SubModule_List = NULL; + (*Channel)->Trigger_List = NULL; + (*Channel)->Event_Cpt_List = NULL; + + /* Recherche de l'identifiant du module maître */ + + if (Master_Module_Name) To_Find.Name = Master_Module_Name; + else To_Find.Name = getenv (MASTER_MODULE_ENV); + + if (To_Find.Name) + { + rc = DS_Node_Find (LOG_Base->KMOD, &Node, &To_Find, NULL); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to find master module \"%s\"", Master_Module_Name); + LOG_Error_Print (); + } + + (*Channel)->Master_ModuleId = ((LOGT_Module *)(Node->Value))->Id; + } + + /* Création de la liste des sous-modules associée au channel (dans le même heap que la liste des channels) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_CHANNEL_LIST_NAME), &((*Channel)->SubModule_List), NDD_DS_LIST | NDD_MN_FILO, LOG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to create the channel submodule list"); + LOG_Error_Print (); + return rc; + } + else strcpy ((*Channel)->SubModule_List->Manager, "LOG_Channel_SubModuleList_Manager"); + + /* Ajout d'un premier sous-module correspondant au nom du module */ + + rc = LOG_Channel_Enter (*Channel, Module_Name); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to add a first submodule to the channel"); + LOG_Error_Print (); + return rc; + } + + /* Création de la liste des triggers associée au channel (dans le même heap que la liste des channels) */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_CHANNEL_LIST_NAME), &((*Channel)->Trigger_List), NDD_DS_LIST | NDD_MN_FILO, LOG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to create the channel trigger list"); + LOG_Error_Print (); + return rc; + } + else strcpy ((*Channel)->Trigger_List->Manager, "LOG_Channel_TriggerList_Manager"); + + /* Création de la liste de compteurs d'événements associée au channel (dans le même heap que la liste des channels)*/ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_CHANNEL_LIST_NAME), &((*Channel)->Event_Cpt_List), NDD_DS_TREE | NDD_MN_AUTO_EQU, LOG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to create the channel event counter list"); + LOG_Error_Print (); + return rc; + } + else strcpy ((*Channel)->Event_Cpt_List->Manager, "LOG_Channel_Event_CptList_Manager"); + + /* Création de la liste des tables de routage associée au channel (dans le même heap que la liste des channels)*/ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_CHANNEL_LIST_NAME), &((*Channel)->RTab_List), NDD_DS_LIST | NDD_MN_ORDERED, LOG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to create the channel rooting table list"); + LOG_Error_Print (); + return rc; + } + else strcpy ((*Channel)->RTab_List->Manager, "LOG_Channel_RTabList_Manager"); + + /* Ajout de la table de routage globale maître (GMRT) à la liste (pas la GDRT) */ + + rc = LOG_RTab_Add (*Channel, LOG_Base->GMRT); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to add the GDRT table to the rooting table list"); + LOG_Error_Print (); + return rc; + } + + /* Création de la table de routage locale maître */ + + sprintf (DS_Name, "%s_%d_%d_%d", LOGD_LMRT_NAME, (*Channel)->ModuleId, (int)(*Channel)->Pid, Channel_Id); + + rc = DS_Value_Alloc (LOG_Base->LMRT_List, (void **)&LMRT, LOGD_LMRT, DS_Name); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to create the LMRT rooting table"); + LOG_Error_Print (); + return rc; + } + + /* Création de la table de routage locale par défaut */ + + sprintf (DS_Name, "%s_%d_%d_%d", LOGD_LDRT_NAME, (*Channel)->ModuleId, (int)(*Channel)->Pid, Channel_Id); + + rc = DS_Value_Alloc (LOG_Base->LDRT_List, (void **)&LDRT, LOGD_LDRT, DS_Name); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to create the LMRT rooting table"); + LOG_Error_Print (); + return rc; + } + + /* Ajout des tables de routage locales à la liste des tables de routage du channel */ + + rc = LOG_RTab_Add (*Channel, LMRT); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to add the LMRT table to the channel rooting table list"); + LOG_Error_Print (); + return rc; + } + + rc = LOG_RTab_Add (*Channel, LDRT); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to add the LDRT table to the channel rooting table list"); + LOG_Error_Print (); + return rc; + } + + /* Ajout des tables de routage locales aux listes de tables de routage locales de la base */ + + rc = DS_Value_Add (LOG_Base->LMRT_List, (void *)LMRT); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to add the LMRT table to the base LMRT list"); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Add (LOG_Base->LDRT_List, (void *)LDRT); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to add the LDRT table to the base LDRT list"); + LOG_Error_Print (); + return rc; + } + + /* Ajout du channel à la liste des channels */ + + rc = DS_Value_Add (LOG_Base->Channel_List, (void *)(*Channel)); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : unable to add the channel to the base channel list"); + LOG_Error_Print (); + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Entrée dans un sous-module pour un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal */ +/* (I) SubModule_Name : nom du sous-module */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Enter_I ( LOGT_Channel * Channel, const char * SubModule_Name ) +{ + LOGT_Status rc; + char * SubModule; + + rc = DS_Value_Alloc (Channel->SubModule_List, (void **)&SubModule, SubModule_Name); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Enter : unable to create a submodule in channel submodule list"); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Add (Channel->SubModule_List, (void *)SubModule); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Enter : unable to add a submodule to the channel submodule list"); + LOG_Error_Print (); + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Sortie d'un sous-module pour un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal */ +/* (I) SubModule_Name : nom du sous-module */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Leave_I ( LOGT_Channel * Channel, const char * SubModule_Name ) +{ + LOGT_Status rc; + char * Name; + + rc = DS_Value_Remove (Channel->SubModule_List, (void *)SubModule_Name, (void **)&Name); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Leave : unable to remove the submodule from the channel submodule list"); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (Channel->SubModule_List, Name); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Leave : unable to free the submodule name"); + LOG_Error_Print (); + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel à fermer */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Close_I ( LOGT_Channel * Channel ) +{ + LOGT_Status rc; + +/************************ VERSION AVEC LA LIBRAIRIE LOGEVT ********************** + logevt_close_channel ((Channel)Channel->Id); +********************************************************************************/ + + rc = DS_Value_Remove (LOG_Base->Channel_List, (void *)Channel, (void **)&Channel); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Close : unable to remove a channel from the base channel list"); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (LOG_Base->Channel_List, (void *)Channel); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Close : unable to free the channel"); + LOG_Error_Print (); + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Création d'une table de routage utilisateur */ +/*------------------------------------------------------------------------------*/ +/* (O) RTab : adresse du pointeur sur la table de routage */ +/* (I) Name : nom de la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Alloc_I ( LOGT_RTab ** RTab, char * Name ) +{ + LOGT_Status rc; + *RTab = NULL; + + /* Allocation de la nouvelle table */ + + rc = DS_Value_Alloc (LOG_Base->URT_List, (void **)RTab, LOGD_URT, Name); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Alloc : unable to create a rooting table"); + LOG_Error_Print (); + return rc; + } + + /* Ajout de la nouvelle table de routage dans la base */ + + rc = DS_Value_Add (LOG_Base->URT_List, (void *)(*RTab)); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Alloc : unable to add the new rooting table to the base list"); + LOG_Error_Print (); + + DS_Value_Free (LOG_Base->URT_List, RTab); + + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une règle à une table de routage */ +/*------------------------------------------------------------------------------*/ +/* (I) RTab : pointeur sur la table de routage */ +/* (I) Rule_Class : classe de la nouvelle règle */ +/* (I) Rule : pointeur sur la nouvelle règle */ +/* (I) Value : valeur de la nouvelle règle */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Setup_I ( LOGT_RTab * RTab, LOGT_RuleClass Rule_Class, LOGT_Rule * Rule, LOGT_Rooting Value ) +{ + RegExp_t * Compiled_RegExp = NULL; + + /* Si la sélection se fait sur le nom du type d'événement, on compile l'expression régulière */ + + if (Rule_Class == LOGD_SELECT_TYPE) + { + Compiled_RegExp = (RegExp_t *) malloc (RegExp_Size); + + if (!RegExp_Compile ((char *)Rule, Compiled_RegExp)) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Setup : unable to compile the regular expression \"%s\"", (char *)Rule); + LOG_Error_Print (); + if (Compiled_RegExp) free (Compiled_RegExp); + return LOGS_ERRAPI; + } + } + + /* Sélection récursive de tous les types d'événement de la table de routage par défaut (GDRT) */ + + LOG_GDRT_Recursive_Select (0, LOG_Base->GDRT->Root, RTab, Rule_Class, Rule, Value, "", Compiled_RegExp); + + if (Compiled_RegExp) free (Compiled_RegExp); + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une table de routage utilisateur à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) RTab : pointeur sur la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Add_I ( LOGT_Channel * Channel, LOGT_RTab * RTab ) +{ + LOGT_Status rc; + + rc = ND_Value_Add (Channel->RTab_List, (void *)RTab); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Add : unable to add the rooting table to the channel"); + LOG_Error_Print (); + return rc; + } + + (RTab->Nb_Channel)++; + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'une table de routage utilisateur d'un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) RTab : pointeur sur la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Remove_I ( LOGT_Channel * Channel, LOGT_RTab * RTab ) +{ + LOGT_Status rc; + NDT_Node * Node; + + /* On vérifie qu'il s'agit bien d'une table de routage utilisateur */ + + if (RTab->Type != LOGD_URT) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Remove : the rooting table is not a user rooting table"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + /* + Pour rechercher la table de routage à supprimer, on ne peut pas utiliser la fonction ND_Node_Find + car le manager compare les tables selon leur type ce qui ne nous intéresse pas dans le cas présent. + */ + + ND_Node_First_Get (Channel->RTab_List, &Node); + + while (Node && strcmp (RTab->Name, ((LOGT_RTab *)(Node->Value))->Name)) + ND_Node_Next_Get (Node, &Node); + + if (!Node) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Remove : unable to find the rooting table \"%s\" in the channel", RTab->Name); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + rc = ND_Node_Remove (Node); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Remove : unable to remove the rooting table from the channel"); + LOG_Error_Print (); + return rc; + } + + (RTab->Nb_Channel)--; + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'une table de routage utilisateur */ +/*------------------------------------------------------------------------------*/ +/* (I) RTab : pointeur sur la table de routage utilisateur */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Free_I ( LOGT_RTab * RTab ) +{ + LOGT_Status rc; + char RTab_Name [50]; + + strcpy (RTab_Name, RTab->Name); + + /* On ne supprime la table de routage que si elle n'est plus rattachée à aucun channel */ + + if (RTab->Nb_Channel > 0) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Free : unable to free rooting table \"%s\" because it is referenced by some channel", RTab_Name); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + rc = DS_Value_Remove (LOG_Base->URT_List, (void *)RTab, (void **)&RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Free : unable to remove user rooting table \"%s\" from the base list", RTab_Name); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (LOG_Base->URT_List, (void *)RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Free : unable to free the user rooting table \"%s\"", RTab_Name); + LOG_Error_Print (); + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un trigger */ +/*------------------------------------------------------------------------------*/ +/* (O) Trigger : adresse du pointeur sur le trigger mis en place */ +/* (I) Channel : pointeur sur le channel */ +/* (I) RTab : pointeur sur la table de routage à appliquer */ +/* (I) Event_Name : type d'événement déclencheur (expression régulière) */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Trigger_Add_I ( LOGT_Trigger ** Trigger, LOGT_Channel * Channel, LOGT_RTab * RTab, char * Event_Name, LOGT_Flags Mode ) +{ + LOGT_Status rc; + *Trigger = NULL; + + rc = DS_Value_Alloc (Channel->Trigger_List, (void **)Trigger, Event_Name); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Add : unable to create a trigger in the channel trigger list"); + LOG_Error_Print (); + return rc; + } + + (*Trigger)->RTab = RTab; + (*Trigger)->Channel = Channel; + (*Trigger)->Mode = Mode; + + rc = DS_Value_Add (Channel->Trigger_List, (void *)(*Trigger)); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Add : unable to add a trigger to the channel trigger list"); + LOG_Error_Print (); + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'un trigger */ +/*------------------------------------------------------------------------------*/ +/* (I) Trigger : pointeur sur le trigger mis en place */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Trigger_Remove_I ( LOGT_Trigger * Trigger ) +{ + LOGT_Status rc; + + rc = DS_Value_Remove (Trigger->Channel->Trigger_List, (void *)Trigger, (void **)&Trigger); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Remove : unable to remove a trigger from the channel trigger list"); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (Trigger->Channel->Trigger_List, (void *)Trigger); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Remove : unable to free the trigger"); + LOG_Error_Print (); + return rc; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un événement */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un channel */ +/* (O) RC : pointeur sur le code retour associé au type de l'événement */ +/* (I) Support : code du support source */ +/* (I) Data : données de l'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Send_I ( LOGT_Channel * Channel, LOGT_RC * RC, char * Support, va_list Data ) +{ + +/************************ VERSION AVEC LA LIBRAIRIE LOGEVT ********************** + if ((*RC = (LOGT_RC)evtutils_vsend_evt ((Channel)(Channel->Id), Support, Data)) < 0) + return rc; +*********************************************************************************/ + + return LOG_Event_Internal_Send (DATA_ARG_LIST, Channel, RC, Support, Data, NULL); +} + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un événement (PL/SQL ou shell) */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : identifiant du channel */ +/* (I) Support : code du support source */ +/* (I) Data : données de l'événement */ +/*------------------------------------------------------------------------------*/ +/* (O) Retourne le code retour associé au type d'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_RC LOG_Event_External_Send_I ( LOGT_Channel * Channel, char * Support, char * Data ) +{ + +/************************ VERSION AVEC LA LIBRAIRIE LOGEVT ********************** + char * Commande; + char sChannel[256]; + char Erreur[256]; + LOGT_RC RC; + + sprintf (sChannel, "%d", (int)Channel); + Commande = (char *) malloc (strlen (sChannel) + strlen (Support) + strlen (Data) + 3); + sprintf (Commande, "%d %s %s", (int)Channel, Support, Data); + + RC = evtutils_send_shell_evt (Commande, Erreur); + + free (Commande); +*********************************************************************************/ + + LOGT_RC RC = LOGD_RC_WARNING; + + LOG_Event_Internal_Send (DATA_STRING, Channel, &RC, Support, NULL, Data); + + return RC; +} + +/*------------------------------------------------------------------------------*/ +/* Retourne les informations du type par lequel un événement est résolu */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un channel */ +/* (O) Info : pointeur sur les informations à récupérer */ +/* (I) Event_Name : nom de l'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Info_Get_I ( LOGT_Channel * Channel, LOGT_Info ** Info, char * Event_Name ) +{ + LOGT_Status rc; + LOGT_GDRT_Evt * GDRT_Evt; + char * ptr; + NDT_Node * Node; + LOGT_Event_Format To_Find; + + ptr = (char *) malloc (81); + ptr [80] = (char)0; + ptr += 80; + + /* Recherche des informations dans la table de routage par défaut */ + + rc = LOG_GDRT_Event_Find (&GDRT_Evt, &ptr, Event_Name); + if (LOG_ERROR(rc)) return rc; + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Info_Get : unable to find event %s in the GDRT rooting table", Event_Name); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + (*Info)->Event_Name = ptr; + (*Info)->Event_Type = GDRT_Evt->Id; + (*Info)->RC = GDRT_Evt->RC; + (*Info)->Gravite = GDRT_Evt->Gravite; + + /* Recherche du routage dans la liste des tables de routage du channel, sinon routage par défaut */ + + rc = LOG_Channel_Rooting_Find (Channel, GDRT_Evt->Id, &((*Info)->Rooting)); + if (rc != LOGS_OK || (*Info)->Rooting == LOGD_ROOTING_DEFAULT) + (*Info)->Rooting = GDRT_Evt->Rooting; + + /* Recherche du format du type d'événement */ + + To_Find.Event_Type = (*Info)->Event_Type; + + rc = DS_Node_Find (LOG_Base->KFORMAT, &Node, &To_Find, NULL); + if (rc != DSS_OK) (*Info)->Data_List = NULL; + else (*Info)->Data_List = (NDT_Root *)(((LOGT_Event_Format *)(Node->Value))->Data_List); + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Retourne le nombre d'événements envoyés pour chaque code retour */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un channel */ +/* (O) Cpt : pointeur sur un tableau de compteurs d'événement */ +/* (I) RegExpr : expression régulière sur le nom d'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Cpt_Get_I ( LOGT_Channel * Channel, int * Cpt [LOGD_RC_SIZE], char * RegExpr ) +{ + LOGT_Status rc; + NDT_Node * Node; + LOGT_Event_Cpt * Event_Cpt; + LOGT_Info * Info; + int i; + RegExp_t * Compiled_RegExp = NULL; + + /* Initialisation du tableau de compteurs */ + + for (i = 0; i < LOGD_RC_SIZE; i++) (*Cpt)[i] = 0; + + /* Compilation de l'expression régulière */ + + Compiled_RegExp = (RegExp_t *) malloc (RegExp_Size); + + if (!RegExp_Compile (RegExpr, Compiled_RegExp)) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Cpt_Get : unable to compile the regular expression \"%s\"", RegExpr); + LOG_Error_Print (); + if (Compiled_RegExp) free (Compiled_RegExp); + return LOGS_ERRAPI; + } + + /* Traversée de la structure de compteurs */ + + ND_Node_First_Get (Channel->Event_Cpt_List, &Node); + while (Node) + { + Event_Cpt = (LOGT_Event_Cpt *)(Node->Value); + + /* L'événement matche-t'il avec l'expression régulière ? */ + + if (RegExp_Match (Event_Cpt->Name, Compiled_RegExp)) + { + /* Recherche des informations concernant l'événement */ + + rc = LOG_Event_Info_Get (Channel, &Info, Event_Cpt->Name); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Cpt_Get : unable to retrieve information about event \"%s\"", Event_Cpt->Name); + LOG_Error_Print (); + if (Compiled_RegExp) free (Compiled_RegExp); + return rc; + } + + /* Incrémentation du compteur */ + + (*Cpt)[(int)Info->RC] += Event_Cpt->Total; + } + + ND_Node_Next_Get (Node, &Node); + } + + if (Compiled_RegExp) free (Compiled_RegExp); + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* FONCTIONS SECURISEES (LOG_MODE = 0) */ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro de l'instance à ouvrir */ +/* (I) Context : contexte d'utilisation de la librairie */ +/* (I) Open_Mode : mode d'ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Open_C ( int Instance, const char * Context, LOGT_Flags Open_Mode ) +{ + return LOG_Library_Open_I (Instance, Context, Open_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Close_C ( LOGT_Flags Close_Mode ) +{ + return LOG_Library_Close_I (Close_Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Stderr_Set_C ( FILE * Out ) +{ + return LOG_Library_Stderr_Set_I (Out); +} + +/*------------------------------------------------------------------------------*/ +/* Création d'un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (O) Channel : adresse du pointeur sur le canal créé */ +/* (I) Pid : numéro du processus propriétaire du canal */ +/* (I) Channel_Id : identifiant du canal au sein du processus */ +/* (I) Module_Name : nom du module propriétaire du canal */ +/* (I) Master_Module_Name : nom du module primaire */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Open_C (LOGT_Channel ** Channel, int Pid, int Channel_Id, const char * Module_Name, const char * Master_Module_Name ) +{ + *Channel = NULL; + + if (!LOG_Base) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : the library is not open"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : the channel address is undefined"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Module_Name) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Open : the module name is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Channel_Open_I (Channel, Pid, Channel_Id, Module_Name, Master_Module_Name); +} + +/*------------------------------------------------------------------------------*/ +/* Entrée dans un sous-module pour un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal */ +/* (I) SubModule_Name : nom du sous-module */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Enter_C (LOGT_Channel * Channel, const char * SubModule_Name ) +{ + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Enter : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!SubModule_Name) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Enter : the submodule name is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Channel_Enter_I (Channel, SubModule_Name); +} + +/*------------------------------------------------------------------------------*/ +/* Sortie d'un sous-module pour un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal */ +/* (I) SubModule_Name : nom du sous-module */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Leave_C (LOGT_Channel * Channel, const char * SubModule_Name ) +{ + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Leave : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!SubModule_Name) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Leave : the submodule name is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Channel_Leave_I (Channel, SubModule_Name); +} + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel à fermer */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Close_C (LOGT_Channel * Channel) +{ + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Close : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Channel_Close_I (Channel); +} + +/*------------------------------------------------------------------------------*/ +/* Création d'une table de routage utilisateur */ +/*------------------------------------------------------------------------------*/ +/* (O) RTab : adresse du pointeur sur la table de routage */ +/* (I) Name : nom de la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Alloc_C ( LOGT_RTab ** RTab, char * Name ) +{ + if (!LOG_Base) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Alloc : the library is not open"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Name) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Alloc : the rooting table name is undefined"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_RTab_Alloc_I (RTab, Name); +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une règle à une table de routage */ +/*------------------------------------------------------------------------------*/ +/* (I) RTab : pointeur sur la table de routage */ +/* (I) Rule_Class : classe de la nouvelle règle */ +/* (I) Rule : pointeur sur la nouvelle règle */ +/* (I) Value : valeur de la nouvelle règle */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Setup_C (LOGT_RTab * RTab, LOGT_RuleClass Rule_Class, LOGT_Rule * Rule, LOGT_Rooting Value ) +{ + if (!RTab) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Setup : the rooting table is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + /* On vérifie qu'il s'agit bien d'une table de routage utilisateur */ + + if (RTab->Type != LOGD_URT) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Setup : the rooting table is not a user rooting table"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_RTab_Setup_I (RTab, Rule_Class, Rule, Value); +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une table de routage utilisateur à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) RTab : pointeur sur la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Add_C (LOGT_Channel * Channel, LOGT_RTab * RTab ) +{ + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Add : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!RTab) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Add : the rooting table is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_RTab_Add_I (Channel, RTab); +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'une table de routage utilisateur d'un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) RTab : pointeur sur la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Remove_C (LOGT_Channel * Channel, LOGT_RTab * RTab ) +{ + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Remove : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!RTab) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Remove : the rooting table is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_RTab_Remove_I (Channel, RTab ); +} + +/*------------------------------------------------------------------------------*/ +/* Destruction d'une table de routage utilisateur */ +/*------------------------------------------------------------------------------*/ +/* (I) RTab : pointeur sur la table de routage utilisateur */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Free_C ( LOGT_RTab * RTab ) +{ + if (!RTab) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Free : the rooting table is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + /* On vérifie qu'il s'agit bien d'une table de routage utilisateur */ + + if (RTab->Type != LOGD_URT) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Free : rooting table \"%s\" is not a user rooting table", RTab->Name); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_RTab_Free_I (RTab); +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un trigger */ +/*------------------------------------------------------------------------------*/ +/* (O) Trigger : adresse du pointeur sur le trigger mis en place */ +/* (I) Channel : pointeur sur le channel */ +/* (I) RTab : pointeur sur la table de routage à appliquer */ +/* (I) Event_Name : type d'événement déclencheur (expression régulière) */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Trigger_Add_C ( LOGT_Trigger ** Trigger, LOGT_Channel * Channel, LOGT_RTab * RTab, char * Event_Name, LOGT_Flags Mode ) +{ + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Add : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!RTab) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Add : the rooting table is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Event_Name) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Add : the event type is undefined"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Trigger_Add_I (Trigger, Channel, RTab, Event_Name, Mode); +} + +/*------------------------------------------------------------------------------*/ +/* Suppression d'un trigger */ +/*------------------------------------------------------------------------------*/ +/* (I) Trigger : pointeur sur le trigger mis en place */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Trigger_Remove_C ( LOGT_Trigger * Trigger ) +{ + if (!Trigger) + { + sprintf (LOG_Error_Msg, "Error LOG_Trigger_Remove : the trigger is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Trigger_Remove_I (Trigger); +} + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un événement */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un channel */ +/* (O) RC : pointeur sur le code retour associé au type de l'événement */ +/* (I) Support : code du support source */ +/* (I) Data : données de l'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Send_C (LOGT_Channel * Channel, LOGT_RC * RC, char * Support, va_list Data ) +{ + if (!LOG_Base) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Send : the library is not open"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Send : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Event_Send_I (Channel, RC, Support, Data); +} + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un événement (PL/SQL ou shell) */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : identifiant du channel */ +/* (I) Support : code du support source */ +/* (I) Data : données de l'événement */ +/*------------------------------------------------------------------------------*/ +/* (O) Retourne le code retour associé au type d'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_RC LOG_Event_External_Send_C ( LOGT_Channel * Channel, char * Support, char * Data ) +{ + if (!LOG_Base) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_External_Send : the library is not open"); + LOG_Error_Print (); + return LOGD_RC_WARNING; + } + + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_External_Send : the channel is null"); + LOG_Error_Print (); + return LOGD_RC_WARNING; + } + + return LOG_Event_External_Send_I (Channel, Support, Data); +} + +/*------------------------------------------------------------------------------*/ +/* Retourne les informations du type par lequel un événement est résolu */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un channel */ +/* (O) Info : pointeur sur les informations à récupérer */ +/* (I) Event_Name : nom de l'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Info_Get_C ( LOGT_Channel * Channel, LOGT_Info ** Info, char * Event_Name ) +{ + if (!LOG_Base) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Info_Get : the library is not open"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Info_Get : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Info) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Info_Get : the info address is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Event_Name) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Info_Get : the event name is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Event_Info_Get_I (Channel, Info, Event_Name); +} + +/*------------------------------------------------------------------------------*/ +/* Retourne le nombre d'événements envoyés pour chaque code retour */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un channel */ +/* (O) Cpt : pointeur sur un tableau de compteurs d'événement */ +/* (I) RegExpr : expression régulière sur le nom d'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Cpt_Get_C ( LOGT_Channel * Channel, int * Cpt [LOGD_RC_SIZE], char * RegExpr ) +{ + if (!Channel) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Cpt_Get : the channel is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!Cpt) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Cpt_Get : the counter array address is undefined"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!RegExpr) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Cpt_Get : the regular expression is null"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOG_Event_Cpt_Get_I (Channel, Cpt, RegExpr); +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS PRIVEES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un événement (partie commune aux fonctions 'LOG_Event_Send' */ +/* et 'LOG_Event_External_Send' : */ +/*------------------------------------------------------------------------------*/ +/* - récupération des données de l'événement */ +/* - résolution du nom d'événement */ +/* - mise à jour du compteur d'événement */ +/* - traitement de l'événement en fonction du routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Internal_Send (int Mode, LOGT_Channel * Channel, LOGT_RC * RC, char * Support, va_list Data_Arg, char * Data_Str) +{ + LOGT_Status rc; + NDT_Node * Node; + LOGT_Info * Info; + char Event_Name [81]; + char * Event_Data, * Event_Data_Ptr; + size_t Data_Size; + LOGT_Event_Cpt To_Find; + unsigned int Length; + RegExp_t * Compiled_RegExp = NULL; + size_t Msg_Size; + LOGT_Event_Msg_Data * Event_Msg_Data; + + *RC = LOGD_RC_WARNING; + + /* Récupération des données de l'événement */ + + rc = LOG_Event_Data_Get (Mode, Support, &Event_Data, &Data_Size, &Data_Arg, Data_Str); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to retrieve event data from the %s", Mode == DATA_ARG_LIST ? "argument list" : "string"); + LOG_Error_Print (); + if (Event_Data) free (Event_Data); + return rc; + } + + /* Récupération du nom de l'événement */ + + Length = (unsigned int)Event_Data [0]; + strncpy (Event_Name, Event_Data + 1, Length); + Event_Name [Length] = (char)0; + + /* Résolution du nom d'événement */ + + Info = (LOGT_Info *) malloc (sizeof (LOGT_Info)); + if (!Info) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to allocate memory for event information"); + LOG_Error_Print (); + if (Event_Data) free (Event_Data); + return LOGS_ERRMEM; + } + + rc = LOG_Event_Info_Get (Channel, &Info, Event_Name); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to resolve event \"%s\"", Event_Name); + LOG_Error_Print (); + if (Event_Data) free (Event_Data); + return rc; + } + + /* Ajout au compteur d'événements du channel */ + + To_Find.Name = Event_Name; + + rc = ND_Node_Find (Channel->Event_Cpt_List, &Node, &To_Find, NULL); + if (rc != NDS_OK) + { + int Locked; + LOGT_Event_Cpt * Event_Cpt; + + /* + Optimisation : on verrouille nous-même la data structure et + on fait appel aux API sans verrouillage systématique (DS_*_I). + */ + + rc = DS_DataStruct_Lock (Channel->Event_Cpt_List, DSD_WRITE, &Locked); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to lock the channel counter list"); + LOG_Error_Print (); + if (Event_Data) free (Event_Data); + return rc; + } + + rc = DS_Value_Alloc_I (Channel->Event_Cpt_List, (void **)&Event_Cpt, Event_Name); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to create a counter for event \"%s\"", Event_Name); + LOG_Error_Print (); + if (Locked == TRUE) DS_DataStruct_Unlock (Channel->Event_Cpt_List); + if (Event_Data) free (Event_Data); + return rc; + } + + rc = DS_Value_Add_I (Channel->Event_Cpt_List, (void *)Event_Cpt); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to add the event counter \"%s\" to the data structure", Event_Name); + LOG_Error_Print (); + if (Locked == TRUE) DS_DataStruct_Unlock (Channel->Event_Cpt_List); + if (Event_Data) free (Event_Data); + return rc; + } + + if (Locked == TRUE) DS_DataStruct_Unlock (Channel->Event_Cpt_List); + } + else ((LOGT_Event_Cpt *)(Node->Value))->Total++; + + /* Traitement de l'événement en fonction du routage */ + + if (Info->Rooting & LOGD_ROOTING_STDERR) + { + /* Affichage de l'événement sur la sortie standard du process */ + + fprintf (stderr, "[EVENT] %s\n", Event_Name); + } + + if (Info->Rooting & LOGD_ROOTING_DATABASE) + { + MSGT_Message * Event_Msg; + + /* Allocation du message : entête du format de l'événement + données de l'événement (Data_Size) */ + + Msg_Size = sizeof (LOGT_Event_Msg_Header) + 2 * sizeof (unsigned int) + Data_Size; + + rc = MSG_Message_Alloc (&Event_Msg, Msg_Size); + if (rc != MSGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to allocate %d byte(s) for a new message", Msg_Size); + LOG_Error_Print (); + if (Event_Data) free (Event_Data); + return rc; + } + + rc = MSG_Message_Config (Event_Msg, MSGD_CONFIG_TYPE, LOGD_EVENT_MSG_TYPE); + if (rc != MSGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to configure the message as an event message"); + LOG_Error_Print (); + if (Event_Data) free (Event_Data); + MSG_Message_Free (Event_Msg); + return rc; + } + + /* On remplit la zone de données du message selon le format d'un message d'événement */ + + Event_Msg_Data = (LOGT_Event_Msg_Data *)(Event_Msg->Data); + + strcpy (Event_Msg_Data->Header.Version, EVENT_FORMAT_VERSION); + Event_Msg_Data->Header.Sending_Pid = Channel->Pid; + Event_Msg_Data->Header.ModuleId = Channel->ModuleId; + Event_Msg_Data->Header.Master_ModuleId = Channel->Master_ModuleId; + Event_Msg_Data->Event_Type = Info->Event_Type; + Event_Msg_Data->Data_Size = Data_Size; + + Event_Data_Ptr = &(Event_Msg_Data->Event_Data); + strncpy (Event_Data_Ptr, Event_Data, Data_Size); + + /* Envoi du message pour insertion de l'événement en base */ + + rc = MSG_Message_Send (0, Send_Port, Event_Msg); + if (rc != MSGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to send the event through message port \"%s\"", Send_Port->Name); + LOG_Error_Print (); + if (Event_Data) free (Event_Data); + MSG_Message_Free (Event_Msg); + return rc; + } + } + + if (Event_Data) free (Event_Data); + + Compiled_RegExp = (RegExp_t *) malloc (RegExp_Size); + + /* Déclenchement des triggers */ + + ND_Node_First_Get (Channel->Trigger_List, &Node); + + while (Node) + { + LOGT_Trigger * Trigger = (LOGT_Trigger *)(Node->Value); + NDT_Node * Next_Node; + + ND_Node_Next_Get (Node, &Next_Node); + + /* Compilation de l'expression régulière du trigger */ + + if (!RegExp_Compile (Trigger->Event_Name, Compiled_RegExp)) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to compile the trigger regular expression \"%s\"", Trigger->Event_Name); + LOG_Error_Print (); + if (Compiled_RegExp) free (Compiled_RegExp); + return LOGS_ERRAPI; + } + + /* L'événement déclencheur matche-t'il avec l'événement courant ? */ + + if (RegExp_Match (Event_Name, Compiled_RegExp)) + { + /* Déclenchement du trigger */ + + if (LOGD_ADD_MSK (Trigger->Mode)) + { + rc = LOG_RTab_Add (Channel, Trigger->RTab); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to add a rooting table on event \"%s\" when specified by a trigger", Event_Name); + LOG_Error_Print (); + if (Compiled_RegExp) free (Compiled_RegExp); + return rc; + } + } + else if (LOGD_REMOVE_MSK (Trigger->Mode)) + { + rc = LOG_RTab_Remove (Channel, Trigger->RTab); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to remove rooting table \"%s\" on event \"%s\" when specified by a trigger", Trigger->RTab->Name, Event_Name); + LOG_Error_Print (); + + /* On continue quand même */ + } + } + + /* Retrait du trigger s'il n'est actif qu'une seule fois */ + + if (LOGD_ONE_SHOT_MSK (Trigger->Mode)) + { + rc = LOG_Trigger_Remove (Trigger); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Internal_Send : unable to remove a \"one-shot\" trigger on event %s", Event_Name); + LOG_Error_Print (); + if (Compiled_RegExp) free (Compiled_RegExp); + return rc; + } + } + } + + Node = Next_Node; + } + + if (Compiled_RegExp) free (Compiled_RegExp); + + /* Récupération du code retour */ + + *RC = Info->RC; + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* BASE */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +NDT_Status LOG_Base_ChannelList_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Channel ** Channel = va_arg (Args, LOGT_Channel **); + + *Channel = NULL; + + rc = DS_Alloc (Root, sizeof (LOGT_Channel), (void **)Channel); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_ChannelList_Manager : unable to allocate a new channel"); + LOG_Error_Print (); + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_Channel * Channel = (LOGT_Channel *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Channel (address %d) :\n\t- pid = %ld\n\t- ID = %d\n\t- module = %d\n\t- %ld sous-module(s)\n\t- %ld table(s)\n\t- %ld trigger(s)\n\t- %ld compteur(s) d'événement", (int)Channel, Channel->Pid, Channel->Id, Channel->ModuleId, Channel->SubModule_List->Node_Number, Channel->RTab_List->Node_Number, Channel->Trigger_List->Node_Number, Channel->Event_Cpt_List->Node_Number); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Channel * Channel = (LOGT_Channel *) va_arg (Args, void *); + + rc = DS_DataStruct_Close (Channel->RTab_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_ChannelList_Manager : unable to destroy the channel rooting table list"); + LOG_Error_Print (); + + return rc; + } + + rc = DS_DataStruct_Close (Channel->SubModule_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_ChannelList_Manager : unable to destroy the channel submodule list"); + LOG_Error_Print (); + + return rc; + } + + rc = DS_DataStruct_Close (Channel->Trigger_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_ChannelList_Manager : unable to destroy the channel trigger list"); + LOG_Error_Print (); + + return rc; + } + + rc = DS_DataStruct_Close (Channel->Event_Cpt_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_ChannelList_Manager : unable to destroy the channel event counter list"); + LOG_Error_Print (); + + return rc; + } + + rc = DS_Free (Root, Channel); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_ChannelList_Manager : unable to free the channel"); + LOG_Error_Print (); + + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de channels = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_Channel * Channel1, *Channel2; + long comp; + + Channel1 = (LOGT_Channel *) va_arg (Args, void *); + Channel2 = (LOGT_Channel *) va_arg (Args, void *); + + va_end (Args); + + comp = (int)Channel1 - (int)Channel2; + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager d'une liste de tables de routage attachées à la base */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_Base_RTabList_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_RTab ** RTab = va_arg (Args, LOGT_RTab **); + va_list Args_Value = va_arg (Args, va_list); + LOGT_RTType Type = va_arg (Args_Value, LOGT_RTType); + char * Name = va_arg (Args_Value, char *); + char * Heap_Name; + + *RTab = NULL; + + /* Allocation de la table de routage dans le même heap que celui de la liste des tables de routage */ + + rc = DS_Alloc (Root, sizeof (LOGT_RTab) + strlen (Name) + 1, (void **)RTab); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_RTabList_Manager : unable to allocate a new table %s", Name); + LOG_Error_Print (); + return rc; + } + + (*RTab)->Type = Type; + (*RTab)->Nb_Channel = 0; + (*RTab)->Root = NULL; + (*RTab)->Pid = getpid (); + + (*RTab)->Name = (char *)((size_t)(*RTab) + sizeof (LOGT_RTab)); + strcpy ((*RTab)->Name, Name); + + /* Création de la data structure sous-jacente toujours dans le même heap */ + + switch ((int)Type) + { + case LOGD_LMRT: + Heap_Name = LOG_Name_Prefix (LOGD_LMRT_LIST_NAME); + break; + + case LOGD_LDRT: + Heap_Name = LOG_Name_Prefix (LOGD_LDRT_LIST_NAME); + break; + + case LOGD_URT: + default : + Heap_Name = LOG_Name_Prefix (LOGD_URT_LIST_NAME); + break; + } + + rc = DS_DataStruct_Open (Heap_Name, &((*RTab)->Root), NDD_DS_TREE | NDD_MN_AUTO_EQU, LOG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_RTabList_Manager : unable to create the data structure for the rooting table \"%s\"", Name); + LOG_Error_Print (); + return rc; + } + else strcpy ((*RTab)->Root->Manager, "LOG_RTab_Manager"); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_RTab * RTab = (LOGT_RTab *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Table de routage \"%s\" :\n\t- creator = %d\n\t- type = %s\n\t- nombre d'événements = %ld\n\t- attachée à %d channel(s)", RTab->Name, (int)RTab->Pid, LOG_RTType_Label_Get (RTab->Type), RTab->Root->Node_Number, RTab->Nb_Channel); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_RTab * RTab = (LOGT_RTab *) va_arg (Args, void *); + char RTab_Name [50]; + + strcpy (RTab_Name, RTab->Name); + + rc = DS_DataStruct_Close (RTab->Root, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_RTabList_Manager : unable to destroy the data structure of rooting table \"%s\"", RTab_Name); + LOG_Error_Print (); + + return rc; + } + + rc = DS_Free (Root, RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Base_RTabList_Manager : unable to desallocate the rooting table \"%s\"", RTab_Name); + LOG_Error_Print (); + + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de tables de routage = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_RTab * RTab1, * RTab2; + long comp; + + RTab1 = (LOGT_RTab *) va_arg (Args, void *); + RTab2 = (LOGT_RTab *) va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (RTab1->Name, RTab2->Name); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* CHANNEL */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Manager de la liste de tables de routage d'un channel */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_Channel_RTabList_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_RTab * RTab = (LOGT_RTab *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Table de routage \"%s\" :\n\t- type = %s\n\t- nombre d'événements = %ld\n\t- attachée à %d channel(s)", RTab->Name, LOG_RTType_Label_Get (RTab->Type), RTab->Root->Node_Number, RTab->Nb_Channel); + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_RTab * RTab = (LOGT_RTab *) va_arg (Args, void *); + + /* La table de routage globale maître n'est même pas fermée car peut être utilisée par d'autres channels */ + + /* Les tables de routage locales sont supprimées */ + + if (RTab->Type == LOGD_LMRT) + { + rc = DS_Value_Remove (LOG_Base->LMRT_List, (void *)RTab, (void **)&RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_RTabList_Manager : unable to remove the LMRT rooting table from the base list"); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (LOG_Base->LMRT_List, (void *)RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_RTabList_Manager : unable to free the LMRT rooting table"); + LOG_Error_Print (); + return rc; + } + } + + if (RTab->Type == LOGD_LDRT) + { + rc = DS_Value_Remove (LOG_Base->LDRT_List, (void *)RTab, (void **)&RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_RTabList_Manager : unable to remove a LDRT rooting table from the base list"); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (LOG_Base->LDRT_List, (void *)RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_RTabList_Manager : unable to free the LDRT rooting table"); + LOG_Error_Print (); + return rc; + } + } + + /* Les tables de routage utilisateur ne sont supprimées que si elles ne sont plus rattachées à aucun channel */ + + if (RTab->Type == LOGD_URT && RTab->Nb_Channel == 1) + { + rc = DS_Value_Remove (LOG_Base->URT_List, (void *)RTab, (void **)&RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_RTabList_Manager : unable to remove a user rooting table (%p) from the base list", (void *)RTab); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Free (LOG_Base->URT_List, (void *)RTab); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_RTabList_Manager : unable to free the user rooting table (%p)", (void *)RTab); + LOG_Error_Print (); + return rc; + } + } + else (RTab->Nb_Channel)--; + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de tables de routage = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_RTab * RTab1, * RTab2; + long comp; + + RTab1 = (LOGT_RTab *) va_arg (Args, void *); + RTab2 = (LOGT_RTab *) va_arg (Args, void *); + + va_end (Args); + + /* + Pour le tri des tables de routage, la comparaison se fait sur le type : + + - GMRT en 1er + - LMRT en 2ème + - URT ensuite + - LDRT en dernier + + Les types ont été choisis pour qu'on puisse se contenter de trier sur leur valeur. + */ + + comp = RTab1->Type - RTab2->Type; + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + if (comp == 0) return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager de la structure de compteurs d'événements d'un channel */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_Channel_Event_CptList_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Event_Cpt ** Event_Cpt = va_arg (Args, LOGT_Event_Cpt **); + va_list Args_Value = va_arg (Args, va_list); + char * Name = va_arg (Args_Value, char *); + + *Event_Cpt = NULL; + + rc = DS_Alloc (Root, sizeof (LOGT_Event_Cpt) + strlen (Name) + 1, (void **)Event_Cpt); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Event_CptList_Manager : unable to allocate a new event counter"); + LOG_Error_Print (); + return rc; + } + + (*Event_Cpt)->Total = 1; + + (*Event_Cpt)->Name = (char *)((size_t)(*Event_Cpt) + sizeof (LOGT_Event_Cpt)); + strcpy ((*Event_Cpt)->Name, Name); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_Event_Cpt * EventCpt = (LOGT_Event_Cpt *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Compteur :\n\t- événement = %s\n\t- valeur = %d", EventCpt->Name, EventCpt->Total); + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Event_Cpt * EventCpt = (LOGT_Event_Cpt *) va_arg (Args, void *); + + rc = DS_Free (Root, EventCpt); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_Event_CptList_Manager : unable to free an event counter"); + LOG_Error_Print (); + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de compteurs = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_Event_Cpt *Event_Cpt1, *Event_Cpt2; + long comp; + + Event_Cpt1 = (LOGT_Event_Cpt *) va_arg (Args, void *); + Event_Cpt2 = (LOGT_Event_Cpt *) va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (Event_Cpt1->Name, Event_Cpt2->Name); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager de la liste de sous-modules d'un channel */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_Channel_TriggerList_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Trigger ** Trigger = va_arg (Args, LOGT_Trigger **); + va_list Args_Value = va_arg (Args, va_list); + char * Event_Name = va_arg (Args_Value, char *); + + *Trigger = NULL; + + rc = DS_Alloc (Root, sizeof (LOGT_Trigger) + strlen (Event_Name) + 1, (void **)Trigger); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_TriggerList_Manager : unable to allocate a new trigger"); + LOG_Error_Print (); + + return rc; + } + + (*Trigger)->Event_Name = (char *)((size_t)(*Trigger) + sizeof (LOGT_Trigger)); + strcpy ((*Trigger)->Event_Name, Event_Name); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_Trigger * Trigger = (LOGT_Trigger *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Trigger :\n\t- événement déclencheur = \"%s\"\n\t- mode = %s (%s)\n\t- table de routage concernée = \"%s\"", Trigger->Event_Name, LOGD_ADD_MSK (Trigger->Mode) == LOGD_ADD ? "ajout" : "suppression", LOGD_ONE_SHOT_MSK (Trigger->Mode) == LOGD_ONE_SHOT ? "une seule fois" : "permanent", Trigger->RTab->Name); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Trigger * Trigger = (LOGT_Trigger *) va_arg (Args, void *); + + rc = DS_Free (Root, Trigger); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_TriggerList_Manager : unable to free submodule"); + LOG_Error_Print (); + + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de sous-module = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + char * Trigger1, * Trigger2; + long comp; + + Trigger1 = (char *) va_arg (Args, void *); + Trigger2 = (char *) va_arg (Args, void *); + + va_end (Args); + + comp = (long)Trigger1 - (long)Trigger2; + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager de la liste de sous-modules d'un channel */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_Channel_SubModuleList_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + char ** SubModule = va_arg (Args, char **); + va_list Args_Value = va_arg (Args, va_list); + char * Name = va_arg (Args_Value, char *); + + *SubModule = NULL; + + rc = DS_Alloc (Root, strlen (Name) + 1, (void **) SubModule); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_SubModuleList_Manager : unable to allocate a new submodule"); + LOG_Error_Print (); + return rc; + } + + strcpy (*SubModule, Name); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + char *SubModule = (char *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Sous-module \"%s\"", SubModule); + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + char *SubModule = (char *) va_arg (Args, void *); + + rc = DS_Free (Root, SubModule); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Channel_SubModuleList_Manager : unable to free submodule"); + LOG_Error_Print (); + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de sous-module = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + char * SubModule1, * SubModule2; + long comp; + + SubModule1 = (char *) va_arg (Args, void *); + SubModule2 = (char *) va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (SubModule1, SubModule2); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Recherche du routage d'un événement pour un channel donné */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Rooting_Find (LOGT_Channel * Channel, int EvtId, LOGT_Rooting * Rooting) +{ + LOGT_Status rc; + LOGT_RTab * RTab; + NDT_Node * RTab_Node; + NDT_Node * Event_Node = NULL; + LOGT_RTab_Evt To_Find; + + if (!Channel) return LOGS_ERRAPI; + + To_Find.Id = EvtId; + + /* Recherche dans toutes les tables de routage du channel */ + + ND_Node_First_Get (Channel->RTab_List, &RTab_Node); + + while (RTab_Node) + { + RTab = (LOGT_RTab *)(RTab_Node->Value); + + rc = DS_Node_Find (RTab->Root, &Event_Node, &To_Find, NULL); + if (DS_ERROR(rc)) return rc; + if (rc == DSS_OK) + { + *Rooting = ((LOGT_RTab_Evt *)(Event_Node->Value))->Rooting; + + /* Si le routage n'est pas celui de la table précédente, alors on a trouvé ! */ + + if (*Rooting != LOGD_ROOTING_PREVIOUS) return LOGS_OK; + } + + ND_Node_Next_Get (RTab_Node, &RTab_Node); + } + + return LOGS_KO; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* CACHE DES MODULES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Manager du cache de modules */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_KMOD_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Module ** Module = va_arg (Args, LOGT_Module **); + va_list Args_Value = va_arg (Args, va_list); + char * Name = va_arg (Args_Value, char *); + int Id = va_arg (Args_Value, int); + + *Module = NULL; + + rc = DS_Alloc (Root, sizeof (LOGT_Module) + strlen (Name) + 1, (void **)Module); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_KMOD_Manager : unable to allocate a new module for the module cache data structure"); + LOG_Error_Print (); + return rc; + } + + (*Module)->Id = Id; + + (*Module)->Name = (char *)((size_t)(*Module) + sizeof (LOGT_Module)); + strcpy ((*Module)->Name, Name); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_Module * Module = (LOGT_Module *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Module \"%s\" (ID = %d)", Module->Name, Module->Id); + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Module * Module = (LOGT_Module *) va_arg (Args, void *); + + DS_Free (Root, Module); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de modules = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_Module * Module1, * Module2; + long comp; + + Module1 = (LOGT_Module *) va_arg (Args, void *); + Module2 = (LOGT_Module *) va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (Module1->Name, Module2->Name); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* CACHE DES FORMATS D'EVENEMENT */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Manager du cache des formats d'événement */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_KFORMAT_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Event_Format ** Event_Format = va_arg (Args, LOGT_Event_Format **); + va_list Args_Value = va_arg (Args, va_list); + unsigned int Event_Type = va_arg (Args_Value, unsigned int); + + *Event_Format = NULL; + + /* Allocation de la structure LOGT_Event_Format */ + + rc = DS_Alloc (Root, sizeof (LOGT_Event_Format), (void **)Event_Format); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_KFORMAT_Manager : unable to allocate a new event format for the KFORMAT data structure"); + LOG_Error_Print (); + + return rc; + } + + (*Event_Format)->Event_Type = Event_Type; + + /* Création de la liste des données associée au format */ + + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_KFORMAT_NAME), &((*Event_Format)->Data_List), NDD_DS_LIST | NDD_MN_FIFO, LOG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_KFORMAT_Manager : unable to create the event format data list"); + LOG_Error_Print (); + + DS_Free (Root, *Event_Format); + + return rc; + } + else strcpy ((*Event_Format)->Data_List->Manager, "LOG_KFORMAT_DataList_Manager"); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_Event_Format * Event_Format = (LOGT_Event_Format *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Format du type d'événement %d : %ld donnée(s) associée(s)", Event_Format->Event_Type, Event_Format->Data_List->Node_Number); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_Event_Format * Event_Format = (LOGT_Event_Format *) va_arg (Args, void *); + + rc = DS_DataStruct_Close (Event_Format->Data_List, DSD_DESTROY); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_KFORMAT_Manager : unable to destroy the event format data list"); + LOG_Error_Print (); + + return rc; + } + + DS_Free (Root, Event_Format); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de formats d'événement = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_Event_Format * Event_Format1, *Event_Format2; + long comp; + + Event_Format1 = (LOGT_Event_Format *) va_arg (Args, void *); + Event_Format2 = (LOGT_Event_Format *) va_arg (Args, void *); + + va_end (Args); + + comp = Event_Format1->Event_Type - Event_Format2->Event_Type; + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager d'une liste de données associée à un format d'événement */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_KFORMAT_DataList_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + char ** Event_Data = va_arg (Args, char **); + va_list Args_Value = va_arg (Args, va_list); + char * Data = va_arg (Args_Value, char *); + + *Event_Data = NULL; + + rc = DS_Alloc (Root, strlen (Data) + 1, (void **)Event_Data); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_KFORMAT_DataList_Manager : unable to allocate a new data for the event format data list"); + LOG_Error_Print (); + + return rc; + } + + strcpy (*Event_Data, Data); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + char * Event_Data = (char *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Données de format \"%s\"", Event_Data); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + char * Event_Data = (char *) va_arg (Args, void *); + + DS_Free (Root, Event_Data); + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de données associées aux format = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + char * Event_Data1, *Event_Data2; + long comp; + + Event_Data1 = (char *) va_arg (Args, void *); + Event_Data2 = (char *) va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (Event_Data1, Event_Data2); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* TABLE GDRT */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Manager de la table GDRT */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_GDRT_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + char * Event_Name = va_arg (Args, char *); + int EvtId = va_arg (Args, int); + LOGT_Gravite Gravite = va_arg (Args, LOGT_Gravite); + LOGT_RC RC = va_arg (Args, LOGT_RC); + LOGT_Rooting Rooting = va_arg (Args, LOGT_Rooting); + int * Nb_Tree = va_arg (Args, int *); + + return LOG_GDRT_Event_Create (Event_Name, EvtId, Gravite, RC, Rooting, Nb_Tree); + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_GDRT_Evt * GDRT_Evt = (LOGT_GDRT_Evt *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Evénement \"%s\" : ", GDRT_Evt->Name); + + if (GDRT_Evt->Terminal == TRUE) + fprintf (Out, "terminal (ID=%d Gravité='%c' RC=%s Routage=%s) / %ld sous-valeur(s)", GDRT_Evt->Id, (char)(GDRT_Evt->Gravite), LOG_RC_Label_Get (GDRT_Evt->RC), LOG_Rooting_Label_Get (GDRT_Evt->Rooting), GDRT_Evt->Next_Dim ? ((NDT_Root *)(GDRT_Evt->Next_Dim))->Node_Number : 0); + else + fprintf (Out, "non terminal / %ld sous-valeur(s)", GDRT_Evt->Next_Dim ? ((NDT_Root *)(GDRT_Evt->Next_Dim))->Node_Number : 0); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_GDRT_Evt *GDRT_Evt = (LOGT_GDRT_Evt *) va_arg (Args, void *); + + if (GDRT_Evt->Next_Dim) + { + rc = DS_DataStruct_Traverse (GDRT_Evt->Next_Dim, NDD_CMD_DELETE_VALUE, NULL); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Manager : unable to destroy the next dimension of value %s from the GDRT data structure", GDRT_Evt->Name); + LOG_Error_Print (); + + return rc; + } + } + + rc = DS_Free (Root, GDRT_Evt); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Manager : unable to free a value from the GDRT data structure"); + LOG_Error_Print (); + + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre d'événements = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_GDRT_Evt *GDRT_Evt1, *GDRT_Evt2; + long comp; + + GDRT_Evt1 = (LOGT_GDRT_Evt *) va_arg (Args, void *); + GDRT_Evt2 = (LOGT_GDRT_Evt *) va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (GDRT_Evt1->Name, GDRT_Evt2->Name); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Manager des dimensions des événements de la table GDRT */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_GDRT_Dim_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_GDRT_Evt *GDRT_Evt = (LOGT_GDRT_Evt *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Dimension \"%s\" :\n\t- ID = %d\n\t- Gravité = '%c'\n\t- Code retour = %s\n\t- Routage = %s\n\t- Dimension suivante = %ld valeur(s)", GDRT_Evt->Name, GDRT_Evt->Id, (char)(GDRT_Evt->Gravite), LOG_RC_Label_Get (GDRT_Evt->RC), LOG_Rooting_Label_Get (GDRT_Evt->Rooting), GDRT_Evt->Next_Dim ? ((NDT_Root *)(GDRT_Evt->Next_Dim))->Node_Number : 0); + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_GDRT_Evt *GDRT_Evt = (LOGT_GDRT_Evt *) va_arg (Args, void *); + + if (GDRT_Evt->Next_Dim) + { + rc = DS_DataStruct_Traverse (GDRT_Evt->Next_Dim, NDD_CMD_DELETE_VALUE, NULL); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Dim_Manager : unable to destroy the next dimension of value %s from the GDRT data structure", GDRT_Evt->Name); + LOG_Error_Print (); + + return rc; + } + } + + rc = DS_Free (Root, GDRT_Evt); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Dim_Manager : unable to free a value from the GDRT data structure"); + LOG_Error_Print (); + + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre de contextes = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_GDRT_Evt *GDRT_Evt1, *GDRT_Evt2; + long comp; + + GDRT_Evt1 = (LOGT_GDRT_Evt *) va_arg (Args, void *); + GDRT_Evt2 = (LOGT_GDRT_Evt *) va_arg (Args, void *); + + va_end (Args); + + comp = strcmp (GDRT_Evt1->Name, GDRT_Evt2->Name); + + if (comp < 0) return NDS_LOWER; + + if (comp > 0) return NDS_GREATER; + + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Création d'un événement dans la table GDRT */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_GDRT_Event_Create (const char * Event_Name, int Id, LOGT_Gravite Gravite, LOGT_RC RC, LOGT_Rooting Rooting, int *Nb_Tree) +{ + LOGT_Status rc; + int i; + char * ptr; + NDT_Node * Node; + char * Tab_Dim [EVENT_NB_DIM]; + LOGT_GDRT_Evt * Evt; + NDT_Root * Root; + LOGT_GDRT_Evt To_Find; + + ptr = strdup (Event_Name); + + for (i = 0; i < EVENT_NB_DIM; i++) Tab_Dim [i] = NULL; + + /* Récupération des dimensions du type d'événement */ + + i = 0; + + while (i < EVENT_NB_DIM) + { + Tab_Dim [i] = ptr; + + if (i < EVENT_NB_DIM - 1) + { + char sep = (i == 0 ? '@' : ':'); + + if ((ptr = strchr (Tab_Dim [i], sep))) + { + *ptr = (char)0; + ptr++; + } + else i = EVENT_NB_DIM; + } + i++; + } + + /* Création des différentes dimensions (1 dimension = 1 arbre) */ + + Root = LOG_Base->GDRT->Root; + + for (i = 0; i < EVENT_NB_DIM; i++) + { + if (!Tab_Dim [i]) return LOGS_OK; + + /* Ajout de la dimension si elle n'existe pas */ + + To_Find.Name = Tab_Dim [i]; + + rc = ND_Node_Find (Root, &Node, &To_Find, NULL); + if (rc != NDS_OK) + { + /* Allocation de la nouvelle valeur */ + + rc = DS_Alloc (Root, sizeof (LOGT_GDRT_Evt) + strlen (Tab_Dim [i]) + 1, (void **)(&Evt)); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Event_Create : unable to allocate memory for a new value of the dimension %d", i); + LOG_Error_Print (); + return rc; + } + + Evt->Id = 0; + Evt->Gravite = 0; + Evt->RC = 0; + Evt->Rooting = 0; + Evt->Next_Dim = NULL; + Evt->Terminal = FALSE; + + Evt->Name = (char *)((size_t)Evt + sizeof (LOGT_GDRT_Evt)); + strcpy (Evt->Name, Tab_Dim [i]); + + /* Ajout de la valeur */ + + rc = ND_Value_Add (Root, Evt); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Event_Create : unable to add a new value in the data structureof dimension %d", i); + LOG_Error_Print (); + return rc; + } + } + else Evt = (LOGT_GDRT_Evt *)(Node->Value); + + /* Est-on à la fin du nom du type d'événement */ + + if (i == EVENT_NB_DIM - 1 || !Tab_Dim [i + 1]) + { + Evt->Terminal = TRUE; + Evt->Id = Id; + Evt->Gravite = Gravite; + Evt->RC = RC; + Evt->Rooting = Rooting; + return LOGS_OK; + } + + /* Création de la dimension suivante si elle n'existe pas déjà */ + + if (!Evt->Next_Dim) + { + rc = DS_DataStruct_Open (LOG_Name_Prefix (LOGD_GDRT_NAME), &(Evt->Next_Dim), NDD_DS_TREE | NDD_MN_AUTO_EQU, LOG_FILE_MANAGER, 0, DSD_NEW, TRUE); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Event_Create : unable to create a data structure for the dimension %d", i + 1); + LOG_Error_Print (); + return rc; + } + + strcpy (Evt->Next_Dim->Manager, "LOG_GDRT_Dim_Manager"); + + (*Nb_Tree)++; + } + + Root = Evt->Next_Dim; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Recherche dans la table de routage par défaut (GDRT) */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_GDRT_Event_Find (LOGT_GDRT_Evt ** Evt, char ** Complete_Name, char * Event_Name) +{ + LOGT_Status rc; + char * ptr; + int i; + char * Tab_Dim [EVENT_NB_DIM]; + + *Evt = NULL; + + **Complete_Name = (char)0; + + ptr = strdup (Event_Name); + + for (i = 0; i < EVENT_NB_DIM; i++) Tab_Dim [i] = NULL; + + /* Récupération des dimensions du type d'événement */ + + i = 0; + + while (i < EVENT_NB_DIM) + { + Tab_Dim [i] = ptr; + + if (i < EVENT_NB_DIM - 1) + { + char sep = (i == 0 ? '@' : ':'); + + if ((ptr = strchr (Tab_Dim [i], sep))) + { + *ptr = (char)0; + ptr++; + } + else i = EVENT_NB_DIM; + } + i++; + } + + /* Recherche de l'événement */ + + rc = LOG_GDRT_Recursive_Find (Tab_Dim, LOG_Base->GDRT->Root, 0, Evt, Complete_Name); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_GDRT_Event_Find : unable to find event \"%s\"", Event_Name); + LOG_Error_Print (); + + free (Tab_Dim [0]); + + return rc; + } + + free (*Tab_Dim); + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Fonction de recherche récursive dans les différentes dimensions */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_GDRT_Recursive_Find (char ** Tab_Dim, NDT_Root * Root, int Dim, LOGT_GDRT_Evt ** Evt, char ** Complete_Name) +{ + LOGT_Status rc; + int Found, End; + NDT_Node * Node; + char Default_Name [10]; + char * Dim_Name; + char * ptr; + LOGT_GDRT_Evt To_Find; + + if (!Root || !Tab_Dim [Dim]) return LOGS_ERRAPI; + + /* Définition de la valeur par défaut à rechercher */ + + if (Dim == 0) strcpy (Default_Name, "DEFAULT"); + else strcpy (Default_Name, ""); + + Dim_Name = strdup (Tab_Dim [Dim]); + + /* Recherche du type d'événement le plus proche */ + + Found = End = FALSE; + + while (Found == FALSE && End == FALSE) + { + To_Find.Name = Dim_Name; + + if (ND_Node_Find (Root, &Node, &To_Find, NULL) == NDS_OK) + { + /* Résolution de la dimension suivante */ + + if (LOG_GDRT_Recursive_Find (Tab_Dim, ((LOGT_GDRT_Evt *)(Node->Value))->Next_Dim, Dim + 1, Evt, Complete_Name) == LOGS_OK) + { + Found = TRUE; + End = TRUE; + } + else + { + /* Le noeud trouvé est-il terminal ? */ + + if (((LOGT_GDRT_Evt *)(Node->Value))->Terminal == TRUE) + { + *Evt = (LOGT_GDRT_Evt *)(Node->Value); + Found = TRUE; + End = TRUE; + } + } + } + + if (End == FALSE) + { + ptr = strchr (Dim_Name, '.'); + if (ptr) *ptr = (char)0; + else + { + /* + Dernière chance de résoudre la dimension : + - "DEFAULT" pour le nom du type d'événement + - "" pour le contexte + */ + + if (!strcmp (Dim_Name, Default_Name)) End = TRUE; + else strcpy (Dim_Name, Default_Name); + } + } + } + + if (Found == TRUE) + { + if (strlen (Dim_Name)) + { + *Complete_Name -= strlen (Dim_Name); + memcpy (*Complete_Name, Dim_Name, strlen (Dim_Name)); + } + + if (Dim > 0) + { + *Complete_Name -= 1; + **Complete_Name = (Dim == 1 ? '@' : ':'); + } + + rc = LOGS_OK; + } + else rc = LOGS_KO; + + free (Dim_Name); + + return rc; +} + +/*------------------------------------------------------------------------------*/ +/* Sélection récursive des types d'événements dans la GDRT */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_GDRT_Recursive_Select (int Dim, NDT_Root * Root, LOGT_RTab * RTab, LOGT_RuleClass Rule_Class, LOGT_Rule * Rule, LOGT_Rooting Value, const char * Name, char * Compiled_RegExp) +{ + LOGT_Status rc; + NDT_Node * Node; + + if (!Root) return LOGS_ERRAPI; + + ND_Node_First_Get (Root, &Node); + + while (Node) + { + LOGT_GDRT_Evt * GDRT_Evt = (LOGT_GDRT_Evt *)(Node->Value); + int Selected = FALSE; + char Event_Name [81]; + LOGT_Rooting Rooting = (Value == LOGD_ROOTING_DEFAULT ? GDRT_Evt->Rooting : Value); + + if (Dim == 0) strcpy (Event_Name, GDRT_Evt->Name); + else sprintf (Event_Name, "%s%c%s", Name, Dim == 1 ? '@' : ':', GDRT_Evt->Name); + + if (GDRT_Evt->Terminal == TRUE) + { + /* On vérifie si le type d'événement correspond au critère de sélection */ + + switch (Rule_Class) + { + case LOGD_SELECT_ALL: + + Selected = TRUE; + break; + + case LOGD_SELECT_GRV: + + if (GDRT_Evt->Gravite == *(LOGT_Gravite *)Rule) Selected = TRUE; + break; + + case LOGD_SELECT_RC: + + if (GDRT_Evt->RC == *(LOGT_RC *)Rule) Selected = TRUE; + break; + + case LOGD_SELECT_TYPE: + + /* L'événement matche-t'il avec l'expression régulière ? */ + + if (RegExp_Match (Event_Name, Compiled_RegExp) && GDRT_Evt->Terminal == TRUE) Selected = TRUE; + break; + } + } + + if (Selected == TRUE) + { + NDT_Node * Tmp_Node; + LOGT_RTab_Evt Tmp_Evt; + + Tmp_Evt.Id = GDRT_Evt->Id; + + /* Si le type d'événement n'existe pas déjà, on l'ajoute à la table de routage utilisateur */ + + rc = DS_Node_Find (RTab->Root, &Tmp_Node, (void *)&Tmp_Evt, NULL); + if (rc != DSS_OK) + { + LOGT_RTab_Evt * RTab_Evt; + + rc = DS_Value_Alloc (RTab->Root, (void **)&RTab_Evt, GDRT_Evt->Id, Rooting); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Setup : unable to create event type %d for the user rooting table", GDRT_Evt->Id); + LOG_Error_Print (); + return rc; + } + + rc = DS_Value_Add (RTab->Root, (void *)RTab_Evt); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Setup : unable to add event type %d to the user rooting table", GDRT_Evt->Id); + LOG_Error_Print (); + return rc; + } + } + } + + LOG_GDRT_Recursive_Select (Dim + 1, GDRT_Evt->Next_Dim, RTab, Rule_Class, Rule, Value, Event_Name, Compiled_RegExp); + + ND_Node_Next_Get (Node, &Node); + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* AUTRES TABLES DE ROUTAGE (GMRT, LMRT, LDRT, URT) */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Manager des tables de routage autres que GDRT */ +/*------------------------------------------------------------------------------*/ +NDT_Status LOG_RTab_Manager (va_list Args) +{ + LOGT_Status rc; + NDT_Command Command = va_arg (Args, NDT_Command); + + if (Command == NDD_CMD_MAKE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_RTab_Evt ** RTab_Evt = (LOGT_RTab_Evt **) va_arg (Args, void **); + va_list Args_Value = va_arg (Args, va_list); + int Id = (int) va_arg (Args_Value, int); + LOGT_Rooting Rooting = (LOGT_Rooting) va_arg (Args_Value, LOGT_Rooting); + + DST_RootDesc * RootDesc = (DST_RootDesc *)(Root->User); + + rc = DS_Alloc (Root, sizeof (LOGT_RTab_Evt), (void **)RTab_Evt); + if (rc != NDS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Manager : unable to allocate a new event for rooting table \"%s\"", RootDesc ? RootDesc->Heap_Name : "User"); + LOG_Error_Print (); + return rc; + } + + (*RTab_Evt)->Id = Id; + (*RTab_Evt)->Rooting = Rooting; + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_VALUE) + { + LOGT_RTab_Evt * RTab_Evt = (LOGT_RTab_Evt *) va_arg (Args, void *); + FILE * Out = va_arg (Args, FILE *); + + fprintf (Out, "Evénement :\n\t- ID = %d\n\t- Routage = %s", RTab_Evt->Id, LOG_Rooting_Label_Get (RTab_Evt->Rooting)); + + return NDS_OK; + } + + if (Command == NDD_CMD_DELETE_VALUE) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + LOGT_RTab_Evt * RTab_Evt = (LOGT_RTab_Evt *) va_arg (Args, void *); + DST_RootDesc * RootDesc = (DST_RootDesc *)(Root->User); + + rc = DS_Free (Root, (void *)RTab_Evt); + if (rc != DSS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_RTab_Manager : unable to free an event of rooting table \"%s\"", RootDesc ? RootDesc->Heap_Name : "User"); + LOG_Error_Print (); + + return rc; + } + + return NDS_OK; + } + + if (Command == NDD_CMD_PRINT_INFO) + { + NDT_Root * Root = va_arg (Args, NDT_Root *); + FILE * Out = va_arg (Args, FILE *); + const char * Root_Type; + DST_RootDesc * RootDesc; + + switch ((int)(Root->Type & NDD_DS_MSK)) + { + case NDD_DS_LIST : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_ORDERED : Root_Type = "liste triée"; break; + case NDD_MN_FILO : Root_Type = "liste FILO"; break; + case NDD_MN_FIFO : Root_Type = "liste FIFO"; break; + default : Root_Type = "inconnu"; break; + } + break; + + case NDD_DS_TREE : + + switch ((int)(Root->Type & NDD_MN_MSK)) + { + case NDD_MN_AUTO_EQU : Root_Type = "arbre auto-équilibré"; break; + default : Root_Type = "arbre non auto-équilibré"; break; + } + break; + + default : Root_Type = "inconnu"; break; + } + + RootDesc = (DST_RootDesc *)(Root->User); + fprintf (Out, "\n%s\n\t- Structure = %s\n\t- Manager = %s\n\t- Nombre d'événements = %ld\n", RootDesc->Heap_Name, Root_Type, RootDesc->Manager_FileName, Root->Node_Number); + + if (Root->Type & NDD_DS_TREE) + fprintf (Out, "\t- Profondeur maxi = %ld\n\t- Profondeur mini = %ld\n\t- Différence maximale autorisée = %ld\n\t- Nombre d'équilibrages = %ld\n", Root->Max_Depth, Root->Min_Depth, Root->Max_Dif, Root->Nb_Equ); + + return NDS_OK; + } + + if (Command == NDD_CMD_COMP_VALUE) + { + LOGT_RTab_Evt * RTab_Evt1, * RTab_Evt2; + long comp; + + RTab_Evt1 = (LOGT_RTab_Evt *) va_arg (Args, void *); + RTab_Evt2 = (LOGT_RTab_Evt *) va_arg (Args, void *); + + va_end (Args); + + comp = RTab_Evt1->Id - RTab_Evt2->Id; + + if (comp < 0) return NDS_LOWER; + if (comp > 0) return NDS_GREATER; + return NDS_EQUAL; + } + + return NDS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS RELATIVES AUX EVENEMENTS */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Récupération des données de l'événement à partir d'une liste d'arguments */ +/* ou d'une chaîne de caractères. */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Data_Get (int Mode, char * Support, char ** Event_Data, size_t * Data_Size, va_list * Arg_Data, char * Str_Data) +{ + LOGT_Status rc; + char Event_Name [81]; + int Tag; + char Value [256]; + char Macro [256]; + int End = FALSE; + int Context = FALSE; + char * even [3] = {NULL, NULL, NULL}; + char * module [3] = {NULL, NULL, NULL}; + char * mode [3] = {NULL, NULL, NULL}; + char * geo [3] = {NULL, NULL, NULL}; + char * ptr; + char * Ptr_Data = Str_Data; + unsigned int i; + size_t New_Size; + + *Event_Data = NULL; + *Data_Size = 0; + + /* + Récupération des composants du nom de l'événement : + + EVEN1[.EVEN2[.EVEN3]]@[MODULE1[.MODULE2[.MODULE3]]]:[MODE1[.MODE2[.MODE3]]]:[GEO1[.GEO2[.GEO3]]] + + NB : le nom de l'événement est délimité par le tag END_NAME. + */ + + while (End == FALSE) + { + rc = LOG_Event_Data_Tag_Get (Mode, Arg_Data, &Ptr_Data, &Tag, Value); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Get : unable to retrieve event name from the data %s", Mode == DATA_ARG_LIST ? "argument list" : "string"); + LOG_Error_Print (); + return rc; + } + + switch (Tag) + { + case EVEN1: + even [0] = strdup (Value); + break; + + case EVEN2: + even [1] = strdup (Value); + break; + + case EVEN3: + even [2] = strdup (Value); + break; + + case MODULE1: + module [0] = strdup (Value); + Context = TRUE; + break; + + case MODULE2: + module [1] = strdup (Value); + Context = TRUE; + break; + + case MODULE3: + module [2] = strdup (Value); + Context = TRUE; + break; + + case MODE1: + mode [0] = strdup (Value); + Context = TRUE; + break; + + case MODE2: + mode [1] = strdup (Value); + Context = TRUE; + break; + + case MODE3: + mode [2] = strdup (Value); + Context = TRUE; + break; + + case GEO1: + geo [0] = strdup (Value); + Context = TRUE; + break; + + case GEO2: + geo [1] = strdup (Value); + Context = TRUE; + break; + + case GEO3: + geo [2] = strdup (Value); + Context = TRUE; + break; + + case END_NAME: + End = TRUE; + break; + + default : + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Get : unexpected tag %d before END_NAME", Tag); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + } + + /* Reconstitution du nom de l'événement */ + + if (!even [0]) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Get : tag EVEN1 must be defined before END_NAME"); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + strcpy (Event_Name, even [0]); + + for (i = 1; i < 3; i++) + { + if (even [i]) + { + strcat (Event_Name, "."); + strcat (Event_Name, even [i]); + free (even [i]); + } + else break; + } + + if (Context == TRUE) strcat (Event_Name, "@"); + else return LOGS_OK; + + for (i = 0; i < 3; i++) + { + if (module [i]) + { + strcat (Event_Name, i > 0 ? "." : ""); + strcat (Event_Name, module [i]); + free (module [i]); + } + else break; + } + + strcat (Event_Name, ":"); + + for (i = 0; i < 3; i++) + { + if (mode [i]) + { + strcat (Event_Name, i > 0 ? "." : ""); + strcat (Event_Name, mode [i]); + free (mode [i]); + } + else break; + } + + strcat (Event_Name, ":"); + + for (i = 0; i < 3; i++) + { + if (geo [i]) + { + strcat (Event_Name, i > 0 ? "." : ""); + strcat (Event_Name, geo [i]); + free (geo [i]); + } + else break; + } + + /* On recopie le nom de l'événement au début de la chaîne de caractères contenant les données */ + + *Data_Size = 0; + *Event_Data = NULL; + + i = strlen (Event_Name); + New_Size = *Data_Size + i + 1; + *Event_Data = (char *)realloc (*Event_Data, New_Size); + ptr = *Event_Data + *Data_Size; + *Data_Size = New_Size; + *ptr = (char)i; + ptr ++; + memcpy (ptr, (void *)Event_Name, i); + + /* On recopie le code support comme étant la première macro-donnée */ + + i = strlen (Support); + New_Size = *Data_Size + i + 1; + *Event_Data = (char *)realloc (*Event_Data, New_Size); + ptr = *Event_Data + *Data_Size; + *Data_Size = New_Size; + *ptr = (char)i; + ptr ++; + memcpy (ptr, (void *)Support, i); + + /* Récupération des macro-données associées à l'événement */ + + End = FALSE; + + while (End == FALSE) + { + unsigned int j; + + rc = LOG_Event_Data_Macro_Get (Mode, Arg_Data, &Ptr_Data, Macro, Value); + if (rc != LOGS_OK) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Get : unable to retrieve event macro data from the data %s", Mode == DATA_ARG_LIST ? "argument list" : "string"); + LOG_Error_Print (); + return rc; + } + + if (!strcmp (Macro, END_DATA)) break; + + i = strlen (Macro); + j = strlen (Value); + + New_Size = *Data_Size + i + j + 2; + *Event_Data = (char *)realloc (*Event_Data, New_Size); + ptr = *Event_Data + *Data_Size; + *Data_Size = New_Size; + *ptr = (char)i; + ptr ++; + memcpy (ptr, (void *)Macro, i); + ptr += i; + *ptr = (char)j; + ptr ++; + memcpy (ptr, (void *)Value, j); + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération d'un composant (tag et valeur) d'un nom d'événement */ +/* à partir d'une liste d'arguments ou d'une chaîne de caractères. */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Data_Tag_Get (int Mode, va_list * Arg_Data, char ** ptr, int * Tag, char * Value) +{ + if (Mode == DATA_ARG_LIST) + { + *Tag = va_arg (*Arg_Data, int); + if (*Tag != END_NAME) strcpy (Value, va_arg (*Arg_Data, char *)); + return LOGS_OK; + } + + if (Mode == DATA_STRING) + { + char sTag [256]; + + if (LOG_NextString_Get (ptr, sTag) != TRUE) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Tag_Get : missing tag after value %s", Value); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!strcmp (sTag, "EVEN1")) *Tag = EVEN1; + else if (!strcmp (sTag, "EVEN2")) *Tag = EVEN2; + else if (!strcmp (sTag, "EVEN3")) *Tag = EVEN3; + else if (!strcmp (sTag, "MODULE1")) *Tag = MODULE1; + else if (!strcmp (sTag, "MODULE2")) *Tag = MODULE2; + else if (!strcmp (sTag, "MODULE3")) *Tag = MODULE3; + else if (!strcmp (sTag, "MODE1")) *Tag = MODE1; + else if (!strcmp (sTag, "MODE2")) *Tag = MODE2; + else if (!strcmp (sTag, "MODE3")) *Tag = MODE3; + else if (!strcmp (sTag, "GEO1")) *Tag = GEO1; + else if (!strcmp (sTag, "GEO2")) *Tag = GEO2; + else if (!strcmp (sTag, "GEO3")) *Tag = GEO3; + else if (!strcmp (sTag, "END_NAME")) *Tag = END_NAME; + else *Tag = 0; + + if (*Tag != END_NAME) + { + char str [256]; + + if (LOG_NextString_Get (ptr, str) != TRUE) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Tag_Get : missing value after tag %s", sTag); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + strcpy (Value, str); + } + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération d'une macro donnée (tag et valeur) associé à une événement */ +/* à partir d'une liste d'arguments ou d'une chaîne de caractères. */ +/*------------------------------------------------------------------------------*/ +/* Pour une liste d'arguments, une macro-donnée est donnée par un triplet : */ +/* - nom (char *) */ +/* - type (int) */ +/* - valeur (char *) */ +/* */ +/* Pour une chaîne de caractères, une macro-donnée est donnée par un couple : */ +/* - nom (char *) */ +/* - valeur (char *) : les espaces sont remplacés par des '~' */ +/* */ +/* NB : les macro-données sont délimitées par le tag END_DATA. */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Data_Macro_Get (int Mode, va_list * Arg_Data, char ** ptr, char * Macro, char * Value) +{ + if (Mode == DATA_ARG_LIST) + { + int Type; + + strcpy (Macro, va_arg (*Arg_Data, char *)); + + if (!strcmp (Macro, END_DATA)) return LOGS_OK; + + Type = va_arg (*Arg_Data, int); + + switch (Type) + { + case STRING: + strcpy (Value, va_arg (*Arg_Data, char *)); + break; + + case CHAR: + sprintf (Value, "%c", *va_arg (*Arg_Data, char *)); + break; + + case SHORT: + sprintf (Value, "%d", *va_arg (*Arg_Data, short *)); + break; + + case INT: + sprintf (Value, "%d", *va_arg (*Arg_Data, int *)); + break; + + case LONG: + sprintf (Value, "%ld", *va_arg (*Arg_Data, long *)); + break; + + case FLOAT: + sprintf (Value, "%f", *va_arg (*Arg_Data, float *)); + break; + + case DOUBLE: + sprintf (Value, "%f", *va_arg (*Arg_Data, double *)); + break; + + default : + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Macro_Get : unexpected type %d after macro \"%s\"", Type, Macro); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + return LOGS_OK; + } + + if (Mode == DATA_STRING) + { + char * tmp; + + if (LOG_NextString_Get (ptr, Macro) != TRUE) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Macro_Get : missing macro after value %s", Value); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + if (!strcmp (Macro, END_DATA)) return LOGS_OK; + + if (LOG_NextString_Get (ptr, Value) != TRUE || !strcmp (Value, END_DATA)) + { + sprintf (LOG_Error_Msg, "Error LOG_Event_Data_Macro_Get : missing value after macro %s", Macro); + LOG_Error_Print (); + return LOGS_ERRAPI; + } + + /* On remplace les '~' par des espaces */ + + while ((tmp = strchr (Value, '~'))) *tmp = ' '; + + return LOGS_OK; + } + + return LOGS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération de la prochaine valeur dans une chaîne de caractères (valeurs */ +/* séparées par des espaces) */ +/*------------------------------------------------------------------------------*/ +int LOG_NextString_Get (char ** ptr, char * result) +{ + int i = 0; + + /* On recherche le premier caractère différent non blanc (espace, tab, newline) */ + + while (isspace ((int)(**ptr)) && **ptr != (char)0) (*ptr)++; + + if (**ptr == (char)0) return FALSE; + + /* On recopie le pointeur dans la chaîne résultat jusqu'au premier caractère blanc */ + + while (!isspace ((int)(**ptr)) && **ptr != (char)0) + { + result [i] = **ptr; + i++; + (*ptr)++; + } + + result [i] = (char)0; + + return TRUE; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* FONCTIONS DIVERSES */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Récupération du libellé d'un code retour */ +/*------------------------------------------------------------------------------*/ +char * LOG_RC_Label_Get (LOGT_RC RC) +{ + static char Label [20]; + + switch ((int)RC) + { + case LOGD_RC_OK: + strcpy (Label, "OK"); + break; + + case LOGD_RC_ANOERR: + strcpy (Label, "ANOERR"); + break; + + case LOGD_RC_REJDON: + strcpy (Label, "REJDON"); + break; + + case LOGD_RC_REJENR: + strcpy (Label, "REJENR"); + break; + + case LOGD_RC_WARNING: + strcpy (Label, "WARNING"); + break; + + case LOGD_RC_RECYCLE: + strcpy (Label, "RECYCLE"); + break; + + case LOGD_RC_EXIT: + strcpy (Label, "EXIT"); + break; + + case LOGD_RC_ABEND: + strcpy (Label, "ABEND"); + break; + + default : + strcpy (Label, "unknown"); + break; + } + + return Label; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du libellé d'un type de routage */ +/*------------------------------------------------------------------------------*/ +char * LOG_Rooting_Label_Get (LOGT_Rooting Rooting) +{ + static char Label [20]; + + switch ((int)Rooting) + { + case LOGD_ROOTING_NULL: + strcpy (Label, "NULL"); + break; + + case LOGD_ROOTING_STDERR: + strcpy (Label, "STDERR"); + break; + + case LOGD_ROOTING_DATABASE: + strcpy (Label, "BASE"); + break; + + case LOGD_ROOTING_DEFAULT: + strcpy (Label, "DEFAULT"); + break; + + case LOGD_ROOTING_PREVIOUS: + strcpy (Label, "PREVIOUS"); + break; + + default : + strcpy (Label, "unknown"); + break; + } + + return Label; +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du type de table de routage */ +/*------------------------------------------------------------------------------*/ +char * LOG_RTType_Label_Get ( LOGT_RTType RTabType ) +{ + static char Label [20]; + + switch ((int)RTabType) + { + case LOGD_GDRT: + strcpy (Label, "Global Default Rooting Table"); + break; + + case LOGD_GMRT: + strcpy (Label, "Global Master Rooting Table"); + break; + + case LOGD_LDRT: + strcpy (Label, "Local Default Rooting Table"); + break; + + case LOGD_LMRT: + strcpy (Label, "Local Master Rooting Table"); + break; + + case LOGD_URT: + strcpy (Label, "User Rooting Table"); + break; + + default : + strcpy (Label, "unknown"); + break; + } + + return Label; +} + +/*------------------------------------------------------------------------------*/ +/* Routine d'affichage d'un message d'erreur */ +/*------------------------------------------------------------------------------*/ +void LOG_Error_Print ( void ) +{ + if (LOG_stderr) fprintf (LOG_stderr, "%s\n", LOG_Error_Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Pour préfixer les noms de heap avec le contexte de la librairie LIBLOG */ +/*------------------------------------------------------------------------------*/ +static char * LOG_Name_Prefix ( const char * Name ) +{ + static char Prefixed [256]; + + sprintf (Prefixed, "%s/%s", LOG_PREFIX, Name); + + return Prefixed; +} diff --git a/lib/liblog.doc b/lib/liblog.doc new file mode 100644 index 0000000000000000000000000000000000000000..16290821a308da1fce2ceccfdfc94b823d248ef2 GIT binary patch literal 111616 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 T^G{6twb_FBagyqO(GmDxw3vsr literal 0 HcmV?d00001 diff --git a/lib/liblog.h b/lib/liblog.h new file mode 100644 index 0000000..622a80b --- /dev/null +++ b/lib/liblog.h @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Expressions régulières */ + +#ifdef LINUX +#include +typedef regex_t RegExp_t; +#define RegExp_Size sizeof (regex_t) +#define RegExp_Compile(s, e) regcomp (e, s, REG_NOSUB) == 0 +#define RegExp_Match(s, e) regexec (e, s, 0, NULL, 0) != REG_NOMATCH +#else +#include +typedef char RegExp_t; +#define RegExp_Size 256 +#define RegExp_Compile(s, e) compile (s, e, e + RegExp_Size) +#define RegExp_Match(s, e) step (s, e) +#endif + +extern char * strdup (const char *); + +/* Nom de la variable d'environnement définissant la valeur par défaut du module maître */ + +#define MASTER_MODULE_ENV "MASTER" + +#define LOG_FILE_MANAGER "liblog.so" + +/* Tous les heaps et data structures générés par la librairie LIBLOG sont préfixés */ + +#define LOG_PREFIX "LOG" + +/* Port de messages d'envoi des événements */ + +MSGT_Port * Send_Port; + +/* Elément du cache des modules */ + +typedef struct { + char * Name; /* Nom du module (sert à la recherche) */ + int Id; /* Identifiant numérique du type d'événement */ +} LOGT_Module; + +/* Elément de la table de routage GDRT */ + +typedef struct { + char * Name; /* Nom du type d'événement (base de recherche) */ + int Terminal; /* Signifie que le type d'événement existe sans contexte */ + int Id; /* Identifiant numérique du type d'événement */ + LOGT_Gravite Gravite; /* Code gravité */ + LOGT_RC RC; /* Code de retour servant au pilotage */ + LOGT_Rooting Rooting; /* Type de routage par défaut */ + NDT_Root * Next_Dim; /* Dimension suivante = pointeur sur un arbre */ +} LOGT_GDRT_Evt; + +#define EVENT_NB_DIM 4 + +/* Elément d'une table de routage quelconque (hormis la GDRT) */ + +typedef struct { + int Id; /* Identifiant numérique du type d'événement (sert à la recherche) */ + LOGT_Rooting Rooting; /* Type de routage */ +} LOGT_RTab_Evt; + + +/* Définition du nom des différentes ressources de la librairie */ + +/* + Heap dans lequel sera stockée la base de la librairie LIBLOG : + Ce heap ne contient que la structure LOGT_Base qui permet de référencer + les autres ressources système de la librairie. + + Ce heap ne sera constitué que d'une unique segment très petit. +*/ + +#define LOGD_BASE_HEAP_NAME "BASE" +#define LOGD_BASE_HEAP_SEGMENT_SIZE 100 + +/* + Heap dans lequel sont stockées les caches : + Ces heaps contiennent à priori un grand nombre de valeurs. + On les crée donc avec des segments de données suffisamment grands. +*/ + +#define LOGD_KMOD_SEGMENT_SIZE 50000 +#define LOGD_KMOD_NAME "KMOD" + +#define LOGD_KFORMAT_SEGMENT_SIZE 1100000 +#define LOGD_KFORMAT_NAME "KFORMAT" + +#define LOGD_GDRT_SEGMENT_SIZE 400000 +#define LOGD_GDRT_NAME "GDRT" + +/* + En règle générale, les tables de routage suivantes resteront vides : + Leur heap sont donc créés avec des segments de données relativement petits. +*/ + +#define LOGD_EMPTY_RTAB_SEGMENT_SIZE 3000 +#define LOGD_GMRT_NAME "GMRT" +#define LOGD_LDRT_NAME "LDRT" +#define LOGD_LMRT_NAME "LMRT" + +/* + Heap dans lequel sera stockée les listes de tables de routage : + Ces liste ne contiendront pas à priori un grand nombre de valeurs. + Les heaps sous-jacents n'ont donc pas besoin besoin d'être très grands. +*/ + +#define LOGD_RTAB_LIST_SEGMENT_SIZE 100240 +#define LOGD_CHANNEL_LIST_NAME "CHANNEL_REF" +#define LOGD_LDRT_LIST_NAME "LDRT_REF" +#define LOGD_LMRT_LIST_NAME "LMRT_REF" +#define LOGD_URT_LIST_NAME "URT_REF" + +/* Elément d'une structure de compteurs d'événement */ + +typedef struct { + char * Name; /* Nom du type d'événement */ + int Total; /* Nombre total d'envois */ +} LOGT_Event_Cpt; + +SMT_Heap * LOG_Base_Heap; + +/* Compteur d'ouverture de la librairie */ + +unsigned int LOG_Open_Counter = 0; + +/* Flux de sortie des messages d'erreur générés par la librairie */ + +FILE * LOG_stderr; + +/* Entêtes des fonctions privées */ + +NDT_Status LOG_Base_RTabList_Manager (va_list args_ptr); +NDT_Status LOG_Base_ChannelList_Manager (va_list args_ptr); + +NDT_Status LOG_GDRT_Manager (va_list); +NDT_Status LOG_GDRT_Dim_Manager (va_list); +LOGT_Status LOG_GDRT_Event_Find (LOGT_GDRT_Evt **, char **, char *); +LOGT_Status LOG_GDRT_Recursive_Find (char **, NDT_Root *, int, LOGT_GDRT_Evt **, char **); +LOGT_Status LOG_GDRT_Event_Create (const char *, int, LOGT_Gravite, LOGT_RC, LOGT_Rooting, int *); +LOGT_Status LOG_GDRT_Recursive_Select (int, NDT_Root *, LOGT_RTab *, LOGT_RuleClass, LOGT_Rule *, LOGT_Rooting, const char *, char *); + +NDT_Status LOG_KMOD_Manager (va_list); + +NDT_Status LOG_KFORMAT_Manager (va_list); +NDT_Status LOG_KFORMAT_DataList_Manager (va_list); + +NDT_Status LOG_Channel_RTabList_Manager (va_list); +NDT_Status LOG_Channel_Event_CptList_Manager (va_list); +NDT_Status LOG_Channel_SubModuleList_Manager (va_list); +NDT_Status LOG_Channel_TriggerList_Manager (va_list); +LOGT_Status LOG_Channel_Rooting_Find (LOGT_Channel *, int, LOGT_Rooting *); + +NDT_Status LOG_RTab_Manager (va_list); + +#define DATA_ARG_LIST 1 +#define DATA_STRING 2 + +LOGT_Status LOG_Event_Internal_Send (int, LOGT_Channel *, LOGT_RC *, char *, va_list, char *); +LOGT_Status LOG_Event_Data_Get (int, char *, char **, size_t *, va_list *, char *); +LOGT_Status LOG_Event_Data_Tag_Get (int, va_list *, char **, int *, char *); +LOGT_Status LOG_Event_Data_Macro_Get (int, va_list *, char **, char *, char *); + +int LOG_NextString_Get (char ** ptr, char * result); + +char * LOG_RTType_Label_Get (LOGT_RTType); +char * LOG_RC_Label_Get (LOGT_RC); +char * LOG_Rooting_Label_Get (LOGT_Rooting); + +void LOG_Error_Print(void); + +static char * LOG_Name_Prefix (const char *); diff --git a/lib/libtool.3 b/lib/libtool.3 new file mode 100644 index 0000000..a639100 --- /dev/null +++ b/lib/libtool.3 @@ -0,0 +1,424 @@ +'\" t +.\" @(#)LIBTOOL.3 1.0 00/22/02 SMA; +.TH LIBTOOL 3 "22 Feb 2000" +.SH NOM +LIBTOOL (utilitaires pour la librairie LIBLOG) +.SH SYNOPSIS +.LP +.BI "cc [flag ...] file ... -lver -ldl -lnode -lshmem -ldatastr -ladm -llog -ltool [library ...]" +.LP +.BI "#include " +.LP +.BI "TLT_Status TL_Library_Stderr_Set ( FILE * " Out ");" +.LP +.BI "TLT_Status TL_LIBLOG_Load ( TL_Cache " To_Load " );" +.LP +.BI "TLT_Status TL_LIBLOG_Unload ( TL_Cache " To_Unload " );" +.LP +.BI "TLT_Status TL_Channel_RTab_Add ( LOGT_Channel * " Channel ", char * " Kunf_Name " );" +.LP +.BI "TLT_Status TL_Channel_Trigger_Add ( LOGT_Channel * " Channel ", char * " Kunf_Name " );" +.LP +.SH DESCRIPTION +.LP +La bibliotheque LIBTOOL fournit un ensemble d'utilitaires lies a la librairie LIBLOG : +.LP +.RS 3 +- Creation de tables de routage et de triggers a partir de fichiers de configuration KUNF +.LP +- Mise a jour des caches de donnees de la librairie LIBLOG (cache des modules, cache des formats d'evenement, table de routage par defaut +.RS -3 +.LP +.SH FONCTIONS +.LP +.BI "TLT_Status TL_Library_Stderr_Set ( FILE * " Out " );" +.LP +.RS 3 +Cette fonction permet de definir +.I Out +comme la sortie standard des messages d'erreur de la librarie. +.RS -3 +.LP +.BI "TLT_Status TL_LIBLOG_Load ( TL_Cache " To_Load " );" +.LP +.RS 3 +Cette fonction permet de charger les caches de donnees de la base de la librairie LIBLOG +.LP +L'argument +.I To_Load +represente la liste des caches de donnees a charger +, sous forme d'une combinaison binaire des trois valeurs suivantes : +.LP +.RS 3 +- +.B TLD_KMOD +: pour charger le cache de modules +.LP +- +.B TLD_KFORMAT +: pour charger le cache de formats d'evenement +.LP +- +.B TLD_GDRT +: pour charger la table de routage par defaut +.LP +.RS -3 +NB : les caches doivent etre prealablement vides avant d'etre charges. +.LP +.RS -3 +.BI "TLT_Status TL_LIBLOG_Unload ( TL_Cache " To_Unload " );" +.LP +.RS 3 +Cette fonction permet de vider les caches de donnees de la base de la librairie LIBLOG +.LP +L'argument +.I To_Unload +represente la liste des caches de donnees a vider +, sous forme d'une combinaison binaire des trois valeurs suivantes : +.RS 3 +.LP +- +.B TLD_KMOD +: pour vider le cache de modules +.LP +- +.B TLD_KFORMAT +: pour vider le cache de formats d'evenement +.LP +- +.B TLD_GDRT +: pour vider la table de routage par defaut +.RS -3 +.LP +.RS -3 +.BI "TLT_Status TL_Channel_RTab_Add ( LOGT_Channel * " Channel ", char * " Kunf_Name " );" +.LP +.RS 3 +Cette fonction permet d'ajouter toutes les tables de routage d'une section KUNF a un channel. +.LP +Elle attend les parametres suivants : +.LP +.RS 3 +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (In) +.I Kunf_Name +: le nom de la section KUNF +.RS -3 +.LP +.RS -3 +.BI "TLT_Status TL_Channel_Trigger_Add ( LOGT_Channel * " Channel ", char * " Kunf_Name " );" +.LP +.RS 3 +Cette fonction permet d'ajouter tous les triggers d'une section KUNF a un channel. +.LP +Elle attend les parametres suivants : +.RS 3 +.LP +* (In) +.I Channel +: un pointeur sur le channel +.LP +* (In) +.I Kunf_Name +: le nom de la section KUNF +.RS -3 +.LP +.SH FICHIER DE CONFIGURATION +.LP +Le fichier KUNF contient deux types de sections: +.RS 3 +.LP +- +.B [ROOTING_TABLE] +: liste des tables de routage +.LP +- +.B [TRIGGER] +: liste des triggers +.RS -3 +.LP +Chaque table de routage est identifiee par une sous-section de la forme +.B [ROOTING_TABLE:] +. +.LP +Les regles de routage sont designees par une section de la forme +.B [ROOTING_TABLE::] +. +.LP +Une regle de routage definit les proprietes suivantes : +.RS 3 +.LP +* +.B class +: ce tag definit la classe de la regle et peut prendre les valeurs suivantes : +.LP +.RS 3 +- +.B ALL +pour selectionner tous les evenements +.LP +- +.B GRV +pour selectionner les evenements selon leur gravite +.LP +- +.B RC +pour selectionner les evenements selon leur code retour associe +.LP +- +.B TYPE +pour selectionner les evenements selon leur type +.RS -3 +.LP +* +.B rule +: ce tag definit la regle elle-meme et peut prendre les valeurs suivantes : +.LP +.RS 3 +- pour la classe +.B ALL +: aucune valeur a definir +.LP +- pour la classe +.B GRV +: +.B INFO +, +.B TRACE +, +.B FONCT +, +.B DETAIL +, +.B STAT +, +.B ERR +, +.B REJDON +, +.B REJENR +, +.B WARNING +, +.B RECYCLE +, +.B EXIT +, +.B ABEND +.LP +- pour la classe +.B RC +: +.B OK +, +.B ANOERR +, +.B REJDON +, +.B REJENR +, +.B WARNING +, +.B RECYCLE +, +.B EXIT +, +.B ABEND +.LP +- pour la classe +.B TYPE +: expression reguliere sur le type d'evenement +.LP +.I Attention +: le caractere ':' etant interdit dans les sections kunf, on le notera conventionnellement par "{2pts}". +.LP +Les expressions regulieres seront notees selon le standard UNIX (voir regexp). +.LP +.RS -3 +* +.B rooting +: ce tag definit le routage associe a la regle et peut prendre les valeurs suivantes : +.LP +.RS 3 +- +.B DATABASE +: routage de l'evenement vers la base de suivi +.LP +- +.B STDERR +: routage de l'evenement vers la sortie standard d'erreur +.LP +- +.B NULL +: routage de l'evenement vers /dev/null (i.e l'evenement n'est pas traite) +.LP +- +.B DEFAULT +: routage par defaut +.LP +- +.B PREVIOUS +: routage de la table precedente du channel +.RS -3 +.LP +.RS -3 +Chaque trigger est identifie par une section de la forme +.B [ROOTING_TABLE:] +. +.LP +A un trigger sont associees plusieurs proprietes : +.RS 3 +.LP +* +.B event +: ce tag designe le type d'evenement declencheur du trigger (expression reguliere) +.LP +* +.B type +: ce tag definit le type du trigger et peut prendre les valeurs suivantes : +.RS 3 +.LP +- +.B ADD +pour un trigger qui ajoute une table de routage a un channel +.LP +- +.B REMOVE +pour un trigger qui supprime une table de routage d'un channel +.RS -3 +.LP +* +.B mode +: ce tag designe la persistance du trigger et peut prendre les valeurs suivantes : +.RS 3 +.LP +- +.B ONE_SHOT +pour un trigger qui ne fonctionne qu'une seule fois +.LP +- +.B PERMANENT +pour un trigger qui fonctionne tant qu'il n'est pas desactive +.RS -3 +.LP +* +.B rooting_table +: ce tag definit le nom de la table de routage concernee par le trigger +.RS -3 +.LP +.LP +.I Exemple +: +.LP +.RS 3 +[ROOTING_TABLE] +.LP +[ROOTING_TABLE:TOTO] +.LP +[ROOTING_TABLE:TOTO:RULE1] +.LP +class=ALL +.LP +rooting=DATABASE +.LP +[ROOTING_TABLE:TOTO:RULE2] +.LP +class=RC +.LP +rule=REJENR +.LP +rooting=STDERR+DATABASE +.LP +[ROOTING_TABLE:TOTO:RULE3] +.LP +class=TYPE +.LP +rule=COMPTEUR.* +.LP +rooting=NULL +.LP +[ROOTING_TABLE:TITI] +.LP +[ROOTING_TABLE:TOTO:RULE1] +.LP +class=ALL +.LP +rooting=PREVIOUS +.LP +[ROOTING_TABLE:TOTO:RULE2] +.LP +class=GRV +.LP +rule=WARNING +.LP +rooting=DEFAULT +.LP +[ROOTING_TABLE:TOTO:RULE3] +.LP +class=RC +.LP +rule=ABEND +.LP +rooting=STDERR +.LP +[ROOTING_TABLE:TOTO:RULE4] +.LP +class=TYPE +.LP +rule=*SQLERR* +.LP +rooting=STDERR +.LP +[TRIGGER] +.LP +[TRIGGER:TATA] +.LP +event=COMPTEUR.*@.*{2pts}.*{2pts}TB.* +.LP +type=ADD +.LP +rooting_table=TOTO +.LP +mode=ONE_SHOT +.LP +.RS -3 +Dans l'exemple ci-dessus, le fichier de configuration definit deux tables de routage nommees TOTO (3 regles) et TITI (4 regles) et un trigger nomme TATA. +.LP +.I NB +: les noms des regles de routage sont libres. Ils doivent seulement etre differents les uns des autres pour une meme table de routage. +.LP +Pour davantage de precisions sur la notion de table de routage ou de trigger, le lecteur se referera a la documentation de la librairie LIBLOG. +.LP +.RS -3 +.SH CODES RETOUR +.LP +Toutes les fonctions constituant l'API de la librairie LIBTOOL retournent un code de type +.B TLT_Status +: +.LP +.RS 3 +- +.B TLS_OK +si la fonction s'est correctement executee +.LP +- +.B TLS_KO +si une erreur s'est produite +.RS -3 +.LP +En cas d'erreur, la variable +.B TL_Error_Msg +contient un message du type : +.LP +.RS 3 +Error : +.RS -3 +.LP +Dans une prochaine version, la librairie proposera des codes retour plus explicites, permettant de distinguer les differents types d'erreur. +.LP +.SH VOIR AUSSI +.B liblog +(3) diff --git a/lib/libtool.doc b/lib/libtool.doc new file mode 100644 index 0000000000000000000000000000000000000000..20c610854b9f75f6e43f455f8023fc47de1b6a94 GIT binary patch literal 47104 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 UubQo1oAaGBjn);eA6E(d4}<|_6#xJL literal 0 HcmV?d00001 diff --git a/lib/libtool.h b/lib/libtool.h new file mode 100644 index 0000000..c36daa2 --- /dev/null +++ b/lib/libtool.h @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern char * strdup (const char *); + +FILE * TL_stderr = NULL; + +char TL_Info_Msg[256]; + +/* Déclarations pour ORACLE */ + +void pipo(void); +void pipo(void) +{ + unsigned int x; + x = sqlstm.sqlvsn; +} + +#define sqlstm _sqlstm + +extern void sqlglm(char *, size_t *, size_t *); + +#define SQL_OK 0 +#define SQL_NO_DATA_FOUND 1403 +#define SQL_FETCHED_COLUMN_NULL -1405 + +char * oracx = NULL; + +void TL_Info_Print (void); +void TL_Error_Print (void); +TLT_Status TL_RTab_Add (LOGT_Channel *, char *); +TLT_Status TL_Trigger_Add (LOGT_Channel *, char *); +TLT_Status TL_GDRT_Load(void); +TLT_Status TL_KMOD_Load(void); +TLT_Status TL_KFORMAT_Load(void); +TLT_Status TL_GDRT_Unload(void); +TLT_Status TL_KMOD_Unload(void); +TLT_Status TL_KFORMAT_Unload(void); +TLT_Status TL_Param_Get (void); +TLT_Status TL_Database_Connect (void); +char * Oracle_Message_Get (void); +char * trim (char *); + diff --git a/lib/libtool.pc b/lib/libtool.pc new file mode 100644 index 0000000..583f83c --- /dev/null +++ b/lib/libtool.pc @@ -0,0 +1,1369 @@ +/* + Utilisation des API de la LIBDATASTR en mode optimisé : + - pas de vérif systématique des arguments + - pas de verrouillage systématique des data structures +*/ + +#define DS_MODE 2 + +/* Utilisation des API de la LIBLOG en mode optimisé */ + +#define LOG_MODE 1 + +#include + +VER_INFO_EXPORT (libtool, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +EXEC SQL INCLUDE SQLCA; +EXEC SQL INCLUDE ORACA; +EXEC ORACLE OPTION (ORACA=YES); + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Library_Stderr_Set ( FILE * Out ) +{ + TL_stderr = Out; + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Chargement des caches de la librairie LIBLOG */ +/*------------------------------------------------------------------------------*/ +/* (I) ToLoad : liste des caches de données à charger */ +/* (combinaison de TLD_KMOD, TLD_KFORMAT et TLD_GDRT) */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_LIBLOG_Load ( TLT_Cache ToLoad ) +{ + int Locked; + + if (!LOG_Base) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : the LIBLOG library is not open"); + TL_Error_Print (); + return TLS_KO; + } + + if (TL_Param_Get () != TLS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to retrieve parameters from KUNF"); + TL_Error_Print (); + return TLS_KO; + } + + /* Connexion à la base de données du suivi */ + + if (TL_Database_Connect () != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to connect to database"); + TL_Error_Print (); + return TLS_KO; + } + + if (ToLoad & TLD_KMOD) + { + /* Verrouillage du cache des modules */ + + if (DS_DataStruct_Lock (LOG_Base->KMOD, DSD_WRITE, &Locked) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to lock the KMOD data structure for writing"); + TL_Error_Print (); + return TLS_KO; + } + + /* Conversion du cache des modules en liste FIFO pour faciliter les insertions */ + + if (DS_DataStruct_Convert (LOG_Base->KMOD, NDD_DS_LIST|NDD_MN_FIFO) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to convert the KMOD data structure to a FIFO list"); + TL_Error_Print (); + return TLS_KO; + } + + /* Chargement du cache des modules */ + + if (TL_KMOD_Load () != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to load KMOD data structure from database"); + TL_Error_Print (); + return TLS_KO; + } + + /* Conversion du cache des modules en arbre auto-équilibré pour faciliter les recherches */ + + if (DS_DataStruct_Convert (LOG_Base->KMOD, NDD_DS_TREE|NDD_MN_AUTO_EQU) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to convert the KMOD data structure to a tree"); + TL_Error_Print (); + return TLS_KO; + } + + /* Déverrouillage du cache des modules */ + + if (DS_DataStruct_Unlock (LOG_Base->KMOD) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to unlock the KMODdata structure"); + TL_Error_Print (); + return TLS_KO; + } + } + + if (ToLoad & TLD_KFORMAT) + { + /* Verrouillage du cache des formats d'événement */ + + if (DS_DataStruct_Lock (LOG_Base->KFORMAT, DSD_WRITE, &Locked) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to lock the KFORMAT data structure for writing"); + TL_Error_Print (); + return TLS_KO; + } + + /* Conversion du cache des formats d'événement en liste FIFO pour faciliter les insertions */ + + if (DS_DataStruct_Convert (LOG_Base->KFORMAT, NDD_DS_LIST|NDD_MN_FIFO) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to convert the KFORMAT data structure to a FIFO list"); + TL_Error_Print (); + return TLS_KO; + } + + /* Chargement du cache des formats d'événement */ + + if (TL_KFORMAT_Load () != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to load KFORMAT data structure from database"); + TL_Error_Print (); + return TLS_KO; + } + + /* Conversion du cache des formats d'événement en arbre auto-équilibré pour faciliter les recherches */ + + if (DS_DataStruct_Convert (LOG_Base->KFORMAT, NDD_DS_TREE|NDD_MN_AUTO_EQU) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to convert the KFORMAT data structure to a tree"); + TL_Error_Print (); + return TLS_KO; + } + + /* Déverrouillage du cache des formats d'événement */ + + if (DS_DataStruct_Unlock (LOG_Base->KFORMAT) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to unlock the KFORMAT data structure"); + TL_Error_Print (); + return TLS_KO; + } + } + + if (ToLoad & TLD_GDRT) + { + /* Verrouillage de la table de routage GDRT en écriture */ + + if (DS_DataStruct_Lock (LOG_Base->GDRT->Root, DSD_WRITE, &Locked) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to lock the GDRT data structure for writing"); + TL_Error_Print (); + return TLS_KO; + } + + /* Conversion de la table de routage GDRT en liste FIFO pour faciliter les insertions */ + + if (DS_DataStruct_Convert (LOG_Base->GDRT->Root, NDD_DS_LIST|NDD_MN_FIFO) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to convert the GDRT data structure to a FIFO list"); + TL_Error_Print (); + return TLS_KO; + } + + /* Chargement de la table de routage GDRT */ + + if (TL_GDRT_Load () != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to load the GDRT data structure from database"); + TL_Error_Print (); + return TLS_KO; + } + + /* Conversion de la table de routage GDRT en arbre auto-équilibré pour faciliter les recherches */ + + if (DS_DataStruct_Convert (LOG_Base->GDRT->Root, NDD_DS_TREE|NDD_MN_AUTO_EQU) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to convert the GDRT data structure to a tree"); + TL_Error_Print (); + return TLS_KO; + } + + /* Déverrouillage de la table de routage GDRT */ + + if (DS_DataStruct_Unlock (LOG_Base->GDRT->Root) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Load : unable to unlock the GDRT data structure"); + TL_Error_Print (); + return TLS_KO; + } + } + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Déchargement des caches de la librairie LIBLOG */ +/*------------------------------------------------------------------------------*/ +/* (I) ToUnload : liste des caches de données à décharger */ +/* (combinaison de TLD_KMOD, TLD_KFORMAT et TLD_GDRT) */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_LIBLOG_Unload (TLT_Cache ToUnload) +{ + SMT_Heap * Heap; + size_t Size; + int Locked; + + if (!LOG_Base) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : the LIBLOG library is not open"); + TL_Error_Print (); + return TLS_KO; + } + + if (ToUnload & TLD_KMOD) + { + /* Verrouillage du cache des modules */ + + if (DS_DataStruct_Lock (LOG_Base->KMOD, DSD_WRITE, &Locked) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to lock the KMOD data structure for writing"); + TL_Error_Print (); + return TLS_KO; + } + + /* Déchargement du cache des modules */ + + if (TL_KMOD_Unload () != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to unload KMOD data structure"); + TL_Error_Print (); + return TLS_KO; + } + + /* Compression du heap sous-jacent */ + + if (SM_Heap_IsOpen (( (DST_RootDesc *)(LOG_Base->KMOD->User))->Heap_Name, &Heap) == SMS_OK) + SM_Heap_Compress (Heap, &Size); + + /* Déverrouillage du cache des modules */ + + if (DS_DataStruct_Unlock (LOG_Base->KMOD) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to unlock the KMOD data structure"); + TL_Error_Print (); + return TLS_KO; + } + } + + if (ToUnload & TLD_KFORMAT) + { + /* Verrouillage du cache des formats d'événement en écriture */ + + if (DS_DataStruct_Lock (LOG_Base->KFORMAT, DSD_WRITE, &Locked) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to lock the KFORMAT data structure for writing"); + TL_Error_Print (); + return TLS_KO; + } + + /* Déchargement du cache des formats d'événement */ + + if (TL_KFORMAT_Unload () != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to unload KFORMAT data structure"); + TL_Error_Print (); + return TLS_KO; + } + + /* Compression du heap sous-jacent */ + + if (SM_Heap_IsOpen (( (DST_RootDesc *)(LOG_Base->KFORMAT->User))->Heap_Name, &Heap) == SMS_OK) + SM_Heap_Compress (Heap, &Size); + + /* Déverrouillage du cache des formats d'événement */ + + if (DS_DataStruct_Unlock (LOG_Base->KFORMAT) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to unlock the KFORMAT data structure"); + TL_Error_Print (); + return TLS_KO; + } + } + + if (ToUnload & TLD_GDRT) + { + /* Verrouillage de la table de routage GDRT en écriture */ + + if (DS_DataStruct_Lock (LOG_Base->GDRT->Root, DSD_WRITE, &Locked) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to lock the GDRT data structure for writing"); + TL_Error_Print (); + return TLS_KO; + } + + /* Déchargement de la table GDRT */ + + if (TL_GDRT_Unload () != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to unload GDRT data structure"); + TL_Error_Print (); + return TLS_KO; + } + + /* Compression du heap sous-jacent */ + + if (SM_Heap_IsOpen (( (DST_RootDesc *)(LOG_Base->GDRT->Root->User))->Heap_Name, &Heap) == SMS_OK) + SM_Heap_Compress (Heap, &Size); + + /* Déverrouillage de la table de routage GDRT */ + + if (DS_DataStruct_Unlock (LOG_Base->GDRT->Root) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_LIBLOG_Unload : unable to unlock the GDRT data structure"); + TL_Error_Print (); + return TLS_KO; + } + } + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Affectation de toutes les tables de routage d'une section KUNF à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) Kunf_Name : nom de la section KUNF */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Channel_RTab_Add (LOGT_Channel * My_Channel, const char * Kunf_Name) +{ + KITEM * Item; + + if (!My_Channel) + { + sprintf (TL_Error_Msg, "Error TL_Channel_RTab_Add : the channel is null"); + TL_Error_Print (); + return TLS_KO; + } + + kunfig_open (NULL, KUNFIG_OPEN_SIMPLEACCESS|KUNFIG_OPEN_OVERRIDINGENV); + + /* Recherche de la section KUNF passée en paramètre */ + + Item = kunfig_directfindentry (Kunf_Name); + + if (!Item) + { + sprintf (TL_Error_Msg, "Error TL_Channel_RTab_Add : unable to find section \"%s\"", Kunf_Name); + TL_Error_Print (); + + kunfig_close (); + + return TLS_KO; + } + + /* On descend dans l'arborescence de la section pour récupérer la liste des tables de routage */ + + Item = kunfig_down (Item, KUNFIG_LOCAL); + + while (Item) + { + char * Table_Name = kunfig_getname (Item); + char Name [256]; + + sprintf (Name, "%s:%s", Kunf_Name, Table_Name); + + if (TL_RTab_Add (My_Channel, Name) != TLS_OK) + { + sprintf (TL_Error_Msg, "Error TL_Channel_RTab_Add : unable to add rooting table %s to the channel", Table_Name); + TL_Error_Print (); + + kunfig_close (); + + return TLS_KO; + } + + Item = kunfig_next (Item, KUNFIG_LOCAL); + } + + kunfig_close (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Affectation de tous les triggers d'une section KUNF à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) Kunf_Name : nom de la section KUNF */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Channel_Trigger_Add (LOGT_Channel * My_Channel, const char * Kunf_Name) +{ + KITEM * Item; + + if (!My_Channel) + { + sprintf (TL_Error_Msg, "Error TL_Channel_Trigger_Add : the channel is null"); + TL_Error_Print (); + return TLS_KO; + } + + kunfig_open (NULL, KUNFIG_OPEN_SIMPLEACCESS|KUNFIG_OPEN_OVERRIDINGENV); + + /* Recherche de la section KUNF passée en paramètre */ + + Item = kunfig_directfindentry (Kunf_Name); + + if (!Item) + { + sprintf (TL_Error_Msg, "Error TL_Channel_Trigger_Add : unable to find section \"%s\"", Kunf_Name); + TL_Error_Print (); + + kunfig_close (); + + return TLS_KO; + } + + /* On descend dans l'arborescence de la section pour récupérer la liste des triggers */ + + Item = kunfig_down (Item, KUNFIG_LOCAL); + + while (Item) + { + char * Trigger_Name = kunfig_getname (Item); + char Name [256]; + + sprintf (Name, "%s:%s", Kunf_Name, Trigger_Name); + + if (TL_Trigger_Add (My_Channel, Name) != TLS_OK) + { + sprintf (TL_Error_Msg, "Error TL_Channel_Trigger_Add : unable to add trigger %s to the channel", Trigger_Name); + TL_Error_Print (); + + kunfig_close (); + + return TLS_KO; + } + + Item = kunfig_next (Item, KUNFIG_LOCAL); + } + + kunfig_close (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ +/* Fonctions privées */ +/*------------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------*/ +/* Chargement du cache des modules */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_KMOD_Load ( void ) +{ + int Id_Module; + char Cd_Module [81]; + + int Nb_Modules = 0; + + /* Récupération des modules */ + + EXEC SQL DECLARE cursor_module CURSOR FOR SELECT ID_MODULE, CD_MODULE FROM TB_MODULE WHERE DAT_FIN_EFFET IS NOT NULL; + + EXEC SQL OPEN cursor_module; + + if (sqlca.sqlcode != SQL_OK) + { + sprintf (TL_Error_Msg, "Error TL_KMOD_Load : unable to open cursor to retrieve modules from the database (%s)", Oracle_Message_Get ()); + TL_Error_Print (); + EXEC SQL CLOSE cursor_module; + return TLS_KO; + } + + EXEC SQL FETCH cursor_module INTO :Id_Module, :Cd_Module; + + while (sqlca.sqlcode == SQL_OK || sqlca.sqlcode == SQL_FETCHED_COLUMN_NULL) + { + void * Value; + + if (DS_Value_Alloc (LOG_Base->KMOD, &Value, trim (Cd_Module), Id_Module) != NDS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KMOD_Load : unable to create a module for the KMOD data structure"); + TL_Error_Print (); + return TLS_KO; + } + + if (DS_Value_Add (LOG_Base->KMOD, Value) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KMOD_Load : unable to add a module to the KMOD data structure"); + TL_Error_Print (); + EXEC SQL CLOSE cursor_module; + return TLS_KO; + } + + Nb_Modules++; + + EXEC SQL FETCH cursor_module INTO :Id_Module, :Cd_Module; + } + + if (sqlca.sqlcode != SQL_NO_DATA_FOUND) + { + sprintf (TL_Error_Msg, "Error TL_KMOD_Load : unable to fetch cursor to retrieve modules from the database (%s)", Oracle_Message_Get ()); + TL_Error_Print (); + EXEC SQL CLOSE cursor_module; + return TLS_KO; + } + + EXEC SQL CLOSE cursor_module; + + sprintf (TL_Info_Msg, "TL_KMOD_Load : %d module(s) loaded in the KMOD data structure", Nb_Modules); + TL_Info_Print (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Déchargement du cache des modules */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_KMOD_Unload ( void ) +{ + if (DS_DataStruct_Traverse (LOG_Base->KMOD, NDD_CMD_DELETE_VALUE, NULL) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KMOD_Unload : unable to delete all values from the KMOD data structure"); + TL_Error_Print (); + return TLS_KO; + } + + sprintf (TL_Info_Msg, "The KMOD data structure has been successfully unloaded"); + TL_Info_Print (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Chargement du cache des formats d'événement */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_KFORMAT_Load ( void ) +{ + char Data [81]; + unsigned int Event_Type; + LOGT_Event_Format * Format; + NDT_Node * Node; + char * Format_Data; + int Nb_Event_Format = 0; + int Nb_Event_Data = 0; + + /* Récupération des formats d'événement */ + + EXEC SQL DECLARE cursor_format CURSOR FOR + SELECT TB_TYPE_EVEN.CD_TYPE_EVEN, TB_DONNEE.CD_DONNEE + FROM TB_TYPE_EVEN, TA_DONNEE_FORMAT, TB_DONNEE + WHERE TB_TYPE_EVEN.ID_FORMAT = TA_DONNEE_FORMAT.ID_FORMAT + AND TA_DONNEE_FORMAT.DAT_EFFET_FORMAT <= SYSDATE + AND TA_DONNEE_FORMAT.DAT_EFFET <= SYSDATE + AND TB_DONNEE.CD_DONNEE = TA_DONNEE_FORMAT.CD_DONNEE + AND TB_DONNEE.DAT_EFFET = TA_DONNEE_FORMAT.DAT_EFFET_DONNEE; + + EXEC SQL OPEN cursor_format; + + if (sqlca.sqlcode != SQL_OK) + { + sprintf (TL_Error_Msg, "Error TL_KFORMAT_Load : unable to open cursor to retrieve event formats from the database (%s)", Oracle_Message_Get ()); + TL_Error_Print (); + EXEC SQL CLOSE cursor_format; + return TLS_KO; + } + + EXEC SQL FETCH cursor_format INTO :Event_Type, :Data; + + while (sqlca.sqlcode == SQL_OK || sqlca.sqlcode == SQL_FETCHED_COLUMN_NULL) + { + LOGT_Event_Format Tmp_Event_Format; + + Tmp_Event_Format.Event_Type = Event_Type; + + if (ND_Node_Find (LOG_Base->KFORMAT, &Node, (void *)(&Tmp_Event_Format), NULL) != NDS_OK) + { + /* Création du format de l'événement */ + + if (DS_Value_Alloc (LOG_Base->KFORMAT, (void **)&Format, Event_Type) != NDS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KFORMAT_Load : unable to create a value for the KFORMAT data structure"); + TL_Error_Print (); + EXEC SQL CLOSE cursor_format; + return TLS_KO; + } + + if (DS_Value_Add (LOG_Base->KFORMAT, (void *)Format) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KFORMAT_Load : unable to add an event format to the KFORMAT data structure"); + TL_Error_Print (); + EXEC SQL CLOSE cursor_format; + return TLS_KO; + } + + Nb_Event_Format++; + } + else + Format = (LOGT_Event_Format *)(Node->Value); + + /* Création de la donnée du format */ + + if (DS_Value_Alloc (Format->Data_List, (void **)&Format_Data, trim (Data)) != NDS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KFORMAT_Load : unable to create a data for the event format data list"); + TL_Error_Print (); + EXEC SQL CLOSE cursor_format; + return TLS_KO; + } + + if (DS_Value_Add (Format->Data_List, (void *)Format_Data) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KFORMAT_Load : unable to add a data to the event format data list"); + TL_Error_Print (); + EXEC SQL CLOSE cursor_format; + return TLS_KO; + } + + Nb_Event_Data++; + + EXEC SQL FETCH cursor_format INTO :Event_Type, :Data; + } + + if (sqlca.sqlcode != SQL_NO_DATA_FOUND) + { + sprintf (TL_Error_Msg, "Error TL_KFORMAT_Load : unable to fetch cursor to retrieve formats from the database (%s)", Oracle_Message_Get ()); + TL_Error_Print (); + EXEC SQL CLOSE cursor_format; + return TLS_KO; + } + + EXEC SQL CLOSE cursor_format; + + sprintf (TL_Info_Msg, "TL_KFORMAT_Load : %d format(s) and %d data(s) loaded in the KFORMAT data structure", Nb_Event_Format, Nb_Event_Data); + TL_Info_Print (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Déchargement du cache des formats d'événement */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_KFORMAT_Unload ( void ) +{ + if (DS_DataStruct_Traverse (LOG_Base->KFORMAT, NDD_CMD_DELETE_VALUE, NULL) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_KFORMAT_Unload : unable to delete all values from the KFORMAT data structure"); + TL_Error_Print (); + return TLS_KO; + } + + sprintf (TL_Info_Msg, "The KFORMAT data structure has been successfully unloaded"); + TL_Info_Print (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Chargement de la table de routage par défaut (GDRT) */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_GDRT_Load ( void ) +{ + int cd_type_even; + int cd_retour; + char cd_gravite [2]; + int rooting; + char nom_type_even [81]; + int Nb_Event = 0; + int Nb_Tree = 0; + + /* Sélection des types d'événement correspondant à la règle */ + + EXEC SQL DECLARE cursor_evt CURSOR FOR + SELECT CD_TYPE_EVEN, NOM_TYPE_EVEN, TB_TYPE_EVEN.CD_GRAVITE, CD_RETOUR, NIV_SORTIE FROM TB_TYPE_EVEN, TB_GRAVITE WHERE TB_TYPE_EVEN.CD_GRAVITE = TB_GRAVITE.CD_GRAVITE; + + EXEC SQL OPEN cursor_evt; + + if (sqlca.sqlcode != SQL_OK) + { + sprintf (TL_Error_Msg, "Error TL_GDRT_Load : unable to open cursor to retrieve event types from the database (%s)", Oracle_Message_Get ()); + TL_Error_Print (); + EXEC SQL CLOSE cursor_evt; + return TLS_KO; + } + + EXEC SQL FETCH cursor_evt INTO :cd_type_even, :nom_type_even, :cd_gravite, :cd_retour, :rooting; + + while (sqlca.sqlcode == SQL_OK || sqlca.sqlcode == SQL_FETCHED_COLUMN_NULL) + { + if (ND_Manager_Exec (LOG_Base->GDRT->Root->Manager, NDD_CMD_MAKE_VALUE, trim (nom_type_even), cd_type_even, (LOGT_Gravite)cd_gravite [0], (LOGT_RC)cd_retour, (LOGT_Rooting)rooting, &Nb_Tree) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_GDRT_Load : unable to add event \"%s\" to the GDRT data structure", trim (nom_type_even)); + TL_Error_Print (); + EXEC SQL CLOSE cursor_evt; + return TLS_KO; + } + + Nb_Event++; + + EXEC SQL FETCH cursor_evt INTO :cd_type_even, :nom_type_even, :cd_gravite, :cd_retour, :rooting; + } + + if (sqlca.sqlcode != SQL_NO_DATA_FOUND) + { + sprintf (TL_Error_Msg, "Error TL_GDRT_Load : unable to fetch cursor to retrieve event types from the database (%s)", Oracle_Message_Get ()); + TL_Error_Print (); + EXEC SQL CLOSE cursor_evt; + return TLS_KO; + } + + EXEC SQL CLOSE cursor_evt; + + sprintf (TL_Info_Msg, "TL_GDRT_Load : %d event(s) loaded (%d tree(s) created) in the GDRT data structure", Nb_Event, Nb_Tree); + TL_Info_Print (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Déchargement de la table de routage GDRT */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_GDRT_Unload ( void ) +{ + if (DS_DataStruct_Traverse (LOG_Base->GDRT->Root, NDD_CMD_DELETE_VALUE, NULL) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_GDRT_Unload : unable to delete all values from the GDRT data structure"); + TL_Error_Print (); + return TLS_KO; + } + + sprintf (TL_Info_Msg, "The GDRT data structure has been successfully unloaded"); + TL_Info_Print (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Connexion à la base de suivi */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Database_Connect ( void ) +{ + EXEC SQL CONNECT :oracx; + + if (sqlca.sqlcode != SQL_OK) + { + sprintf (TL_Error_Msg, "Error TL_Database_Connect %s", Oracle_Message_Get ()); + TL_Error_Print (); + return TLS_KO; + } + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une table de routage utilisateur à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) Kunf_Name : nom de la section kunf de la table de routage */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_RTab_Add (LOGT_Channel * My_Channel, char * Kunf_Name) +{ + KITEM * Item; + LOGT_RuleClass RuleClass; + LOGT_Rule * Rule; + LOGT_Rooting Rooting; + LOGT_RTab * RTab; + char * ptr; + char RTab_Name [100]; + char sRule [256]; + + /* Recherche de la section relative à la table de routage */ + + Item = kunfig_directfindentry (Kunf_Name); + + if (!Item) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : unable to find section \"%s\"", Kunf_Name); + TL_Error_Print (); + return TLS_KO; + } + + /* Création de la table de routage utilisateur */ + + if ((ptr = strrchr (Kunf_Name, ':')) ) ptr ++; + else ptr = Kunf_Name; + + sprintf (RTab_Name, "%s_%d_%ld_%d", ptr, My_Channel->ModuleId, My_Channel->Pid, My_Channel->Id); + + if (LOG_RTab_Alloc (&RTab, RTab_Name) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : unable to allocate memory for rooting table %s", RTab_Name); + TL_Error_Print (); + + return TLS_KO; + } + + /* On descend dans l'arborescence de la table de routage pour récupérer les règles associées */ + + Item = kunfig_down (Item, KUNFIG_LOCAL); + + while (Item) + { + char Name [256]; + char * Value; + char * Rule_Name = kunfig_getname (Item); + + /* Récupération de la classe de la règle */ + + sprintf (Name, "%s:%s:class", Kunf_Name, Rule_Name); + Value = kunfig_directfindvalue (KUNFIG_LOCAL, Name); + + if (!Value) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : class is missing in section \"%s\"", Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + + if (!strcmp (Value, "ALL")) + RuleClass = LOGD_SELECT_ALL; + else if (!strcmp (Value, "GRV")) + RuleClass = LOGD_SELECT_GRV; + else if (!strcmp (Value, "RC")) + RuleClass = LOGD_SELECT_RC; + else if (!strcmp (Value, "TYPE")) + RuleClass = LOGD_SELECT_TYPE; + else + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : unknown class \"%s\" in section \"%s\"", Value, Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + + /* Récupération de la règle */ + + if (RuleClass != LOGD_SELECT_ALL) + { + sprintf (Name, "%s:%s:rule", Kunf_Name, Rule_Name); + Value = kunfig_directfindvalue (KUNFIG_LOCAL, Name); + + if (!Value) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : rule is missing in section \"%s\"", Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + } + + /* Vérifications d'usage sur la règle */ + + if (RuleClass == LOGD_SELECT_GRV) + { + LOGT_Gravite Gravite; + + if (!strcmp (Value, "INFO")) + { + Gravite = LOGD_GRV_INFO; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "TRACE")) + { + Gravite = LOGD_GRV_TRACE; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "FONCT")) + { + Gravite = LOGD_GRV_FONCT; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "DETAIL")) + { + Gravite = LOGD_GRV_DETAIL; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "STAT")) + { + Gravite = LOGD_GRV_STAT; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "ERR")) + { + Gravite = LOGD_GRV_ERR; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "REJDON")) + { + Gravite = LOGD_GRV_REJDON; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "REJENR")) + { + Gravite = LOGD_GRV_REJENR; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "WARNING")) + { + Gravite = LOGD_GRV_WARNING; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "RECYCLE")) + { + Gravite = LOGD_GRV_RECYCLE; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "EXIT")) + { + Gravite = LOGD_GRV_EXIT; + Rule = (LOGT_Rule *)(&Gravite); + } + else if (!strcmp (Value, "ABEND")) + { + Gravite = LOGD_GRV_ABEND; + Rule = (LOGT_Rule *)(&Gravite); + } + else + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : bad rule \"%s\" in section \"%s\"", Value, Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + } + else if (RuleClass == LOGD_SELECT_RC) + { + LOGT_RC RC; + + if (!strcmp (Value, "OK")) + { + RC = LOGD_RC_OK; + Rule = (LOGT_Rule *)(&RC); + } + else if (!strcmp (Value, "ANOERR")) + { + RC = LOGD_RC_ANOERR; + Rule = (LOGT_Rule *)(&RC); + } + else if (!strcmp (Value, "REJDON")) + { + RC = LOGD_RC_REJDON; + Rule = (LOGT_Rule *)(&RC); + } + else if (!strcmp (Value, "REJENR")) + { + RC = LOGD_RC_REJENR; + Rule = (LOGT_Rule *)(&RC); + } + else if (!strcmp (Value, "WARNING")) + { + RC = LOGD_RC_WARNING; + Rule = (LOGT_Rule *)(&RC); + } + else if (!strcmp (Value, "RECYCLE")) + { + RC = LOGD_RC_RECYCLE; + Rule = (LOGT_Rule *)(&RC); + } + else if (!strcmp (Value, "EXIT")) + { + RC = LOGD_RC_EXIT; + Rule = (LOGT_Rule *)(&RC); + } + else if (!strcmp (Value, "ABEND")) + { + RC = LOGD_RC_ABEND; + Rule = (LOGT_Rule *)(&RC); + } + else + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : bad rule \"%s\" in section \"%s\"", Value, Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + } + else if (RuleClass == LOGD_SELECT_TYPE) + { + /* La section kunf ne peut pas comporter le caractère ':' qui a donc été remplacé par "{2pts}" */ + + strcpy (sRule, Value); + + while ((ptr = strstr (sRule, "{2pts}")) ) + { + char Tmp [256]; + + strcpy (Tmp, ptr + 6); + + *ptr = ':'; + ptr++; + *ptr = (char)0; + strcat (sRule, Tmp); + } + + Rule = (LOGT_Rule *)sRule; + } + + /* Récupération du routage de la règle */ + + sprintf (Name, "%s:%s:rooting", Kunf_Name, Rule_Name); + Value = kunfig_directfindvalue (KUNFIG_LOCAL, Name); + + if (!Value) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : rooting is missing in section \"%s\"", Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + + Rooting = 0; + + if (strstr (Value, "DATABASE")) Rooting += LOGD_ROOTING_DATABASE; + + if (strstr (Value, "NULL")) Rooting += LOGD_ROOTING_NULL; + + if (strstr (Value, "STDERR")) Rooting += LOGD_ROOTING_STDERR; + + if (strstr (Value, "PREVIOUS")) Rooting += LOGD_ROOTING_PREVIOUS; + + if (strstr (Value, "DEFAULT")) Rooting += LOGD_ROOTING_DEFAULT; + + if (Rooting == 0) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : bad rooting \"%s\" in section \"%s\"", Value, Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + + /* Mise à jour de la table de routage */ + + if (LOG_RTab_Setup (RTab, RuleClass, Rule, Rooting) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : unable to apply rule %s to the rooting table", Rule_Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + + Item = kunfig_next (Item, KUNFIG_LOCAL); + } + + /* Ajout de la table de routage au channel */ + + if (LOG_RTab_Add (My_Channel, RTab) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_RTab_Add : unable to add rooting table %s to the channel", RTab_Name); + TL_Error_Print (); + + LOG_RTab_Free (RTab); + + return TLS_KO; + } + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un trigger à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) Kunf_Name : nom de la section kunf du trigger */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Trigger_Add (LOGT_Channel * My_Channel, char * Kunf_Name) +{ + LOGT_Trigger * Trigger; + LOGT_RTab * RTab; + char Type_Evt [256]; + LOGT_Flags Mode; + LOGT_Flags Type; + LOGT_RTab Tmp_RTab; + NDT_Node * Node; + char Name [256]; + char * Value; + + /* Récupération du type d'événement déclencheur du trigger (expression régulière) */ + + sprintf (Name, "%s:event", Kunf_Name); + Value = kunfig_directfindvalue (KUNFIG_LOCAL, Name); + + if (!Value) + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : missing trigger event type in section \"%s\"", Kunf_Name); + TL_Error_Print (); + + return TLS_KO; + } + else + { + char * ptr; + + /* La section kunf ne peut pas comporter le caractère ':' qui a donc été remplacé par "{2pts}" */ + + strcpy (Type_Evt, Value); + + while ((ptr = strstr (Type_Evt, "{2pts}")) ) + { + char Tmp [256]; + + strcpy (Tmp, ptr + 6); + + *ptr = ':'; + ptr++; + *ptr = (char)0; + strcat (Type_Evt, Tmp); + } + } + + /* Récupération du type du trigger */ + + sprintf (Name, "%s:type", Kunf_Name); + Value = kunfig_directfindvalue (KUNFIG_LOCAL, Name); + if (!Value) + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : missing trigger type in section \"%s\"", Kunf_Name); + TL_Error_Print (); + + return TLS_KO; + } + + /* Vérifications d'usage sur le type */ + + if (!strcmp (Value, "ADD")) + Type = LOGD_ADD; + else if (!strcmp (Value, "REMOVE")) + Type = LOGD_REMOVE; + else + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : bad trigger type \"%s\" in section \"%s\"", Value, Kunf_Name); + TL_Error_Print (); + + return TLS_KO; + } + + /* Récupération du mode de fonctionnement du trigger */ + + sprintf (Name, "%s:mode", Kunf_Name); + Value = kunfig_directfindvalue (KUNFIG_LOCAL, Name); + if (!Value) + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : missing trigger mode in section \"%s\"", Kunf_Name); + TL_Error_Print (); + + return TLS_KO; + } + + /* Vérifications d'usage sur le mode */ + + if (!strcmp (Value, "ONE_SHOT")) + Mode = LOGD_ONE_SHOT; + else if (!strcmp (Value, "PERMANENT")) + Mode = LOGD_PERMANENT; + else + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : bad trigger mode \"%s\" in section \"%s\"", Value, Kunf_Name); + TL_Error_Print (); + + return TLS_KO; + } + + /* Récupération de la table de routage concernée */ + + sprintf (Name, "%s:rooting_table", Kunf_Name); + Value = kunfig_directfindvalue (KUNFIG_LOCAL, Name); + + if (!Value) + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : missing trigger rooting table in section \"%s\"", Kunf_Name); + TL_Error_Print (); + } + + sprintf (Name, "%s_%d_%ld_%d", Value, My_Channel->ModuleId, My_Channel->Pid, My_Channel->Id); + Tmp_RTab.Name = Name; + + /* Recherche de la table de routage dans la liste de la base */ + + if (DS_Node_Find (LOG_Base->URT_List, &Node, (void *)(&Tmp_RTab), NULL) != DSS_OK) + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : rooting table \"%s\" is undefined", Value); + TL_Error_Print (); + + return TLS_KO; + } + + RTab = (LOGT_RTab *)(Node->Value); + + /* Création du trigger */ + + if (LOG_Trigger_Add (&Trigger, My_Channel, RTab, Type_Evt, Type | Mode) != LOGS_OK) + { + sprintf (TL_Error_Msg, "Error TL_Trigger_Add : unable to create trigger %s", Kunf_Name); + TL_Error_Print (); + return TLS_KO; + } + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Routine d'affichage d'un message d'erreur */ +/*------------------------------------------------------------------------------*/ +void TL_Error_Print ( void ) +{ + if (TL_stderr) fprintf (TL_stderr, "%s\n", TL_Error_Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Routine d'affichage d'un message d'information */ +/*------------------------------------------------------------------------------*/ +void TL_Info_Print ( void ) +{ + fprintf (stdout, "%s\n", TL_Info_Msg); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération des paramétres */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Param_Get ( void ) +{ + char * Login, * Pwd, * Sid, * Kunf_Name, * Env; + char Name [256]; + + if (kunfig_open (NULL, KUNFIG_OPEN_SIMPLEACCESS|KUNFIG_OPEN_OVERRIDINGENV) != KUNFIG_ERROR_NONE) + { + sprintf (TL_Error_Msg, "Error TL_Param_Get : unable to open kunfig file"); + TL_Error_Print (); + return TLS_KO; + } + + if ((Env = getenv ("BDM_PROFILE")) ) + { + Kunf_Name = (char * )malloc ( strlen ("ADMIN:INSTALL_SUIVI") + strlen (Env) + 2); + sprintf (Kunf_Name, "ADMIN:INSTALL_SUIVI:%s", Env); + } + else + Kunf_Name = strdup ("ADMIN:INSTALL_SUIVI"); + + /* Récupération des paramètres de connexion à la base de suivi */ + + sprintf (Name, "%s:login", Kunf_Name); + if ((Login = kunfig_directfindvalue (KUNFIG_INHERIT, Name)) == NULL) + { + sprintf (TL_Error_Msg, "Error TL_Param_Get : unable to find %s in KUNF", Name); + TL_Error_Print (); + free (Kunf_Name); + return TLS_KO; + } + + sprintf (Name, "%s:password", Kunf_Name); + if ((Pwd = kunfig_directfindvalue (KUNFIG_INHERIT, Name)) == NULL) + { + sprintf (TL_Error_Msg, "Error TL_Param_Get : unable to find %s in KUNF", Name); + TL_Error_Print (); + free (Kunf_Name); + return TLS_KO; + } + + if (oracx) free (oracx); + + sprintf (Name, "%s:instance", Kunf_Name); + if ((Sid = kunfig_directfindvalue (KUNFIG_INHERIT, Name)) ) + { + oracx = (char * )malloc (strlen (Login) + strlen (Pwd) + strlen (Sid) + 3); + sprintf (oracx, "%s/%s@%s", Login, Pwd, Sid); + } + else + { + oracx = (char * )malloc (strlen (Login) + strlen (Pwd) + 2); + sprintf (oracx, "%s/%s", Login, Pwd); + } + + free (Kunf_Name); + + kunfig_close (); + + return TLS_OK; +} + +/*------------------------------------------------------------------------------*/ +/* Suppression des espaces en début et fin de chaîne des caractères */ +/*------------------------------------------------------------------------------*/ +char * trim (char * str) +{ + char * ptr1, * ptr2; + + ptr1 = ptr2 = str; + + while (*ptr1 == ' ') ptr1++; + + if (ptr1 != str) + { + while (*ptr1 != '\0') + { + *ptr2 = *ptr1; + ptr2++; + ptr1++; + } + + *ptr2 = *ptr1; + } + else + { + while (*ptr1 != '\0') ptr1++; + ptr2 = ptr1; + } + + if (ptr2 > str) + { + ptr2--; + while (*ptr2 == ' ') ptr2--; + ptr2++; + *ptr2 = '\0'; + } + + return (str); +} + +/*------------------------------------------------------------------------------*/ +/* Récupération du message Oracle */ +/*------------------------------------------------------------------------------*/ +char * Oracle_Message_Get ( void ) +{ + size_t buf_len, oracle_text_len; + static char oracle_text [200]; + + buf_len = sizeof (oracle_text); + sqlglm (oracle_text, &buf_len, &oracle_text_len); + + trim (oracle_text); + + return oracle_text; +} diff --git a/lib/log.h b/lib/log.h new file mode 100644 index 0000000..902b269 --- /dev/null +++ b/lib/log.h @@ -0,0 +1,516 @@ +#ifndef _LIBLOG +#define _LIBLOG + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/*********** Anciennes librairies ************** +#include +#include +************************************************/ + +/* Codes retour des fonctions de l'API */ + +typedef int LOGT_Status; + +#define LOGS_OK DSS_OK /* La fonction s'est correctement exécutée et a produit un résultat */ +#define LOGS_KO DSS_KO /* La fonction s'est correctement exécutée mais n'a pas produit de résultat */ + +#define LOGS_ERRMEM MSGS_ERRMEM /* Problème d'allocation mémoire */ +#define LOGS_ERRAPI MSGS_ERRAPI /* Utilisation incorrecte des API */ +#define LOGS_ERRSHM MSGS_ERRSHM /* Problème relatif aux segments de mémoire partagée */ +#define LOGS_ERRSEM MSGS_ERRSEM /* Problème relatif à l'utilisation des sémaphores */ +#define LOGS_ERRSIG MSGS_ERRSIG /* Opération sur sémpahore interrompue par un signal système */ +#define LOGS_ERRDLL MSGS_ERRDLL /* Problème de chargement dynamique de librairie */ + +#define LOG_ERROR(s) (s < 0) /* Tous les codes retour négatifs correspondent à des erreurs */ + +/* Notion de routage (possibilité de les combiner par addition binaire) */ + +typedef int LOGT_Rooting; + +#define LOGD_ROOTING_DATABASE 0x01 /* Routage vers la base de suivi */ +#define LOGD_ROOTING_STDERR 0x02 /* Routage vers la sortie standard d'erreur */ +#define LOGD_ROOTING_DEFAULT 0x04 /* Routage de la table de routage par défaut */ +#define LOGD_ROOTING_PREVIOUS 0x08 /* Routage de la table de routage précédente */ +#define LOGD_ROOTING_NULL 0x10 /* Routage vers /dev/null */ + +#define LOGD_ROOTING_DATABASE_MSK(a) (LOGD_ROOTING_DATABASE & a) +#define LOGD_ROOTING_STDERR_MSK(a) (LOGD_ROOTING_STDERR & a) + +/* Notion de gravité (classe d'événement) */ + +typedef int LOGT_Gravite; + +#define LOGD_GRV_INFO 'I' +#define LOGD_GRV_TRACE 'T' +#define LOGD_GRV_FONCT 'F' +#define LOGD_GRV_DETAIL 'L' +#define LOGD_GRV_STAT 'S' +#define LOGD_GRV_ERR 'E' +#define LOGD_GRV_REJDON 'D' +#define LOGD_GRV_REJENR 'R' +#define LOGD_GRV_WARNING 'W' +#define LOGD_GRV_RECYCLE 'Y' +#define LOGD_GRV_EXIT 'X' +#define LOGD_GRV_ABEND 'A' + +/* Notion de code retour (pour le pilotage) */ + +typedef int LOGT_RC; + +#define LOGD_RC_OK 0 /* Continuation */ +#define LOGD_RC_ANOERR 4 /* Anomalie */ +#define LOGD_RC_REJDON 6 /* Rejet de la donnée */ +#define LOGD_RC_REJENR 7 /* Rejet de l'enregistrement */ +#define LOGD_RC_WARNING 8 /* Evénement inconnu */ +#define LOGD_RC_RECYCLE 10 /* Recyclage de l'enregistrement */ +#define LOGD_RC_EXIT 14 /* Sortie du traitement */ +#define LOGD_RC_ABEND 16 /* Interruption du traitement */ + +#define LOGD_RC_SIZE 17 /* Taille des tableaux de codes retour (voir fonction LOG_Event_Cpt_Get) */ + +/* Type de table de routage */ + +typedef int LOGT_RTType; + +#define LOGD_GMRT 0 /* Global Master Rooting Table */ +#define LOGD_LMRT 1 /* Local Master Rooting Table */ +#define LOGD_URT 2 /* User Rooting Table */ +#define LOGD_LDRT 3 /* Local Default Rooting Table */ +#define LOGD_GDRT 4 /* Global Default Rooting Table */ + +/* Notion de table de routage */ + +typedef struct { + char * Name; /* Nom de la table de routage */ + LOGT_RTType Type; /* Type de la table de routage */ + NDT_Root * Root; /* Pointeur sur la structure contenant les événements */ + int Nb_Channel; /* Nombre de canaux auquels est rattachée la table */ + pid_t Pid; /* Processus propriétaire de la table de routage (utile au garbage collector) */ +} LOGT_RTab; + + +#define LOGD_RTAB_DEFAULT 0 /* Référence à la table de routage par défaut */ +#define LOGD_RTAB_PREVIOUS 1 /* Référence à la table de routage précédente */ + +/* Notion de classe de règle de sélection des événements */ + +typedef int LOGT_RuleClass; + +#define LOGD_SELECT_ALL 1 /* Règle appliquée à tous les événements */ +#define LOGD_SELECT_GRV 2 /* Règle appliquée aux événements d'une certaine gravité */ +#define LOGD_SELECT_RC 3 /* Règle appliquée aux événements associés à un certain code retour */ +#define LOGD_SELECT_TYPE 4 /* Règle appliquée aux événements d'un certain type */ + +/* Notion de règle de sélection des événements */ + +typedef void LOGT_Rule; /* Contient le code gravité, code retour ou type d'événement selon la classe de la règle */ + +/* Différents indicateurs */ + +typedef int LOGT_Flags; + +/* Modes d'ouverture et de fermeture */ + +#define LOGD_CREATE SMD_CREATE /* Création */ +#define LOGD_OPEN SMD_OPEN /* Ouverture simple */ +#define LOGD_DESTROY SMD_DESTROY /* Destruction */ +#define LOGD_CLOSE SMD_CLOSE /* Fermeture simple */ + +/* Flags de debug sur l'ouverture de la librairie */ + +#define LOGD_DEBUG_NONE SMD_DEBUG_NONE /* pour n'afficher aucun message généré par les diverses librairies */ +#define LOGD_DEBUG SMD_DEBUG /* pour afficher les messages générés par la librairie */ +#define LOGD_DEBUG_ALL SMD_DEBUG_ALL /* pour afficher les messages générés par toutes les librairies sous-jacentes */ + +#define LOGD_DEBUG_MSK (MSGD_DEBUG & MSGD_DEBUG_ALL) + +/* Mode de fonctionnement d'un trigger */ + +#define LOGD_ADD 0x01 /* Trigger d'ajout de table de routage */ +#define LOGD_REMOVE 0x02 /* Trigger de suppression de table de routage */ +#define LOGD_ONE_SHOT 0x04 /* Trigger actif une seul fois */ +#define LOGD_PERMANENT 0x08 /* Trigger actif en permanence */ + +#define LOGD_ADD_MSK(a) (LOGD_ADD & a) +#define LOGD_REMOVE_MSK(a) (LOGD_REMOVE & a) +#define LOGD_ONE_SHOT_MSK(a) (LOGD_ONE_SHOT & a) +#define LOGD_PERMANENT_MSK(a) (LOGD_PERMANENT & a) + +/* Notion de channel */ + +typedef struct { + pid_t Pid; /* Processus propriétaire du channel */ + int Id; /* Identifiant du channel */ + int ModuleId; /* Identifiant du module envoyeur */ + int Master_ModuleId; /* Identifiant du module primaire */ + NDT_Root * RTab_List; /* Liste de tables de routage */ + NDT_Root * SubModule_List; /* Liste des sous-modules */ + NDT_Root * Trigger_List; /* Liste des triggers posés sur le channel */ + NDT_Root * Event_Cpt_List; /* Liste de compteurs d'événements */ +} LOGT_Channel; + +/* Notion de trigger (ajout ou suppression dynamique de tables de routage) */ + +typedef struct LOGT_Trigger +{ + char * Event_Name; /* Evénement déclencheur du trigger */ + LOGT_RTab * RTab; /* Table de routage utilisateur concernée */ + LOGT_Flags Mode; /* Mode de fonctionnement du trigger */ + LOGT_Channel * Channel; /* Channel auquel est rattaché le trigger */ +} LOGT_Trigger; + +/* Base système de la librairie LIBLOG */ + +typedef struct { + NDT_Root * KMOD; /* Cache des modules */ + NDT_Root * KFORMAT; /* Cache des formats d'événement */ + LOGT_RTab * GDRT; /* Table GDRT */ + LOGT_RTab * GMRT; /* Table GMRT */ + NDT_Root * LMRT_List; /* Liste des LMRT */ + NDT_Root * LDRT_List; /* Liste des LDRT */ + NDT_Root * URT_List; /* Liste des URT */ + NDT_Root * Channel_List; /* Liste des channels */ +} LOGT_Base; + +LOGT_Base * LOG_Base = NULL; + +/* Informations sur un type d'événement */ + +typedef struct { + unsigned int Event_Type; /* Identifiant du type d'événement */ + char * Event_Name; /* Nom du type d'événément */ + LOGT_Rooting Rooting; /* Routage associé */ + LOGT_Gravite Gravite; /* Code gravité associé */ + LOGT_RC RC; /* Code retour associé */ + NDT_Root * Data_List; /* Liste des données du format de l'événement */ +} LOGT_Info; + +/* Format d'un type d'événement */ + +typedef struct { + unsigned int Event_Type; /* Type d'événement */ + NDT_Root * Data_List; /* Liste des données du format */ +} LOGT_Event_Format; + +/* Message explicite des erreurs générées par la librairie LINLOG */ + +char LOG_Error_Msg [256]; + +/* Identifiant du port de messages pour l'envoi des événements */ + +#define LOGD_EVENT_PORT_NAME "EVENT_PORT" + +/* Type des messages qui contiennent les événements */ + +#define LOGD_EVENT_MSG_TYPE 100 + +/* + Formatage des événements par les clients de la LIBLOG : + + EVEN1[.EVEN2[.EVEN3]]@[MODULE1[.MODULE2[.MODULE3]]]:[MODE1[.MODE2[.MODE3]]]:[GEO1[.GEO2[.GEO3]]] + + */ + +#define EVEN1 0x00000101 +#define EVEN2 0x00000102 +#define EVEN3 0x00000103 +#define MODULE1 0x00000201 +#define MODULE2 0x00000202 +#define MODULE3 0x00000203 +#define MODE1 0x00000301 +#define MODE2 0x00000302 +#define MODE3 0x00000303 +#define GEO1 0x00000401 +#define GEO2 0x00000402 +#define GEO3 0x00000403 + +#define DEFAULT -1L +#define CHAR 0L +#define STRING 1L +#define SHORT 2L +#define INT 3L +#define LONG 4L +#define FLOAT 5L +#define DOUBLE 6L + +#define END_NAME -1 +#define END_DATA "END_DATA" + +/* Format d'un message contenant un événement */ + +#define EVENT_FORMAT_VERSION_SIZE 10 /* sur 10 caractères max */ +#define EVENT_FORMAT_VERSION "V1.0" + +/* Zone de données du message : + + - Version de format de message : 10 octets | + - Numéro de processus envoyeur : 4 octets | Entête + - Identifiant du module envoyeur : 4 octets | + - Identifiant du module primaire : 4 octets | + + - Identifiant du type d'événement : 4 octets + + - Taille du nom de l'événement : 1 octet | + - Nom de l'événement | + - Taille du code support : 1 octet | + - Code support | + - Taille du nom de la macro-donnée : 1 octet | Evénement | + - Nom de la macro-donnée | | + - Taille de la valeur de la macro-donnée : 1 octet | | N fois + - Valeur de la macro-donnée | | +*/ + +typedef struct { + char Version [EVENT_FORMAT_VERSION_SIZE]; + unsigned int Sending_Pid; + unsigned int ModuleId; + unsigned int Master_ModuleId; +} LOGT_Event_Msg_Header; + +typedef struct { + LOGT_Event_Msg_Header Header; + unsigned int Event_Type; + size_t Data_Size; + char Event_Data; +} LOGT_Event_Msg_Data; + +/* Définition des alias de l'API */ + +#ifndef LOG_MODE +#define LOG_MODE 0 +#endif + +#if LOG_MODE == 1 + + /* API sans vérification des arguments */ + +# define LOG_Library_Open LOG_Library_Open_I +# define LOG_Library_Close LOG_Library_Close_I +# define LOG_Library_Stderr_Set LOG_Library_Stderr_Set_I +# define LOG_Channel_Open LOG_Channel_Open_I +# define LOG_Channel_Enter LOG_Channel_Enter_I +# define LOG_Channel_Leave LOG_Channel_Leave_I +# define LOG_Channel_Close LOG_Channel_Close_I +# define LOG_RTab_Alloc LOG_RTab_Alloc_I +# define LOG_RTab_Setup LOG_RTab_Setup_I +# define LOG_RTab_Add LOG_RTab_Add_I +# define LOG_RTab_Remove LOG_RTab_Remove_I +# define LOG_RTab_Free LOG_RTab_Free_I +# define LOG_Trigger_Add LOG_Trigger_Add_I +# define LOG_Trigger_Remove LOG_Trigger_Remove_I +# define LOG_Event_Send LOG_Event_Send_I +# define LOG_Event_External_Send LOG_Event_External_Send_I +# define LOG_Event_Info_Get LOG_Event_Info_Get_I +# define LOG_Event_Cpt_Get LOG_Event_Cpt_Get_I + +#else + + /* API avec vérification des arguments */ + +# define LOG_Library_Open LOG_Library_Open_C +# define LOG_Library_Close LOG_Library_Close_C +# define LOG_Library_Stderr_Set LOG_Library_Stderr_Set_C +# define LOG_Channel_Open LOG_Channel_Open_C +# define LOG_Channel_Enter LOG_Channel_Enter_C +# define LOG_Channel_Leave LOG_Channel_Leave_C +# define LOG_Channel_Close LOG_Channel_Close_C +# define LOG_RTab_Alloc LOG_RTab_Alloc_C +# define LOG_RTab_Setup LOG_RTab_Setup_C +# define LOG_RTab_Add LOG_RTab_Add_C +# define LOG_RTab_Remove LOG_RTab_Remove_C +# define LOG_RTab_Free LOG_RTab_Free_C +# define LOG_Trigger_Add LOG_Trigger_Add_C +# define LOG_Trigger_Remove LOG_Trigger_Remove_C +# define LOG_Event_Send LOG_Event_Send_C +# define LOG_Event_External_Send LOG_Event_External_Send_C +# define LOG_Event_Info_Get LOG_Event_Info_Get_C +# define LOG_Event_Cpt_Get LOG_Event_Cpt_Get_C + +#endif + +/*------------------------------------------------------------------------------*/ +/* Ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Instance : numéro de l'instance à ouvrir */ +/* (I) Context : contexte d'utilisation de la librairie */ +/* (I) Open_Mode : mode d'ouverture de la librairie */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Open_I ( int Instance, const char * Context, LOGT_Flags Open_Mode ); +LOGT_Status LOG_Library_Open_C ( int Instance, const char * Context, LOGT_Flags Open_Mode ); + +/*------------------------------------------------------------------------------*/ +/* Fermeture de l'instance de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Close_Mode : mode de fermeture de la librairie */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Close_I ( LOGT_Flags Close_Mode ); +LOGT_Status LOG_Library_Close_C ( LOGT_Flags Close_Mode ); + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Library_Stderr_Set_I ( FILE * Out ); +LOGT_Status LOG_Library_Stderr_Set_C ( FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Création d'un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (O) Channel : adresse du pointeur sur le canal créé */ +/* (I) Pid : numéro du processus propriétaire du canal */ +/* (I) Channel_Id : identifiant du canal au sein du processus */ +/* (I) Module_Name : nom du module propriétaire du canal */ +/* (I) Master_Module_Name : nom du module primaire */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Open_I (LOGT_Channel ** Channel, int Pid, int Channel_Id, const char * Module_Name, const char * Master_Module_Name); +LOGT_Status LOG_Channel_Open_C (LOGT_Channel ** Channel, int Pid, int Channel_Id, const char * Module_Name, const char * Master_Module_Name); + +/*------------------------------------------------------------------------------*/ +/* Entrée dans un sous-module pour un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal */ +/* (I) SubModule_Name : nom du sous-module */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Enter_I ( LOGT_Channel * Channel, const char * SubModule_Name ); +LOGT_Status LOG_Channel_Enter_C ( LOGT_Channel * Channel, const char * SubModule_Name ); + +/*------------------------------------------------------------------------------*/ +/* Sortie d'un sous-module pour un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal */ +/* (I) SubModule_Name : nom du sous-module */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Leave_I ( LOGT_Channel * Channel, const char * SubModule_Name ); +LOGT_Status LOG_Channel_Leave_C ( LOGT_Channel * Channel, const char * SubModule_Name ); + +/*------------------------------------------------------------------------------*/ +/* Fermeture d'un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal à fermer */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Channel_Close_I ( LOGT_Channel * Channel); +LOGT_Status LOG_Channel_Close_C ( LOGT_Channel * Channel); + +/*------------------------------------------------------------------------------*/ +/* Création d'une table de routage utilisateur */ +/*------------------------------------------------------------------------------*/ +/* (O) RTab : adresse du pointeur sur la table de routage */ +/* (I) Name : nom de la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Alloc_I ( LOGT_RTab ** RTab, char * Name ); +LOGT_Status LOG_RTab_Alloc_C ( LOGT_RTab ** RTab, char * Name ); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une règle à une table de routage */ +/*------------------------------------------------------------------------------*/ +/* (I) RTab : pointeur sur la table de routage */ +/* (I) RuleClass : classe de la nouvelle règle */ +/* (I) Rule : pointeur sur la nouvelle règle */ +/* (I) Value : valeur de la nouvelle règle */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Setup_I ( LOGT_RTab * RTab, LOGT_RuleClass RuleClass, LOGT_Rule * Rule, LOGT_Rooting Value ); +LOGT_Status LOG_RTab_Setup_C ( LOGT_RTab * RTab, LOGT_RuleClass RuleClass, LOGT_Rule * Rule, LOGT_Rooting Value ); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'une table de routage à un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal de communication */ +/* (I) RTab : pointeur sur la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Add_I ( LOGT_Channel * Channel, LOGT_RTab * RTab ); +LOGT_Status LOG_RTab_Add_C ( LOGT_Channel * Channel, LOGT_RTab * RTab ); + +/*------------------------------------------------------------------------------*/ +/* Suppression d'une table de routage d'un canal de communication */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le canal de communication */ +/* (I) RTab : pointeur sur la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Remove_I ( LOGT_Channel * Channel, LOGT_RTab * RTab ); +LOGT_Status LOG_RTab_Remove_C ( LOGT_Channel * Channel, LOGT_RTab * RTab ); + +/*------------------------------------------------------------------------------*/ +/* Destruction d'une table de routage */ +/*------------------------------------------------------------------------------*/ +/* (I) RTab : pointeur sur la table de routage */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_RTab_Free_I ( LOGT_RTab * RTab ); +LOGT_Status LOG_RTab_Free_C ( LOGT_RTab * RTab ); + +/*------------------------------------------------------------------------------*/ +/* Ajout d'un trigger */ +/*------------------------------------------------------------------------------*/ +/* (O) Trigger : adresse du pointeur sur le trigger mis en place */ +/* (I) Channel : pointeur sur le canal de communication */ +/* (I) RTab : pointeur sur la table de routage à appliquer */ +/* (I) Type_Evt : type d'événement déclencheur ( expression régulière ) */ +/* (I) Mode : mode de fonctionnement du trigger */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Trigger_Add_I ( LOGT_Trigger ** Trigger, LOGT_Channel * Channel, LOGT_RTab * RTab, char * Type_Evt, LOGT_Flags Mode ); +LOGT_Status LOG_Trigger_Add_C ( LOGT_Trigger ** Trigger, LOGT_Channel * Channel, LOGT_RTab * RTab, char * Type_Evt, LOGT_Flags Mode ); + +/*------------------------------------------------------------------------------*/ +/* Suppression d'un trigger */ +/*------------------------------------------------------------------------------*/ +/* (I) Trigger : pointeur sur le trigger mis en place */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Trigger_Remove_I ( LOGT_Trigger * Trigger ); +LOGT_Status LOG_Trigger_Remove_C ( LOGT_Trigger * Trigger ); + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un événement */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un canal de communication */ +/* (O) RC : pointeur sur le code retour associé à l'événement */ +/* (I) Cd_Support : code du support source */ +/* (I) Data : données de l'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Send_I ( LOGT_Channel * Channel, LOGT_RC * RC, char * Cd_Support, va_list Data ); +LOGT_Status LOG_Event_Send_C ( LOGT_Channel * Channel, LOGT_RC * RC, char * Cd_Support, va_list Data ); + +/*------------------------------------------------------------------------------*/ +/* Envoi d'un événement ( PL/SQL ou shell ) */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : identifiant du channel */ +/* (I) Cd_Support : code du support source */ +/* (I) Data : données de l'événement */ +/*------------------------------------------------------------------------------*/ +/* (O) Retourne le code retour associé au type d'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_RC LOG_Event_External_Send_I ( LOGT_Channel * Channel, char * Cd_Support, char * Data ); +LOGT_RC LOG_Event_External_Send_C ( LOGT_Channel * Channel, char * Cd_Support, char * Data ); + +/*------------------------------------------------------------------------------*/ +/* Retourne les informations du type par lequel un événement est résolu */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un canal de communication */ +/* (O) Info : pointeur sur les informations à récupérer */ +/* (I) Event_Name : nom de l'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Info_Get_I ( LOGT_Channel * Channel, LOGT_Info ** Info, char * Event_Name ); +LOGT_Status LOG_Event_Info_Get_C ( LOGT_Channel * Channel, LOGT_Info ** Info, char * Event_Name ); + +/*------------------------------------------------------------------------------*/ +/* Retourne le nombre d'événements envoyés par code retour */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur un canal de communication */ +/* (O) Cpt : pointeur sur un tableau de compteurs d'événement */ +/* (I) RegExpr : expression régulière sur le nom d'événement */ +/*------------------------------------------------------------------------------*/ +LOGT_Status LOG_Event_Cpt_Get_I ( LOGT_Channel * Channel, int * Cpt [LOGD_RC_SIZE], char * RegExpr ); +LOGT_Status LOG_Event_Cpt_Get_C ( LOGT_Channel * Channel, int * Cpt [LOGD_RC_SIZE], char * RegExpr ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/tool.h b/lib/tool.h new file mode 100644 index 0000000..c4250c6 --- /dev/null +++ b/lib/tool.h @@ -0,0 +1,68 @@ +#ifndef _LIBTOOL +#define _LIBTOOL + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Codes retour des fonctions de l'API */ + +typedef int TLT_Status; + +#define TLS_OK LOGS_OK +#define TLS_KO LOGS_KO + +typedef int TLT_Cache; + +#define TLD_KMOD 0001 +#define TLD_KFORMAT 0010 +#define TLD_GDRT 0100 + +char TL_Error_Msg[256]; + +/*------------------------------------------------------------------------------*/ +/* Définition de la sortie standard des messages d'erreur de la librairie */ +/*------------------------------------------------------------------------------*/ +/* (I) Out : flux de sortie des messages d'erreur */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Library_Stderr_Set ( FILE * Out ); + +/*------------------------------------------------------------------------------*/ +/* Chargement des caches de la librairie LIBLOG */ +/*------------------------------------------------------------------------------*/ +/* (I) ToLoad : liste des caches de données à charger */ +/* (combinaison de TLD_KMOD, TLD_KFORMAT et TLD_GDRT) */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_LIBLOG_Load (TLT_Cache ToLoad); + +/*------------------------------------------------------------------------------*/ +/* Déchargement des caches de la librairie LIBLOG */ +/*------------------------------------------------------------------------------*/ +/* (I) ToUnload : liste des caches de données à décharger */ +/* (combinaison de TLD_KMOD, TLD_KFORMAT et TLD_GDRT) */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_LIBLOG_Unload (TLT_Cache ToUnload); + +/*------------------------------------------------------------------------------*/ +/* Affectation de toutes les tables de routage d'une section KUNF à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) Kunf_Nm : nom de la section KUNF */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Channel_RTab_Add (LOGT_Channel * My_Channel, const char * Kunf_Nm); + +/*------------------------------------------------------------------------------*/ +/* Affectation de tous les triggers d'une section KUNF à un channel */ +/*------------------------------------------------------------------------------*/ +/* (I) Channel : pointeur sur le channel */ +/* (I) Kunf_Nm : nom de la section KUNF */ +/*------------------------------------------------------------------------------*/ +TLT_Status TL_Channel_Trigger_Add (LOGT_Channel * My_Channel, const char * Kunf_Nm); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/util/logadmin.c b/util/logadmin.c new file mode 100644 index 0000000..72db8c8 --- /dev/null +++ b/util/logadmin.c @@ -0,0 +1,426 @@ +#include +#include +#include +#include +#include +#include +#include + +VER_INFO_EXPORT (logadmin, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +#define USAGE "Usage : %s [ --help | --version [-v] | --create | --destroy | --load [1|2|3] ] | --unload [1|2|3] ]\n" + +typedef struct { + double sec; + struct timeval start; + struct timeval stop; +} cpt; + +#define t_start(x){gettimeofday(&(x.start), NULL);} +#define t_stop(x){gettimeofday(&(x.stop), NULL); x.sec = (double)(x.stop.tv_sec) - (double)(x.start.tv_sec) + ((double)(x.stop.tv_usec) - (double)(x.start.tv_usec)) / 1000000;} +cpt t_exec; + +#define QUIT 0 +#define BASE_INIT 1 +#define BASE_OPEN 2 +#define BASE_INFO 3 +#define BASE_CLOSE 4 +#define BASE_END 5 +#define BASE_LOAD 6 +#define BASE_UNLOAD 7 +#define SHOW_CHANNEL_LIST 8 +#define SHOW_RTAB_LIST 9 +#define CHANNEL_DUMP 10 +#define RTAB_DUMP 11 +#define TEST_EVENT 12 + +char menu [1000]; +char tmp [100]; + +void init_menu (void); +int print_menu (void); +char * Get_Rooting (LOGT_Rooting); +char * Get_RC (LOGT_RC); + +int main (int argc, char ** argv) +{ + int choice, i; + char Name [100]; + LOGT_Channel * My_Channel; + char Answer[10]; + NDT_Node * Node; + NDT_Root * Root; + LOGT_RTab RTab; + int Mode; + LOGT_Info * Info; + + TL_Library_Stderr_Set (stderr); + + /* Lancement de commande d'administration ? */ + + if (argc >= 2) + { + if (!strcmp (argv [1], "--help")) + { + fprintf (stderr, USAGE, argv [0]); + return -1; + } + else if (!strcmp (argv [1], "--version")) + { + if (argc >= 3 && !strcmp (argv [2], "-v")) + return VER_Object_Print (stdout, VERD_VERBOSE); + else + return VER_Object_Print (stdout, VERD_MINIMAL); + } + else if (!strcmp (argv [1], "--create")) + { + if (SM_Library_Open (0, NULL, SMD_OPEN | SMD_DEBUG_ALL) != SMS_OK) + { + fprintf (stderr, "=> Impossible d'ouvrir l'instance de la LIBSHMEM\n"); + return -1; + } + + if (LOG_Library_Open (0, NULL, LOGD_CREATE | SMD_DEBUG_ALL) != LOGS_OK) + { + fprintf (stderr, "=> Création de la LIBLOG impossible\n"); + return -1; + } + + return 0; + } + else if (!strcmp (argv [1], "--load")) + { + Mode = 0; + + if (argc > 2) + { + if (strchr (argv [2], '1')) Mode += TLD_KMOD; + if (strchr (argv [2], '2')) Mode += TLD_KFORMAT; + if (strchr (argv [2], '3')) Mode += TLD_GDRT; + } + + if (LOG_Library_Open (0, NULL, LOGD_OPEN | SMD_DEBUG_ALL) != LOGS_OK) + { + fprintf (stderr, "=> Ouverture de la LIBLOG impossible\n"); + return -1; + } + + if (TL_LIBLOG_Load (Mode) != LOGS_OK) + { + fprintf (stderr, "=> Chargement de la LIBLOG impossible\n"); + return -1; + } + return 0; + } + else if (!strcmp (argv [1], "--unload")) + { + Mode = 0; + + if (argc > 2) + { + if (strchr (argv [2], '1')) Mode += TLD_KMOD; + if (strchr (argv [2], '2')) Mode += TLD_KFORMAT; + if (strchr (argv [2], '3')) Mode += TLD_GDRT; + } + + if (LOG_Library_Open (0, NULL, LOGD_OPEN | SMD_DEBUG_ALL) != LOGS_OK) + { + fprintf (stderr, "=> Ouverture de la LIBLOG impossible\n"); + return -1; + } + + if (TL_LIBLOG_Unload (Mode) != LOGS_OK) + { + fprintf (stderr, "=> Déchargement de la LIBLOG impossible\n"); + return -1; + } + return 0; + } + else if (!strcmp (argv [1], "--destroy")) + { + if (LOG_Library_Open (0, NULL, LOGD_OPEN | SMD_DEBUG_ALL) != LOGS_OK) + { + fprintf (stderr, "=> Ouverture de la LIBLOG à détruire impossible\n"); + return -1; + } + + if (LOG_Library_Close (LOGD_DESTROY) != LOGS_OK) + { + fprintf (stderr, "=> Destruction de la LIBLOG impossible\n"); + return -1; + } + return 0; + } + else + { + fprintf (stderr, USAGE, argv [0]); + return -1; + } + } + + /* Lancement du menu intercatif */ + + init_menu (); + + choice = print_menu (); + + while (choice != QUIT) + { + strcpy (Answer, "yes"); + + switch (choice) + { + case BASE_INIT: + fprintf (stdout, "\nReturn code = %s\n", \ + LOG_Library_Open (0, NULL, LOGD_CREATE | SMD_DEBUG_ALL) == LOGS_OK ? "OK" : "NOK" ); + break; + + case BASE_OPEN: + fprintf (stdout, "\nReturn code = %s\n", \ + LOG_Library_Open (0, NULL, LOGD_OPEN | SMD_DEBUG_ALL) == LOGS_OK ? "OK" : "NOK" ); + break; + + case BASE_END: + fprintf (stdout, "\nReturn code = %s\n", \ + LOG_Library_Close (LOGD_DESTROY) == LOGS_OK ? "OK" : "NOK" ); + break; + + case BASE_CLOSE: + fprintf (stdout, "\nReturn code = %s\n", \ + LOG_Library_Close (LOGD_CLOSE) == LOGS_OK ? "OK" : "NOK" ); + break; + + case BASE_INFO: + DS_DataStruct_Info_Print (LOG_Base->KMOD, stdout); + DS_DataStruct_Info_Print (LOG_Base->KFORMAT, stdout); + DS_DataStruct_Info_Print (LOG_Base->GDRT->Root, stdout); + DS_DataStruct_Info_Print (LOG_Base->LMRT_List, stdout); + DS_DataStruct_Info_Print (LOG_Base->LDRT_List, stdout); + DS_DataStruct_Info_Print (LOG_Base->URT_List, stdout); + DS_DataStruct_Info_Print (LOG_Base->Channel_List, stdout); + break; + + case BASE_LOAD: + fprintf (stdout, "\nCache to load ? (KMOD=1, KFORMAT=2, GDRT=3) "); + gets (Name); + Mode = 0; + if (strchr (Name, '1')) Mode |= TLD_KMOD; + if (strchr (Name, '2')) Mode += TLD_KFORMAT; + if (strchr (Name, '3')) Mode += TLD_GDRT; + fprintf (stdout, "\nReturn code = %s\n", TL_LIBLOG_Load (Mode) == LOGS_OK ? "OK" : "NOK" ); + + break; + + case BASE_UNLOAD: + fprintf (stdout, "\nCache to unload ? (KMOD=1, KFORMAT=2, GDRT=3) "); + gets (Name); + Mode = 0; + if (strchr (Name, '1')) Mode += TLD_KMOD; + if (strchr (Name, '2')) Mode += TLD_KFORMAT; + if (strchr (Name, '3')) Mode += TLD_GDRT; + fprintf (stdout, "\nReturn code = %s\n", TL_LIBLOG_Unload (Mode) == LOGS_OK ? "OK" : "NOK" ); + + break; + + case SHOW_RTAB_LIST: + DS_DataStruct_Print (LOG_Base->LMRT_List, stdout); + DS_DataStruct_Print (LOG_Base->LDRT_List, stdout); + DS_DataStruct_Print (LOG_Base->URT_List, stdout); + break; + + case SHOW_CHANNEL_LIST: + DS_DataStruct_Print (LOG_Base->Channel_List, stdout); + break; + + case CHANNEL_DUMP: + fprintf (stdout, "\nChannel address ? "); + gets (Name); + i = atoi (Name); + + if (DS_Node_Find (LOG_Base->Channel_List, &Node, (void *)i, NULL) != DSS_OK) + fprintf (stdout, "Unable to find channel at address %d\n", i); + else + { + My_Channel = (LOGT_Channel *)(Node->Value); + + ND_Manager_Exec (LOG_Base->Channel_List->Manager, NDD_CMD_PRINT_VALUE, &My_Channel, stdout); + + if (fprintf (stdout, "\n\nShow rooting tables ? (y/n) ") && gets (tmp) && *tmp == 'y') + DS_DataStruct_Print (My_Channel->RTab_List, stdout); + + if (fprintf (stdout, "\nShow submodules ? (y/n) ") && gets (tmp) && *tmp == 'y') + DS_DataStruct_Print (My_Channel->SubModule_List, stdout); + + if (fprintf (stdout, "\nShow triggers ? (y/n) ") && gets (tmp) && *tmp == 'y') + DS_DataStruct_Print (My_Channel->Trigger_List, stdout); + + if (fprintf (stdout, "\nShow event counters ? (y/n) ") && gets (tmp) && *tmp == 'y') + DS_DataStruct_Print (My_Channel->Event_Cpt_List, stdout); + } + break; + + case RTAB_DUMP: + fprintf (stdout, "\nTable Name ? "); + gets (Name); + RTab.Name = Name; + if ((DS_Node_Find (LOG_Base->LMRT_List, &Node, &RTab, NULL) == DSS_OK && (Root = LOG_Base->LMRT_List)) || + (DS_Node_Find (LOG_Base->LDRT_List, &Node, &RTab, NULL) == DSS_OK && (Root = LOG_Base->LDRT_List)) || + (DS_Node_Find (LOG_Base->URT_List, &Node, &RTab, NULL) == DSS_OK && (Root = LOG_Base->URT_List))) + { + ND_Manager_Exec (Root->Manager, NDD_CMD_PRINT_VALUE, (void **)&(Node->Value), stdout); + + if (fprintf (stdout, "\n\nShow events ? (y/n) ") && gets (tmp) && *tmp == 'y') + DS_DataStruct_Print (((LOGT_RTab *)(Node->Value))->Root, stdout); + } + else + fprintf (stdout, "\nUnable to find rooting table \"%s\"\n", Name); + + break; + + case TEST_EVENT: + fprintf (stdout, "\nEvent name ? "); + gets (Name); + Info = (LOGT_Info *)malloc(sizeof(LOGT_Info)); + t_start (t_exec); + if (LOG_Event_Info_Get(NULL, &Info, Name) != LOGS_OK) + { + fprintf (stdout, "\nEvénement \"%s\" non résolu\n", Name); + t_stop (t_exec); + } + else + { + t_stop (t_exec); + fprintf (stdout, "\nEvénement \"%s\" résolu en %.4f sec :\n", Name, t_exec.sec); + fprintf (stdout, "\t- Type : %s (%d)\n", Info->Event_Name, Info->Event_Type); + fprintf (stdout, "\t- Routage : %s\n", Get_Rooting(Info->Rooting)); + fprintf (stdout, "\t- Gravité : %c\n", (char)Info->Gravite); + fprintf (stdout, "\t- Code retour : %s\n", Get_RC(Info->RC)); + fprintf (stdout, "\t- Format :"); + if (Info->Data_List) + { + ND_Node_First_Get(Info->Data_List, &Node); + i = 0; + while (Node) + { + if (i > 0) fprintf (stdout, ","); + fprintf (stdout, " %s", (char *)(Node->Value)); + ND_Node_Next_Get (Node, &Node); + i++; + } + } + fprintf (stdout, "\n\n"); + } + free(Info); + break; + + case QUIT: + fprintf (stdout, "\nExiting program ...\n"); + break; + + default: + fprintf (stdout, "\nUndefined choice %d\n", choice); + } + choice = print_menu (); + } + return 0; +} + +void init_menu (void) +{ + sprintf (menu, "Menu :\n"); + sprintf (tmp, " - %2d) %-25s", QUIT, "Quit"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", BASE_INIT, "Init library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", BASE_OPEN, "Open library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", BASE_INFO, "Info library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", BASE_CLOSE, "Close library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", BASE_END, "End library"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", BASE_LOAD, "Load library cache"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", BASE_UNLOAD, "Unload library cache"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", SHOW_CHANNEL_LIST, "Show channels"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", SHOW_RTAB_LIST, "Show rooting tables"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s", CHANNEL_DUMP, "Dump a channel"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", RTAB_DUMP, "Dump a rooting table"); strcat (menu, tmp); + sprintf (tmp, " - %2d) %-25s\n", TEST_EVENT, "Test an event"); strcat (menu, tmp); +} + +int print_menu (void) +{ + fprintf (stdout, "---------------------------------------------------------------------------\n%s", menu); + + tmp[0] = '\0'; + while (tmp[0] == '\0') + { + printf ("\nChoice ? "); + gets (tmp); + } + + return atoi (tmp); +} + +char *Get_Rooting(LOGT_Rooting Rooting) +{ + static char lib[20]; + + switch ((int)Rooting) + { + case LOGD_ROOTING_NULL: + strcpy(lib, "NULL"); + break; + case LOGD_ROOTING_STDERR: + strcpy(lib, "STDERR"); + break; + case LOGD_ROOTING_DATABASE: + strcpy(lib, "BASE"); + break; + case LOGD_ROOTING_DEFAULT: + strcpy(lib, "DEFAULT"); + break; + case LOGD_ROOTING_PREVIOUS: + strcpy(lib, "PREVIOUS"); + break; + default: + strcpy(lib, "unknown"); + break; + } + + return lib; +} + +char *Get_RC(LOGT_RC RC) +{ + static char lib[20]; + + switch ((int)RC) + { + case LOGD_RC_OK: + strcpy(lib, "OK"); + break; + case LOGD_RC_ANOERR: + strcpy(lib, "ANOERR"); + break; + case LOGD_RC_REJDON: + strcpy(lib, "REJDON"); + break; + case LOGD_RC_REJENR: + strcpy(lib, "REJENR"); + break; + case LOGD_RC_WARNING: + strcpy(lib, "WARNING"); + break; + case LOGD_RC_RECYCLE: + strcpy(lib, "RECYCLE"); + break; + case LOGD_RC_EXIT: + strcpy(lib, "EXIT"); + break; + case LOGD_RC_ABEND: + strcpy(lib, "ABEND"); + break; + default: + strcpy(lib, "unknown"); + break; + } + + return lib; +} + diff --git a/util/logagent.c b/util/logagent.c new file mode 100644 index 0000000..2705ba9 --- /dev/null +++ b/util/logagent.c @@ -0,0 +1,504 @@ +#include +#include +#include +#include +#include +#define MSG_MODE 1 +#include +#include +#include + +VER_INFO_EXPORT (logagent, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +void Parse_Arg (int , char **); +void Event_Msg_Process ( MSGT_Message * ); +void System_Msg_Process ( MSGT_Message * ); +void Info_Trace ( void ); + +unsigned int End_Agent, Nb_Event, Nb_System_Msg; +MSGT_Port * Private_Port, * Event_Port; +MSGT_PortList * Private_PortList; + +unsigned int Num_Agent, Status, Debug; +char Debug_Trace [512]; + +/*--------------------------------------------------------------------------------------------------*/ +/* Fonction principale */ +/*--------------------------------------------------------------------------------------------------*/ +int main ( int argc, char ** argv ) +{ + MSGT_Message * Msg; + char Private_Port_Name [256]; + + /* Récupération des arguments de la ligne de commande */ + + Parse_Arg (argc, argv); + + /* Démarrage de l'agent */ + + Status = ACTIVE; + + /* Ouverture de la librairie LIBMSG */ + + if (MSG_Library_Open (NULL, NULL, MSGD_OPEN) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible d'ouvrir la librairie LIBMSG"); + Info_Trace (); + return KO; + } + + /* Ouverture du port de message dans lequel sont envoyés les événements */ + + if (MSG_Port_Open (LOGD_EVENT_PORT_NAME, &Event_Port, MSGD_OPEN | MSGD_CREATE) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible d'ouvrir le port de messages des événements"); + Info_Trace (); + MSG_Library_Close (MSGD_CLOSE); + return KO; + } + + /* Ouverture (cas du restart) ou création du port privé de l'agent */ + + sprintf (Private_Port_Name, "Agent_%d_port", Num_Agent); + + if (MSG_Port_Open (Private_Port_Name, &Private_Port, MSGD_OPEN | MSGD_CREATE) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de d'ouvrir ou de créer mon port de messages privé"); + Info_Trace (); + MSG_Port_Close (Event_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return KO; + } + + /* Création d'une liste de ports (port public + port privé) que l'agent va écouter */ + + if (MSG_PortList_Open (&Private_PortList) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de créer ma liste de ports"); + Info_Trace (); + MSG_Port_Close (Event_Port, MSGD_CLOSE); + MSG_Port_Close (Private_Port, MSGD_DESTROY); + MSG_Library_Close (MSGD_CLOSE); + return KO; + } + + if (MSG_PortList_Port_Add (Private_PortList, Private_Port) != MSGS_OK || MSG_PortList_Port_Add (Private_PortList, Event_Port) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible d'ajouter les ports privé et public à ma liste de ports"); + Info_Trace (); + MSG_PortList_Close (Private_PortList); + MSG_Port_Close (Event_Port, MSGD_CLOSE); + MSG_Port_Close (Private_Port, MSGD_DESTROY); + MSG_Library_Close (MSGD_CLOSE); + return KO; + } + + sprintf (Debug_Trace, "démarrage en mode trace %s", Debug == TRUE ? "activé" : "désactivé"); + Info_Trace (); + + /* Boucle principale */ + + Nb_System_Msg = 0; + Nb_Event = 0; + End_Agent = FALSE; + + while (End_Agent == FALSE) + { + unsigned int Expected_Type; + + if (Status == ACTIVE) + { + /* Quand l'agent est actif, il traite tous les types de messages */ + + Expected_Type = MSGD_NO_TYPE; + } + else + { + /* Quand l'agent est stoppé, il ne traite que les messages système */ + + Expected_Type = MSGD_SYSTEM_GENERIC; + } + + /* Ecoute des ports de messages de la liste */ + + if (MSG_PortList_Listen (Private_PortList, Expected_Type, &Msg, MSGD_WAIT) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de réceptionner un message depuis l'un des ports écoutés"); + Info_Trace (); + MSG_PortList_Close (Private_PortList); + MSG_Port_Close (Private_Port, MSGD_DESTROY); + MSG_Library_Close (MSGD_CLOSE); + return KO; + } + + /* Traitement du message */ + + switch (Msg->Type) + { + case LOGD_EVENT_MSG_TYPE: + + /* Il s'agit d'un événement */ + + Event_Msg_Process (Msg); + Nb_Event ++; + + break; + + default: + + /* Il s'agit d'un message système */ + + System_Msg_Process (Msg); + Nb_System_Msg ++; + + break; + } + } + + /* Suppression de la liste de ports de l'agent */ + + if (MSG_PortList_Close (Private_PortList) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de supprimer ma liste de ports"); + Info_Trace (); + MSG_Port_Close (Private_Port, MSGD_DESTROY); + MSG_Library_Close (MSGD_CLOSE); + return KO; + } + + /* Suppression du port privé de l'agent */ + + if (MSG_Port_Close (Private_Port, MSGD_DESTROY) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de supprimer mon port de messages privé"); + Info_Trace (); + MSG_Library_Close (MSGD_CLOSE); + return KO; + } + + /* Fermeture de la librairie */ + + if (MSG_Library_Close (MSGD_CLOSE) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de fermer la librairie LIBMSG"); + Info_Trace (); + return KO; + } + + strcpy (Debug_Trace, "terminé"); + Info_Trace (); + + return OK; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Récupération de la ligne de commande */ +/*--------------------------------------------------------------------------------------------------*/ +void Parse_Arg (int argc, char ** argv) +{ + int i; + + Debug = FALSE; + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-h")) + { + fprintf (stderr, "Usage : %s [ [--help|-h] | --version [-v] | -id [--debug] ]\n", argv [0]); + exit (1); + } + + if (!strcmp (argv[i], "-id")) + { + i++; + if (i == argc) + { + fprintf (stderr, "Argument manquant après \"%s\"\n", argv[i - 1]); + exit (0); + } + + Num_Agent = atoi (argv[i]); + continue; + } + + if (!strcmp (argv[i], "--version")) + { + if (i+1 < argc && !strcmp (argv[i+1], "-v")) + { + VER_Object_Print (stdout, VERD_VERBOSE); + exit (0); + } + else + { + VER_Object_Print (stdout, VERD_MINIMAL); + exit (0); + } + } + + if (!strcmp (argv[i], "--debug")) + { + Debug = TRUE; + continue; + } + + fprintf (stderr, "Option invalide \"%s\"\n", argv[i]); + exit (0); + } + + if (Num_Agent == 0) + { + fprintf (stderr, "Option \"-id\" manquante ou bien valeur incorrecte (doit être > 0)\n"); + exit (0); + } +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Traitement d'un message contenant un événement */ +/*--------------------------------------------------------------------------------------------------*/ +void Event_Msg_Process (MSGT_Message * Msg) +{ + LOGT_Event_Msg_Data * Msg_Data; + unsigned int Length, Event_Type; + char Event_Name [256]; + char Cd_Support [256]; + char Data_Name [256]; + char Data_Value [256]; + unsigned int i; + char * Event_Data_Ptr; + + /* Récupération des données de l'entête de l'événement */ + + Msg_Data = (LOGT_Event_Msg_Data *)(Msg->Data); + + /* Vérification de la version du format */ + + if (strcmp (Msg_Data->Header.Version, EVENT_FORMAT_VERSION)) + { + sprintf (Debug_Trace, "version du format de message \"%s\" incorrect (\"%s\" attendu)", Msg_Data->Header.Version, EVENT_FORMAT_VERSION); + Info_Trace (); + + /* Suppression du message */ + + MSG_Message_Free (Msg); + + return; + } + + sprintf (Debug_Trace, "réception d'un événement de la part du processus %d (module %d/%d)", + Msg_Data->Header.Sending_Pid, + Msg_Data->Header.ModuleId, + Msg_Data->Header.Master_ModuleId); + + /* Récupération de l'identifiant du type d'événement */ + + Event_Type = Msg_Data->Event_Type; + + /* Récupération du nom de l'événement */ + + Event_Data_Ptr = &(Msg_Data->Event_Data); + + i = 0; + Length = (unsigned int)(Event_Data_Ptr [i]); + strncpy (Event_Name, Event_Data_Ptr + i + 1, Length); + Event_Name [Length] = (char)0; + + i += 1 + Length; + + if (Debug == TRUE) fprintf (stderr, "%s\nEvénement \"%s\" (type=%d):", Debug_Trace, Event_Name, Event_Type); + + Length = (unsigned int)(Event_Data_Ptr [i]); + strncpy (Cd_Support, Event_Data_Ptr + i + 1, Length); + Cd_Support [Length] = (char)0; + + if (Debug == TRUE) fprintf (stderr, "%s\n\t- support=\"%s\"\n", Debug_Trace, Cd_Support); + + i += 1 + Length; + + /* Récupération des macro-données */ + + while (i < Msg_Data->Data_Size) + { + /* Récupération du nom de la macro-donnée */ + + Length = (unsigned int)(Event_Data_Ptr [i]); + strncpy (Data_Name, Event_Data_Ptr + i + 1, Length); + Data_Name [Length] = (char)0; + + i += 1 + Length; + + if (i < Msg->Size) + { + /* Récupération de la valeur de la macro-donnée */ + + Length = (unsigned int)(Event_Data_Ptr [i]); + strncpy (Data_Value, Event_Data_Ptr + i + 1, Length); + Data_Value [Length] = (char)0; + + i += 1 + Length; + } + else + { + strcpy (Debug_Trace, "mauvais format d'événement"); + Info_Trace (); + } + + if (Debug == TRUE) fprintf (stderr, "\t- %s=%s\n", Data_Name, Data_Value); + } + + /* Traitement de l'événement + + ... + ... + ... + + */ + + + /* Renvoi du message à l'envoyeur */ + + if (MSG_Message_Reply (Msg) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de renvoyer le message de l'événement à son envoyeur"); + Info_Trace (); + } +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Traitement d'un message système par un agent */ +/*--------------------------------------------------------------------------------------------------*/ +void System_Msg_Process (MSGT_Message * Msg) +{ + /* Pour accuser réception du message système, on commence par remplir les données liées à l'agent */ + + ((Agent_Stat *)(Msg->Data))->Num_Agent = Num_Agent; + ((Agent_Stat *)(Msg->Data))->Pid = getpid (); + + switch (Msg->Type) + { + case MSGD_SYSTEM_STOP_REQUEST: + + if (Status == ACTIVE) + { + /* On indique que la requête a bien été prise en compte */ + + ((Agent_Stat *)(Msg->Data))->Answer = TRUE; + + /* Pause de l'agent jusqu'à réception d'un message MSGD_SYSTEM_CONTINUE_REQUEST */ + + Status = STOPPED; + + strcpy (Debug_Trace, "pause"); + Info_Trace (); + } + else + { + /* On indique que la requête n'a pas été prise en compte */ + + ((Agent_Stat *)(Msg->Data))->Answer = FALSE; + } + + break; + + case MSGD_SYSTEM_CONTINUE_REQUEST: + + if (Status == STOPPED) + { + /* On indique que la requête a bien été prise en compte */ + + ((Agent_Stat *)(Msg->Data))->Answer = TRUE; + + /* Reprise de l'agent */ + + Status = ACTIVE; + + strcpy (Debug_Trace, "reprise"); + Info_Trace (); + } + else + { + /* On indique que la requête n'a pas été prise en compte */ + + ((Agent_Stat *)(Msg->Data))->Answer = FALSE; + } + + break; + + case MSGD_SYSTEM_SHUTDOWN_REQUEST: + + /* Fin de la boucle principale de l'agent */ + + End_Agent = TRUE; + + strcpy (Debug_Trace, "terminaison en cours..."); + Info_Trace (); + + break; + + case MSGD_SYSTEM_STATUS_REQUEST: + + /* On informe le superviseur sur l'état dans lequel on se trouve */ + + ((Agent_Stat *)(Msg->Data))->Status = Status; + ((Agent_Stat *)(Msg->Data))->Debug = Debug; + + break; + + case MSGD_SYSTEM_INFO_REQUEST: + + /* On informe le superviseur sur le nombre de messages (système et événement) traités */ + + ((Agent_Stat *)(Msg->Data))->Cpt_Event = Nb_Event; + ((Agent_Stat *)(Msg->Data))->Cpt_System = Nb_System_Msg; + + break; + + case MSGD_SYSTEM_TRACEON_REQUEST: + + Debug = TRUE; + strcpy (Debug_Trace, "activation du mode trace"); + Info_Trace (); + + break; + + case MSGD_SYSTEM_TRACEOFF_REQUEST: + + strcpy (Debug_Trace, "désactivation du mode trace"); + Info_Trace (); + Debug = FALSE; + + break; + + default : + + /* On indique que la requête n'a pas été prise en compte */ + + ((Agent_Stat *)(Msg->Data))->Answer = FALSE; + + break; + } + + /* On accuse réception du message */ + + MSG_Message_Reply (Msg); +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Affichage sur la sortie standard d'erreur d'un message généré par un agent */ +/*--------------------------------------------------------------------------------------------------*/ +void Info_Trace ( void ) +{ + time_t dts; + struct tm * dt; + char Current_Date [25]; + + if (Debug == TRUE) + { + /* Récupère la date courante */ + + time (&dts); + dt = localtime (&dts); + sprintf (Current_Date, "%02d/%02d/%04d %02d:%02d:%02d", dt->tm_mday, dt->tm_mon + 1, dt->tm_year + 1900, dt->tm_hour, dt->tm_min, dt->tm_sec); + + fprintf (stderr, "[%s] Agent n°%d : %s\n", Current_Date, Num_Agent, Debug_Trace); + } +} diff --git a/util/logagent.h b/util/logagent.h new file mode 100644 index 0000000..bbe6dfa --- /dev/null +++ b/util/logagent.h @@ -0,0 +1,24 @@ + +#define ANSWER_SIZE 1000 /* Taille minimale des messages système adressés au superviseur */ +#define DEFAULT_TIMEOUT 5 /* Nombre de secondes avant lesquelles les agents devront répondre aux requêtes du superviseur */ +#define NB_MAX_AGENT 50 /* Nombre maximal d'agents pouvant être suivis par le superviseur */ + +/* Etats possibles d'un agent */ + +#define STOPPED 0 +#define ACTIVE 1 + +#define OK 1 +#define KO -1 + +/* Structure contenant les informations qu'un agent renvoie au superviseur */ + +typedef struct { + unsigned int Num_Agent; /* Numéro de l 'agent */ + pid_t Pid; /* Identifiant du processus de l'agent */ + unsigned int Status; /* Etat dans lequel se trouve l'agent */ + unsigned int Debug; /* Mode debug dans lequel se trouve l'agent */ + unsigned int Cpt_Event; /* Nombre d'événements traités */ + unsigned int Cpt_System; /* Nombre de messages système traités */ + unsigned int Answer; /* Réponse de l'agent à la requête */ +} Agent_Stat; diff --git a/util/logbench.c b/util/logbench.c new file mode 100644 index 0000000..798d5b4 --- /dev/null +++ b/util/logbench.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#define LOG_MODE 1 +#include +#include + +typedef struct { + double sec; + long count; + struct timeval start; + struct timeval stop; +} cpt; + +#define t_init(x) {x.sec = 0; x.count = 0;} +#define t_start(x) {gettimeofday(&(x.start), NULL);} +#define t_stop(x) {gettimeofday(&(x.stop), NULL); x.sec += (double)(x.stop.tv_sec) - (double)(x.start.tv_sec) + ((double)(x.stop.tv_usec) - (double)(x.start.tv_usec)) / 1000000; x.count++;} + +int main (int argc, char ** argv) +{ + LOGT_Channel * My_Channel; + char Line [1000], * Event_Data; + FILE * fid; + unsigned int Nb_Send, Line_Number, i; + cpt Compteur; + + if (argc != 2) + { + fprintf (stderr, "Usage : %s \n", argv [0]); + return -1; + } + + /* Ouverture du fichier de test */ + + fid = fopen (argv [1], "r"); + if (!fid) + { + fprintf (stderr, "Unable to open file \"%s\" for reading\n", argv [1]); + return -1; + } + + /* Ouverture de la librairie */ + + if (LOG_Library_Open (0, NULL, LOGD_OPEN | LOGD_DEBUG_ALL) != LOGS_OK) + { + fprintf (stderr, "\n=> Impossible d'ouvrir la librairie LIBLOG\n"); + return -1; + } + + /* Ouverture d'un channel */ + + if (LOG_Channel_Open (&My_Channel, 0, 1, "IPR_CAVpopulate2.pc", "IPR_CAV") != LOGS_OK) + { + fprintf (stderr, "\n=> Impossible d'ouvrir un channel\n"); + return -1; + } + + /* Ajout des tables de routage utilisateur */ + + if (TL_Channel_RTab_Add (My_Channel, "UTILS:ROOTING:ROOTING_TABLE") != TLS_OK) + { + fprintf (stderr, "\n=> Impossible d'ajouter les tables de routage au channel\n"); + LOG_Channel_Close (My_Channel); + return -1; + } + + /* Ajout des triggers */ + + if (TL_Channel_Trigger_Add (My_Channel, "UTILS:ROOTING:TRIGGER") != TLS_OK) + { + fprintf (stderr, "\n=> Impossible d'ajouter les triggers au channel\n"); + LOG_Channel_Close (My_Channel); + return -1; + } + + /* Initialisation du compteur */ + + t_init (Compteur); + + /* Envoi des événements paramétrés dans le fichier */ + + Line_Number = 1; + + while (!feof (fid) && fgets (Line, 1000, fid)) + { + /* Récupération des informations dans la ligne du fichier */ + + Event_Data = strchr (Line, '#'); + + if (Event_Data == NULL) + { + fprintf (stderr, "Warning ligne n°%d : format incorrect (caractère '#' manquant)\n", Line_Number); + } + else + { + *Event_Data = (char)0; + + Nb_Send = atoi (Line); + + if (Nb_Send <= 0) + { + fprintf (stderr, "Warning ligne n°%d : valeur (%d) incorrecte avant le caracatère '#'\n", Line_Number, Nb_Send); + Nb_Send = 1; + } + + Event_Data++; + + for (i = 0; i < Nb_Send; i++) + { + t_start (Compteur); + + /* Envoi de l'événement proprement dit */ + + if (LOG_Event_External_Send (My_Channel, argv [1], Event_Data) == LOGD_RC_WARNING) + fprintf (stderr, "Warning ligne n°%d : code retour WARNING sur envoi de l'événement\n", Line_Number); + + t_stop (Compteur); + } + } + + Line_Number++; + } + + fclose (fid); + + /* Affichage du résultat du benchmark */ + + fprintf (stdout, "%ld événements envoyés en %.2f sec (%.2f évt/sec)\n", Compteur.count, Compteur.sec, Compteur.count / Compteur.sec); + + /* Fermeture du channel */ + + if (LOG_Channel_Close (My_Channel) != LOGS_OK) + { + fprintf (stderr, "\n=> Impossible de fermer le channel\n"); + return -1; + } + + /* Fermeture de la librairie */ + + if (LOG_Library_Close (LOGD_CLOSE) != LOGS_OK) + { + fprintf (stderr, "\n=> Impossible de fermer la librairie LIBLOG\n"); + return -1; + } + + return 1; +} + diff --git a/util/logresolve.c b/util/logresolve.c new file mode 100644 index 0000000..dd2ca6f --- /dev/null +++ b/util/logresolve.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#define ND_MODE 1 +#include +#define LOG_MODE 1 +#include + +VER_INFO_EXPORT (logresolve, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +typedef struct { + double sec; + struct timeval start; + struct timeval stop; +} cpt; + +#define t_start(x){gettimeofday (&(x.start), NULL);} +#define t_stop(x){gettimeofday (&(x.stop), NULL); x.sec = (double)(x.stop.tv_sec) - (double)(x.start.tv_sec) + \ +((double)(x.stop.tv_usec) - (double)(x.start.tv_usec)) / 1000000;} +cpt t_exec; + +char * Get_Rooting (LOGT_Rooting); +char * Get_RC (LOGT_RC); + +#define USAGE "Usage : %s [ --help | --version [-v] | --event ]\n" + +int main (int argc, char **argv) +{ + LOGT_Info * Info; + char * Event; + int i; + + if (argc >= 2) + { + if (!strcmp (argv [1], "--help")) + { + fprintf (stderr, USAGE, argv [0]); + return 1; + } + else if (!strcmp (argv [1], "--version")) + { + if (argc >= 3 && !strcmp (argv [2], "-v")) + return VER_Object_Print (stdout, VERD_VERBOSE); + else + return VER_Object_Print (stdout, VERD_MINIMAL); + } + else if (!strcmp (argv [1], "--event")) + { + if (argc != 3) + { + fprintf (stderr, USAGE, argv [0]); + return 0; + } + + Event = argv [2]; + } + else + { + fprintf (stderr, USAGE, argv [0]); + return 0; + } + } + else + { + fprintf (stderr, USAGE, argv [0]); + return 0; + } + + /* Récupération des informations sur un événement */ + + Info = (LOGT_Info *) malloc (sizeof (LOGT_Info)); + + if (LOG_Library_Open (0, NULL, LOGD_OPEN | LOGD_DEBUG_ALL) != LOGS_OK) + { + fprintf (stderr, "=> Ouverture de la librairie LIBLOG impossible\n"); + return 0; + } + + t_start (t_exec); + + if (LOG_Event_Info_Get (NULL, &Info, Event) != LOGS_OK) + { + t_stop (t_exec); + fprintf (stderr, "=> Impossible de résoudre l'événement \"%s\"\n", Event); + } + else + { + NDT_Node * Node; + + t_stop (t_exec); + fprintf (stdout, "\nEvénement \"%s\" résolu en %.4f sec :\n", Event, t_exec.sec); + fprintf (stdout, "\t- Type : %s (Id=%d)\n", Info->Event_Name, Info->Event_Type); + fprintf (stdout, "\t- Routage : %s\n", Get_Rooting (Info->Rooting)); + fprintf (stdout, "\t- Gravité : %c\n", (char)Info->Gravite); + fprintf (stdout, "\t- Code retour : %s\n", Get_RC (Info->RC)); + fprintf (stdout, "\t- Format :"); + if (Info->Data_List) + { + ND_Node_First_Get (Info->Data_List, &Node); + i = 0; + while (Node) + { + if (i > 0) fprintf (stdout, ","); + fprintf (stdout, " %s", (char *)(Node->Value)); + ND_Node_Next_Get (Node, &Node); + i++; + } + } + fprintf (stdout, "\n\n"); + } + + LOG_Library_Close (LOGD_CLOSE); + + free (Info); + + return 0; +} + +char * Get_Rooting (LOGT_Rooting Rooting) +{ + static char lib [20]; + + switch ((int)Rooting) + { + case LOGD_ROOTING_NULL: + strcpy (lib, "NULL"); + break; + case LOGD_ROOTING_STDERR: + strcpy (lib, "STDERR"); + break; + case LOGD_ROOTING_DATABASE: + strcpy (lib, "BASE"); + break; + case LOGD_ROOTING_DEFAULT: + strcpy (lib, "DEFAULT"); + break; + case LOGD_ROOTING_PREVIOUS: + strcpy (lib, "PREVIOUS"); + break; + default: + strcpy (lib, "unknown"); + break; + } + + return lib; +} + +char * Get_RC (LOGT_RC RC) +{ + static char lib [20]; + + switch ((int)RC) + { + case LOGD_RC_OK: + strcpy (lib, "OK"); + break; + case LOGD_RC_ANOERR: + strcpy (lib, "ANOERR"); + break; + case LOGD_RC_REJDON: + strcpy (lib, "REJDON"); + break; + case LOGD_RC_REJENR: + strcpy (lib, "REJENR"); + break; + case LOGD_RC_WARNING: + strcpy (lib, "WARNING"); + break; + case LOGD_RC_RECYCLE: + strcpy (lib, "RECYCLE"); + break; + case LOGD_RC_EXIT: + strcpy (lib, "EXIT"); + break; + case LOGD_RC_ABEND: + strcpy (lib, "ABEND"); + break; + default: + strcpy (lib, "unknown"); + break; + } + + return lib; +} diff --git a/util/logsupervisor.c b/util/logsupervisor.c new file mode 100644 index 0000000..d0e798f --- /dev/null +++ b/util/logsupervisor.c @@ -0,0 +1,1246 @@ +#include +#include +#include +#include +#include +#include +#include +#ifdef LINUX +#include +#include +#else +#include +#include +#endif +#include +#include +#define ND_MODE 1 +#include +#define MSG_MODE 1 +#include +#include + +extern int sigignore(int sig); + +VER_INFO_EXPORT (logsupervisor, "$Revision: 1.1 $", "$Name: $", __FILE__, "$Author: smas $") + +/*--------------------------------------------------------------------------------------------------*/ + +#define Date_IsSet(tvp) ((tvp).tv_sec || (tvp).tv_usec) +#define Date_Compare(tvp, uvp) ((tvp).tv_sec < (uvp).tv_sec || ((tvp).tv_sec == (uvp).tv_sec && (tvp).tv_usec < (uvp).tv_usec)) + +/* Tableau permettant de référéncer les agents suivis par le superviseur */ + +typedef struct { + pid_t Pid; /* Identifiant du processus */ + short int Restarted; /* Indique si l'agent est déjà tombé puis a été redémarré */ + short int GivenUp; /* Indique si l'agent a été abandonné (car tombé plusieur fois) */ +} Agent_Ref; + +Agent_Ref * Tab_Agent; + +/* Requêtes à traiter par le superviseur (classées par type de message système) */ + +typedef struct { + struct timeval Request_Date; /* Date de début de la requête */ + unsigned int Nb_Reply; /* Nombre de réponses recues de la part des agents */ + Agent_Stat Reply_Stat [NB_MAX_AGENT]; /* Statistiques des agents ayant répondu */ + NDT_Root * Msg_List; /* Liste chaînée des messages en attente sur cette requête */ +} Waiting_Request; + +Waiting_Request Tab_Request [MSGD_NB_SYSTEM_MESSAGE]; + +char Debug_Trace [256]; +unsigned int Timeout; + +/*--------------------------------------------------------------------------------------------------*/ + +#define AGENT_PATH "logagent" + +#define SUPERVISOR_START 1 +#define SUPERVISOR_PING 2 +#define SUPERVISOR_STATUS_GET 3 +#define SUPERVISOR_INFO_GET 4 +#define SUPERVISOR_STOP_AGENT 5 +#define SUPERVISOR_CONTINUE_AGENT 6 +#define SUPERVISOR_TRACEON 7 +#define SUPERVISOR_TRACEOFF 8 +#define SUPERVISOR_SHUTDOWN 9 + +void Parse_Arg ( int, char ** ); +void Supervisor_Start ( void ); +void Supervisor_Request (unsigned int, size_t, int); +void Supervisor_Ping ( void ); +void Supervisor_Status_Get ( void ); +void Supervisor_Info_Get ( void ); +void Supervisor_Agent_Stop ( void ); +void Supervisor_Agent_Continue ( void ); +void Supervisor_Shutdown ( void ); + +void System_Msg_Process ( MSGT_Message * ); +int Agent_Msg_Send ( unsigned int, unsigned int, int ); +int Agent_Start ( unsigned int ); +void Agent_Restart ( int signum ); +char * Agent_Status_Get ( unsigned int Agent_Status, unsigned int Agent_Debug ); +void Request_Answer ( unsigned int Idx ); +void Timeout_Handle ( int signum ); +void Info_Trace ( void ); +char * Status_Get ( void ); +NDT_Status Request_List_Manager ( va_list ); + +unsigned int Nb_Agent, Nb_GivenUp, End_Supervisor, Status, Debug, Action; +MSGT_Port * Supervisor_Port, * System_Port; + +/*--------------------------------------------------------------------------------------------------*/ + +int main ( int argc , char ** argv ) +{ + /* Récupération des arguments de la ligne de commande */ + + Parse_Arg (argc, argv); + + /* Lancement de l'action sur le superviseur */ + + switch (Action) + { + case SUPERVISOR_START: + Supervisor_Start (); + break; + + case SUPERVISOR_PING: + Supervisor_Request (MSGD_SYSTEM_PING_REQUEST, sizeof (MSGT_PingData), MSGD_SYSTEM_HIGH_PRIORITY); + break; + + case SUPERVISOR_STATUS_GET: + Supervisor_Request (MSGD_SYSTEM_STATUS_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); + break; + + case SUPERVISOR_INFO_GET: + Supervisor_Request (MSGD_SYSTEM_INFO_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); + break; + + case SUPERVISOR_STOP_AGENT: + Supervisor_Request (MSGD_SYSTEM_STOP_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); + break; + + case SUPERVISOR_CONTINUE_AGENT: + Supervisor_Request (MSGD_SYSTEM_CONTINUE_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); + break; + + case SUPERVISOR_TRACEON: + Supervisor_Request (MSGD_SYSTEM_TRACEON_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); + break; + + case SUPERVISOR_TRACEOFF: + Supervisor_Request (MSGD_SYSTEM_TRACEOFF_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); + break; + + case SUPERVISOR_SHUTDOWN: + Supervisor_Request (MSGD_SYSTEM_SHUTDOWN_REQUEST, ANSWER_SIZE, MSGD_SYSTEM_HIGH_PRIORITY); + break; + + default: + break; + } + + return OK; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Récupération de la ligne de commande */ +/*--------------------------------------------------------------------------------------------------*/ +void Parse_Arg (int argc, char ** argv) +{ + int i; + + Debug = FALSE; + Nb_Agent = 0; + Timeout = 0; + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "--help") || !strcmp (argv[i], "-h")) + { + char Usage [1000]; + + sprintf (Usage, + "Usage : %s \nOptions :\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n\t%-50s\t%s\n", + argv [0], + "--help | -h", "-> Affiche l'aide courante", + "--version [-v]", "-> Affiche le numéro de version", + "--start [--debug] [--timeout ]", "-> Démarre le superviseur et agents", + "--ping", "-> Ping le superviseur", + "--status", "-> Affiche le status de tous les agents et du superviseur", + "--info", "-> Affiche des informations statistiques de tous les agents", + "--stop", "-> Stoppe tous les agents", + "--continue", "-> Continue tous les agents stoppés", + "--traceon", "-> Active le mode trace du superviseur et des agents", + "--traceoff", "-> Désactive le mode trace du superviseur et des agents", + "--shutdown", "-> Tue tous les agents et le superviseur"); + fprintf (stderr, Usage); + exit (1); + } + + if (!strcmp (argv[i], "--version")) + { + if (i+1 < argc && !strcmp (argv[i+1], "-v")) + { + VER_Object_Print (stdout, VERD_VERBOSE); + exit (0); + } + else + { + VER_Object_Print (stdout, VERD_MINIMAL); + exit (0); + } + } + + if (!strcmp (argv[i], "--start")) + { + Action = SUPERVISOR_START; + i++; + if (i == argc) + { + fprintf (stderr, "Missing argument after %s\n", argv[i - 1]); + exit (0); + } + + if ((Nb_Agent = atoi (argv[i])) <= 0) + { + fprintf (stderr, "Bad value (%s) after %s\n", argv[i], argv[i - 1]); + exit (0); + } + + continue; + } + + if (!strcmp (argv[i], "--ping")) + { + Action = SUPERVISOR_PING; + continue; + } + + if (!strcmp (argv[i], "--status")) + { + Action = SUPERVISOR_STATUS_GET; + continue; + } + + if (!strcmp (argv[i], "--info")) + { + Action = SUPERVISOR_INFO_GET; + continue; + } + + if (!strcmp (argv[i], "--stop")) + { + Action = SUPERVISOR_STOP_AGENT; + continue; + } + + if (!strcmp (argv[i], "--continue")) + { + Action = SUPERVISOR_CONTINUE_AGENT; + continue; + } + + if (!strcmp (argv[i], "--traceon")) + { + Action = SUPERVISOR_TRACEON; + continue; + } + + if (!strcmp (argv[i], "--traceoff")) + { + Action = SUPERVISOR_TRACEOFF; + continue; + } + + if (!strcmp (argv[i], "--shutdown")) + { + Action = SUPERVISOR_SHUTDOWN; + continue; + } + + if (!strcmp (argv[i], "--debug")) + { + Debug = TRUE; + continue; + } + + if (!strcmp (argv[i], "--timeout")) + { + i++; + if (i == argc) + { + fprintf (stderr, "Missing argument after %s\n", argv[i - 1]); + exit (0); + } + + if ((Timeout = atoi (argv[i])) <= 0) + { + fprintf (stderr, "Bad value (%s) after %s\n", argv[i], argv[i - 1]); + exit (0); + } + + continue; + } + + fprintf (stderr, "Option invalide \"%s\"\n", argv[i]); + exit (0); + } + + if (Timeout == 0) Timeout = DEFAULT_TIMEOUT; +} + +/*--------------------------------------------------------------------------------------------------*/ +/*--------------------------------------- SUPERVISEUR ----------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------------------------------*/ +/* Envoie une requête au superviseur */ +/*--------------------------------------------------------------------------------------------------*/ +void Supervisor_Request (unsigned int Type, size_t Size, int Priority) +{ + MSGT_Message * Msg; + + Debug = TRUE; + + /* Ouverture de la librairie LIBLOG */ + + if (MSG_Library_Open (0, NULL, MSGD_OPEN | MSGD_DEBUG_ALL) != MSGS_OK) + { + fprintf (stderr, "=> Impossible d'ouvrir la librairie LIBMSG\n"); + return; + } + + /* Ouverture du port de messages du superviseur */ + + if (MSG_Port_Open (MSGD_SUPERVISOR_PORT_NAME, &Supervisor_Port, MSGD_OPEN) != MSGS_OK) + { + fprintf (stderr, "=> Impossible d'ouvrir le port de messages du superviseur\n"); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* Création / ouverture du port système dont on se sert pour les accusés réception */ + + if (MSG_Port_Open (MSGD_SYSTEM_PORT_NAME, &System_Port, MSGD_OPEN | MSGD_CREATE) != MSGS_OK) + { + fprintf (stderr, "=> Impossible d'ouvrir ou de créer le port de messages système\n"); + MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* Création du message */ + + if (MSG_Message_Alloc (&Msg, Size) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de créer un message\n"); + MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); + MSG_Port_Close (System_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + memset (Msg->Data, 0, Msg->Size); + + if (MSG_Message_Config (Msg, MSGD_CONFIG_TYPE, Type) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de configurer le type du message\n"); + MSG_Message_Free (Msg); + MSG_Port_Close (System_Port, MSGD_CLOSE); + MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + if (MSG_Message_Config (Msg, MSGD_CONFIG_PRIORITY, Priority) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de configurer la priorité du message\n"); + MSG_Message_Free (Msg); + MSG_Port_Close (System_Port, MSGD_CLOSE); + MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* Envoi du message avec demande d'accusé réception dans le port système */ + + if (MSG_Message_Send (MSGD_SYSTEM_PORT_NAME, Supervisor_Port, Msg) != MSGS_OK) + { + fprintf (stderr, "=> Impossible d'envoyer le message\n"); + MSG_Port_Close (System_Port, MSGD_CLOSE); + MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* Fermeture du port de messages du superviseur */ + + if (MSG_Port_Close (Supervisor_Port, MSGD_CLOSE) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de fermer le port de messages du superviseur\n"); + MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* Ecoute du port de messages système */ + + if (MSG_Message_Receive (System_Port, MSGD_NO_TYPE, &Msg, MSGD_WAIT) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de réceptionner un message dans le port système\n"); + MSG_Message_Free (Msg); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + if (Msg->Type == MSGD_SYSTEM_PING_REPLY) + { + double send_delay, rcv_delay, ping_delay; + struct timeval t1, t2, t3, t4; + + t1 = ((MSGT_PingData *)(Msg->Data))->Snd1; + t2 = ((MSGT_PingData *)(Msg->Data))->Rcv1; + t3 = ((MSGT_PingData *)(Msg->Data))->Snd2; + t4 = ((MSGT_PingData *)(Msg->Data))->Rcv2; + + send_delay = (double)(t2.tv_sec) - (double)(t1.tv_sec) + ((double)(t2.tv_usec) - (double)(t1.tv_usec)) / 1000000; + rcv_delay = (double)(t4.tv_sec) - (double)(t3.tv_sec) + ((double)(t4.tv_usec) - (double)(t3.tv_usec)) / 1000000; + ping_delay = (double)(t4.tv_sec) - (double)(t1.tv_sec) + ((double)(t4.tv_usec) - (double)(t1.tv_usec)) / 1000000; + + fprintf (stdout, "Ping = %.4f sec (Aller = %.4f sec / Retour = %.4f sec)\n", ping_delay, send_delay, rcv_delay); + } + else + { + /* Autres messages système */ + + fprintf (stdout, (char *)(Msg->Data)); + } + + /* Désallocation du message */ + + if (MSG_Message_Free (Msg) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de supprimer le message\n"); + MSG_Port_Close (System_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* Fermeture du port de messages système */ + + if (MSG_Port_Close (System_Port, MSGD_CLOSE) != MSGS_OK) + { + fprintf (stderr, "=> Impossible de fermer le port de messages système\n"); + MSG_Library_Close (MSGD_CLOSE); + return ; + } + + MSG_Library_Close (MSGD_CLOSE); +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Procédure de démarrage du superviseur */ +/*--------------------------------------------------------------------------------------------------*/ +void Supervisor_Start ( void ) +{ + MSGT_Message * Msg; + unsigned int i; + + Nb_GivenUp = 0; + End_Supervisor = FALSE; + Status = ACTIVE; + + /* Allocation d'un tableau pour référencer les agents */ + + Tab_Agent = (Agent_Ref *)malloc (Nb_Agent * sizeof (Agent_Ref)); + + if (!Tab_Agent) + { + strcpy (Debug_Trace, "impossible d'allouer de la mémoire pour référencer les agents"); + Info_Trace (); + return; + } + + /* Initialisation du tableau des requêtes soumises au superviseur */ + + for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) + { + memset (&(Tab_Request [i]), 0, sizeof (Waiting_Request)); + ND_DataStruct_Open (&(Tab_Request [i].Msg_List), NDD_DS_LIST | NDD_MN_FIFO, NULL, NULL, NULL, TRUE); + strcpy (Tab_Request [i].Msg_List->Manager, "Request_List_Manager"); + } + + /* Ouverture de la librairie LIBMSG */ + + if (MSG_Library_Open (0, NULL, MSGD_OPEN) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible d'ouvrir la librairie LIBMSG"); + Info_Trace (); + return; + } + + /* Ouverture / création du port de messages du superviseur */ + + if (MSG_Port_Open (MSGD_SUPERVISOR_PORT_NAME, &Supervisor_Port, MSGD_OPEN | MSGD_CREATE) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible d'ouvrir mon port de messages privé"); + Info_Trace (); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* On trappe le signal SIGCHLD pour détecter les agents qui tombent */ + + signal (SIGCHLD, Agent_Restart); + + /* Lancement des agents */ + + for (i = 1; i <= Nb_Agent; i++) Agent_Start (i); + + /* Boucle principale du superviseur */ + + while (End_Supervisor == FALSE) + { + /* Ecoute du port de messages du superviseur */ + + int rc = MSG_Message_Receive (Supervisor_Port, MSGD_NO_TYPE, &Msg, MSGD_WAIT); + + switch (rc) + { + case MSGS_OK: + + /* Traitement des messages envoyés au superviseur */ + + System_Msg_Process (Msg); + + break; + + case MSGS_ERRSIG: + + /* On continue à boucler sur l'écoute */ + + break; + + default: + strcpy (Debug_Trace, "impossible de réceptionner un message dans mon port du messages privé"); + Info_Trace (); + MSG_Message_Free (Msg); + MSG_Port_Close (Supervisor_Port, MSGD_CLOSE); + MSG_Library_Close (MSGD_CLOSE); + return; + } + } + + /* Fermeture du port de messages du superviseur */ + + if (MSG_Port_Close (Supervisor_Port, MSGD_CLOSE) != MSGS_OK) + { + strcpy (Debug_Trace, "impossible de fermer mon port de messages privé"); + Info_Trace (); + MSG_Library_Close (MSGD_CLOSE); + return; + } + + /* Fermeture de la librairie LIBMSG */ + + MSG_Library_Close (MSGD_CLOSE); + + /* Désallocation des ressources locales */ + + for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) + { + if (Tab_Request [i].Msg_List) ND_DataStruct_Close (Tab_Request [i].Msg_List); + } + + strcpy (Debug_Trace, "terminé"); + Info_Trace (); +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Traitement d'un message système par le superviseur */ +/*--------------------------------------------------------------------------------------------------*/ +void System_Msg_Process (MSGT_Message * Msg) +{ + unsigned int Idx; + unsigned int i; + + /* S'agit-il d'un message de type REQUEST ou REPLY ? */ + + if (MSGD_IS_SYSTEM_REQUEST (Msg->Type)) + { + Idx = (Msg->Type - 1) / 2; + + /* Le message est-il de taille suffisante pour que l'on y réponde ? */ + + if (Msg->Size < ANSWER_SIZE) + { + /* On le supprime : tant pis pour l'envoyeur ! */ + + MSG_Message_Free (Msg); + + sprintf (Debug_Trace, "la requête envoyée par \"%s\" ne sera pas prise en compte car le message est de taille insuffisante (%d octets minimum)", Msg->From, ANSWER_SIZE); + Info_Trace (); + + return; + } + + /* + Mise du message en attente : on y répondra lorque tous les + agents y auront répondu ou bien lorsque le timeout aura expiré. + */ + + ND_Value_Add (Tab_Request [Idx].Msg_List, Msg); + + /* On regarde si une requête du même type était déjà en cours */ + + if (Tab_Request [Idx].Msg_List->Node_Number == 1) + { + /* S'il s'agit d'une requête SHUTDOWN_REQUEST, il faut désormais ignorer les signaux de type SIGCHLD */ + + if (Msg->Type == MSGD_SYSTEM_SHUTDOWN_REQUEST) + sigignore (SIGCHLD); + + /* On prend en compte les requêtes TRACEON_REQUEST et TRACEOFF_REQUEST */ + + if (Msg->Type == MSGD_SYSTEM_TRACEON_REQUEST) + { + Debug = TRUE; + sprintf (Debug_Trace, "activation du mode trace"); + Info_Trace (); + } + + if (Msg->Type == MSGD_SYSTEM_TRACEOFF_REQUEST) + { + sprintf (Debug_Trace, "désactivation du mode trace"); + Info_Trace (); + Debug = FALSE; + } + + /* On mémorise la date de la requête */ + + gettimeofday (&(Tab_Request [Idx].Request_Date), NULL); + + if (Nb_Agent - Nb_GivenUp == 0) + { + /* S'il n'y a plus d'agent valide, on répond tout de suite à la requête */ + + Request_Answer (Idx); + } + else + { + /* Sinon, on initie une alarme ... */ + + signal (SIGALRM, Timeout_Handle); + alarm (Timeout); + + /* ... et on transmet la requête à tous les agents qui devront y répondre avant le timeout */ + + for (i = 1; i <= Nb_Agent; i++) + { + if (Tab_Agent [i -1].GivenUp == FALSE) + { + if (Agent_Msg_Send (i, Msg->Type, MSGD_SYSTEM_HIGH_PRIORITY) != OK) + { + sprintf (Debug_Trace, "impossible de transmettre la requête à l'agent n°%d", i); + Info_Trace (); + } + } + } + } + } + } + else if (MSGD_IS_SYSTEM_REPLY (Msg->Type)) /* Il s'agit d'une réponse d'un agent */ + { + Idx = (Msg->Type / 2) - 1; + + /* Une requête de ce type a-t'elle déjà été lancée ? */ + + if (Tab_Request [Idx].Msg_List->Node_Number > 0) + { + int Num_Agent; + Agent_Stat * Stat; + + Tab_Request [Idx].Nb_Reply++; + + /* Mise à jour de statistiques : on recopie celles renvoyés par l'agent dans notre tableau */ + + Stat = (Agent_Stat *)(Msg->Data); + + Num_Agent = Stat->Num_Agent; + + Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Num_Agent = Stat->Num_Agent; + Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Pid = Stat->Pid; + Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Cpt_Event = Stat->Cpt_Event; + Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Cpt_System = Stat->Cpt_System; + Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Status = Stat->Status; + Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Debug = Stat->Debug; + Tab_Request [Idx].Reply_Stat [Num_Agent - 1].Answer = Stat->Answer; + + /* Tous les agents ont-ils répondu à la requête ? */ + + if (Tab_Request [Idx].Nb_Reply == Nb_Agent - Nb_GivenUp) + { + /* On répond à la requête */ + + Request_Answer (Idx); + } + else + { + /* Tous les agents n'ont pas encore répondu : on attend encore */ + } + } + else + { + /* L'agent a répondu trop tard : tant pis pour lui, on ne tient pas compte de cette réponse */ + } + + /* On supprime le message */ + + MSG_Message_Free (Msg); + } +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Réponse à une requête (procédure exécutée au timeout ou bien lorsque tous les agents ont répondu)*/ +/*--------------------------------------------------------------------------------------------------*/ +void Request_Answer ( unsigned int Idx ) +{ + char Answer [ANSWER_SIZE]; + unsigned int i, j; + unsigned int Type = 2 * Idx + 1; + NDT_Node * Node, * Next_Node; + NDT_Root * Msg_List; + char str [256]; + + Answer [0] = (char)0; + + /* Réponse concernant le superviseur lui-même */ + + switch (Type) + { + case MSGD_SYSTEM_TRACEON_REQUEST: + + sprintf (str, "Superviseur : mode trace activé\n"); + strcat (Answer, str); + break; + + case MSGD_SYSTEM_TRACEOFF_REQUEST: + + sprintf (str, "Superviseur : mode trace désactivé\n"); + strcat (Answer, str); + break; + + case MSGD_SYSTEM_STATUS_REQUEST: + + sprintf (str, "Superviseur : %s\n", Status_Get ()); + strcat (Answer, str); + break; + + case MSGD_SYSTEM_INFO_REQUEST: + + /* Informations concernant les agents suivis */ + + sprintf (str, "Superviseur :\n\t- %d agent(s) suivi(s)\n\t- %d agent(s) abandonné(s)\n", Nb_Agent - Nb_GivenUp, Nb_GivenUp); + strcat (Answer, str); + + /* On compte le nombre de requêtes en attente */ + + j = 0; + for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) + if (i != Idx && Tab_Request [i].Msg_List->Node_Number > 0) j++; + + sprintf (str, "\t- %d requête(s) en attente de réponse de la part des agents\n", j); + strcat (Answer, str); + + /* On consolide les statistiques des agents concernant le nombre d'événements traités */ + + j = 0; + for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) + j += Tab_Request [Idx].Reply_Stat [i].Cpt_Event; + + sprintf (str, "\t- %d événement(s) traité(s) par l'ensemble des agents ayant répondu\n\n", j); + strcat (Answer, str); + + break; + + case MSGD_SYSTEM_SHUTDOWN_REQUEST: + + End_Supervisor = TRUE; + + strcpy (Debug_Trace, "terminaison en cours..."); + Info_Trace (); + + break; + + default: + + break; + } + + /* Réponse concernant les agents auxquels la requête a été transmise */ + + sprintf (str, "%d/%d agent(s) ont répondu à la requête%s\n", Tab_Request [Idx].Nb_Reply, Nb_Agent - Nb_GivenUp, Tab_Request [Idx].Nb_Reply > 0 ? " :" : "."); + strcat (Answer, str); + + for (i = 0; i < Nb_Agent; i++) + { + if (Tab_Agent [i].GivenUp == TRUE) continue; + + sprintf (str, "\t- Agent n°%d (process %ld) : ", i + 1, Tab_Agent [i].Pid); + strcat (Answer, str); + + if (Tab_Request [Idx].Reply_Stat [i].Num_Agent == 0) + strcat (Answer, "pas de réponse\n"); + else + { + switch (Type) + { + case MSGD_SYSTEM_STOP_REQUEST: + sprintf (str, "%s\n", Tab_Request [Idx].Reply_Stat [i].Answer == TRUE ? "stoppé" : "déjà stoppé"); + strcat (Answer, str); + break; + + case MSGD_SYSTEM_CONTINUE_REQUEST: + sprintf (str, "%s\n", Tab_Request [Idx].Reply_Stat [i].Answer == TRUE ? "repris" : "déjà actif"); + strcat (Answer, str); + break; + + case MSGD_SYSTEM_SHUTDOWN_REQUEST: + strcat (Answer, "arrêté\n"); + break; + + case MSGD_SYSTEM_STATUS_REQUEST: + sprintf (str, "%s\n", Agent_Status_Get (Tab_Request [Idx].Reply_Stat [i].Status, Tab_Request [Idx].Reply_Stat [i].Debug)); + strcat (Answer, str); + break; + + case MSGD_SYSTEM_INFO_REQUEST: + sprintf (str, "%d événement(s) traité(s) / %d message(s) système(s) reçu(s)\n", Tab_Request [Idx].Reply_Stat [i].Cpt_Event, Tab_Request [Idx].Reply_Stat [i].Cpt_System); + strcat (Answer, str); + break; + + case MSGD_SYSTEM_TRACEON_REQUEST: + strcat (Answer, "mode trace activé\n"); + break; + + case MSGD_SYSTEM_TRACEOFF_REQUEST: + strcat (Answer, "mode trace désactivé\n"); + break; + + default: + break; + } + } + } + + if (Type == MSGD_SYSTEM_SHUTDOWN_REQUEST) strcat (Answer, "Superviseur terminé.\n"); + + /* On répond à tous les messages en attente sur cette requête */ + + Msg_List = Tab_Request [Idx].Msg_List; + + ND_Node_First_Get (Msg_List, &Node); + + while (Node) + { + MSGT_Message * Msg = (MSGT_Message *)(Node->Value); + char * Msg_Data = Msg->Data; + + ND_Node_Next_Get (Node, &Next_Node); + + ND_Node_Remove (Node); + + /* On remplit le champ de données du message */ + + if (strlen (Answer) >= Msg->Size) + { + sprintf (Debug_Trace, "attention, le message (%d octets) n'est pas assez long pour contenir toute la réponse (%d caractères)\n", Msg->Size, strlen (Answer)); + Info_Trace (); + strncpy (Msg_Data, Answer, Msg->Size - 1); + Msg_Data [Msg->Size - 1] = (char)0; + } + else strcpy (Msg_Data, Answer); + + /* On renvoie le message à son envoyeur */ + + MSG_Message_Reply (Msg); + + /* Message suivant */ + + Node = Next_Node; + } + + /* On réinitialise les données concernant la requête */ + + memset (&(Tab_Request [Idx]), 0, sizeof (Waiting_Request)); + Tab_Request [Idx].Msg_List = Msg_List; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Procédure appelée lorsqu'un timeout expire */ +/*--------------------------------------------------------------------------------------------------*/ +void Timeout_Handle ( int signum ) +{ + unsigned int i, Older; + int Found = FALSE; + + /* On recherche la requête la plus ancienne */ + + for (i = 0; i < MSGD_NB_SYSTEM_MESSAGE; i++) + { + if (Date_IsSet (Tab_Request [i].Request_Date) && (Found == FALSE || Date_Compare (Tab_Request [i].Request_Date, Tab_Request [Older].Request_Date))) + { + Found = TRUE; + Older = i; + } + } + + /* On répond à la requête */ + + if (Found == TRUE) + { + strcpy (Debug_Trace, "timeout expiré => réponse à la requête la plus ancienne"); + Info_Trace (); + Request_Answer (Older); + } +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Redémarrage automatique d'un agent tombé */ +/*--------------------------------------------------------------------------------------------------*/ +void Agent_Restart ( int signum ) +{ + unsigned int Found, i; + pid_t Child_Pid; +#ifdef LINUX + int Child_Info; +#else + siginfo_t Child_Info; +#endif + unsigned int Restart; + + /* On réinitialise le trap du signal SIGCHLD */ + + signal (SIGCHLD, Agent_Restart); + + /* On récupère les informations concernant le processus fils qui est tombé */ + +#ifdef LINUX + Child_Pid = waitpid (-1, &Child_Info, WNOHANG); + + if (Child_Pid == -1) + { + sprintf (Debug_Trace, "impossible de récupérer les informations concernant un processus fils tombé"); + Info_Trace (); + return; + } +#else + if (waitid (P_ALL, 0, &Child_Info, WEXITED) == -1) + { + sprintf (Debug_Trace, "impossible de récupérer les informations concernant un processus fils tombé"); + Info_Trace (); + return; + } + + Child_Pid = Child_Info.si_pid; +#endif + + /* On recherche l'agent correspondant au process fils tombé */ + + Found = FALSE; + i = 0; + while (i < Nb_Agent && Found == FALSE) + { + if (Tab_Agent [i].GivenUp == FALSE) + { + if (Tab_Agent [i].Pid == Child_Pid) Found = TRUE; + else i++; + + } + else i++; + } + + if (Found == FALSE) + { + sprintf (Debug_Trace, "impossible de trouver l'agent correspondant au processus fils %ld tombé", Child_Pid); + Info_Trace (); + return; + } + + /* Analyse de la raison pour laquelle le fils est tombé */ + +#ifdef LINUX + if (WIFEXITED(Child_Info)) +#else + if (Child_Info.si_code == CLD_EXITED) +#endif + { + /* L'agent s'est terminé tout seul (comme un grand !!!) : on ne le relance pas */ + + Restart = FALSE; + +#ifdef LINUX + sprintf (Debug_Trace, "détection agent n°%d terminé avec code retour %d", i + 1, WEXITSTATUS(Child_Info)); +#else + sprintf (Debug_Trace, "détection agent n°%d terminé avec code retour %d", i + 1, Child_Info.si_status); +#endif + Info_Trace (); + } +#ifdef LINUX + else if (WIFSIGNALED(Child_Info) && WTERMSIG(Child_Info) == SIGKILL) +#else + else if (Child_Info.si_code == CLD_KILLED) +#endif + { + /* L'agent a à priori été tué volontairement : on ne le relance donc pas */ + + Restart = FALSE; + + sprintf (Debug_Trace, "détection agent n°%d tué", i + 1); + Info_Trace (); + + } +#ifdef LINUX + else if WIFSIGNALED(Child_Info) +#else + else if (Child_Info.si_code == CLD_DUMPED) +#endif + { + /* L'agent s'est terminé anormallement : on essaie de relancer l'agent */ + + Restart = TRUE; + +#ifdef LINUX + sprintf (Debug_Trace, "détection agent n°%d tombé suite à signal %d", i + 1, WTERMSIG(Child_Info)); +#else + sprintf (Debug_Trace, "détection agent n°%d tombé suite à signal %d", i + 1, Child_Info.si_status); +#endif + Info_Trace (); + } + else Restart = TRUE; + + if (Restart == TRUE) + { + /* Une tentative de relance a-t'elle déjà été lancée ? */ + + if (Tab_Agent [i].Restarted == TRUE) + { + sprintf (Debug_Trace, "abandon de l'agent n°%d", i + 1); + Info_Trace (); + Tab_Agent [i].GivenUp = TRUE; + Nb_GivenUp ++; + } + else + { + /* On redémarre l'agent */ + + sprintf (Debug_Trace, "relance de l'agent n°%d", i + 1); + Info_Trace (); + + Agent_Start (i + 1); + + Tab_Agent [i].Restarted = TRUE; + } + } + else + { + sprintf (Debug_Trace, "abandon de l'agent n°%d", i + 1); + Info_Trace (); + Tab_Agent [i].GivenUp = TRUE; + Nb_GivenUp ++; + } +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Envoi d'un message à un agent */ +/*--------------------------------------------------------------------------------------------------*/ +int Agent_Msg_Send ( unsigned int Num_Agent, unsigned int Type, int Priority ) +{ + MSGT_Message * Msg; + char Agent_Port_Name [256]; + MSGT_Port * Agent_Port; + + /* Ouverture du port de messages privé d'un agent dont on connait le numéro */ + + sprintf (Agent_Port_Name, "Agent_%d_port", Num_Agent); + + if (MSG_Port_Open (Agent_Port_Name, &Agent_Port, MSGD_OPEN) != MSGS_OK) + { + sprintf (Debug_Trace, "impossible d'ouvrir le port de messages \"%s\"", Agent_Port_Name); + Info_Trace (); + return KO; + } + + /* Création du message (de la taille d'un message système standard du superviseur aux agents) */ + + if (MSG_Message_Alloc (&Msg, sizeof (Agent_Stat)) != MSGS_OK) + { + sprintf (Debug_Trace, "impossible de créer un message destiné à l'agent n°%d", Num_Agent); + Info_Trace (); + MSG_Port_Close (Agent_Port, MSGD_CLOSE); + return KO; + } + + /* Initialisation des données du message */ + + memset (Msg->Data, 0, Msg->Size); + + /* Configuration du type de message */ + + if (MSG_Message_Config (Msg, MSGD_CONFIG_TYPE, Type) != MSGS_OK) + { + sprintf (Debug_Trace, "impossible de configurer le type du message destiné à l'agent n°%d", Num_Agent); + Info_Trace (); + MSG_Message_Free (Msg); + MSG_Port_Close (Agent_Port, MSGD_CLOSE); + return KO; + } + + /* Configuration de la priorité du message */ + + if (MSG_Message_Config (Msg, MSGD_CONFIG_PRIORITY, Priority) != MSGS_OK) + { + sprintf (Debug_Trace, "impossible de configurer la priorité du message destiné à l'agent n°%d", Num_Agent); + Info_Trace (); + MSG_Message_Free (Msg); + MSG_Port_Close (Agent_Port, MSGD_CLOSE); + return KO; + } + + /* Envoi du message avec demande d'accusé réception dans le port du superviseur */ + + if (MSG_Message_Send (MSGD_SUPERVISOR_PORT_NAME, Agent_Port, Msg) != MSGS_OK) + { + sprintf (Debug_Trace, "impossible d'envoyer le message destiné à l'agent n°%d", Num_Agent); + Info_Trace (); + MSG_Message_Free (Msg); + MSG_Port_Close (Agent_Port, MSGD_CLOSE); + return KO; + } + + /* Fermeture du port de messages d'envoi */ + + if (MSG_Port_Close (Agent_Port, MSGD_CLOSE) != MSGS_OK) + { + sprintf (Debug_Trace, "impossible de fermer le port de messages de l'agent n°%d", Num_Agent); + Info_Trace (); + MSG_Message_Free (Msg); + MSG_Port_Close (Agent_Port, MSGD_CLOSE); + return KO; + } + + return OK; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Démarrage d'un agent */ +/*--------------------------------------------------------------------------------------------------*/ +int Agent_Start ( unsigned int Num_Agent ) +{ + pid_t Agent_Pid; + + if (Num_Agent > NB_MAX_AGENT) + { + strcpy (Debug_Trace, "Limite maximale du nombre d'agents atteinte"); + Info_Trace (); + return KO; + } + + /* On crée un process fils */ + +#ifdef LINUX + Agent_Pid = fork (); +#else + /* Sous Solaris, il faut utiliser la fonction fork1() pour supporter le multi-thread */ + + Agent_Pid = fork1 (); +#endif + + if (Agent_Pid != 0) + { + /* Code pour le processus père (superviseur) : on référence le processus fils comme nouvel agent */ + + Tab_Agent [Num_Agent - 1].Pid = Agent_Pid; + Tab_Agent [Num_Agent - 1].Restarted = FALSE; + Tab_Agent [Num_Agent - 1].GivenUp = FALSE; + sprintf (Debug_Trace, "lancement de l'agent n°%d", Num_Agent); + Info_Trace (); + } + else + { + char sNum_Agent [10]; + + sprintf (sNum_Agent, "%d", Num_Agent); + + /* Code pour le processus fils (agent) */ + + if (Debug == TRUE) + execlp (AGENT_PATH, AGENT_PATH, "-id", sNum_Agent, "--debug", NULL, NULL); + else + execlp (AGENT_PATH, AGENT_PATH, "-id", sNum_Agent, NULL, NULL); + + sprintf (Debug_Trace, "erreur lors du lancement de l'agent n°%d (execl: errno %d)", Num_Agent, errno); + Info_Trace (); + + exit (KO); + } + + return OK; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Affichage sur la sortie standard d'erreur d'un message généré par le superviseur */ +/*--------------------------------------------------------------------------------------------------*/ +void Info_Trace ( void ) +{ + time_t dts; + struct tm * dt; + char Current_Date [25]; + + if (Debug) + { + /* Récupère la date courante */ + + time (&dts); + dt = localtime (&dts); + sprintf (Current_Date, "%02d/%02d/%04d %02d:%02d:%02d", dt->tm_mday, dt->tm_mon + 1, dt->tm_year + 1900, dt->tm_hour, dt->tm_min, dt->tm_sec); + + fprintf (stderr, "[%s] Superviseur : %s\n", Current_Date, Debug_Trace); + } +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Affiche le statut du superviseur */ +/*--------------------------------------------------------------------------------------------------*/ +char * Status_Get ( void ) +{ + static char Status_Str [256]; + + sprintf (Status_Str, "Timeout = %d sec / Trace = %s", Timeout, Debug == TRUE ? "On" : "Off"); + + return Status_Str; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Affiche le statut d'un agent */ +/*--------------------------------------------------------------------------------------------------*/ +char * Agent_Status_Get ( unsigned int Agent_Status, unsigned int Agent_Debug ) +{ + static char Status_Str [256]; + + sprintf (Status_Str, "Statut = %s / Trace = %s", Agent_Status == ACTIVE ? "actif" : "stoppé", Agent_Debug == TRUE ? "On" : "Off"); + + return Status_Str; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Manager d'une liste de messages en attente sur une requête */ +/*--------------------------------------------------------------------------------------------------*/ +NDT_Status Request_List_Manager (va_list Args) +{ + return NDS_OK; +}