xref: /freebsd-src/contrib/ntp/sntp/libopts/pgusage.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
1ea906c41SOllivier Robert 
22b15cb3dSCy Schubert /**
32b15cb3dSCy Schubert  * \file pgusage.c
4ea906c41SOllivier Robert  *
5ea906c41SOllivier Robert  *   Automated Options Paged Usage module.
6ea906c41SOllivier Robert  *
72b15cb3dSCy Schubert  * @addtogroup autoopts
82b15cb3dSCy Schubert  * @{
92b15cb3dSCy Schubert  */
102b15cb3dSCy Schubert /*
11ea906c41SOllivier Robert  *  This routine will run run-on options through a pager so the
12ea906c41SOllivier Robert  *  user may examine, print or edit them at their leisure.
132b15cb3dSCy Schubert  *
142b15cb3dSCy Schubert  *  This file is part of AutoOpts, a companion to AutoGen.
152b15cb3dSCy Schubert  *  AutoOpts is free software.
16*a466cc55SCy Schubert  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
172b15cb3dSCy Schubert  *
182b15cb3dSCy Schubert  *  AutoOpts is available under any one of two licenses.  The license
192b15cb3dSCy Schubert  *  in use must be one of these two and the choice is under the control
202b15cb3dSCy Schubert  *  of the user of the license.
212b15cb3dSCy Schubert  *
222b15cb3dSCy Schubert  *   The GNU Lesser General Public License, version 3 or later
232b15cb3dSCy Schubert  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
242b15cb3dSCy Schubert  *
252b15cb3dSCy Schubert  *   The Modified Berkeley Software Distribution License
262b15cb3dSCy Schubert  *      See the file "COPYING.mbsd"
272b15cb3dSCy Schubert  *
282b15cb3dSCy Schubert  *  These files have the following sha256 sums:
292b15cb3dSCy Schubert  *
302b15cb3dSCy Schubert  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
312b15cb3dSCy Schubert  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
322b15cb3dSCy Schubert  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
33ea906c41SOllivier Robert  */
34ea906c41SOllivier Robert 
352b15cb3dSCy Schubert #if defined(HAVE_WORKING_FORK)
36276da39aSCy Schubert static inline FILE *
open_tmp_usage(char ** buf)372b15cb3dSCy Schubert open_tmp_usage(char ** buf)
382b15cb3dSCy Schubert {
392b15cb3dSCy Schubert     char * bf;
402b15cb3dSCy Schubert     size_t bfsz;
412b15cb3dSCy Schubert 
422b15cb3dSCy Schubert     {
432b15cb3dSCy Schubert         unsigned int my_pid = (unsigned int)getpid();
442b15cb3dSCy Schubert         char const * tmpdir = getenv(TMPDIR);
452b15cb3dSCy Schubert         if (tmpdir == NULL)
462b15cb3dSCy Schubert             tmpdir = tmp_dir;
472b15cb3dSCy Schubert         bfsz = TMP_FILE_FMT_LEN + strlen(tmpdir) + 10;
482b15cb3dSCy Schubert         bf   = AGALOC(bfsz, "tmp fil");
492b15cb3dSCy Schubert         snprintf(bf, bfsz, TMP_FILE_FMT, tmpdir, my_pid);
502b15cb3dSCy Schubert     }
512b15cb3dSCy Schubert 
522b15cb3dSCy Schubert     {
532b15cb3dSCy Schubert         static mode_t const cmask = S_IRWXO | S_IRWXG;
542b15cb3dSCy Schubert         mode_t svmsk = umask(cmask);
552b15cb3dSCy Schubert         int fd = mkstemp(bf);
562b15cb3dSCy Schubert         (void)umask(svmsk);
572b15cb3dSCy Schubert 
582b15cb3dSCy Schubert         if (fd < 0) {
592b15cb3dSCy Schubert             AGFREE(bf);
602b15cb3dSCy Schubert             return NULL;
612b15cb3dSCy Schubert         }
622b15cb3dSCy Schubert         *buf = bf;
632b15cb3dSCy Schubert         return fdopen(fd, "w");
642b15cb3dSCy Schubert     }
652b15cb3dSCy Schubert }
662b15cb3dSCy Schubert 
67276da39aSCy Schubert static inline char *
mk_pager_cmd(char const * fname)682b15cb3dSCy Schubert mk_pager_cmd(char const * fname)
692b15cb3dSCy Schubert {
702b15cb3dSCy Schubert     /*
712b15cb3dSCy Schubert      * Page the file and remove it when done.  For shell script processing,
722b15cb3dSCy Schubert      * we must redirect the output to the current stderr, otherwise stdout.
732b15cb3dSCy Schubert      */
742b15cb3dSCy Schubert     fclose(option_usage_fp);
752b15cb3dSCy Schubert     option_usage_fp = NULL;
762b15cb3dSCy Schubert 
772b15cb3dSCy Schubert     {
782b15cb3dSCy Schubert         char const * pager  = (char const *)getenv(PAGER_NAME);
792b15cb3dSCy Schubert         size_t bfsz;
802b15cb3dSCy Schubert         char * res;
812b15cb3dSCy Schubert 
82ea906c41SOllivier Robert         /*
832b15cb3dSCy Schubert          *  Use the "more(1)" program if "PAGER" has not been defined
84ea906c41SOllivier Robert          */
852b15cb3dSCy Schubert         if (pager == NULL)
862b15cb3dSCy Schubert             pager = MORE_STR;
87ea906c41SOllivier Robert 
88276da39aSCy Schubert         bfsz = 2 * strlen(fname) + strlen(pager) + PAGE_USAGE_FMT_LEN;
892b15cb3dSCy Schubert         res  = AGALOC(bfsz, "more cmd");
902b15cb3dSCy Schubert         snprintf(res, bfsz, PAGE_USAGE_FMT, pager, fname);
91276da39aSCy Schubert         AGFREE(fname);
922b15cb3dSCy Schubert         return res;
932b15cb3dSCy Schubert     }
942b15cb3dSCy Schubert }
952b15cb3dSCy Schubert #endif
96ea906c41SOllivier Robert 
97ea906c41SOllivier Robert /*=export_func  optionPagedUsage
98ea906c41SOllivier Robert  * private:
99ea906c41SOllivier Robert  *
1002b15cb3dSCy Schubert  * what:  emit help text and pass through a pager program.
1012b15cb3dSCy Schubert  * arg:   + tOptions * + opts + program options descriptor +
1022b15cb3dSCy Schubert  * arg:   + tOptDesc * + od   + the descriptor for this arg +
103ea906c41SOllivier Robert  *
104ea906c41SOllivier Robert  * doc:
105ea906c41SOllivier Robert  *  Run the usage output through a pager.
106ea906c41SOllivier Robert  *  This is very handy if it is very long.
1072b15cb3dSCy Schubert  *  This is disabled on platforms without a working fork() function.
108ea906c41SOllivier Robert =*/
109ea906c41SOllivier Robert void
optionPagedUsage(tOptions * opts,tOptDesc * od)1102b15cb3dSCy Schubert optionPagedUsage(tOptions * opts, tOptDesc * od)
111ea906c41SOllivier Robert {
1122b15cb3dSCy Schubert #if ! defined(HAVE_WORKING_FORK)
1132b15cb3dSCy Schubert     if ((od->fOptState & OPTST_RESET) != 0)
1142b15cb3dSCy Schubert         return;
1152b15cb3dSCy Schubert 
1162b15cb3dSCy Schubert     (*opts->pUsageProc)(opts, EXIT_SUCCESS);
117ea906c41SOllivier Robert #else
1182b15cb3dSCy Schubert     static bool sv_print_exit = false;
1192b15cb3dSCy Schubert     static char * fil_name = NULL;
120ea906c41SOllivier Robert 
121ea906c41SOllivier Robert     /*
122ea906c41SOllivier Robert      *  IF we are being called after the usage proc is done
123ea906c41SOllivier Robert      *     (and thus has called "exit(2)")
124ea906c41SOllivier Robert      *  THEN invoke the pager to page through the usage file we created.
125ea906c41SOllivier Robert      */
126ea906c41SOllivier Robert     switch (pagerState) {
127ea906c41SOllivier Robert     case PAGER_STATE_INITIAL:
128ea906c41SOllivier Robert     {
1292b15cb3dSCy Schubert         if ((od->fOptState & OPTST_RESET) != 0)
1302b15cb3dSCy Schubert             return;
1312b15cb3dSCy Schubert         option_usage_fp = open_tmp_usage(&fil_name);
132ea906c41SOllivier Robert         if (option_usage_fp == NULL)
1332b15cb3dSCy Schubert             (*opts->pUsageProc)(opts, EXIT_SUCCESS);
134ea906c41SOllivier Robert 
135ea906c41SOllivier Robert         pagerState    = PAGER_STATE_READY;
1362b15cb3dSCy Schubert         sv_print_exit = print_exit;
137ea906c41SOllivier Robert 
138ea906c41SOllivier Robert         /*
139ea906c41SOllivier Robert          *  Set up so this routine gets called during the exit logic
140ea906c41SOllivier Robert          */
141ea906c41SOllivier Robert         atexit((void(*)(void))optionPagedUsage);
142ea906c41SOllivier Robert 
143ea906c41SOllivier Robert         /*
144ea906c41SOllivier Robert          *  The usage procedure will now put the usage information into
1452b15cb3dSCy Schubert          *  the temporary file we created above.  Keep any shell commands
1462b15cb3dSCy Schubert          *  out of the result.
147ea906c41SOllivier Robert          */
1482b15cb3dSCy Schubert         print_exit = false;
1492b15cb3dSCy Schubert         (*opts->pUsageProc)(opts, EXIT_SUCCESS);
150ea906c41SOllivier Robert 
151ea906c41SOllivier Robert         /* NOTREACHED */
152ea906c41SOllivier Robert         _exit(EXIT_FAILURE);
153ea906c41SOllivier Robert     }
154ea906c41SOllivier Robert 
155ea906c41SOllivier Robert     case PAGER_STATE_READY:
1562b15cb3dSCy Schubert         fil_name = mk_pager_cmd(fil_name);
157ea906c41SOllivier Robert 
1582b15cb3dSCy Schubert         if (sv_print_exit) {
1592b15cb3dSCy Schubert             fputs("\nexit 0\n", stdout);
1602b15cb3dSCy Schubert             fclose(stdout);
1612b15cb3dSCy Schubert             dup2(STDERR_FILENO, STDOUT_FILENO);
162ea906c41SOllivier Robert 
1632b15cb3dSCy Schubert         } else {
164ea906c41SOllivier Robert             fclose(stderr);
165ea906c41SOllivier Robert             dup2(STDOUT_FILENO, STDERR_FILENO);
166ea906c41SOllivier Robert         }
167ea906c41SOllivier Robert 
1682b15cb3dSCy Schubert         ignore_val( system( fil_name));
1692b15cb3dSCy Schubert         AGFREE(fil_name);
1702b15cb3dSCy Schubert 
171ea906c41SOllivier Robert     case PAGER_STATE_CHILD:
172ea906c41SOllivier Robert         /*
173ea906c41SOllivier Robert          *  This is a child process used in creating shell script usage.
174ea906c41SOllivier Robert          */
175ea906c41SOllivier Robert         break;
176ea906c41SOllivier Robert     }
177ea906c41SOllivier Robert #endif
178ea906c41SOllivier Robert }
179ea906c41SOllivier Robert 
1802b15cb3dSCy Schubert /** @}
1812b15cb3dSCy Schubert  *
182ea906c41SOllivier Robert  * Local Variables:
183ea906c41SOllivier Robert  * mode: C
184ea906c41SOllivier Robert  * c-file-style: "stroustrup"
185ea906c41SOllivier Robert  * indent-tabs-mode: nil
186ea906c41SOllivier Robert  * End:
187ea906c41SOllivier Robert  * end of autoopts/pgusage.c */
188