1 /*
2 ** Copyright (C) 2008-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  SiLK plugin implementation
11 **
12 */
13 
14 #include <silk/silk.h>
15 
16 RCSIDENT("$SiLK: skplugin.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
17 
18 #include <silk/rwrec.h>
19 #include <silk/skdllist.h>
20 #include <silk/skplugin.h>
21 #include <silk/skstream.h>
22 #include <silk/skvector.h>
23 #include <dlfcn.h>
24 
25 
26 /* LOCAL DEFINES AND TYPEDEFS */
27 
28 /* the value of HANDLE_FIELD is a true value if the application
29  * handles fields */
30 #define HANDLE_FIELD                                    \
31     (skp_handle_type(SKPLUGIN_APP_CUT)                  \
32      | skp_handle_type(SKPLUGIN_APP_SORT)               \
33      | skp_handle_type(SKPLUGIN_APP_GROUP)              \
34      | skp_handle_type(SKPLUGIN_APP_UNIQ_FIELD)         \
35      | skp_handle_type(SKPLUGIN_APP_UNIQ_VALUE)         \
36      | skp_handle_type(SKPLUGIN_APP_STATS_FIELD)        \
37      | skp_handle_type(SKPLUGIN_APP_STATS_VALUE))
38 
39 /* another macro to say whether an application supports fields */
40 #define SKPLUGIN_FNS_FIELD                      \
41     (SKPLUGIN_APP_CUT |                         \
42      SKPLUGIN_APP_SORT |                        \
43      SKPLUGIN_APP_GROUP |                       \
44      SKPLUGIN_APP_UNIQ_FIELD |                  \
45      SKPLUGIN_APP_UNIQ_VALUE |                  \
46      SKPLUGIN_APP_STATS_FIELD |                 \
47      SKPLUGIN_APP_STATS_VALUE)
48 
49 /* print a message and exit the application if memory for the object
50  * 'x' is NULL */
51 #define CHECK_MEM(x)                                            \
52     if (x) { /* no-op */ } else {                               \
53         skAppPrintErr(("skplugin: unable to allocate memory"    \
54                        " for object %s at %s:%d"),              \
55                       #x, __FILE__, __LINE__);                  \
56         abort();                                                \
57     }
58 
59 /*
60  *  ASSERT_RESULT(ar_func_args, ar_type, ar_expected);
61  *
62  *    ar_func_args  -- is a function and any arugments it requires
63  *    ar_type       -- is the type that ar_func_args returns
64  *    ar_expected   -- is the expected return value from ar_func_args
65  *
66  *    If assert() is disabled, simply call 'ar_func_args'.
67  *
68  *    If assert() is enabled, call 'ar_func_args', capture its result,
69  *    and assert() that its result is 'ar_expected'.
70  */
71 #ifdef  NDEBUG
72 /* asserts are disabled; just call the function */
73 #define ASSERT_RESULT(ar_func_args, ar_type, ar_expected)  ar_func_args
74 #else
75 #define ASSERT_RESULT(ar_func_args, ar_type, ar_expected)       \
76     do {                                                        \
77         ar_type ar_rv = (ar_func_args);                         \
78         assert(ar_rv == (ar_expected));                         \
79     } while(0)
80 #endif
81 
82 
83 /* members common to all three groups of plugins: (1) those that
84  * filter, (2) those that transform, and (3) those that support
85  * fields */
86 typedef struct skp_function_common_st {
87     const char                 *plugin_name;
88     skplugin_callback_fn_t      init;
89     skplugin_callback_fn_t      cleanup;
90     skplugin_callback_fn_t      cbfree;
91     void                       *data;
92     sk_dllist_t                *extra;
93     ssize_t                    *extra_remap;
94     size_t                      remap_size;
95 } skp_function_common_t;
96 
97 /* filter identifier */
98 /* typedef struct skp_filter_st skplugin_filter_t; // skplugin.h */
99 typedef struct skp_filter_st {
100     skp_function_common_t       common; /* Must be first element */
101     skplugin_filter_fn_t        filter;
102 } skp_filter_t;
103 
104 /* transformer identifier */
105 /* typedef struct skp_transform_st skplugin_transform_t; // skplugin.h */
106 typedef struct skp_transform_st {
107     skp_function_common_t       common; /* Must be first element */
108     skplugin_transform_fn_t     transform;
109 } skp_transform_t;
110 
111 /* field identifier */
112 /* typedef struct skp_field_st skplugin_field_t;  // skplugin.h */
113 typedef struct skp_field_st {
114     skp_function_common_t       common; /* Must be first element */
115     skplugin_text_fn_t          rec_to_text;
116     skplugin_bin_fn_t           rec_to_bin;
117     skplugin_bin_fn_t           add_rec_to_bin;
118     skplugin_bin_to_text_fn_t   bin_to_text;
119     skplugin_bin_merge_fn_t     bin_merge;
120     skplugin_bin_cmp_fn_t       bin_compare;
121     skplugin_fn_mask_t          fn_mask;
122     char                       *title;
123     char                      **names;
124     char                       *description;
125     uint8_t                    *initial_value;
126     size_t                      field_width_text;
127     size_t                      field_width_bin;
128 } skp_field_t;
129 
130 
131 typedef struct skp_option_st {
132     /* opt[1] is the sentinel */
133     struct option         opt[2];
134     skplugin_help_fn_t    help_fn;
135     skplugin_option_fn_t  opt_fn;
136     const char           *help_string;
137     const char           *plugin_name;
138     void                 *cbdata;
139 } skp_option_t;
140 
141 
142 /* LOCAL VARIABLE DEFINITIONS */
143 
144 /* Whether to print debug information when loading a plugin */
145 static int skp_debug = 0;
146 
147 /* Set to non-zero once skPluginSetup has been called */
148 static int skp_initialized = 0;
149 
150 /* Set to non-zero when we are in the process of running a a plugin's
151    setup function */
152 static int skp_in_plugin_init = 0;
153 
154 /* The current operating plugin */
155 static const char *skp_current_plugin_name = NULL;
156 
157 /* A list of plugin names */
158 static sk_dllist_t *skp_plugin_names = NULL;
159 
160 /* Specifies the types of functionality the app wants from its
161  * plugins */
162 static skplugin_fn_mask_t *skp_app_type = NULL;
163 
164 /* Holds the extra arguments the application says it will handle */
165 static sk_dllist_t *skp_app_support_extra_args = NULL;
166 
167 /* Holds the application extra arg array for the plugin to use */
168 static char **skp_app_extra_arg_array;
169 
170 /* Holds the extra arguments the plugins require */
171 static sk_dllist_t *skp_plugin_extra_args = NULL;
172 
173 /* Holds the plugin extra arg array for the app to use */
174 static char **skp_plugin_extra_arg_array;
175 
176 /* Holds the extra arguments the application will actually use */
177 static sk_dllist_t *skp_app_use_extra_args = NULL;
178 
179 /* Holds the command line option information */
180 static sk_dllist_t *skp_option_list = NULL;
181 
182 /* Holds the filter functions */
183 static sk_dllist_t *skp_filter_list = NULL;
184 
185 /* Holds the transform functions */
186 static sk_dllist_t *skp_transform_list = NULL;
187 
188 /* Holds the list of fields */
189 static sk_dllist_t *skp_field_list = NULL;
190 
191 /* Holds the list of active fields */
192 static sk_dllist_t *skp_active_field_list = NULL;
193 
194 /* Holds the list of non-function specific plugin cleanup functions */
195 static sk_dllist_t *skp_cleanup_list = NULL;
196 
197 /* The library dlopen() handles */
198 static sk_dllist_t *skp_library_list = NULL;
199 
200 /* Function to call to open streams.  Applications may set this. */
201 static open_data_input_fn_t open_data_input_fn;
202 
203 /* Whether the current set of loaded plugins are all thread-safe */
204 static int skp_thread_safe = 1;
205 
206 /* Structure representing some members of the skplugin_callbacks_t
207  * structure.  If the verbose flag is set and a field fails to be
208  * registered because callback members are unset, this structure is
209  * used find the missing members' names for the error message. */
210 static const struct skp_callback_string_st {
211     const char *name;
212     uint32_t    bit;
213 } skp_callback_string[] = {
214     {"rec_to_bin",      SKPLUGIN_FN_REC_TO_BIN},
215     {"add_rec_to_bin",  SKPLUGIN_FN_ADD_REC_TO_BIN},
216     {"bin_to_text",     SKPLUGIN_FN_BIN_TO_TEXT},
217     {"rec_to_text",     SKPLUGIN_FN_REC_TO_TEXT},
218     {"bin_merge",       SKPLUGIN_FN_MERGE},
219     {"bin_compare",     SKPLUGIN_FN_COMPARE},
220     {"bin_bytes",       SKPLUGIN_FN_BIN_BYTES},
221     {"column_width",    SKPLUGIN_FN_COLUMN_WIDTH},
222     {NULL,              0}      /* sentinel */
223 };
224 
225 /* A number whose length is greater than the sum of the lengths of the
226  * above strings, including an extra 2 char padding per field. */
227 #define MAX_CALLBACKS_STRING_WIDTH 200
228 
229 
230 /* LOCAL FUNCTION PROTOTYPES */
231 
232 static sk_dllist_t *skp_arg_list_from_array(const char **array);
233 static char **skp_arg_array_from_list(sk_dllist_t *list);
234 static char **skp_arg_array_from_string(const char *string);
235 static void skp_arg_array_destroy(char **array);
236 static void skp_arg_add_to_list(const char *arg, sk_dllist_t *list);
237 static void skp_arg_list_add_to_list(sk_dllist_t *src, sk_dllist_t *dest);
238 static int skp_arg_list_subset_of_list(sk_dllist_t *subset, sk_dllist_t *set);
239 static int skp_option_handler(clientData  cData, int opt_index, char *opt_arg);
240 static void skp_function_common_destroy(void *vcommon);
241 static void skp_function_field_destroy(void *vfield);
242 static skplugin_fn_mask_t skp_field_mask(const skplugin_callbacks_t *regdata);
243 static void
244 skp_setup_remap(
245     skp_function_common_t  *common,
246     sk_dllist_t            *extra_map);
247 static void **
248 skp_remap(
249     const skp_function_common_t    *common,
250     void                          **extra);
251 static int
252 skp_list_find(
253     sk_dll_iter_t      *iter,
254     const void         *target,
255     sk_dllist_t        *fields);
256 static void skp_unload_library(void *handle);
257 
258 
259 /* FUNCTION DEFINITIONS */
260 
261 /* return 1 if the application handles fields containing one of the
262  * types listed in the 'fn_mask'; return 0 otherwise.  */
263 static int
skp_handle_type(skplugin_fn_mask_t fn_mask)264 skp_handle_type(
265     skplugin_fn_mask_t  fn_mask)
266 {
267     skplugin_fn_mask_t *mask;
268 
269     assert(skp_initialized);
270     assert(skp_app_type);
271 
272     mask = skp_app_type;
273     if (*mask == SKPLUGIN_FN_ANY) {
274         return 1;
275     }
276 
277     for ( ; *mask; ++mask) {
278         if ((fn_mask & *mask) == fn_mask) {
279             return 1;
280         }
281     }
282 
283     return 0;
284 }
285 
286 
287 static int
skp_handle_field(skp_field_t * field,int verbose)288 skp_handle_field(
289     skp_field_t        *field,
290     int                 verbose)
291 {
292     skplugin_fn_mask_t *mask;
293 
294     assert(skp_initialized);
295     assert(skp_app_type);
296     assert(field);
297 
298     mask = skp_app_type;
299     if (*mask == SKPLUGIN_FN_ANY) {
300         return 1;
301     }
302 
303     for ( ; *mask; ++mask) {
304         if ((field->fn_mask & *mask) == *mask) {
305             /* this application can use this field; return */
306             return 1;
307         }
308         /* this field cannot be used; print an explanation if verbose
309          * is set */
310         if (verbose) {
311             char missing_fields[MAX_CALLBACKS_STRING_WIDTH];
312             char *pos = missing_fields;
313             int len = sizeof(missing_fields);
314             const struct skp_callback_string_st *cbs;
315             int rv;
316             int count = 0;
317 
318             for (cbs = skp_callback_string; cbs->name; ++cbs) {
319                 if ((*mask & cbs->bit) && !(field->fn_mask & cbs->bit)) {
320                     rv = snprintf(pos, len, "%s%s",
321                                   (count ? ", " : ""), cbs->name);
322                     len -= rv;
323                     pos += rv;
324                     ++count;
325                     if (len <= 0) {
326                         skAbort();
327                     }
328                 }
329             }
330             skAppPrintErr((SKPLUGIN_DEBUG_ENVAR ": ignoring field '%s' due "
331                            "to missing skplugin_callbacks_t member%s %s"),
332                           field->title, ((count > 1) ? "s" : ""),
333                           missing_fields);
334         }
335     }
336 
337     return 0;
338 }
339 
340 
341 /* This is used to initialize the skplugin library.  'num_entries' is
342  * the number of function mask entries in the vararg list. */
343 void
skPluginSetup(int num_entries,...)344 skPluginSetup(
345     int                 num_entries,
346     ...)
347 {
348     va_list             ap;
349     char               *env_value;
350     int                 rv;
351     skplugin_fn_mask_t  fn_mask;
352     sk_vector_t        *app_type_vec;
353 
354     assert(!skp_initialized);
355     assert(num_entries >= 0);
356 
357 #ifndef NDEBUG
358     /* verify MAX_CALLBACKS_STRING_WIDTH is large enough to hold a
359      * comma-separated list of the names in skp_callback_string */
360     {
361         const struct skp_callback_string_st *cbs;
362         size_t len;
363 
364         len = 0;
365         for (cbs = skp_callback_string; cbs->name; ++cbs) {
366             len += 2 + strlen(cbs->name);
367         }
368         assert(len < MAX_CALLBACKS_STRING_WIDTH);
369     }
370 #endif  /* NDEBUG */
371 
372     /* Check for debugging */
373     env_value = getenv(SKPLUGIN_DEBUG_ENVAR);
374     if ((env_value != NULL) && (env_value[0] != '\0')) {
375         skp_debug = 1;
376     }
377 
378     /* Make the application type array */
379     app_type_vec = skVectorNew(sizeof(skplugin_fn_mask_t));
380     CHECK_MEM(app_type_vec);
381     va_start(ap, num_entries);
382     while (num_entries--) {
383         fn_mask = va_arg(ap, skplugin_fn_mask_t);
384         rv = skVectorAppendValue(app_type_vec, &fn_mask);
385         CHECK_MEM(rv == 0);
386     }
387     fn_mask = 0;
388     rv = skVectorAppendValue(app_type_vec, &fn_mask);
389     CHECK_MEM(rv == 0);
390     va_end(ap);
391     skp_app_type = (skplugin_fn_mask_t*)calloc(skVectorGetCount(app_type_vec),
392                                                sizeof(skplugin_fn_mask_t));
393     CHECK_MEM(skp_app_type);
394     skVectorToArray(skp_app_type, app_type_vec);
395     skVectorDestroy(app_type_vec);
396 
397     /* Set once we have a proper skp_app_type */
398     skp_initialized = 1;
399 
400     /* Create all the internal lists */
401     skp_app_support_extra_args = skDLListCreate(free);
402     CHECK_MEM(skp_app_support_extra_args);
403     skp_app_extra_arg_array = NULL;
404     skp_plugin_extra_args = skDLListCreate(free);
405     CHECK_MEM(skp_plugin_extra_args);
406     skp_plugin_extra_arg_array = NULL;
407     skp_app_use_extra_args = skDLListCreate(free);
408     CHECK_MEM(skp_app_use_extra_args);
409     skp_option_list = skDLListCreate(free);
410     CHECK_MEM(skp_option_list);
411     if (skp_handle_type(SKPLUGIN_APP_FILTER)) {
412         skp_filter_list = skDLListCreate(skp_function_common_destroy);
413         CHECK_MEM(skp_filter_list);
414     }
415     if (skp_handle_type(SKPLUGIN_APP_TRANSFORM)) {
416         skp_transform_list = skDLListCreate(skp_function_common_destroy);
417         CHECK_MEM(skp_transform_list);
418     }
419     if (HANDLE_FIELD) {
420         skp_field_list = skDLListCreate(skp_function_field_destroy);
421         CHECK_MEM(skp_field_list);
422         skp_active_field_list = skDLListCreate(NULL);
423         CHECK_MEM(skp_active_field_list);
424     }
425     skp_cleanup_list = skDLListCreate(NULL);
426     CHECK_MEM(skp_cleanup_list);
427     skp_library_list = skDLListCreate(skp_unload_library);
428     CHECK_MEM(skp_library_list);
429     skp_plugin_names = skDLListCreate(free);
430     CHECK_MEM(skp_plugin_names);
431 }
432 
433 
434 /* Unloads all plugins and frees all plugin data.  Does not call
435  * cleanup functions. */
436 void
skPluginTeardown(void)437 skPluginTeardown(
438     void)
439 {
440     assert(skp_initialized);
441 
442     skDLListDestroy(skp_app_support_extra_args);
443     skp_arg_array_destroy(skp_app_extra_arg_array);
444     skDLListDestroy(skp_plugin_extra_args);
445     skp_arg_array_destroy(skp_plugin_extra_arg_array);
446     skDLListDestroy(skp_app_use_extra_args);
447     skDLListDestroy(skp_option_list);
448     if (skp_handle_type(SKPLUGIN_APP_FILTER)) {
449         skDLListDestroy(skp_filter_list);
450     }
451     if (skp_handle_type(SKPLUGIN_APP_TRANSFORM)) {
452         skDLListDestroy(skp_transform_list);
453     }
454     if (HANDLE_FIELD) {
455         skDLListDestroy(skp_field_list);
456         skDLListDestroy(skp_active_field_list);
457     }
458     skDLListDestroy(skp_cleanup_list);
459     skDLListDestroy(skp_plugin_names);
460 
461     free(skp_app_type);
462     skp_app_type = NULL;
463 
464     /* Unload all the libraries */
465     skDLListDestroy(skp_library_list);
466 
467     skp_initialized = 0;
468 }
469 
470 
471 /* Sets the extra arguments that the application handles.  'extra' is
472  * a NULL terminated array of strings.  If 'extra' is NULL, no extra
473  * arguments are registered.  (This is the default) */
474 void
skPluginSetAppExtraArgs(const char ** extra)475 skPluginSetAppExtraArgs(
476     const char        **extra)
477 {
478     assert(skp_initialized);
479 
480     skDLListDestroy(skp_app_support_extra_args);
481     skDLListDestroy(skp_app_use_extra_args);
482 
483     /* These are the arguments this app supports */
484     skp_app_support_extra_args = skp_arg_list_from_array(extra);
485 
486     /* By default, these are also the arguments this app will use.  To
487      * change this, call skPluginSetUsedAppExtraArgs(). */
488     skp_app_use_extra_args = skp_arg_list_from_array(extra);
489 
490     return;
491 }
492 
493 
494 /* Create an sk_dllist_t from a char ** */
495 static sk_dllist_t *
skp_arg_list_from_array(const char ** array)496 skp_arg_list_from_array(
497     const char        **array)
498 {
499     const char **arg;
500     sk_dllist_t *list = skDLListCreate(free);
501 
502     CHECK_MEM(list);
503 
504     if (array == NULL) {
505         return list;
506     }
507 
508     for (arg = array; *arg != NULL; arg++) {
509         char *arg_dup = strdup(*arg);
510 
511         CHECK_MEM(arg_dup);
512         CHECK_MEM(0 == skDLListPushTail(list, arg_dup));
513     }
514 
515     return list;
516 }
517 
518 /* Create a char ** from a sk_dllist_t */
519 static char **
skp_arg_array_from_list(sk_dllist_t * list)520 skp_arg_array_from_list(
521     sk_dllist_t        *list)
522 {
523     char          **array;
524     size_t          count;
525     size_t          i;
526     sk_dll_iter_t   iter;
527     const char     *arg;
528 
529     if (skDLListIsEmpty(list)) {
530         return NULL;
531     }
532 
533     /* Count the elements of the list */
534     skDLLAssignIter(&iter, list);
535     for (count = 0; skDLLIterForward(&iter, NULL) == 0; count++)
536         ;  /* empty */
537 
538     /* Create the array */
539     array = (char **)calloc(count + 1, sizeof(char *));
540     CHECK_MEM(array);
541 
542     /* Fill the array */
543     for (i = 0; skDLLIterForward(&iter, (void **)&arg); i++) {
544         array[i] = strdup(arg);
545         CHECK_MEM(array[i]);
546     }
547 
548     return array;
549 }
550 
551 
552 /* Create a single entry char ** from a string */
553 static char **
skp_arg_array_from_string(const char * str)554 skp_arg_array_from_string(
555     const char         *str)
556 {
557     char **array;
558 
559     /* Create the array */
560     array = (char **)calloc(2, sizeof(char *));
561     CHECK_MEM(array);
562 
563     /* Fill the array */
564     array[0] = strdup(str);
565     CHECK_MEM(array[0]);
566 
567     return array;
568 }
569 
570 
571 /* Destroy a char** */
572 static void
skp_arg_array_destroy(char ** array)573 skp_arg_array_destroy(
574     char              **array)
575 {
576     char **arg;
577 
578     if (!array) {
579         return;
580     }
581 
582     for (arg = array; *arg; arg++) {
583         free(*arg);
584     }
585 
586     free(array);
587 }
588 
589 
590 /* Find the location of a string is in an arg list */
591 static ssize_t
skp_arg_location(const char * arg,sk_dllist_t * list)592 skp_arg_location(
593     const char         *arg,
594     sk_dllist_t        *list)
595 {
596     sk_dll_iter_t  iter;
597     char          *list_arg;
598     ssize_t        loc;
599 
600     skDLLAssignIter(&iter, list);
601     for (loc = 0; skDLLIterForward(&iter, (void **)&list_arg) == 0; loc++) {
602         if (strcmp(arg, list_arg) == 0) {
603             return loc;
604         }
605     }
606 
607     return -1;
608 }
609 
610 
611 /* Add an argument uniquely to an argument list */
612 static void
skp_arg_add_to_list(const char * arg,sk_dllist_t * list)613 skp_arg_add_to_list(
614     const char         *arg,
615     sk_dllist_t        *list)
616 {
617     if (skp_arg_location(arg, list) == -1) {
618         char *duplicate = strdup(arg);
619         CHECK_MEM(duplicate);
620         CHECK_MEM(0 == skDLListPushTail(list, duplicate));
621     }
622 }
623 
624 
625 /* Add an elements of an argument list uniquely to another list */
626 static void
skp_arg_list_add_to_list(sk_dllist_t * src,sk_dllist_t * dest)627 skp_arg_list_add_to_list(
628     sk_dllist_t        *src,
629     sk_dllist_t        *dest)
630 {
631     sk_dll_iter_t  iter;
632     const char    *arg;
633 
634     skDLLAssignIter(&iter, src);
635     while (skDLLIterForward(&iter, (void **)&arg) == 0) {
636         skp_arg_add_to_list(arg, dest);
637     }
638 }
639 
640 
641 
642 /* Check if an argumnt list is a subset of another argument list */
643 static int
skp_arg_list_subset_of_list(sk_dllist_t * subset,sk_dllist_t * set)644 skp_arg_list_subset_of_list(
645     sk_dllist_t        *subset,
646     sk_dllist_t        *set)
647 {
648     const char    *arg;
649     sk_dll_iter_t  iter;
650 
651     skDLLAssignIter(&iter, subset);
652 
653     while (skDLLIterForward(&iter, (void **)&arg) == 0) {
654         if (skp_arg_location(arg, set) == -1) {
655             return 0;
656         }
657     }
658 
659     return 1;
660 }
661 
662 #if 0
663 /* Check to see if there is a duplicate name in a list of fields */
664 static int
665 skp_find_name(
666     const char         *name,
667     sk_dllist_t        *list)
668 {
669     sk_dll_iter_t  iter;
670     skp_field_t   *field;
671     char         **fieldname;
672 
673     skDLLAssignIter(&iter, list);
674     while (skDLLIterForward(&iter, (void **)&field) == 0) {
675         for (fieldname = field->names; *fieldname; fieldname++) {
676             if (strcasecmp(name, *fieldname) == 0) {
677                 return  1;
678             }
679         }
680     }
681 
682     return 0;
683 }
684 #endif  /* 0 */
685 
686 
687 /* Gets the applications list of extra arguments as a NULL-terminated
688  * list of strings. */
689 const char **
skpinGetAppExtraArgs(void)690 skpinGetAppExtraArgs(
691     void)
692 {
693     assert(skp_initialized);
694 
695     if (!skp_app_extra_arg_array) {
696         assert(skp_app_support_extra_args);
697         skp_app_extra_arg_array = skp_arg_array_from_list(
698             skp_app_support_extra_args);
699     }
700 
701     return (const char **)skp_app_extra_arg_array;
702 }
703 
704 
705 /* Gets the list of extra arguments of the application that the
706  * plugins support.  The returned array will be a NULL-terminated list
707  * of strings. */
708 const char **
skPluginGetPluginExtraArgs(void)709 skPluginGetPluginExtraArgs(
710     void)
711 {
712     assert(skp_initialized);
713 
714     if (!skp_plugin_extra_arg_array) {
715         assert(skp_plugin_extra_args);
716         skp_plugin_extra_arg_array = skp_arg_array_from_list(
717             skp_plugin_extra_args);
718     }
719 
720     return (const char **)skp_plugin_extra_args;
721 }
722 
723 
724 /* Sets which extra arguments the application will actually use.
725  * 'extra' is a NULL * terminated array of strings.  If 'extra' is
726  * NULL, no extra arguments are registered.  */
727 void
skPluginSetUsedAppExtraArgs(const char ** extra)728 skPluginSetUsedAppExtraArgs(
729     const char        **extra)
730 {
731     sk_dll_iter_t    iter;
732     skp_filter_t    *filt;
733     skp_transform_t *transform;
734     skp_field_t     *field;
735 
736     assert(skp_initialized);
737 
738     skDLListDestroy(skp_app_use_extra_args);
739     skp_app_use_extra_args = skp_arg_list_from_array(extra);
740 
741     if (!skp_arg_list_subset_of_list(skp_app_use_extra_args,
742                                      skp_app_support_extra_args))
743     {
744         skAppPrintErr("skPluginSetUsedAppExtraArgs: "
745                       "Not subset of supported extra arguments");
746         exit(EXIT_FAILURE);
747     }
748 
749     skDLLAssignIter(&iter, skp_filter_list);
750     while (skDLLIterForward(&iter, (void **)&filt) == 0) {
751         skp_setup_remap(&filt->common, skp_app_use_extra_args);
752     }
753 
754     skDLLAssignIter(&iter, skp_transform_list);
755     while (skDLLIterForward(&iter, (void **)&transform) == 0) {
756         skp_setup_remap(&transform->common, skp_app_use_extra_args);
757     }
758 
759     skDLLAssignIter(&iter, skp_field_list);
760     while (skDLLIterForward(&iter, (void **)&field) == 0) {
761         skp_setup_remap(&field->common, skp_app_use_extra_args);
762     }
763 }
764 
765 
766 /* Set function that skpinOpenDataInputStream() uses. */
767 void
skPluginSetOpenInputFunction(open_data_input_fn_t open_fn)768 skPluginSetOpenInputFunction(
769     open_data_input_fn_t    open_fn)
770 {
771     open_data_input_fn = open_fn;
772 }
773 
774 
775 /* Create and open a stream to process 'filename'. */
776 int
skpinOpenDataInputStream(skstream_t ** stream,skcontent_t content_type,const char * filename)777 skpinOpenDataInputStream(
778     skstream_t        **stream,
779     skcontent_t         content_type,
780     const char         *filename)
781 {
782     int rv;
783 
784     assert(stream);
785     assert(filename);
786 
787     if (open_data_input_fn) {
788         return open_data_input_fn(stream, content_type, filename);
789     }
790 
791     if ((rv = (skStreamCreate(stream, SK_IO_READ, content_type)))
792         || (rv = skStreamBind((*stream), filename))
793         || (rv = skStreamOpen(*stream)))
794     {
795         skStreamPrintLastErr((*stream), rv, &skAppPrintErr);
796         skStreamDestroy(stream);
797         return -1;
798     }
799     return 0;
800 }
801 
802 
803 /* Register an option for command-line processing.
804  *   opt(opt_arg, data) will be called back when the option_name is
805  *       seen as an option.  If no arg is given, opt_arg will be NULL.
806  *   mode should be one of NO_ARG, OPTIONAL_ARG, or REQUIRED_ARG.
807  *   num_entries is the number of app_types in the va-list.
808  *   app_types should be SKPLUGIN_APP_ANY or a list of
809  *       SKPLUGIN_APP_FILTER, SKPLUGIN_APP_CUT, etc.
810  */
811 skplugin_err_t
skpinRegOption2(const char * option_name,skplugin_arg_mode_t mode,const char * option_help_string,skplugin_help_fn_t option_help_fn,skplugin_option_fn_t opt_callback_fn,void * callback_data,int num_entries,...)812 skpinRegOption2(
813     const char             *option_name,
814     skplugin_arg_mode_t     mode,
815     const char             *option_help_string,
816     skplugin_help_fn_t      option_help_fn,
817     skplugin_option_fn_t    opt_callback_fn,
818     void                   *callback_data,
819     int                     num_entries,
820     ...)
821 {
822     va_list            ap;
823     skplugin_fn_mask_t fn_mask;
824     skplugin_err_t     rv = SKPLUGIN_ERR_DID_NOT_REGISTER;
825     skp_option_t      *optrec;
826 
827     assert(skp_initialized);
828     assert(skp_in_plugin_init);
829 
830     if (num_entries < 0) {
831         skAbort();
832     }
833     if (NULL == option_name || NULL == opt_callback_fn) {
834         return SKPLUGIN_ERR;
835     }
836 
837     va_start(ap, num_entries);
838     while (num_entries--) {
839         fn_mask = va_arg(ap, skplugin_fn_mask_t);
840         if (!skp_handle_type(fn_mask)) {
841             continue;
842         }
843 
844         optrec = (skp_option_t *)calloc(1, sizeof(*optrec));
845         CHECK_MEM(optrec);
846 
847         optrec->opt[0].name = (char*)option_name;
848         optrec->opt[0].has_arg = mode;
849         optrec->help_string = option_help_string;
850         optrec->help_fn = option_help_fn;
851         optrec->opt_fn = opt_callback_fn;
852         optrec->cbdata = callback_data;
853         optrec->plugin_name = skp_current_plugin_name;
854 
855         if (0 != skOptionsRegister(optrec->opt, skp_option_handler, optrec)) {
856             free(optrec);
857             rv = SKPLUGIN_ERR_FATAL;
858             break;
859         }
860 
861         CHECK_MEM(0 == skDLListPushTail(skp_option_list, optrec));
862 
863         rv = SKPLUGIN_OK;
864         break;
865     }
866     va_end(ap);
867 
868     return rv;
869 }
870 
871 skplugin_err_t
skpinRegOption(skplugin_fn_mask_t fn_mask,const char * option_name,skplugin_arg_mode_t mode,const char * option_help,skplugin_option_fn_t opt,void * data)872 skpinRegOption(
873     skplugin_fn_mask_t      fn_mask,
874     const char             *option_name,
875     skplugin_arg_mode_t     mode,
876     const char             *option_help,
877     skplugin_option_fn_t    opt,
878     void                   *data)
879 {
880     return skpinRegOption2(option_name, mode, option_help, NULL, opt, data,
881                            1, fn_mask);
882 }
883 
884 skplugin_err_t
skpinRegOptionWithHelpFn(skplugin_fn_mask_t fn_mask,const char * option_name,skplugin_arg_mode_t mode,skplugin_help_fn_t option_help,skplugin_option_fn_t opt,void * data)885 skpinRegOptionWithHelpFn(
886     skplugin_fn_mask_t      fn_mask,
887     const char             *option_name,
888     skplugin_arg_mode_t     mode,
889     skplugin_help_fn_t      option_help,
890     skplugin_option_fn_t    opt,
891     void                   *data)
892 {
893     return skpinRegOption2(option_name, mode, NULL, option_help, opt, data,
894                            1, fn_mask);
895 }
896 
897 
898 /* Option handler for plugin options */
899 static int
skp_option_handler(clientData cData,int UNUSED (opt_index),char * opt_arg)900 skp_option_handler(
901     clientData          cData,
902     int          UNUSED(opt_index),
903     char               *opt_arg)
904 {
905     skplugin_err_t  err;
906     skp_option_t   *optrec              = (skp_option_t *)cData;
907     int             save_in_plugin_init = skp_in_plugin_init;
908 
909     assert(optrec);
910 
911     skp_in_plugin_init = 1;
912     skp_current_plugin_name = optrec->plugin_name;
913     err = optrec->opt_fn(opt_arg, optrec->cbdata);
914     skp_current_plugin_name = NULL;
915     skp_in_plugin_init = save_in_plugin_init;
916 
917     return (err != SKPLUGIN_OK);
918 }
919 
920 
921 /* Called by plug-in to register a filter predicate. */
922 skplugin_err_t
skpinRegFilter(skp_filter_t ** return_filter,const skplugin_callbacks_t * regdata,void * cbdata)923 skpinRegFilter(
924     skp_filter_t                  **return_filter,
925     const skplugin_callbacks_t     *regdata,
926     void                           *cbdata)
927 {
928     skp_filter_t *filter_data;
929     sk_dllist_t  *extra;
930 
931     assert(skp_initialized);
932     assert(skp_in_plugin_init);
933 
934     if (return_filter) {
935         *return_filter = NULL;
936     }
937 
938     if (!skp_handle_type(SKPLUGIN_FN_FILTER)) {
939         return SKPLUGIN_OK;
940     }
941 
942     assert(skp_filter_list);
943 
944     if (NULL == regdata) {
945         if (skp_debug) {
946             skAppPrintErr((SKPLUGIN_DEBUG_ENVAR
947                            ": ignoring filter due to NULL regdata"));
948         }
949         return SKPLUGIN_ERR;
950     }
951     if (NULL == regdata->filter) {
952         if (skp_debug) {
953             skAppPrintErr((SKPLUGIN_DEBUG_ENVAR
954                            ": ignoring filter due to NULL filter() callback"));
955         }
956         return SKPLUGIN_ERR;
957     }
958 
959     extra = skp_arg_list_from_array(regdata->extra);
960     CHECK_MEM(extra);
961 
962     if (!skp_arg_list_subset_of_list(extra, skp_app_support_extra_args)) {
963         skAppPrintErr("skpinRegFilterWithExtraArgsDLL: "
964                       "extra arguments required by plugin "
965                       "not supported by application");
966         exit(EXIT_FAILURE);
967     }
968 
969     filter_data = (skp_filter_t *)calloc(1, sizeof(*filter_data));
970     CHECK_MEM(filter_data);
971 
972     filter_data->common.plugin_name = skp_current_plugin_name;
973     filter_data->common.init = regdata->init;
974     filter_data->common.cleanup = regdata->cleanup;
975     filter_data->common.extra = extra;
976     filter_data->common.data = cbdata;
977     filter_data->filter = regdata->filter;
978 
979     CHECK_MEM(0 == skDLListPushTail(skp_filter_list, filter_data));
980 
981     skp_arg_list_add_to_list(extra, skp_plugin_extra_args);
982 
983     skp_setup_remap(&filter_data->common, skp_app_support_extra_args);
984 
985     if (return_filter) {
986         *return_filter = filter_data;
987     }
988 
989     return SKPLUGIN_OK;
990 }
991 
992 
993 /* Called by plug-in to register a transformation predicate */
994 skplugin_err_t
skpinRegTransformer(skp_transform_t ** return_transformer,const skplugin_callbacks_t * regdata,void * cbdata)995 skpinRegTransformer(
996     skp_transform_t               **return_transformer,
997     const skplugin_callbacks_t     *regdata,
998     void                           *cbdata)
999 {
1000     skp_transform_t *transform_data;
1001     sk_dllist_t     *extra;
1002 
1003     assert(skp_initialized);
1004     assert(skp_in_plugin_init);
1005 
1006     if (return_transformer) {
1007         *return_transformer = NULL;
1008     }
1009 
1010     if (!skp_handle_type(SKPLUGIN_FN_TRANSFORM)) {
1011         return SKPLUGIN_OK;
1012     }
1013 
1014     assert(skp_transform_list);
1015 
1016     if (NULL == regdata) {
1017         if (skp_debug) {
1018             skAppPrintErr((SKPLUGIN_DEBUG_ENVAR
1019                            ": ignoring transformer due to NULL regdata"));
1020         }
1021         return SKPLUGIN_ERR;
1022     }
1023     if (NULL == regdata->transform) {
1024         if (skp_debug) {
1025             skAppPrintErr((SKPLUGIN_DEBUG_ENVAR
1026                            ": ignoring transformer due to NULL transform()"
1027                            " callback"));
1028         }
1029         return SKPLUGIN_ERR;
1030     }
1031 
1032     extra = skp_arg_list_from_array(regdata->extra);
1033     CHECK_MEM(extra);
1034 
1035     if (!skp_arg_list_subset_of_list(extra, skp_app_support_extra_args)) {
1036         skAppPrintErr("skpinRegTransformWithExtraArgsDLL: "
1037                       "extra arguments required by plugin "
1038                       "not supported by application");
1039         exit(EXIT_FAILURE);
1040     }
1041 
1042     transform_data = (skp_transform_t *)calloc(1, sizeof(*transform_data));
1043     CHECK_MEM(transform_data);
1044 
1045     transform_data->common.plugin_name = skp_current_plugin_name;
1046     transform_data->common.init = regdata->init;
1047     transform_data->common.cleanup = regdata->cleanup;
1048     transform_data->common.extra = extra;
1049     transform_data->common.data = cbdata;
1050     transform_data->transform = regdata->transform;
1051 
1052     CHECK_MEM(0 == skDLListPushTail(skp_transform_list, transform_data));
1053 
1054     skp_arg_list_add_to_list(extra, skp_plugin_extra_args);
1055 
1056     skp_setup_remap(&transform_data->common, skp_app_support_extra_args);
1057 
1058     if (return_transformer) {
1059         *return_transformer = transform_data;
1060     }
1061 
1062     return SKPLUGIN_OK;
1063 }
1064 
1065 
1066 /* Called by plug-in to register a field */
1067 skplugin_err_t
skpinRegField(skplugin_field_t ** return_field,const char * name,const char * description,const skplugin_callbacks_t * regdata,void * cbdata)1068 skpinRegField(
1069     skplugin_field_t              **return_field,
1070     const char                     *name,
1071     const char                     *description,
1072     const skplugin_callbacks_t     *regdata,
1073     void                           *cbdata)
1074 {
1075     skplugin_field_t *field;
1076     sk_dllist_t      *extra;
1077 
1078     assert(skp_initialized);
1079     assert(skp_in_plugin_init);
1080 
1081     if (return_field) {
1082         *return_field = NULL;
1083     }
1084 
1085     /* return if this application does not support fields */
1086     if (!HANDLE_FIELD) {
1087         return SKPLUGIN_OK;
1088     }
1089 
1090     assert(skp_field_list);
1091 
1092     if (!name) {
1093         if (skp_debug) {
1094             skAppPrintErr(SKPLUGIN_DEBUG_ENVAR
1095                           ": ignoring field due to NULL name");
1096         }
1097         return SKPLUGIN_ERR;
1098     }
1099     if (!regdata) {
1100         if (skp_debug) {
1101             skAppPrintErr((SKPLUGIN_DEBUG_ENVAR
1102                            ": ignoring field '%s' due to NULL regdata"),
1103                           name);
1104         }
1105         return SKPLUGIN_ERR;
1106     }
1107 #if 0
1108     if (skp_find_name(name, skp_field_list)) {
1109         skAppPrintErr("A field already has the name, \"%s\"", name);
1110         return SKPLUGIN_ERR;
1111     }
1112 #endif  /* 0 */
1113 
1114     extra = skp_arg_list_from_array(regdata->extra);
1115     CHECK_MEM(extra);
1116 
1117     if (!skp_arg_list_subset_of_list(extra, skp_app_support_extra_args)) {
1118         skAppPrintErr(("Error when registering field '%s': Extra arguments "
1119                        "required by plug-in not supported by application"),
1120                       name);
1121         exit(EXIT_FAILURE);
1122     }
1123 
1124     field = (skplugin_field_t *)calloc(1, sizeof(*field));
1125     CHECK_MEM(field);
1126 
1127     field->common.plugin_name = skp_current_plugin_name;
1128     field->common.init = regdata->init;
1129     field->common.cleanup = regdata->cleanup;
1130     field->common.extra = extra;
1131     field->common.data = cbdata;
1132     field->title = strdup(name);
1133     CHECK_MEM(field->title);
1134     if (description) {
1135         field->description = strdup(description);
1136         CHECK_MEM(field->description);
1137     }
1138     field->names = skp_arg_array_from_string(name);
1139     field->rec_to_text = regdata->rec_to_text;
1140     field->rec_to_bin = regdata->rec_to_bin;
1141     field->add_rec_to_bin = regdata->add_rec_to_bin;
1142     field->bin_to_text = regdata->bin_to_text;
1143     field->field_width_text = regdata->column_width;
1144     field->field_width_bin = regdata->bin_bytes;
1145     field->bin_merge = regdata->bin_merge;
1146     field->bin_compare = regdata->bin_compare;
1147     if (regdata->initial && regdata->bin_bytes) {
1148         field->initial_value = (uint8_t*)malloc(regdata->bin_bytes);
1149         CHECK_MEM(field->initial_value);
1150         memcpy(field->initial_value, regdata->initial, regdata->bin_bytes);
1151     }
1152 
1153     field->fn_mask = skp_field_mask(regdata);
1154 
1155     /* when debugging, complain when a field is not usable at all by
1156      * this application.  No messages are generated for key field that
1157      * cannot be used as aggregate value, and vice versa. */
1158     if (skp_debug && !skp_handle_field(field, 0)) {
1159         skp_handle_field(field, 1);
1160     }
1161 
1162     CHECK_MEM(0 == skDLListPushTail(skp_field_list, field));
1163 
1164     skp_arg_list_add_to_list(extra, skp_plugin_extra_args);
1165 
1166     skp_setup_remap(&field->common, skp_app_support_extra_args);
1167 
1168     if (return_field) {
1169         *return_field = field;
1170     }
1171 
1172     return SKPLUGIN_OK;
1173 }
1174 
1175 
1176 /* Adjust a field's field mask */
1177 static skplugin_fn_mask_t
skp_field_mask(const skplugin_callbacks_t * regdata)1178 skp_field_mask(
1179     const skplugin_callbacks_t *regdata)
1180 {
1181     skplugin_fn_mask_t mask = 0;
1182 
1183     if (regdata->bin_bytes) {
1184         mask |= SKPLUGIN_FN_BIN_BYTES;
1185     }
1186     if (regdata->column_width) {
1187         mask |= SKPLUGIN_FN_COLUMN_WIDTH;
1188     }
1189     if (regdata->rec_to_text) {
1190         mask |= SKPLUGIN_FN_REC_TO_TEXT;
1191     }
1192     if (regdata->rec_to_bin) {
1193         mask |= SKPLUGIN_FN_REC_TO_BIN;
1194     }
1195     if (regdata->add_rec_to_bin) {
1196         mask |= SKPLUGIN_FN_ADD_REC_TO_BIN;
1197     }
1198     if (regdata->bin_to_text) {
1199         mask |= SKPLUGIN_FN_BIN_TO_TEXT;
1200     }
1201     if (regdata->bin_merge) {
1202         mask |= SKPLUGIN_FN_MERGE;
1203     }
1204     if (regdata->bin_compare) {
1205         mask |= SKPLUGIN_FN_COMPARE;
1206     }
1207     if (regdata->filter) {
1208         mask |= SKPLUGIN_FN_FILTER;
1209     }
1210     if (regdata->transform) {
1211         mask |= SKPLUGIN_FN_TRANSFORM;
1212     }
1213     if (regdata->initial) {
1214         mask |= SKPLUGIN_FN_INITIAL;
1215     }
1216 
1217     return mask;
1218 }
1219 
1220 
1221 /*
1222  *    Returns the function mask for a field.
1223  */
1224 skplugin_fn_mask_t
skPluginFieldFnMask(const skplugin_field_t * field)1225 skPluginFieldFnMask(
1226     const skplugin_field_t *field)
1227 {
1228     return field->fn_mask;
1229 }
1230 
1231 
1232 /* Destroy a skp_function_t object */
1233 static void
skp_function_common_destroy(void * vcommon)1234 skp_function_common_destroy(
1235     void               *vcommon)
1236 {
1237     skp_function_common_t *common = (skp_function_common_t *)vcommon;
1238 
1239     if (common->extra) {
1240         skDLListDestroy(common->extra);
1241     }
1242     if (common->cbfree) {
1243         common->cbfree(common->data);
1244     }
1245     free(common);
1246 }
1247 
1248 /* Destroy a skp_field_t object */
1249 static void
skp_function_field_destroy(void * vfield)1250 skp_function_field_destroy(
1251     void               *vfield)
1252 {
1253     skp_field_t *field = (skp_field_t *)vfield;
1254 
1255     free(field->title);
1256     if (field->description) {
1257         free(field->description);
1258     }
1259     if (field->initial_value) {
1260         free(field->initial_value);
1261     }
1262     skp_arg_array_destroy(field->names);
1263     skp_function_common_destroy(vfield);
1264 }
1265 
1266 
1267 /* Create an extra arg remapping for a function */
1268 static void
skp_setup_remap(skp_function_common_t * common,sk_dllist_t * extra_map)1269 skp_setup_remap(
1270     skp_function_common_t  *common,
1271     sk_dllist_t            *extra_map)
1272 {
1273     sk_dll_iter_t  iter;
1274     size_t         count;
1275     ssize_t        loc;
1276     size_t         i;
1277     int            out_of_order = 0;
1278     const char    *arg;
1279 
1280     if (common->extra_remap) {
1281         free(common->extra_remap);
1282         common->extra_remap = NULL;
1283         common->remap_size = 0;
1284     }
1285 
1286     skDLLAssignIter(&iter, common->extra);
1287     for (count = 0; skDLLIterForward(&iter, (void **)&arg) == 0; count++) {
1288         loc = skp_arg_location(arg, extra_map);
1289         assert(loc != -1);
1290         if (loc != (ssize_t)count) {
1291             out_of_order = 1;
1292         }
1293     }
1294 
1295     if (!out_of_order) {
1296         /* No mapping needed */
1297         return;
1298     }
1299 
1300     common->extra_remap = (ssize_t *)malloc(sizeof(ssize_t) * count);
1301     CHECK_MEM(common->extra_remap);
1302     skDLLAssignIter(&iter, common->extra);
1303     for (i = 0; i < count; i++) {
1304         ASSERT_RESULT(skDLLIterForward(&iter, (void **)&arg),
1305                       int, 0);
1306         loc = skp_arg_location(arg, extra_map);
1307         assert(loc != -1);
1308         common->extra_remap[i] = loc;
1309     }
1310 
1311     common->remap_size = count;
1312 }
1313 
1314 
1315 /* Remaps extra args from application order to plugin function order */
1316 static void **
skp_remap(const skp_function_common_t * common,void ** extra)1317 skp_remap(
1318     const skp_function_common_t    *common,
1319     void                          **extra)
1320 {
1321     size_t   i;
1322     void   **remap = (void**)malloc(sizeof(void *) * common->remap_size);
1323 
1324     CHECK_MEM(remap);
1325 
1326     for (i = 0; i < common->remap_size; i++) {
1327         remap[i] = extra[common->extra_remap[i]];
1328     }
1329 
1330     return remap;
1331 }
1332 
1333 static skplugin_err_t
skPluginRunInitHelper(const skp_function_common_t * common,const char * code_type)1334 skPluginRunInitHelper(
1335     const skp_function_common_t    *common,
1336     const char                     *code_type)
1337 {
1338     skplugin_err_t err = SKPLUGIN_OK;
1339 
1340     if (common->init) {
1341         skp_in_plugin_init = 1;
1342         err = common->init(common->data);
1343         skp_in_plugin_init = 0;
1344         if (err == SKPLUGIN_ERR_FATAL) {
1345             skAppPrintErr("Fatal error in initializing %s code", code_type);
1346             exit(EXIT_FAILURE);
1347         }
1348     }
1349 
1350     return err;
1351 }
1352 
1353 
1354 static skplugin_err_t
skPluginRunCleanupHelper(const skp_function_common_t * common,const char * code_type)1355 skPluginRunCleanupHelper(
1356     const skp_function_common_t    *common,
1357     const char                     *code_type)
1358 {
1359     skplugin_err_t err = SKPLUGIN_OK;
1360 
1361     if (common->cleanup) {
1362         skp_in_plugin_init = 1;
1363         err = common->cleanup(common->data);
1364         skp_in_plugin_init = 0;
1365         if (err == SKPLUGIN_ERR_FATAL) {
1366             skAppPrintErr("Fatal error in cleaning up %s code", code_type);
1367             exit(EXIT_FAILURE);
1368         }
1369     }
1370 
1371     return err;
1372 }
1373 
1374 
1375 /*
1376  *    Runs the init routines for the apps and fields (if activated)
1377  *    listed.  If app does not include SKPLUGIN_APP_FIELDS, field_mask
1378  *    is ignored.  If this includes SKPLUGIN_APP_FIELDS, you should
1379  *    not run skPluginFieldRunInitialize on the individual fields,
1380  *    unless you know the initialization functions will be idempotent.
1381  */
1382 static skplugin_err_t
skPluginRunHelper(skplugin_fn_mask_t fn_mask,skplugin_err_t (* helper)(const skp_function_common_t *,const char *))1383 skPluginRunHelper(
1384     skplugin_fn_mask_t  fn_mask,
1385     skplugin_err_t    (*helper)(const skp_function_common_t *, const char *))
1386 {
1387     sk_dll_iter_t          iter;
1388     skplugin_err_t         err;
1389     skp_function_common_t *common;
1390 
1391     assert(skp_initialized);
1392     assert(!skp_in_plugin_init);
1393 
1394     if (skp_handle_type(SKPLUGIN_FN_FILTER) &&
1395         ((fn_mask == SKPLUGIN_FN_ANY) || (fn_mask & SKPLUGIN_FN_FILTER)))
1396     {
1397         skDLLAssignIter(&iter, skp_filter_list);
1398         while (skDLLIterForward(&iter, (void **)&common) == 0) {
1399             err = helper(common, "filter");
1400             if (err == SKPLUGIN_FILTER_IGNORE) {
1401                 skDLLIterDel(&iter);
1402                 skp_function_common_destroy(common);
1403             } else if (err != SKPLUGIN_OK) {
1404                 return err;
1405             }
1406         }
1407     }
1408 
1409     if (skp_handle_type(SKPLUGIN_FN_TRANSFORM) &&
1410         ((fn_mask == SKPLUGIN_FN_ANY) || (fn_mask & SKPLUGIN_FN_TRANSFORM)))
1411     {
1412         skDLLAssignIter(&iter, skp_transform_list);
1413         while (skDLLIterForward(&iter, (void **)&common) == 0) {
1414             err = helper(common, "transformer");
1415             if (err == SKPLUGIN_FILTER_IGNORE) {
1416                 skDLLIterDel(&iter);
1417                 skp_function_common_destroy(common);
1418             } else if (err != SKPLUGIN_OK) {
1419                 return err;
1420             }
1421         }
1422     }
1423 
1424     if (HANDLE_FIELD &&
1425         ((fn_mask == SKPLUGIN_FN_ANY) || (fn_mask & SKPLUGIN_FNS_FIELD)))
1426     {
1427         skp_field_t *field;
1428 
1429         skDLLAssignIter(&iter, skp_active_field_list);
1430         while (skDLLIterForward(&iter, (void **)&field) == 0) {
1431             if (fn_mask == SKPLUGIN_FN_ANY || (fn_mask & field->fn_mask)) {
1432                 common = &field->common;
1433                 err = helper(common, "field");
1434                 if (err != SKPLUGIN_OK && err != SKPLUGIN_FILTER_IGNORE) {
1435                     return err;
1436                 }
1437             }
1438         }
1439     }
1440 
1441     return SKPLUGIN_OK;
1442 }
1443 
1444 
1445 skplugin_err_t
skPluginRunInititialize(skplugin_fn_mask_t fn_mask)1446 skPluginRunInititialize(
1447     skplugin_fn_mask_t  fn_mask)
1448 {
1449     return skPluginRunHelper(fn_mask, skPluginRunInitHelper);
1450 }
1451 
1452 
1453 /* Runs a specific plugin field's initialization function. */
1454 skplugin_err_t
skPluginFieldRunInitialize(const skplugin_field_t * field)1455 skPluginFieldRunInitialize(
1456     const skplugin_field_t *field)
1457 {
1458     skplugin_err_t err;
1459 
1460     assert(field);
1461     assert(skp_initialized);
1462     assert(!skp_in_plugin_init);
1463 
1464     err = skPluginRunInitHelper(&field->common, "field");
1465     if (err != SKPLUGIN_OK  && err != SKPLUGIN_FILTER_IGNORE) {
1466         return err;
1467     }
1468 
1469     return SKPLUGIN_OK;
1470 }
1471 
1472 
1473 skplugin_err_t
skPluginRunCleanup(skplugin_fn_mask_t fn_mask)1474 skPluginRunCleanup(
1475     skplugin_fn_mask_t  fn_mask)
1476 {
1477     skplugin_err_t        err;
1478     skplugin_cleanup_fn_t cleanup;
1479 
1480     if (skp_in_plugin_init) {
1481         /* We never expect this to be set when this function is
1482          * called.  Someone has probably called exit() from within a
1483          * plug-in initialization function which is causing an
1484          * atexit() handler to invoke skPluginRunCleanup().  Simply
1485          * return since we do not know which plug-in called exit(). */
1486         return SKPLUGIN_OK;
1487     }
1488 
1489     err = skPluginRunHelper(fn_mask, skPluginRunCleanupHelper);
1490 
1491     if (SKPLUGIN_OK == err) {
1492         sk_dll_iter_t iter;
1493 
1494         skDLLAssignIter(&iter, skp_cleanup_list);
1495         while (skDLLIterForward(&iter, (void **)&cleanup) == 0) {
1496             skDLLIterDel(&iter);
1497             cleanup();
1498         }
1499     }
1500 
1501     return err;
1502 }
1503 
1504 
1505 /* Runs a specific plugin field's cleanup function. */
1506 skplugin_err_t
skPluginFieldRunCleanup(const skplugin_field_t * field)1507 skPluginFieldRunCleanup(
1508     const skplugin_field_t *field)
1509 {
1510     skplugin_err_t err;
1511 
1512     assert(field);
1513     assert(skp_initialized);
1514     assert(!skp_in_plugin_init);
1515 
1516     err = skPluginRunCleanupHelper(&field->common, "field");
1517 
1518     return err;
1519 }
1520 
1521 
1522 /* Returns 1 if any filters are currently registered, 0 if not. */
1523 int
skPluginFiltersRegistered(void)1524 skPluginFiltersRegistered(
1525     void)
1526 {
1527     assert(skp_initialized);
1528     assert(!skp_in_plugin_init);
1529     assert(skp_handle_type(SKPLUGIN_FN_FILTER));
1530 
1531     return !skDLListIsEmpty(skp_filter_list);
1532 }
1533 
1534 
1535 /* Runs the filter functions over the record 'rec'.  The 'extra'
1536  * fields are determined by the current set of arguments registed by
1537  * skPluginRegisterUsedAppExtraArgs().  */
1538 skplugin_err_t
skPluginRunFilterFn(const rwRec * rec,void ** extra)1539 skPluginRunFilterFn(
1540     const rwRec        *rec,
1541     void              **extra)
1542 {
1543     sk_dll_iter_t iter;
1544     skp_filter_t *filt;
1545 
1546     assert(skp_initialized);
1547     assert(!skp_in_plugin_init);
1548     assert(skp_handle_type(SKPLUGIN_FN_FILTER));
1549 
1550     skDLLAssignIter(&iter, skp_filter_list);
1551 
1552     while (skDLLIterForward(&iter, (void **)&filt) == 0) {
1553         skplugin_err_t err;
1554 
1555         if (filt->common.extra_remap == NULL) {
1556             err = filt->filter(rec, filt->common.data, extra);
1557         } else {
1558             void **remap = skp_remap(&filt->common, extra);
1559             err = filt->filter(rec, filt->common.data, remap);
1560             free(remap);
1561         }
1562 
1563         switch (err) {
1564           case SKPLUGIN_FILTER_PASS:
1565             break;
1566 
1567           case SKPLUGIN_FILTER_PASS_NOW:
1568             return SKPLUGIN_FILTER_PASS;
1569 
1570           case SKPLUGIN_FILTER_FAIL:
1571           case SKPLUGIN_FILTER_IGNORE:
1572           case SKPLUGIN_ERR:
1573           case SKPLUGIN_ERR_SYSTEM:
1574             return err;
1575 
1576           case SKPLUGIN_OK:
1577             return SKPLUGIN_ERR;
1578 
1579           case SKPLUGIN_ERR_FATAL:
1580           case SKPLUGIN_ERR_VERSION_TOO_NEW:
1581           case SKPLUGIN_ERR_DID_NOT_REGISTER:
1582             skAppPrintErr("Fatal error running filter");
1583             exit(EXIT_FAILURE);
1584         }
1585     }
1586 
1587     return SKPLUGIN_FILTER_PASS;
1588 }
1589 
1590 
1591 /* Runs the transform functions over the record 'rec'.  'extra'
1592  * fields are determined by the current set of arguments registed by
1593  * skPluginRegisterUsedAppExtraArgs(). */
1594 skplugin_err_t
skPluginRunTransformFn(rwRec * rec,void ** extra)1595 skPluginRunTransformFn(
1596     rwRec              *rec,
1597     void              **extra)
1598 {
1599     sk_dll_iter_t    iter;
1600     skp_transform_t *transform;
1601 
1602     assert(skp_initialized);
1603     assert(!skp_in_plugin_init);
1604     assert(skp_handle_type(SKPLUGIN_FN_TRANSFORM));
1605 
1606     skDLLAssignIter(&iter, skp_transform_list);
1607 
1608     while (skDLLIterForward(&iter, (void **)&transform) == 0) {
1609         skplugin_err_t err;
1610 
1611         if (transform->common.extra_remap == NULL) {
1612             err = transform->transform(rec, transform->common.data, extra);
1613         } else {
1614             void **remap = skp_remap(&transform->common, extra);
1615             err = transform->transform(rec, transform->common.data, remap);
1616             free(remap);
1617         }
1618 
1619         switch (err) {
1620           case SKPLUGIN_FILTER_PASS:
1621             break;
1622 
1623           case SKPLUGIN_FILTER_PASS_NOW:
1624             return SKPLUGIN_FILTER_PASS;
1625 
1626           case SKPLUGIN_FILTER_FAIL:
1627           case SKPLUGIN_FILTER_IGNORE:
1628           case SKPLUGIN_ERR:
1629           case SKPLUGIN_ERR_SYSTEM:
1630             return err;
1631 
1632           case SKPLUGIN_OK:
1633             return SKPLUGIN_ERR;
1634 
1635           case SKPLUGIN_ERR_FATAL:
1636           case SKPLUGIN_ERR_VERSION_TOO_NEW:
1637           case SKPLUGIN_ERR_DID_NOT_REGISTER:
1638             skAppPrintErr("Fatal error running transform");
1639             exit(EXIT_FAILURE);
1640         }
1641     }
1642 
1643     return SKPLUGIN_FILTER_PASS;
1644 }
1645 
1646 /* Retrieves a pointer to the constant names of a field (NULL terminated) */
1647 skplugin_err_t
skPluginFieldName(const skplugin_field_t * field,const char *** name)1648 skPluginFieldName(
1649     const skplugin_field_t     *field,
1650     const char               ***name)
1651 {
1652     assert(skp_initialized);
1653     assert(!skp_in_plugin_init);
1654     assert(field);
1655 
1656     *name = (const char **)field->names;
1657 
1658     return SKPLUGIN_OK;
1659 }
1660 
1661 /* Retrieves a pointer to the constant title of a field */
1662 skplugin_err_t
skPluginFieldTitle(const skplugin_field_t * field,const char ** title)1663 skPluginFieldTitle(
1664     const skplugin_field_t     *field,
1665     const char                **title)
1666 {
1667     assert(skp_initialized);
1668     assert(!skp_in_plugin_init);
1669     assert(field);
1670 
1671     *title = field->title;
1672     return SKPLUGIN_OK;
1673 }
1674 
1675 /* Retrieves a pointer to the constant description of a field, or NULL
1676  * if none */
1677 skplugin_err_t
skPluginFieldDescription(const skplugin_field_t * field,const char ** description)1678 skPluginFieldDescription(
1679     const skplugin_field_t     *field,
1680     const char                **description)
1681 {
1682     assert(skp_initialized);
1683     assert(!skp_in_plugin_init);
1684     assert(field);
1685 
1686     *description = field->description;
1687     return SKPLUGIN_OK;
1688 }
1689 
1690 /* Returns the name of the plugin that created this field */
1691 skplugin_err_t
skPluginFieldGetPluginName(const skplugin_field_t * field,const char ** plugin_name)1692 skPluginFieldGetPluginName(
1693     const skplugin_field_t     *field,
1694     const char                **plugin_name)
1695 {
1696     assert(skp_initialized);
1697     assert(!skp_in_plugin_init);
1698     assert(field);
1699 
1700     *plugin_name = field->common.plugin_name;
1701     return SKPLUGIN_OK;
1702 }
1703 
1704 /* Retrieves the length of bins for this field.  Returns SKPLUGIN_ERR
1705  * if none. */
1706 skplugin_err_t
skPluginFieldGetLenBin(const skplugin_field_t * field,size_t * len)1707 skPluginFieldGetLenBin(
1708     const skplugin_field_t *field,
1709     size_t                 *len)
1710 {
1711     assert(skp_initialized);
1712     assert(!skp_in_plugin_init);
1713     assert(field);
1714 
1715     if (field->rec_to_bin || field->add_rec_to_bin || field->bin_to_text) {
1716         *len = field->field_width_bin;
1717         return SKPLUGIN_OK;
1718     }
1719 
1720     return SKPLUGIN_ERR;
1721 }
1722 
1723 /* Retrieves the maximum length of text fields (including terminating
1724  * null) for this field.  Returns SKPLUGIN_ERR if none. */
1725 skplugin_err_t
skPluginFieldGetLenText(const skplugin_field_t * field,size_t * len)1726 skPluginFieldGetLenText(
1727     const skplugin_field_t *field,
1728     size_t                 *len)
1729 {
1730     assert(skp_initialized);
1731     assert(!skp_in_plugin_init);
1732     assert(field);
1733 
1734     if (field->rec_to_text || field->bin_to_text) {
1735         *len = field->field_width_text;
1736         return SKPLUGIN_OK;
1737     }
1738 
1739     return SKPLUGIN_ERR;
1740 }
1741 
1742 
1743 /* Retrieves the initial binary value for this aggregate. */
1744 skplugin_err_t
skPluginFieldGetInitialValue(const skplugin_field_t * aggregate,uint8_t * initial_value)1745 skPluginFieldGetInitialValue(
1746     const skplugin_field_t *aggregate,
1747     uint8_t                *initial_value)
1748 {
1749     assert(skp_initialized);
1750     assert(!skp_in_plugin_init);
1751     assert(aggregate);
1752     assert(aggregate->field_width_bin || initial_value);
1753 
1754     if (aggregate->initial_value) {
1755         memcpy(initial_value, aggregate->initial_value,
1756                aggregate->field_width_bin);
1757     } else {
1758         memset(initial_value, 0, aggregate->field_width_bin);
1759     }
1760 
1761     return SKPLUGIN_OK;
1762 }
1763 
1764 
1765 
1766 /* Runs the bin function that converts from record to bin value for
1767  * this field.  'extra' fields are determined by the current set of
1768  * arguments registed by skPluginRegisterUsedAppExtraArgs(). */
1769 skplugin_err_t
skPluginFieldRunRecToBinFn(const skplugin_field_t * field,uint8_t * bin,const rwRec * rec,void ** extra)1770 skPluginFieldRunRecToBinFn(
1771     const skplugin_field_t     *field,
1772     uint8_t                    *bin,
1773     const rwRec                *rec,
1774     void                      **extra)
1775 {
1776     skplugin_err_t err;
1777 
1778     assert(skp_initialized);
1779     assert(!skp_in_plugin_init);
1780     assert(field);
1781     assert(bin);
1782 
1783     if (field->common.extra_remap == NULL) {
1784         err = field->rec_to_bin(rec, bin, field->common.data, extra);
1785     } else {
1786         void **remap = skp_remap(&field->common, extra);
1787         err = field->rec_to_bin(rec, bin, field->common.data, remap);
1788         free(remap);
1789     }
1790 
1791     return err;
1792 }
1793 
1794 
1795 /* Runs the bin function that adds to the bin value for this field
1796  * based on a given record.  'extra' fields are determined by the
1797  * current set of arguments registed by
1798  * skPluginRegisterUsedAppExtraArgs(). */
1799 skplugin_err_t
skPluginFieldRunAddRecToBinFn(const skplugin_field_t * field,uint8_t * bin,const rwRec * rec,void ** extra)1800 skPluginFieldRunAddRecToBinFn(
1801     const skplugin_field_t     *field,
1802     uint8_t                    *bin,
1803     const rwRec                *rec,
1804     void                      **extra)
1805 {
1806     skplugin_err_t err;
1807 
1808     assert(skp_initialized);
1809     assert(!skp_in_plugin_init);
1810     assert(field);
1811     assert(bin);
1812 
1813     if (field->common.extra_remap == NULL) {
1814         err = field->add_rec_to_bin(rec, bin, field->common.data, extra);
1815     } else {
1816         void **remap = skp_remap(&field->common, extra);
1817         err = field->add_rec_to_bin(rec, bin, field->common.data, remap);
1818         free(remap);
1819     }
1820 
1821     return err;
1822 }
1823 
1824 
1825 /* Runs the bin function that converts from bin value to text value
1826    for this field */
1827 skplugin_err_t
skPluginFieldRunBinToTextFn(const skplugin_field_t * field,char * text,size_t width,const uint8_t * bin)1828 skPluginFieldRunBinToTextFn(
1829     const skplugin_field_t *field,
1830     char                   *text,
1831     size_t                  width,
1832     const uint8_t          *bin)
1833 {
1834     assert(skp_initialized);
1835     assert(!skp_in_plugin_init);
1836     assert(field);
1837     assert(text);
1838 
1839     return field->bin_to_text(bin, text, width, field->common.data);
1840 }
1841 
1842 
1843 /* Runs the bin function that converts from record to text value for
1844    this field */
1845 skplugin_err_t
skPluginFieldRunRecToTextFn(const skplugin_field_t * field,char * text,size_t width,const rwRec * rec,void ** extra)1846 skPluginFieldRunRecToTextFn(
1847     const skplugin_field_t     *field,
1848     char                       *text,
1849     size_t                      width,
1850     const rwRec                *rec,
1851     void                      **extra)
1852 {
1853     skplugin_err_t err;
1854 
1855     assert(skp_initialized);
1856     assert(!skp_in_plugin_init);
1857     assert(field);
1858     assert(text);
1859 
1860     if (field->common.extra_remap == NULL) {
1861         err = field->rec_to_text(rec, text, width, field->common.data, extra);
1862     } else {
1863         void **remap = skp_remap(&field->common, extra);
1864         err = field->rec_to_text(rec, text, width, field->common.data, remap);
1865         free(remap);
1866     }
1867 
1868     return err;
1869 }
1870 
1871 /* Runs the function that merges two binary values for this field.
1872  * The binary value in 'src' is merged with 'dst', and the result is
1873  * put back in 'dst'. */
1874 skplugin_err_t
skPluginFieldRunBinMergeFn(const skplugin_field_t * field,uint8_t * dst,const uint8_t * src)1875 skPluginFieldRunBinMergeFn(
1876     const skplugin_field_t *field,
1877     uint8_t                *dst,
1878     const uint8_t          *src)
1879 {
1880     assert(skp_initialized);
1881     assert(!skp_in_plugin_init);
1882     assert(field);
1883     assert(dst);
1884     assert(src);
1885 
1886     if (field->bin_merge == NULL) {
1887         return SKPLUGIN_ERR;
1888     }
1889 
1890     return field->bin_merge(dst, src, field->common.data);
1891 }
1892 
1893 /* Runs the function that compares two binary values for this field.
1894  * The binary value in 'a' is compared with 'b', and the result (less
1895  * than zero, zero, greater than zero) is put in 'val'. */
1896 skplugin_err_t
skPluginFieldRunBinCompareFn(const skplugin_field_t * field,int * val,const uint8_t * a,const uint8_t * b)1897 skPluginFieldRunBinCompareFn(
1898     const skplugin_field_t *field,
1899     int                    *val,
1900     const uint8_t          *a,
1901     const uint8_t          *b)
1902 {
1903     assert(skp_initialized);
1904     assert(!skp_in_plugin_init);
1905     assert(field);
1906     assert(val);
1907     assert(a);
1908     assert(b);
1909 
1910     if (field->bin_compare == NULL) {
1911         *val = memcmp(a, b, field->field_width_bin);
1912         return SKPLUGIN_OK;
1913     }
1914 
1915     return field->bin_compare(val, a, b, field->common.data);
1916 }
1917 
1918 
1919 /* Get the iterator of a specific item in a list.  Return -1 if not
1920  * found. */
1921 static int
skp_list_find(sk_dll_iter_t * iter,const void * target,sk_dllist_t * fields)1922 skp_list_find(
1923     sk_dll_iter_t      *iter,
1924     const void         *target,
1925     sk_dllist_t        *fields)
1926 {
1927     void *item;
1928 
1929     skDLLAssignIter(iter, fields);
1930     while (skDLLIterForward(iter, &item) == 0) {
1931         if (item == target) {
1932             return 0;
1933         }
1934     }
1935 
1936     return -1;
1937 }
1938 
1939 /* Activate a field.  All fields start deactivated.  Activating a
1940  * field allows its init and cleanup functions to run. */
1941 skplugin_err_t
skPluginFieldActivate(const skplugin_field_t * field)1942 skPluginFieldActivate(
1943     const skplugin_field_t *field)
1944 {
1945     int           rv;
1946     sk_dll_iter_t iter;
1947 
1948     assert(skp_initialized);
1949     assert(!skp_in_plugin_init);
1950     assert(field);
1951     assert(skp_list_find(&iter, field, skp_field_list) == 0);
1952 
1953     rv = skp_list_find(&iter, field, skp_active_field_list);
1954     if (rv == -1) {
1955         CHECK_MEM(0 == skDLListPushTail(skp_active_field_list, (void*)field));
1956     }
1957 
1958     return SKPLUGIN_OK;
1959 }
1960 
1961 /* Deactivate a field.  All fields start deactivated */
1962 skplugin_err_t
skPluginFieldDeactivate(const skplugin_field_t * field)1963 skPluginFieldDeactivate(
1964     const skplugin_field_t *field)
1965 {
1966     int           rv;
1967     sk_dll_iter_t iter;
1968 
1969     assert(skp_initialized);
1970     assert(!skp_in_plugin_init);
1971     assert(field);
1972     assert(skp_list_find(&iter, field, skp_filter_list) == 0);
1973 
1974     rv = skp_list_find(&iter, field, skp_active_field_list);
1975     if (rv == 0) {
1976         rv = skDLLIterDel(&iter);
1977         assert(rv == 0);
1978     }
1979 
1980     return SKPLUGIN_OK;
1981 }
1982 
1983 
1984 /*
1985  *     Compares the version number of the plugin api supported by the
1986  *     plugin with the version reported by the application.  If
1987  *     sk_msg_fn_t is non-null, will print version mismatches via the
1988  *     error function.  Returns SKPLUGIN_OK if the versions "match",
1989  *     or a value that can be returned from the setup function (either
1990  *     SKPLUGIN_ERR or SKPLUGIN_ERR_VERSION_TOO_NEW).
1991  */
1992 skplugin_err_t
skpinSimpleCheckVersion(uint16_t protocol_major,uint16_t protocol_minor,uint16_t plugin_major,uint16_t plugin_minor,sk_msg_fn_t errfn)1993 skpinSimpleCheckVersion(
1994     uint16_t            protocol_major,
1995     uint16_t            protocol_minor,
1996     uint16_t            plugin_major,
1997     uint16_t            plugin_minor,
1998     sk_msg_fn_t         errfn)
1999 {
2000     switch (SKPLUGIN_VERSION_CHECK(protocol_major, protocol_minor,
2001                                    plugin_major, plugin_minor))
2002     {
2003       case SKPLUGIN_VERSION_TOO_NEW:
2004         if (errfn) {
2005             errfn(("The version of the skplugin protocol is too new "
2006                    "(%d.%d > %d.%d)"), protocol_major, protocol_minor,
2007                   plugin_major, plugin_minor);
2008         }
2009         return SKPLUGIN_ERR_VERSION_TOO_NEW;
2010       case SKPLUGIN_VERSION_OLD:
2011         if (errfn) {
2012          errfn(("The version of the skplugin protocol is too old "
2013                 "(%d.%d < %d.%d)"), protocol_major, protocol_minor,
2014                plugin_major, plugin_minor);
2015         }
2016         return SKPLUGIN_ERR;
2017       case SKPLUGIN_VERSION_OK:
2018         break;
2019       default:
2020         skAbort();
2021     }
2022     return SKPLUGIN_OK;
2023 }
2024 
2025 
2026 /* Set field widths for a field.  Meant to be used within an init
2027  * function. */
2028 skplugin_err_t
skpinSetFieldWidths(skplugin_field_t * field,size_t field_width_text,size_t field_width_bin)2029 skpinSetFieldWidths(
2030     skplugin_field_t   *field,
2031     size_t              field_width_text,
2032     size_t              field_width_bin)
2033 {
2034     assert(skp_in_plugin_init);
2035 
2036     if (!field) {
2037         return SKPLUGIN_ERR;
2038     }
2039 
2040     field->field_width_text = field_width_text;
2041     field->field_width_bin = field_width_bin;
2042 
2043     return SKPLUGIN_OK;
2044 }
2045 
2046 
2047 /* Add an alias for a field. */
2048 skplugin_err_t
skpinAddFieldAlias(skplugin_field_t * field,const char * alias)2049 skpinAddFieldAlias(
2050     skplugin_field_t   *field,
2051     const char         *alias)
2052 {
2053     char **entry;
2054     char **new_names;
2055     int count;
2056 
2057     assert(skp_in_plugin_init);
2058 
2059     /* If field is NULL, nothing to do */
2060     if (NULL == field) {
2061         return SKPLUGIN_OK;
2062     }
2063 
2064     count = 1;                  /* One to account for the NULL pointer */
2065     for (entry = field->names; *entry; entry++) {
2066         if (strcmp(*entry, alias) == 0) {
2067             return SKPLUGIN_ERR;
2068         }
2069         count++;
2070     }
2071 
2072     new_names = (char **)realloc(field->names, sizeof(char *) * (count + 1));
2073     CHECK_MEM(new_names);
2074     new_names[count - 1] = strdup(alias);
2075     CHECK_MEM(new_names[count - 1]);
2076     new_names[count] = NULL;
2077     field->names = new_names;
2078 
2079     return SKPLUGIN_OK;
2080 }
2081 
2082 /* Sets a field's title */
2083 skplugin_err_t
skpinSetFieldTitle(skplugin_field_t * field,const char * title)2084 skpinSetFieldTitle(
2085     skplugin_field_t   *field,
2086     const char         *title)
2087 {
2088     assert(skp_initialized);
2089     assert(skp_in_plugin_init);
2090 
2091     if (!field || !title) {
2092         return SKPLUGIN_ERR;
2093     }
2094 
2095     assert(field->title);
2096     free(field->title);
2097     field->title = strdup(title);
2098     CHECK_MEM(field->title);
2099 
2100     return SKPLUGIN_OK;
2101 }
2102 
2103 /* Register a cleanup function for the plugin.  This will be called by
2104  * skPluginRunCleanup after all the function-specific cleanups are
2105  * called. */
2106 skplugin_err_t
skpinRegCleanup(skplugin_cleanup_fn_t cleanup)2107 skpinRegCleanup(
2108     skplugin_cleanup_fn_t   cleanup)
2109 {
2110     void *clean_fn;
2111 
2112     assert(skp_initialized);
2113     assert(skp_in_plugin_init);
2114     assert(cleanup);
2115 
2116     if (NULL == cleanup) {
2117         return SKPLUGIN_ERR;
2118     }
2119 
2120     /* This avoids a function * to void * warning by the compiler. */
2121     *((skplugin_cleanup_fn_t *)&clean_fn) = cleanup;
2122     CHECK_MEM(0 == skDLListPushTail(skp_cleanup_list, clean_fn));
2123 
2124     return SKPLUGIN_OK;
2125 }
2126 
2127 /* Declare this plugin to be non-safe. */
2128 void
skpinSetThreadNonSafe(void)2129 skpinSetThreadNonSafe(
2130     void)
2131 {
2132     assert(skp_initialized);
2133     assert(skp_in_plugin_init);
2134 
2135     skp_thread_safe = 0;
2136 }
2137 
2138 /* Returns 1 if the plugin can be safely be run in a threaded context,
2139    0 otherwise. */
2140 int
skPluginIsThreadSafe(void)2141 skPluginIsThreadSafe(
2142     void)
2143 {
2144     assert(skp_initialized);
2145     assert(!skp_in_plugin_init);
2146 
2147     return skp_thread_safe;
2148 }
2149 
2150 /* Binds an iterator around all fields that contain information that
2151  * matches the field_mask.  If 'all_fields' is false, will only
2152  * iterate over "activated" fields.  */
2153 skplugin_err_t
skPluginFieldIteratorBind(skplugin_field_iter_t * iter,skplugin_fn_mask_t fn_mask,int all_fields)2154 skPluginFieldIteratorBind(
2155     skplugin_field_iter_t  *iter,
2156     skplugin_fn_mask_t      fn_mask,
2157     int                     all_fields)
2158 {
2159     assert(skp_initialized);
2160     assert(!skp_in_plugin_init);
2161     assert(iter);
2162 
2163     if (!HANDLE_FIELD) {
2164         return SKPLUGIN_ERR;
2165     }
2166 
2167     iter->fn_mask = fn_mask;
2168     iter->all_fields = all_fields;
2169 
2170     return skPluginFieldIteratorReset(iter);
2171 }
2172 
2173 
2174 /* Resets a field iterator so it can be iterated over again */
2175 skplugin_err_t
skPluginFieldIteratorReset(skplugin_field_iter_t * iter)2176 skPluginFieldIteratorReset(
2177     skplugin_field_iter_t  *iter)
2178 {
2179     assert(skp_initialized);
2180     assert(!skp_in_plugin_init);
2181     assert(iter);
2182 
2183     if (iter->all_fields) {
2184         skDLLAssignIter(&iter->list_iter, skp_field_list);
2185     } else {
2186         skDLLAssignIter(&iter->list_iter, skp_active_field_list);
2187     }
2188 
2189     return SKPLUGIN_OK;
2190 }
2191 
2192 /* Retrieves the field identifier for the next field, returns 1 on
2193    success, 0 on failure. */
2194 int
skPluginFieldIteratorNext(skplugin_field_iter_t * iter,skplugin_field_t ** rfield)2195 skPluginFieldIteratorNext(
2196     skplugin_field_iter_t  *iter,
2197     skplugin_field_t      **rfield)
2198 {
2199     skp_field_t *field;
2200 
2201     assert(skp_initialized);
2202     assert(!skp_in_plugin_init);
2203     assert(iter);
2204 
2205     for (;;) {
2206         int rv = skDLLIterForward(&iter->list_iter, (void **)&field);
2207         if (rv != 0) {
2208             return 0;
2209         }
2210         if ((iter->fn_mask == SKPLUGIN_FN_ANY) ||
2211             ((iter->fn_mask & field->fn_mask) == iter->fn_mask))
2212         {
2213             if (rfield) {
2214                 *rfield = field;
2215             }
2216             return 1;
2217         }
2218     }
2219 
2220     skAbort();                  /* NOTREACHED */
2221 }
2222 
2223 /* Print the usage information registered by plugins to 'fh'.*/
2224 skplugin_err_t
skPluginOptionsUsage(FILE * fh)2225 skPluginOptionsUsage(
2226     FILE               *fh)
2227 {
2228     sk_dll_iter_t       iter;
2229     skp_option_t       *option;
2230 
2231     assert(skp_initialized);
2232     assert(!skp_in_plugin_init);
2233     assert(fh);
2234 
2235     skDLLAssignIter(&iter, skp_option_list);
2236     while (skDLLIterForward(&iter, (void **)&option) == 0) {
2237         if (option->help_fn) {
2238             option->help_fn(fh, &option->opt[0], option->cbdata);
2239         } else {
2240             fprintf(fh, "--%s %s. %s\n",
2241                     option->opt[0].name, SK_OPTION_HAS_ARG(option->opt[0]),
2242                     option->help_string ? option->help_string : "");
2243         }
2244     }
2245 
2246     return SKPLUGIN_OK;
2247 }
2248 
2249 /* Unload a library opened by dlopen() */
2250 static void
skp_unload_library(void * handle)2251 skp_unload_library(
2252     void               *handle)
2253 {
2254     int rv = dlclose(handle);
2255     if (rv != 0) {
2256         skAppPrintErr("dlclose: %s", dlerror());
2257     }
2258 }
2259 
2260 
2261 /* Given a setup function, execute it and add the plugin to the list */
2262 static skplugin_err_t
skp_add_plugin(void * handle,const char * name,skplugin_setup_fn_t setup_fn)2263 skp_add_plugin(
2264     void                   *handle,
2265     const char             *name,
2266     skplugin_setup_fn_t     setup_fn)
2267 {
2268     skplugin_err_t err;
2269 
2270     /* Call the setup function */
2271     skp_in_plugin_init = 1;
2272     skp_current_plugin_name = strdup(name);
2273     CHECK_MEM(skp_current_plugin_name);
2274     CHECK_MEM(0 == skDLListPushTail(skp_plugin_names,
2275                                     (void *)skp_current_plugin_name));
2276     err = setup_fn(SKPLUGIN_INTERFACE_VERSION_MAJOR,
2277                    SKPLUGIN_INTERFACE_VERSION_MINOR, NULL);
2278     skp_current_plugin_name = NULL;
2279     skp_in_plugin_init = 0;
2280 
2281     if (err == SKPLUGIN_OK) {
2282         if (handle) {
2283             CHECK_MEM(0 == skDLListPushTail(skp_library_list, handle));
2284         }
2285     } else if (err == SKPLUGIN_ERR_FATAL) {
2286         skAppPrintErr("Fatal error loading plugin %s", name);
2287         exit(EXIT_FAILURE);
2288     } else {
2289         sk_dllist_t           *list[3];
2290         sk_dll_iter_t          iter;
2291         skp_function_common_t *common;
2292         size_t                 i;
2293         char                  *plugin_name;
2294 
2295         ASSERT_RESULT(skDLListPopTail(skp_plugin_names, (void **)&plugin_name),
2296                       int, 0);
2297         if (plugin_name == NULL) {
2298             skAppPrintErr(("Fatal error loading plugin %s "
2299                            "(could not unload)"), name);
2300             exit(EXIT_FAILURE);
2301         }
2302         list[0] = skp_filter_list;
2303         list[1] = skp_transform_list;
2304         list[2] = skp_field_list;
2305 
2306         /* Loop through all registered filters, transforms, and
2307          * fields, and remove any created by this plugin. */
2308         for (i = 0; i < sizeof(list) / sizeof(list[0]); i++) {
2309             if (list[i]) {
2310                 skDLLAssignIter(&iter, list[i]);
2311                 while (skDLLIterForward(&iter, (void **)&common) == 0) {
2312                     if (common->plugin_name == plugin_name) {
2313                         skDLLIterDel(&iter);
2314                         if (list[i] == skp_field_list) {
2315                             skp_function_field_destroy(common);
2316                         } else {
2317                             skp_function_common_destroy(common);
2318                         }
2319                     }
2320                 }
2321             }
2322         }
2323         free(plugin_name);
2324 
2325         if (handle) {
2326             skp_unload_library(handle);
2327         }
2328     }
2329 
2330     return err;
2331 }
2332 
2333 
2334 /* Given a name and a setup function, acts as if the setup function
2335  * was from a plugin. */
2336 skplugin_err_t
skPluginAddAsPlugin(const char * name,skplugin_setup_fn_t setup_fn)2337 skPluginAddAsPlugin(
2338     const char             *name,
2339     skplugin_setup_fn_t     setup_fn)
2340 {
2341     return skp_add_plugin(NULL, name, setup_fn);
2342 }
2343 
2344 
2345 /* Loads the plugin represented by the filename 'name'. */
2346 skplugin_err_t
skPluginLoadPlugin(const char * name,int complain_on_error)2347 skPluginLoadPlugin(
2348     const char         *name,
2349     int                 complain_on_error)
2350 {
2351     void                *handle;
2352     char                 plugin_path[PATH_MAX+1];
2353     skplugin_setup_fn_t  setup_fn;
2354     skplugin_err_t       err;
2355     const char          *error_prefix = "";
2356 
2357     assert(skp_initialized);
2358     assert(!skp_in_plugin_init);
2359     assert(name);
2360 
2361     if (!complain_on_error) {
2362         error_prefix = (SKPLUGIN_DEBUG_ENVAR ": ");
2363     }
2364 
2365     /* Attempt to find the full path to the plug-in, and set
2366      * 'plugin_path' to its path; if we cannot find the path, copy the
2367      * plug-in's name to 'plugin_path' and we'll let dlopen() handle
2368      * finding the plug-in. */
2369     if (skp_debug) {
2370         skAppPrintErr(SKPLUGIN_DEBUG_ENVAR ": attempting to find plugin '%s'",
2371                       name);
2372     }
2373     if (!skFindPluginPath(name, plugin_path, PATH_MAX,
2374                           (skp_debug ? (SKPLUGIN_DEBUG_ENVAR ": ") : NULL)))
2375     {
2376         strncpy(plugin_path, name, PATH_MAX);
2377         plugin_path[PATH_MAX] = '\0';
2378     }
2379 
2380     /* try to dlopen() the plug-in  */
2381     if (skp_debug > 0) {
2382         skAppPrintErr(SKPLUGIN_DEBUG_ENVAR ": dlopen'ing '%s'", plugin_path);
2383     }
2384     handle = dlopen(plugin_path, RTLD_NOW | RTLD_GLOBAL);
2385     if (!handle) {
2386         if (complain_on_error || (skp_debug > 0)) {
2387             skAppPrintErr("%sdlopen warning: %s", error_prefix, dlerror());
2388         }
2389         return SKPLUGIN_ERR_SYSTEM;
2390     }
2391     if (skp_debug > 0) {
2392         skAppPrintErr(SKPLUGIN_DEBUG_ENVAR ": dlopen() successful");
2393     }
2394 
2395     /* Find the setup function */
2396     *((void **)&setup_fn) = dlsym(handle, SKPLUGIN_SETUP_FN_NAME);
2397     if (setup_fn == NULL) {
2398         if (complain_on_error || skp_debug > 0) {
2399             skAppPrintErr(("%sFunction '" SKPLUGIN_SETUP_FN_NAME "' not found"),
2400                           error_prefix);
2401         }
2402         skp_unload_library(handle);
2403         return SKPLUGIN_ERR;
2404     } else {
2405         err = skp_add_plugin(handle, plugin_path, setup_fn);
2406         if (err != SKPLUGIN_OK && (complain_on_error || skp_debug > 0)) {
2407             skAppPrintErr(("%sFunction '" SKPLUGIN_SETUP_FN_NAME "'"
2408                            " returned a non-OK error status"), error_prefix);
2409         }
2410     }
2411 
2412     return err;
2413 }
2414 
2415 /*
2416 ** Local Variables:
2417 ** mode:c
2418 ** indent-tabs-mode:nil
2419 ** c-basic-offset:4
2420 ** End:
2421 */
2422