From 2be324ee17454ae5c5a32a3533aced861d103074 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sat, 10 Feb 2018 16:00:45 +0000 Subject: [PATCH] Macros: return macro-presence status from "exim -bP macro " --- doc/doc-docbook/spec.xfpt | 4 + doc/doc-txt/NewStuff | 2 + src/src/exim.c | 35 ++-- src/src/functions.h | 2 +- src/src/readconf.c | 344 ++++++++++++++++++-------------------- 5 files changed, 190 insertions(+), 197 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 972cdc76e..2c783d700 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -3162,6 +3162,10 @@ If invoked by an admin user, then &%macro%&, &%macro_list%& and &%macros%& are available, similarly to the drivers. Because macros are sometimes used for storing passwords, this option is restricted. The output format is one item per line. +.new +For the "-bP macro " form, if no such macro is found +the exit status will be nonzero. +.wen .vitem &%-bp%& .oindex "&%-bp%&" diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 8464872b4..e123910c2 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -39,6 +39,8 @@ Version 4.91 10. Builtin feature-macros _CRYPTO_HASH_SHA3 and _CRYPTO_SIGN_ED25519, library version dependent. +11. "exim -bP macro " returns caller-usable status. + Version 4.90 ------------ diff --git a/src/src/exim.c b/src/src/exim.c index f0f373f60..3f1e153fd 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -4573,30 +4573,33 @@ if (test_retry_arg >= 0) if (list_options) { + BOOL fail = FALSE; set_process_info("listing variables"); - if (recipients_arg >= argc) readconf_print(US"all", NULL, flag_n); - else for (i = recipients_arg; i < argc; i++) + if (recipients_arg >= argc) + fail = !readconf_print(US"all", NULL, flag_n); + else for (i = recipients_arg; i < argc; i++) + { + if (i < argc - 1 && + (Ustrcmp(argv[i], "router") == 0 || + Ustrcmp(argv[i], "transport") == 0 || + Ustrcmp(argv[i], "authenticator") == 0 || + Ustrcmp(argv[i], "macro") == 0 || + Ustrcmp(argv[i], "environment") == 0)) { - if (i < argc - 1 && - (Ustrcmp(argv[i], "router") == 0 || - Ustrcmp(argv[i], "transport") == 0 || - Ustrcmp(argv[i], "authenticator") == 0 || - Ustrcmp(argv[i], "macro") == 0 || - Ustrcmp(argv[i], "environment") == 0)) - { - readconf_print(argv[i+1], argv[i], flag_n); - i++; - } - else readconf_print(argv[i], NULL, flag_n); + fail |= !readconf_print(argv[i+1], argv[i], flag_n); + i++; } - exim_exit(EXIT_SUCCESS, US"main"); + else + fail = !readconf_print(argv[i], NULL, flag_n); + } + exim_exit(fail ? EXIT_FAILURE : EXIT_SUCCESS, US"main"); } if (list_config) { set_process_info("listing config"); - readconf_print(US"config", NULL, flag_n); - exim_exit(EXIT_SUCCESS, US"main"); + exim_exit(readconf_print(US"config", NULL, flag_n) + ? EXIT_SUCCESS : EXIT_FAILURE, US"main"); } diff --git a/src/src/functions.h b/src/src/functions.h index d8a78e7c2..857781bdb 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -336,7 +336,7 @@ extern void readconf_driver_init(uschar *, driver_instance **, extern uschar *readconf_find_option(void *); extern void readconf_main(BOOL); extern void readconf_options_from_list(optionlist *, unsigned, const uschar *, uschar *); -extern void readconf_print(uschar *, uschar *, BOOL); +extern BOOL readconf_print(uschar *, uschar *, BOOL); extern uschar *readconf_printtime(int); extern uschar *readconf_readname(uschar *, int, uschar *); extern int readconf_readtime(const uschar *, int, BOOL); diff --git a/src/src/readconf.c b/src/src/readconf.c index 87960805f..acf64570a 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -2320,10 +2320,10 @@ Arguments: last one more than the offset of the last entry in optop no_labels do not show "foo = " at the start. -Returns: nothing +Returns: boolean success */ -static void +static BOOL print_ol(optionlist *ol, uschar *name, void *options_block, optionlist *oltop, int last, BOOL no_labels) { @@ -2336,30 +2336,30 @@ gid_t *gidlist; uschar *s; uschar name2[64]; -if (ol == NULL) +if (!ol) { printf("%s is not a known option\n", name); - return; + return FALSE; } /* Non-admin callers cannot see options that have been flagged secure by the "hide" prefix. */ -if (!admin_user && (ol->type & opt_secure) != 0) +if (!admin_user && ol->type & opt_secure) { if (no_labels) printf("%s\n", hidden); else printf("%s = %s\n", name, hidden); - return; + return TRUE; } /* Else show the value of the option */ value = ol->value; -if (options_block != NULL) +if (options_block) { - if ((ol->type & opt_public) == 0) + if (!(ol->type & opt_public)) options_block = (void *)(((driver_instance *)options_block)->options_block); value = (void *)(US options_block + (long int)value); } @@ -2368,15 +2368,15 @@ switch(ol->type & opt_mask) { case opt_stringptr: case opt_rewrite: /* Show the text value */ - s = *((uschar **)value); - if (!no_labels) printf("%s = ", name); - printf("%s\n", (s == NULL)? US"" : string_printing2(s, FALSE)); - break; + s = *(USS value); + if (!no_labels) printf("%s = ", name); + printf("%s\n", s ? string_printing2(s, FALSE) : US""); + break; case opt_int: - if (!no_labels) printf("%s = ", name); - printf("%d\n", *((int *)value)); - break; + if (!no_labels) printf("%s = ", name); + printf("%d\n", *((int *)value)); + break; case opt_mkint: { @@ -2399,22 +2399,22 @@ switch(ol->type & opt_mask) printf("%d\n", x); } } - break; + break; case opt_Kint: { int x = *((int *)value); if (!no_labels) printf("%s = ", name); if (x == 0) printf("0\n"); - else if ((x & 1023) == 0) printf("%dM\n", x >> 10); - else printf("%dK\n", x); + else if ((x & 1023) == 0) printf("%dM\n", x >> 10); + else printf("%dK\n", x); } - break; + break; case opt_octint: - if (!no_labels) printf("%s = ", name); - printf("%#o\n", *((int *)value)); - break; + if (!no_labels) printf("%s = ", name); + printf("%#o\n", *((int *)value)); + break; /* Can be negative only when "unset", in which case integer */ @@ -2437,124 +2437,115 @@ switch(ol->type & opt_mask) printf("\n"); } } - break; + break; /* If the numerical value is unset, try for the string value */ case opt_expand_uid: - if (! *get_set_flag(name, oltop, last, options_block)) - { - sprintf(CS name2, "*expand_%.50s", name); - ol2 = find_option(name2, oltop, last); - if (ol2 != NULL) + if (! *get_set_flag(name, oltop, last, options_block)) { - void *value2 = ol2->value; - if (options_block != NULL) - value2 = (void *)(US options_block + (long int)value2); - s = *((uschar **)value2); - if (!no_labels) printf("%s = ", name); - printf("%s\n", (s == NULL)? US"" : string_printing(s)); - break; + sprintf(CS name2, "*expand_%.50s", name); + if ((ol2 = find_option(name2, oltop, last))) + { + void *value2 = ol2->value; + if (options_block) + value2 = (void *)(US options_block + (long int)value2); + s = *(USS value2); + if (!no_labels) printf("%s = ", name); + printf("%s\n", s ? string_printing(s) : US""); + break; + } } - } - /* Else fall through */ + /* Else fall through */ case opt_uid: - if (!no_labels) printf("%s = ", name); - if (! *get_set_flag(name, oltop, last, options_block)) - printf("\n"); - else - { - pw = getpwuid(*((uid_t *)value)); - if (pw == NULL) - printf("%ld\n", (long int)(*((uid_t *)value))); - else printf("%s\n", pw->pw_name); - } - break; + if (!no_labels) printf("%s = ", name); + if (! *get_set_flag(name, oltop, last, options_block)) + printf("\n"); + else + if ((pw = getpwuid(*((uid_t *)value)))) + printf("%s\n", pw->pw_name); + else + printf("%ld\n", (long int)(*((uid_t *)value))); + break; /* If the numerical value is unset, try for the string value */ case opt_expand_gid: - if (! *get_set_flag(name, oltop, last, options_block)) - { - sprintf(CS name2, "*expand_%.50s", name); - ol2 = find_option(name2, oltop, last); - if (ol2 != NULL && (ol2->type & opt_mask) == opt_stringptr) + if (! *get_set_flag(name, oltop, last, options_block)) { - void *value2 = ol2->value; - if (options_block != NULL) - value2 = (void *)(US options_block + (long int)value2); - s = *((uschar **)value2); - if (!no_labels) printf("%s = ", name); - printf("%s\n", (s == NULL)? US"" : string_printing(s)); - break; + sprintf(CS name2, "*expand_%.50s", name); + if ( (ol2 = find_option(name2, oltop, last)) + && (ol2->type & opt_mask) == opt_stringptr) + { + void *value2 = ol2->value; + if (options_block) + value2 = (void *)(US options_block + (long int)value2); + s = *(USS value2); + if (!no_labels) printf("%s = ", name); + printf("%s\n", s ? string_printing(s) : US""); + break; + } } - } - /* Else fall through */ + /* Else fall through */ case opt_gid: - if (!no_labels) printf("%s = ", name); - if (! *get_set_flag(name, oltop, last, options_block)) - printf("\n"); - else - { - gr = getgrgid(*((int *)value)); - if (gr == NULL) - printf("%ld\n", (long int)(*((int *)value))); - else printf("%s\n", gr->gr_name); - } - break; + if (!no_labels) printf("%s = ", name); + if (! *get_set_flag(name, oltop, last, options_block)) + printf("\n"); + else + if ((gr = getgrgid(*((int *)value)))) + printf("%s\n", gr->gr_name); + else + printf("%ld\n", (long int)(*((int *)value))); + break; case opt_uidlist: - uidlist = *((uid_t **)value); - if (!no_labels) printf("%s =", name); - if (uidlist != NULL) - { - int i; - uschar sep = ' '; - if (no_labels) sep = '\0'; - for (i = 1; i <= (int)(uidlist[0]); i++) + uidlist = *((uid_t **)value); + if (!no_labels) printf("%s =", name); + if (uidlist) { - uschar *name = NULL; - pw = getpwuid(uidlist[i]); - if (pw != NULL) name = US pw->pw_name; - if (sep != '\0') printf("%c", sep); - if (name != NULL) printf("%s", name); - else printf("%ld", (long int)(uidlist[i])); - sep = ':'; + int i; + uschar sep = no_labels ? '\0' : ' '; + for (i = 1; i <= (int)(uidlist[0]); i++) + { + uschar *name = NULL; + if ((pw = getpwuid(uidlist[i]))) name = US pw->pw_name; + if (sep != '\0') printf("%c", sep); + if (name) printf("%s", name); + else printf("%ld", (long int)(uidlist[i])); + sep = ':'; + } } - } - printf("\n"); - break; + printf("\n"); + break; case opt_gidlist: - gidlist = *((gid_t **)value); - if (!no_labels) printf("%s =", name); - if (gidlist != NULL) - { - int i; - uschar sep = ' '; - if (no_labels) sep = '\0'; - for (i = 1; i <= (int)(gidlist[0]); i++) + gidlist = *((gid_t **)value); + if (!no_labels) printf("%s =", name); + if (gidlist) { - uschar *name = NULL; - gr = getgrgid(gidlist[i]); - if (gr != NULL) name = US gr->gr_name; - if (sep != '\0') printf("%c", sep); - if (name != NULL) printf("%s", name); - else printf("%ld", (long int)(gidlist[i])); - sep = ':'; + int i; + uschar sep = no_labels ? '\0' : ' '; + for (i = 1; i <= (int)(gidlist[0]); i++) + { + uschar *name = NULL; + if ((gr = getgrgid(gidlist[i]))) name = US gr->gr_name; + if (sep != '\0') printf("%c", sep); + if (name) printf("%s", name); + else printf("%ld", (long int)(gidlist[i])); + sep = ':'; + } } - } - printf("\n"); - break; + printf("\n"); + break; case opt_time: - if (!no_labels) printf("%s = ", name); - printf("%s\n", readconf_printtime(*((int *)value))); - break; + if (!no_labels) printf("%s = ", name); + printf("%s\n", readconf_printtime(*((int *)value))); + break; case opt_timelist: { @@ -2562,42 +2553,42 @@ switch(ol->type & opt_mask) int *list = (int *)value; if (!no_labels) printf("%s = ", name); for (i = 0; i < list[1]; i++) - printf("%s%s", (i == 0)? "" : ":", readconf_printtime(list[i+2])); + printf("%s%s", i == 0 ? "" : ":", readconf_printtime(list[i+2])); printf("\n"); } - break; + break; case opt_bit: - printf("%s%s\n", ((*((int *)value)) & (1 << ((ol->type >> 16) & 31)))? - "" : "no_", name); - break; + printf("%s%s\n", ((*((int *)value)) & (1 << ((ol->type >> 16) & 31)))? + "" : "no_", name); + break; case opt_expand_bool: - sprintf(CS name2, "*expand_%.50s", name); - ol2 = find_option(name2, oltop, last); - if (ol2 != NULL && ol2->value != NULL) - { - void *value2 = ol2->value; - if (options_block != NULL) - value2 = (void *)(US options_block + (long int)value2); - s = *((uschar **)value2); - if (s != NULL) + sprintf(CS name2, "*expand_%.50s", name); + if ((ol2 = find_option(name2, oltop, last)) && ol2->value) { - if (!no_labels) printf("%s = ", name); - printf("%s\n", string_printing(s)); - break; + void *value2 = ol2->value; + if (options_block) + value2 = (void *)(US options_block + (long int)value2); + s = *(USS value2); + if (s) + { + if (!no_labels) printf("%s = ", name); + printf("%s\n", string_printing(s)); + break; + } + /* s == NULL => string not set; fall through */ } - /* s == NULL => string not set; fall through */ - } - /* Fall through */ + /* Fall through */ case opt_bool: case opt_bool_verify: case opt_bool_set: - printf("%s%s\n", (*((BOOL *)value))? "" : "no_", name); - break; + printf("%s%s\n", (*((BOOL *)value))? "" : "no_", name); + break; } +return TRUE; } @@ -2636,10 +2627,10 @@ Arguments: type NULL or driver type name, as described above no_labels avoid the "foo = " at the start of an item -Returns: nothing +Returns: Boolean success */ -void +BOOL readconf_print(uschar *name, uschar *type, BOOL no_labels) { BOOL names_only = FALSE; @@ -2649,7 +2640,7 @@ driver_instance *d = NULL; macro_item *m; int size = 0; -if (type == NULL) +if (!type) { if (*name == '+') { @@ -2662,9 +2653,7 @@ if (type == NULL) &hostlist_anchor, &localpartlist_anchor }; for (i = 0; i < 4; i++) - { - t = tree_search(*(anchors[i]), name+1); - if (t != NULL) + if ((t = tree_search(*(anchors[i]), name+1))) { found = TRUE; if (no_labels) @@ -2673,54 +2662,50 @@ if (type == NULL) printf("%slist %s = %s\n", types[i], name+1, ((namedlist_block *)(t->data.ptr))->string); } - } if (!found) printf("no address, domain, host, or local part list called \"%s\" " "exists\n", name+1); - return; + return found; } if ( Ustrcmp(name, "configure_file") == 0 || Ustrcmp(name, "config_file") == 0) { printf("%s\n", CS config_main_filename); - return; + return TRUE; } if (Ustrcmp(name, "all") == 0) { for (ol = optionlist_config; ol < optionlist_config + nelem(optionlist_config); ol++) - { - if ((ol->type & opt_hidden) == 0) - print_ol(ol, US ol->name, NULL, - optionlist_config, nelem(optionlist_config), - no_labels); - } - return; + if (!(ol->type & opt_hidden)) + (void) print_ol(ol, US ol->name, NULL, + optionlist_config, nelem(optionlist_config), + no_labels); + return TRUE; } if (Ustrcmp(name, "local_scan") == 0) { - #ifndef LOCAL_SCAN_HAS_OPTIONS +#ifndef LOCAL_SCAN_HAS_OPTIONS printf("local_scan() options are not supported\n"); - #else + return FALSE; +#else for (ol = local_scan_options; ol < local_scan_options + local_scan_options_count; ol++) - { - print_ol(ol, US ol->name, NULL, local_scan_options, - local_scan_options_count, no_labels); - } - #endif - return; + (void) print_ol(ol, US ol->name, NULL, local_scan_options, + local_scan_options_count, no_labels); + return TRUE; +#endif } if (Ustrcmp(name, "config") == 0) { print_config(admin_user, no_labels); - return; + return TRUE; } if (Ustrcmp(name, "routers") == 0) @@ -2733,47 +2718,40 @@ if (type == NULL) type = US"transport"; name = NULL; } - else if (Ustrcmp(name, "authenticators") == 0) { type = US"authenticator"; name = NULL; } - else if (Ustrcmp(name, "macros") == 0) { type = US"macro"; name = NULL; } - else if (Ustrcmp(name, "router_list") == 0) { type = US"router"; name = NULL; names_only = TRUE; } - else if (Ustrcmp(name, "transport_list") == 0) { type = US"transport"; name = NULL; names_only = TRUE; } - else if (Ustrcmp(name, "authenticator_list") == 0) { type = US"authenticator"; name = NULL; names_only = TRUE; } - else if (Ustrcmp(name, "macro_list") == 0) { type = US"macro"; name = NULL; names_only = TRUE; } - else if (Ustrcmp(name, "environment") == 0) { if (environ) @@ -2789,15 +2767,13 @@ if (type == NULL) puts(CS *p); } } - return; + return TRUE; } else - { - print_ol(find_option(name, optionlist_config, nelem(optionlist_config)), + return print_ol(find_option(name, + optionlist_config, nelem(optionlist_config)), name, NULL, optionlist_config, nelem(optionlist_config), no_labels); - return; - } } /* Handle the options for a router or transport. Skip options that are flagged @@ -2832,47 +2808,55 @@ else if (Ustrcmp(type, "macro") == 0) if (!admin_user) { fprintf(stderr, "exim: permission denied\n"); - exit(EXIT_FAILURE); + return FALSE; } if (name) if ((m = macro_search(name))) macro_print(m->tnode.name, m->tnode.data.ptr, (void *)(long)names_only); else + { printf("%s %s not found\n", type, name); + return FALSE; + } else tree_walk(tree_macros, macro_print, (void *)(long)names_only); - return; + return TRUE; } if (names_only) { for (; d; d = d->next) printf("%s\n", CS d->name); - return; + return TRUE;; } /* Either search for a given driver, or print all of them */ for (; d; d = d->next) { + BOOL rc = FALSE; if (!name) printf("\n%s %s:\n", d->name, type); else if (Ustrcmp(d->name, name) != 0) continue; for (ol = ol2; ol < ol2 + size; ol++) - if ((ol->type & opt_hidden) == 0) - print_ol(ol, US ol->name, d, ol2, size, no_labels); + if (!(ol->type & opt_hidden)) + rc |= print_ol(ol, US ol->name, d, ol2, size, no_labels); for (ol = d->info->options; ol < d->info->options + *(d->info->options_count); ol++) - if ((ol->type & opt_hidden) == 0) - print_ol(ol, US ol->name, d, d->info->options, *(d->info->options_count), no_labels); + if (!(ol->type & opt_hidden)) + rc |= print_ol(ol, US ol->name, d, d->info->options, + *d->info->options_count, no_labels); - if (name) return; + if (name) return rc; } -if (name) printf("%s %s not found\n", type, name); +if (!name) return TRUE; + +printf("%s %s not found\n", type, name); +return FALSE; } -- 2.30.2