1 /*
2  * Copyright 2009-2017 Citrix Ltd and other contributors
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; version 2.1 only. with the special
7  * exception on linking described in file LICENSE.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  */
14 
15 #ifndef XL_UTILS_H
16 #define XL_UTILS_H
17 
18 #include <getopt.h>
19 
20 /* For calls which return an errno on failure */
21 #define CHK_ERRNOVAL( call ) ({                                         \
22         int chk_errnoval = (call);                                      \
23         if (chk_errnoval < 0)                                           \
24             abort();                                                    \
25         else if (chk_errnoval > 0) {                                    \
26             fprintf(stderr,"xl: fatal error: %s:%d: %s: %s\n",          \
27                     __FILE__,__LINE__, strerror(chk_errnoval), #call);  \
28             exit(EXIT_FAILURE);                                         \
29         }                                                               \
30     })
31 
32 /* For calls which return -1 and set errno on failure */
33 #define CHK_SYSCALL( call ) ({                                          \
34         if ((call) == -1) {                                             \
35             fprintf(stderr,"xl: fatal error: %s:%d: %s: %s\n",          \
36                     __FILE__,__LINE__, strerror(errno), #call);         \
37             exit(EXIT_FAILURE);                                         \
38         }                                                               \
39     })
40 
41 #define MUST( call ) ({                                                 \
42         int must_rc = (call);                                           \
43         if (must_rc < 0) {                                              \
44             fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: %s\n",       \
45                     __FILE__,__LINE__, must_rc, #call);                 \
46             exit(EXIT_FAILURE);                                         \
47         }                                                               \
48     })
49 
50 #define STR_HAS_PREFIX( a, b )  \
51     ( strncmp(a, b, strlen(b)) == 0 )
52 #define STR_SKIP_PREFIX( a, b ) \
53     ( STR_HAS_PREFIX(a, b) ? ((a) += strlen(b), 1) : 0 )
54 
55 #define LOG(_f, _a...)   dolog(__FILE__, __LINE__, __func__, _f "\n", ##_a)
56 
57 /*
58  * Wraps def_getopt into a convenient loop+switch to process all
59  * arguments. This macro is intended to be called from main_XXX().
60  *
61  *   SWITCH_FOREACH_OPT(int *opt, "OPTS",
62  *                      const struct option *longopts,
63  *                      const char *commandname,
64  *                      int num_opts_req) { ...
65  *
66  * opt:               pointer to an int variable, holds the current option
67  *                    during processing.
68  * OPTS:              short options, as per getopt_long(3)'s optstring argument.
69  *                    do not include "h"; will be provided automatically
70  * longopts:          long options, as per getopt_long(3)'s longopts argument.
71  *                    May be null.
72  * commandname:       name of this command, for usage string.
73  * num_required_opts: number of non-option command line parameters
74  *                    which are required.
75  *
76  * In addition the calling context is expected to contain variables
77  * "argc" and "argv" in the conventional C-style:
78  *   main(int argc, char **argv)
79  * manner.
80  *
81  * Callers should treat SWITCH_FOREACH_OPT as they would a switch
82  * statement over the value of `opt`. Each option given in `opts` (or
83  * `lopts`) should be handled by a case statement as if it were inside
84  * a switch statement.
85  *
86  * In addition to the options provided in opts the macro will handle
87  * the "help" option and enforce a minimum number of non-option
88  * command line pearameters as follows:
89  *  -- if the user passes a -h or --help option. help will be printed,
90  *     and the macro will cause the process to exit with code 0.
91  *  -- if the user does not provided `num_required_opts` non-option
92  *     arguments, the macro will cause the process to exit with code 2.
93  *
94  * Example:
95  *
96  * int main_foo(int argc, char **argv) {
97  *     int opt;
98  *
99  *     SWITCH_FOREACH_OPT(opt, "blah", NULL, "foo", 0) {
100  *      case 'b':
101  *          ... handle b option...
102  *          break;
103  *      case 'l':
104  *          ... handle l option ...
105  *          break;
106  *      case etc etc...
107  *      }
108  *      ... do something useful with the options ...
109  * }
110  */
111 #define SWITCH_FOREACH_OPT(opt, opts, longopts,                         \
112                            commandname, num_required_opts)              \
113     while (((opt) = def_getopt(argc, argv, "h" opts, (longopts),        \
114                                (commandname), (num_required_opts))) != -1) \
115         switch (opt)
116 
117 /* Must be last in list */
118 #define COMMON_LONG_OPTS {"help", 0, 0, 'h'}, \
119                          {0, 0, 0, 0}
120 
121 int def_getopt(int argc, char * const argv[],
122                const char *optstring,
123                const struct option *longopts,
124                const char* helpstr, int reqargs);
125 
126 void dolog(const char *file, int line, const char *func, char *fmt, ...)
127 	__attribute__((format(printf,4,5)));
128 
129 void xvasprintf(char **strp, const char *fmt, va_list ap)
130 	__attribute__((format(printf,2,0)));
131 
132 void xasprintf(char **strp, const char *fmt, ...)
133 	__attribute__((format(printf,2,3)));
134 
135 void *xmalloc(size_t sz);
136 void *xcalloc(size_t n, size_t sz);
137 void *xrealloc(void *ptr, size_t sz);
138 char *xstrdup(const char *x);
139 void string_realloc_append(char **accumulate, const char *more);
140 
141 void flush_stream(FILE *fh);
142 uint32_t find_domain(const char *p) __attribute__((warn_unused_result));
143 
144 void print_bitmap(uint8_t *map, int maplen, FILE *stream);
145 
146 int do_daemonize(char *name, const char *pidfile);
147 #endif /* XL_UTILS_H */
148 
149 /*
150  * Local variables:
151  * mode: C
152  * c-basic-offset: 4
153  * indent-tabs-mode: nil
154  * End:
155  */
156