From 61704628e3ca8c31df1666b3be4b723643dd25db Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 20 Sep 2023 09:10:56 +0200
Subject: Introduce an option to check ROST rule syntax without scanning.

---
 src/analysis/scan/options-int.h |  2 ++
 src/analysis/scan/options.c     | 45 +++++++++++++++++++++++++++++++++++++++++
 src/analysis/scan/options.h     |  6 ++++++
 src/rost.c                      | 44 ++++++++++++++++++++++++++++++++++------
 4 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/src/analysis/scan/options-int.h b/src/analysis/scan/options-int.h
index 4e85974..e8ae428 100644
--- a/src/analysis/scan/options-int.h
+++ b/src/analysis/scan/options-int.h
@@ -36,6 +36,8 @@ struct _GScanOptions
 
     GType data_backend;                     /* Choix du moteur d'analyse   */
 
+    bool check_only;                        /* Qu'une validation syntaxique*/
+
     bool print_json;                        /* Sortie au format json ?     */
     bool print_strings;                     /* Affichage de correspondances*/
     bool print_stats;                       /* Affichage de statistiques ? */
diff --git a/src/analysis/scan/options.c b/src/analysis/scan/options.c
index 2147bb5..637c821 100644
--- a/src/analysis/scan/options.c
+++ b/src/analysis/scan/options.c
@@ -86,6 +86,8 @@ static void g_scan_options_init(GScanOptions *options)
 {
     options->data_backend = G_TYPE_INVALID;
 
+    options->check_only = false;
+
     options->print_json = false;
     options->print_strings = false;
     options->print_stats = false;
@@ -201,6 +203,49 @@ void g_scan_options_set_backend_for_data(GScanOptions *options, GType backend)
 *                                                                             *
 *  Paramètres  : options = ensemble d'options d'analyses à consulter.         *
 *                                                                             *
+*  Description : Indique un besoin limité à une validation syntaxique.        *
+*                                                                             *
+*  Retour      : Etat de l'option visée à conservé.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_options_get_check_only(const GScanOptions *options)
+{
+    bool result;                            /* Statut à retourner          */
+
+    result = options->check_only;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : options = ensemble d'options d'analyses à modifier.          *
+*                state   = état de l'option visée à conserver.                *
+*                                                                             *
+*  Description : Mémorise un besoin de validation syntaxique uniquement.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_options_set_check_only(GScanOptions *options, bool state)
+{
+    options->check_only = state;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : options = ensemble d'options d'analyses à consulter.         *
+*                                                                             *
 *  Description : Impose le format JSON comme type de sortie.                  *
 *                                                                             *
 *  Retour      : Etat de l'option visée à conservé.                           *
diff --git a/src/analysis/scan/options.h b/src/analysis/scan/options.h
index 6b027e3..c6db838 100644
--- a/src/analysis/scan/options.h
+++ b/src/analysis/scan/options.h
@@ -57,6 +57,12 @@ GType g_scan_options_get_backend_for_data(const GScanOptions *);
 /* Sélectionne un type de moteur d'analyse pour données brutes. */
 void g_scan_options_set_backend_for_data(GScanOptions *, GType);
 
+/* Indique un besoin limité à une validation syntaxique. */
+bool g_scan_options_get_check_only(const GScanOptions *);
+
+/* Mémorise un besoin de validation syntaxique uniquement. */
+void g_scan_options_set_check_only(GScanOptions *, bool);
+
 /* Impose le format JSON comme type de sortie. */
 bool g_scan_options_get_print_json(const GScanOptions *);
 
diff --git a/src/rost.c b/src/rost.c
index 928aa12..efe18e5 100644
--- a/src/rost.c
+++ b/src/rost.c
@@ -22,6 +22,7 @@
  */
 
 
+#include <assert.h>
 #include <getopt.h>
 #include <libgen.h>
 #include <locale.h>
@@ -91,6 +92,7 @@ static void show_rost_help(const char *name)
     printf("\n");
 
     printf("\t-A --algorithm=name\tSelect one of the available algorithms for data: bitmap, acism (default: acsim).\n");
+    printf("\t-C --check-only\t\tValidate the rule syntax without performing a scan (discard the file/dir argument).\n");
     printf("\t-j --print-json\t\tPrint matching strings in JSON format.\n");
     printf("\t-s --print-strings\tPrint matching strings.\n");
     printf("\t-S --print-stats\tPrint rules' statistics.\n");
@@ -215,6 +217,7 @@ int main(int argc, char **argv)
     int result;                             /* Bilan de l'exécution        */
     bool show_help;                         /* Affichage de l'aide ?       */
     bool show_version;                      /* Affichage de la version ?   */
+    bool check_only;                        /* Validation uniquement       */
     LogMessageType verbosity;               /* Niveau de filtre de message */
     GScanOptions *options;                  /* Options d'analyses          */
     int index;                              /* Indice d'argument           */
@@ -233,6 +236,7 @@ int main(int argc, char **argv)
         { "help",           no_argument,        NULL,   'h' },
         { "version",        no_argument,        NULL,   'v' },
         { "algorithm",      required_argument,  NULL,   'A' },
+        { "check-only",     no_argument,        NULL,   'C' },
         { "print-json",     no_argument,        NULL,   'j' },
         { "print-strings",  no_argument,        NULL,   's' },
         { "print-stats",    no_argument,        NULL,   'S' },
@@ -247,6 +251,7 @@ int main(int argc, char **argv)
     show_help = false;
     show_version = false;
 
+    check_only = false;
     verbosity = LMT_INFO;
 
     options = g_scan_options_new();
@@ -255,7 +260,7 @@ int main(int argc, char **argv)
 
     while (true)
     {
-        ret = getopt_long(argc, argv, "hvA:jsSV:", long_options, &index);
+        ret = getopt_long(argc, argv, "hvA:CjsSV:", long_options, &index);
         if (ret == -1) break;
 
         switch (ret)
@@ -277,6 +282,11 @@ int main(int argc, char **argv)
                     g_scan_options_set_backend_for_data(options, G_TYPE_INVALID);
                 break;
 
+            case 'C':
+                check_only = true;
+                g_scan_options_set_check_only(options, true);
+                break;
+
             case 'j':
                 g_scan_options_set_print_json(options, true);
                 break;
@@ -297,10 +307,11 @@ int main(int argc, char **argv)
 
     }
 
-    if ((optind + 1) != argc && (optind + 2) != argc)
+    if ((check_only && (optind + 0) != argc && (optind + 1) != argc)
+        || (!check_only && (optind + 1) != argc && (optind + 2) != argc))
     {
+        printf("failed: check=%d optind=%d argc=%d\n", check_only, optind, argc);
         show_rost_help(argv[0]);
-        result = EXIT_FAILURE;
         goto done;
     }
 
@@ -323,7 +334,6 @@ int main(int argc, char **argv)
     if (g_scan_options_get_backend_for_data(options) == G_TYPE_INVALID)
     {
         show_rost_help(argv[0]);
-        result = EXIT_FAILURE;
         goto done;
     }
 
@@ -350,10 +360,26 @@ int main(int argc, char **argv)
 
     /* Traitement des recherches */
 
-    if ((optind + 1) == argc)
+    if ((optind + 0) == argc)
     {
+        assert(check_only);
+
         rules = NULL;
-        target = argv[optind];
+        target = NULL;
+
+    }
+    else if ((optind + 1) == argc)
+    {
+        if (check_only)
+        {
+            rules = argv[optind];
+            target = NULL;
+        }
+        else
+        {
+            rules = NULL;
+            target = argv[optind];
+        }
     }
     else
     {
@@ -382,8 +408,12 @@ int main(int argc, char **argv)
         scanner = g_content_scanner_new_from_file(rules);
 
     if (scanner != NULL)
+        result = EXIT_SUCCESS;
+
+    if (scanner != NULL && !check_only)
     {
         content = g_file_content_new(target);
+        if (content == NULL) goto bad_file_content;
 
         context = g_content_scanner_analyze(scanner, options, content);
 
@@ -406,6 +436,8 @@ int main(int argc, char **argv)
         g_object_unref(G_OBJECT(context));
         g_object_unref(G_OBJECT(content));
 
+ bad_file_content:
+
         g_object_unref(G_OBJECT(scanner));
 
     }
-- 
cgit v0.11.2-87-g4458