Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/sntp/libopts/pgusage.c
Line
Count
Source (jump to first uncovered line)
1
2
/**
3
 * \file pgusage.c
4
 *
5
 *   Automated Options Paged Usage module.
6
 *
7
 * @addtogroup autoopts
8
 * @{
9
 */
10
/*
11
 *  This routine will run run-on options through a pager so the
12
 *  user may examine, print or edit them at their leisure.
13
 *
14
 *  This file is part of AutoOpts, a companion to AutoGen.
15
 *  AutoOpts is free software.
16
 *  AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
17
 *
18
 *  AutoOpts is available under any one of two licenses.  The license
19
 *  in use must be one of these two and the choice is under the control
20
 *  of the user of the license.
21
 *
22
 *   The GNU Lesser General Public License, version 3 or later
23
 *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
24
 *
25
 *   The Modified Berkeley Software Distribution License
26
 *      See the file "COPYING.mbsd"
27
 *
28
 *  These files have the following sha256 sums:
29
 *
30
 *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
31
 *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
32
 *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
33
 */
34
35
#if defined(HAVE_WORKING_FORK)
36
static inline FILE *
37
open_tmp_usage(char ** buf)
38
0
{
39
0
    char * bf;
40
0
    size_t bfsz;
41
42
0
    {
43
0
        unsigned int my_pid = (unsigned int)getpid();
44
0
        char const * tmpdir = getenv(TMPDIR);
45
0
        if (tmpdir == NULL)
46
0
            tmpdir = tmp_dir;
47
0
        bfsz = TMP_FILE_FMT_LEN + strlen(tmpdir) + 10;
48
0
        bf   = AGALOC(bfsz, "tmp fil");
49
0
        snprintf(bf, bfsz, TMP_FILE_FMT, tmpdir, my_pid);
50
0
    }
51
52
0
    {
53
0
        static mode_t const cmask = S_IRWXO | S_IRWXG;
54
0
        mode_t svmsk = umask(cmask);
55
0
        int fd = mkstemp(bf);
56
0
        (void)umask(svmsk);
57
58
0
        if (fd < 0) {
59
0
            AGFREE(bf);
60
0
            return NULL;
61
0
        }
62
0
        *buf = bf;
63
0
        return fdopen(fd, "w");
64
0
    }
65
0
}
66
67
static inline char *
68
mk_pager_cmd(char const * fname)
69
0
{
70
    /*
71
     * Page the file and remove it when done.  For shell script processing,
72
     * we must redirect the output to the current stderr, otherwise stdout.
73
     */
74
0
    fclose(option_usage_fp);
75
0
    option_usage_fp = NULL;
76
77
0
    {
78
0
        char const * pager  = (char const *)getenv(PAGER_NAME);
79
0
        size_t bfsz;
80
0
        char * res;
81
82
        /*
83
         *  Use the "more(1)" program if "PAGER" has not been defined
84
         */
85
0
        if (pager == NULL)
86
0
            pager = MORE_STR;
87
88
0
        bfsz = 2 * strlen(fname) + strlen(pager) + PAGE_USAGE_FMT_LEN;
89
0
        res  = AGALOC(bfsz, "more cmd");
90
0
        snprintf(res, bfsz, PAGE_USAGE_FMT, pager, fname);
91
0
        AGFREE(fname);
92
0
        return res;
93
0
    }
94
0
}
95
#endif
96
97
/*=export_func  optionPagedUsage
98
 * private:
99
 *
100
 * what:  emit help text and pass through a pager program.
101
 * arg:   + tOptions * + opts + program options descriptor +
102
 * arg:   + tOptDesc * + od   + the descriptor for this arg +
103
 *
104
 * doc:
105
 *  Run the usage output through a pager.
106
 *  This is very handy if it is very long.
107
 *  This is disabled on platforms without a working fork() function.
108
=*/
109
void
110
optionPagedUsage(tOptions * opts, tOptDesc * od)
111
0
{
112
#if ! defined(HAVE_WORKING_FORK)
113
    if ((od->fOptState & OPTST_RESET) != 0)
114
        return;
115
116
    (*opts->pUsageProc)(opts, EXIT_SUCCESS);
117
#else
118
0
    static bool sv_print_exit = false;
119
0
    static char * fil_name = NULL;
120
121
    /*
122
     *  IF we are being called after the usage proc is done
123
     *     (and thus has called "exit(2)")
124
     *  THEN invoke the pager to page through the usage file we created.
125
     */
126
0
    switch (pagerState) {
127
0
    case PAGER_STATE_INITIAL:
128
0
    {
129
0
        if ((od->fOptState & OPTST_RESET) != 0)
130
0
            return;
131
0
        option_usage_fp = open_tmp_usage(&fil_name);
132
0
        if (option_usage_fp == NULL)
133
0
            (*opts->pUsageProc)(opts, EXIT_SUCCESS);
134
135
0
        pagerState    = PAGER_STATE_READY;
136
0
        sv_print_exit = print_exit;
137
138
        /*
139
         *  Set up so this routine gets called during the exit logic
140
         */
141
0
        atexit((void(*)(void))optionPagedUsage);
142
143
        /*
144
         *  The usage procedure will now put the usage information into
145
         *  the temporary file we created above.  Keep any shell commands
146
         *  out of the result.
147
         */
148
0
        print_exit = false;
149
0
        (*opts->pUsageProc)(opts, EXIT_SUCCESS);
150
151
        /* NOTREACHED */
152
0
        _exit(EXIT_FAILURE);
153
0
    }
154
155
0
    case PAGER_STATE_READY:
156
0
        fil_name = mk_pager_cmd(fil_name);
157
158
0
        if (sv_print_exit) {
159
0
            fputs("\nexit 0\n", stdout);
160
0
            fclose(stdout);
161
0
            dup2(STDERR_FILENO, STDOUT_FILENO);
162
163
0
        } else {
164
0
            fclose(stderr);
165
0
            dup2(STDOUT_FILENO, STDERR_FILENO);
166
0
        }
167
168
0
        ignore_val( system( fil_name));
169
0
        AGFREE(fil_name);
170
171
0
    case PAGER_STATE_CHILD:
172
        /*
173
         *  This is a child process used in creating shell script usage.
174
         */
175
0
        break;
176
0
    }
177
0
#endif
178
0
}
179
180
/** @}
181
 *
182
 * Local Variables:
183
 * mode: C
184
 * c-file-style: "stroustrup"
185
 * indent-tabs-mode: nil
186
 * End:
187
 * end of autoopts/pgusage.c */