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