]> granicus.if.org Git - postgresql/blob - src/backend/utils/misc/help_config.c
Add description for new GUC context.
[postgresql] / src / backend / utils / misc / help_config.c
1 /*-------------------------------------------------------------------------
2  * help_config.c
3  *
4  * Displays available options under grand unified configuration scheme
5  *
6  * The purpose of this option is to list, sort, and make searchable, all
7  * runtime options available to Postgresql, by their description and grouping.
8  *
9  * Valid command-line options to this program:
10  *
11  *      none            : All available variables are sorted by group and name
12  *                                and formatted nicely. ( for human consumption )
13  *      <string>        : list all the variables whose name matches this string
14  *      -g <string> : list all the variables whose group matches this string
15  *      -l                      : lists all currently defined groups and terminates
16  *      -G                      : no sort by groups (you get strict name order, instead)
17  *      -m                      : output the list in Machine friendly format, with a header row
18  *      -M                      : same as m, except no header
19  *      -h                      : help
20  *
21  * Options whose flag bits are set to GUC_NO_SHOW_ALL, GUC_NOT_IN_SAMPLE,
22  * or GUC_DISALLOW_IN_FILE are not displayed, unless the user specifically
23  * requests that variable by name
24  *
25  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
26  *
27  * IDENTIFICATION
28  *        $Header: /cvsroot/pgsql/src/backend/utils/misc/help_config.c,v 1.2 2003/07/09 17:57:47 momjian Exp $
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres.h"
33
34 #include <fcntl.h>
35 #ifdef HAVE_GETOPT_H
36 #include <getopt.h>
37 #endif
38 #include <errno.h>
39 #include <float.h>
40 #include <limits.h>
41 #include <unistd.h>
42
43 #include "utils/guc.h"
44 #include "utils/guc_tables.h"
45 #include "utils/help_config.h"
46
47 extern int      optind;
48 extern char *optarg;
49
50
51 /*
52  * The following char constructs provide the different formats the variables
53  * can be outputted in.
54  */
55 enum outputFormat
56 {
57         HUMAN_OUTPUT,
58         MACHINE_OUTPUT
59 };
60
61 static const char * const GENERIC_FORMAT[] = {
62         gettext_noop("Name       : %-20s \nContext    : %-20s \nGroup      : %-20s\n"),
63         gettext_noop("%s\t%s\t%s\t")
64 };
65 static const char * const GENERIC_DESC[] = {
66         gettext_noop("Description: %s\n%s\n"),
67         gettext_noop("%s        %s\n")
68 };
69 static const char * const BOOL_FORMAT[] = {
70         gettext_noop("Type       : BOOL\nReset Value: %-s \n"),
71         gettext_noop("BOOL\t%s\t\t\t")
72 };
73 static const char * const INT_FORMAT[] = {
74         gettext_noop("Type       : INT\nReset Value: %-20d \nMin Value  : %-20d \nMax Value  : %-20d \n"),
75         gettext_noop("INT\t%d\t%d\t%d\t")
76 };
77 static const char * const REAL_FORMAT[] = {
78         gettext_noop("Type       : REAL\nReset Value: %-20g \nMin Value  : %-20g \nMax Value  : %-20g \n"),
79         gettext_noop("REAL\t%g\t%g\t%g\t")
80 };
81 static const char * const STRING_FORMAT[] = {
82         gettext_noop("Type       : STRING\nReset Value: %-s \n"),
83         gettext_noop("STRING\t%s\t\t\t")
84 };
85 static const char * const COLUMN_HEADER[] = {
86         "",
87         gettext_noop("NAME\tCONTEXT\tGROUP\tTYPE\tRESET_VALUE\tMIN\tMAX\tSHORT_DESCRIPTION\tLONG_DESCRIPTION\n")
88 };
89 static const char * const ROW_SEPARATOR[] = {
90         "------------------------------------------------------------\n",
91         ""
92 };
93
94 /*
95  * Variables loaded from the command line
96  */
97 static char *nameString = NULL; /* The var name pattern to match */
98 static bool nameRegexBool = false;              /* Match the name pattern as a
99                                                                                  * regex */
100 static char *groupString = NULL;        /* The var group pattern to match */
101 static bool groupRegexBool = false;             /* Match the group pattern as a
102                                                                                  * regex */
103 static enum outputFormat outFormat = HUMAN_OUTPUT;
104 static bool suppressAllHeaders = false; /* MACHINE_OUTPUT output, no column
105                                                                                  * headers */
106 static bool groupResults = true;        /* sort result list by groups */
107
108
109 /*
110  * This union allows us to mix the numerous different types of structs
111  * that we are organizing.
112  */
113 typedef union
114 {
115         struct config_generic generic;
116         struct config_bool bool;
117         struct config_real real;
118         struct config_int integer;
119         struct config_string string;
120 }       mixedStruct;
121
122
123 /* function prototypes */
124 static bool varMatches(mixedStruct * structToTest);
125 static int      compareMixedStructs(const void *, const void *);
126 static mixedStruct **varsToDisplay(int *resultListSize);
127 static const char *usageErrMsg(void);
128 static void helpMessage(void);
129 static void listAllGroups(void);
130 static void printGenericHead(struct config_generic structToPrint);
131 static void printGenericFoot(struct config_generic structToPrint);
132 static void printMixedStruct(mixedStruct * structToPrint);
133 static bool displayStruct(mixedStruct * structToDisplay);
134
135 /*
136  * This array contains the display names for each of the GucContexts available
137  *
138  * Note: these strings are deliberately not localized.
139  */
140 static const char *const GucContext_names[] = {
141         "INTERNAL",
142         "POSTMASTER",
143         "SIGHUP",
144         "BACKEND",
145         "SUSET",
146         "USERLIMIT",
147         "USERSET"
148 };
149
150 /*
151  * Reads in the the command line options and sets the state of the program
152  * accordingly. Initializes the result list and sorts it.
153  */
154 int
155 GucInfoMain(int argc, char *argv[])
156 {
157         mixedStruct **varList;
158         int                     resultListSize;
159         int                     c;
160         int                     i;
161
162         while ((c = getopt(argc, argv, "g:rGmMlh")) != -1)
163         {
164                 switch (c)
165                 {
166                         case 'g':
167                                 groupString = optarg;
168                                 break;
169                         case 'r':                       /* not actually implemented yet */
170                                 nameRegexBool = true;
171                                 break;
172                         case 'G':
173                                 groupResults = false;
174                                 break;
175                         case 'm':
176                                 outFormat = MACHINE_OUTPUT;
177                                 break;
178                         case 'M':
179                                 outFormat = MACHINE_OUTPUT;
180                                 suppressAllHeaders = true;
181                                 break;
182                         case 'l':
183                                 listAllGroups();
184                                 exit(0);
185                         case 'h':
186                                 helpMessage();
187                                 exit(0);
188
189                         default:
190                                 fprintf(stderr, gettext("%s \n Try -h for further details\n"), usageErrMsg());
191                                 exit(1);
192                 }
193         }
194
195         if (optind < argc)
196                 nameString = argv[optind];
197
198         /* get the list of variables that match the user's specs. */
199         varList = varsToDisplay(&resultListSize);
200
201         /* sort them by group if desired */
202         /* (without this, we get the original sort by name from guc.c) */
203         if (groupResults)
204                 qsort(varList, resultListSize,
205                           sizeof(mixedStruct *), compareMixedStructs);
206
207         /* output the results */
208         if (!suppressAllHeaders)
209                 printf(gettext(COLUMN_HEADER[outFormat]));
210
211         for (i = 0; varList[i] != NULL; i++)
212         {
213                 printf(gettext(ROW_SEPARATOR[outFormat]));
214                 printMixedStruct(varList[i]);
215         }
216
217         return 0;
218 }
219
220
221 /*
222  * This function is used to compare two mixedStruct types. It compares based
223  * on the value of the 'group' field, and then the name of the variable.
224  * Each void* is expected to be a pointer to a pointer to a struct.
225  * (This is because it is used by qsort to sort an array of struct pointers)
226  *
227  * Returns an integer less than, equal to, or greater than zero if the first
228  * argument (struct1) is considered to be respectively less than, equal to,
229  * or greater than the second (struct2). The comparison is made frist on the
230  * value of struct{1,2}.generic.group and then struct{1,2}.generic.name. The
231  * groups will display in the order they are defined in enum config_group
232  */
233 static int
234 compareMixedStructs(const void *struct1, const void *struct2)
235 {
236         mixedStruct *structVar1 = *(mixedStruct **) struct1;
237         mixedStruct *structVar2 = *(mixedStruct **) struct2;
238
239         if (structVar1->generic.group > structVar2->generic.group)
240                 return 1;
241         else if (structVar1->generic.group < structVar2->generic.group)
242                 return -1;
243         else
244                 return strcmp(structVar1->generic.name, structVar2->generic.name);
245 }
246
247
248 /*
249  * This function returns a complete list of all the variables to display,
250  * according to what the user wants to see.
251  */
252 static mixedStruct **
253 varsToDisplay(int *resultListSize)
254 {
255         mixedStruct **resultList;
256         int                     arrayIndex;
257         int                     i;
258
259         /* Initialize the guc_variables[] array */
260         build_guc_variables();
261
262         /* Extract just the ones we want to display */
263         resultList = malloc((num_guc_variables + 1) * sizeof(mixedStruct *));
264         arrayIndex = 0;
265
266         for (i = 0; i < num_guc_variables; i++)
267         {
268                 mixedStruct *var = (mixedStruct *) guc_variables[i];
269
270                 if (varMatches(var))
271                         resultList[arrayIndex++] = var;
272         }
273
274         /* add an end marker */
275         resultList[arrayIndex] = NULL;
276
277         *resultListSize = arrayIndex;
278         return resultList;
279 }
280
281
282 /*
283  * This function will return true if the struct passed to it
284  * should be displayed to the user.
285  *
286  * The criteria to determine if the struct should not be displayed is:
287  *      + It's flag bits are set to GUC_NO_SHOW_ALL
288  *      + It's flag bits are set to GUC_NOT_IN_SAMPLE
289  *      + It's flag bits are set to GUC_DISALLOW_IN_FILE
290  */
291 static bool
292 displayStruct(mixedStruct * structToDisplay)
293 {
294         if (structToDisplay->generic.flags & (GUC_NO_SHOW_ALL |
295                                                                                   GUC_NOT_IN_SAMPLE |
296                                                                                   GUC_DISALLOW_IN_FILE))
297                 return false;
298         else
299                 return true;
300 }
301
302
303 /*
304  * Used to determine if a variable matches the user's specifications (stored in
305  * global variables). Returns true if this particular variable information should
306  * be returned to the user.
307  */
308 static bool
309 varMatches(mixedStruct * structToTest)
310 {
311         bool            matches = false;
312         bool            specificSearch = false; /* This is true if the user
313                                                                                  * searched for a variable in
314                                                                                  * particular. */
315
316         if (nameString != NULL && !nameRegexBool)
317         {
318                 if (strstr(structToTest->generic.name, nameString) != NULL)
319                 {
320                         matches = true;
321                         specificSearch = true;
322                 }
323         }
324
325         if (nameString != NULL && nameRegexBool)
326         {
327                 /* We do not support this option yet */
328         }
329
330         if (groupString != NULL && !groupRegexBool)
331         {
332                 if (strstr(config_group_names[structToTest->generic.group], groupString) != NULL)
333                 {
334                         if (nameString != NULL)
335                                 matches = (matches && true);
336                         else
337                                 matches = true;
338                 }
339                 else
340                         matches = false;
341         }
342
343         if (groupString != NULL && groupRegexBool)
344         {
345                 /* We do not support this option yet */
346         }
347
348         /* return all variables */
349         if (nameString == NULL && groupString == NULL)
350                 matches = true;
351
352         if (specificSearch)
353                 return matches;
354         else
355                 return matches && displayStruct(structToTest);
356 }
357
358
359 /*
360  * This function prints out the generic struct passed to it. It will print out
361  * a different format, depending on what the user wants to see.
362  */
363 static void
364 printMixedStruct(mixedStruct * structToPrint)
365 {
366         printGenericHead(structToPrint->generic);
367
368         switch (structToPrint->generic.vartype)
369         {
370
371                 case PGC_BOOL:
372                         printf(gettext(BOOL_FORMAT[outFormat]),
373                                    (structToPrint->bool.reset_val == 0) ?
374                                    gettext("FALSE") : gettext("TRUE"));
375                         break;
376
377                 case PGC_INT:
378                         printf(gettext(INT_FORMAT[outFormat]),
379                                    structToPrint->integer.reset_val,
380                                    structToPrint->integer.min,
381                                    structToPrint->integer.max);
382                         break;
383
384                 case PGC_REAL:
385                         printf(gettext(REAL_FORMAT[outFormat]),
386                                    structToPrint->real.reset_val,
387                                    structToPrint->real.min,
388                                    structToPrint->real.max);
389                         break;
390
391                 case PGC_STRING:
392                         printf(gettext(STRING_FORMAT[outFormat]),
393                                    structToPrint->string.boot_val);
394                         break;
395
396                 default:
397                         printf(gettext("Unrecognized variable type!\n"));
398                         break;
399         }
400
401         printGenericFoot(structToPrint->generic);
402 }
403
404 static void
405 printGenericHead(struct config_generic structToPrint)
406 {
407         printf(gettext(GENERIC_FORMAT[outFormat]),
408                    structToPrint.name,
409                    GucContext_names[structToPrint.context],
410                    gettext(config_group_names[structToPrint.group]));
411 }
412
413 static void
414 printGenericFoot(struct config_generic sPrint)
415 {
416         printf(gettext(GENERIC_DESC[outFormat]),
417                    (sPrint.short_desc == NULL) ? "" : gettext(sPrint.short_desc),
418                    (sPrint.long_desc == NULL) ? "" : gettext(sPrint.long_desc));
419 }
420
421 static void
422 listAllGroups(void)
423 {
424         int                     i;
425
426         printf(gettext("All currently defined groups\n"));
427         printf(gettext("----------------------------\n"));
428         for (i = 0; config_group_names[i] != NULL; i++)
429                 printf(gettext("%s\n"), gettext(config_group_names[i]));
430 }
431
432 static const char *
433 usageErrMsg(void)
434 {
435         return gettext("Usage for --help-config option: [-h] [-g <group>] [-l] [-G] [-m] [-M] [string]\n");
436 }
437
438 static void
439 helpMessage(void)
440 {
441         printf(gettext("Description:\n"
442                                    "--help-config displays all the runtime options available in PostgreSQL.\n"
443                                    "It groups them by category and sorts them by name. If available, it will\n"
444                                    "present a short description, default, max and min values as well as other\n"
445                                    "information about each option.\n\n"
446                                    "With no options specified, it will output all available runtime options\n"
447                                    "in human friendly format, grouped by category and sorted by name.\n\n"
448
449                                    "%s\n"
450
451                                    "General Options:\n"
452                         "  [string]     All options with names that match this string\n"
453                            "  -g GROUP  All options in categories that match GROUP\n"
454                                    "  -l        Prints list of all groups / subgroups\n"
455                                    "  -h        Prints this help message\n"
456                                    "\nOutput Options:\n"
457                                    "  -G        Do not group by category\n"
458                         "  -m           Machine friendly format: tab separated fields\n"
459                                    "  -M        Same as m, except header with column names is suppressed\n"),
460                    usageErrMsg()
461         );
462 }