]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bjson.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / lib / bjson.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Json library routines
22  *
23  *     Kern Sibbald, September MMXII
24  *
25  */
26
27 #include "bacula.h"
28 #include "lib/breg.h"
29
30 extern s_kw msg_types[];
31 extern RES_TABLE resources[];
32
33 union URES {
34    MSGS  res_msgs;
35    RES hdr;
36 };
37
38 #if defined(_MSC_VER)
39 extern "C" { // work around visual compiler mangling variables
40    extern URES res_all;
41 }
42 #else
43 extern URES res_all;
44 #endif
45
46 struct display_filter
47 {
48    /* default                   { { "Director": { "Name": aa, ...} }, { "Job": {..} */
49    bool do_list;             /* [ {}, {}, ..] or { "aa": {}, "bb": {}, ...} */
50    bool do_one;              /* { "Name": "aa", "Description": "test, ... } */
51    bool do_only_data;        /* [ {}, {}, {}, ] */
52    char *resource_type;
53    char *resource_name;
54    regex_t directive_reg;
55 };
56
57 static void sendit(void *sock, const char *fmt, ...)
58 {
59    char buf[3000];
60    va_list arg_ptr;
61
62    va_start(arg_ptr, fmt);
63    bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
64    va_end(arg_ptr);
65    fputs(buf, stdout);
66    fflush(stdout);
67 }
68
69 void init_hpkt(HPKT &hpkt)
70 {
71    memset(&hpkt, 0, sizeof(hpkt));
72    hpkt.edbuf = get_pool_memory(PM_EMSG);
73    hpkt.edbuf2 = get_pool_memory(PM_EMSG);
74    hpkt.json = true;
75    hpkt.hfunc = HF_DISPLAY;
76    hpkt.sendit = sendit;
77 }
78
79 void term_hpkt(HPKT &hpkt)
80 {
81    free_pool_memory(hpkt.edbuf);
82    free_pool_memory(hpkt.edbuf2);
83    memset(&hpkt, 0, sizeof(hpkt));
84 }
85
86 /*
87  * Strip long options out of fo->opts string so that
88  *   they will not give us false matches for regular
89  *   1 or 2 character options.
90  */
91 void strip_long_opts(char *out, const char *in)
92 {
93    const char *p;
94    for (p=in; *p; p++) {
95       switch (*p) {
96       /* V, C, J, and P are long options, skip them */
97       case 'V':
98       case 'C':
99       case 'J':
100       case 'P':
101          while (*p != ':') {
102             p++;       /* skip to after : */
103          }
104          break;
105       /* Copy everything else */
106       default:
107          *out++ = *p;
108          break;
109       }
110    }
111    *out = 0;           /* terminate string */
112 }
113
114 void edit_alist(HPKT &hpkt)
115 {
116    bool f = true;
117    char *citem;
118
119    pm_strcpy(hpkt.edbuf, " [");
120    foreach_alist(citem, hpkt.list) {
121       if (!f) {
122          pm_strcat(hpkt.edbuf, ", ");
123       }
124       pm_strcat(hpkt.edbuf, quote_string(hpkt.edbuf2, citem));
125       f = false;
126    }
127    pm_strcat(hpkt.edbuf, "]");
128 }
129
130 void edit_msg_types(HPKT &hpkt, DEST *dest)
131 {
132    int i, j, count = 0;
133    bool first_type = true;
134    bool found;
135
136    pm_strcpy(hpkt.edbuf, "[");
137    for (i=1; i<M_MAX; i++) {
138       if (bit_is_set(i, dest->msg_types)) {
139          found = false;
140          if (!first_type) pm_strcat(hpkt.edbuf, ",");
141          first_type = false;
142          for (j=0; msg_types[j].name; j++) {
143             if ((int)msg_types[j].token == i) {
144                pm_strcat(hpkt.edbuf, "\"");
145                pm_strcat(hpkt.edbuf, msg_types[j].name);
146                pm_strcat(hpkt.edbuf, "\"");
147                found = true;
148                break;
149             }
150          }
151          if (!found) {
152             sendit(NULL, "No find for type=%d\n", i);
153          }
154          count++;
155       }
156    }
157    /*
158     * Note, if we have more than half of the total items,
159     *   redo using All and !item, which will give fewer items
160     *   total.
161     */
162    if (count > M_MAX/2) {
163       pm_strcpy(hpkt.edbuf, "[\"All\"");
164       for (i=1; i<M_MAX; i++) {
165          if (!bit_is_set(i, dest->msg_types)) {
166             found = false;
167             pm_strcat(hpkt.edbuf, ",");
168             for (j=0; msg_types[j].name; j++) {
169                if ((int)msg_types[j].token == i) {
170                   pm_strcat(hpkt.edbuf, "\"!");
171                   pm_strcat(hpkt.edbuf, msg_types[j].name);
172                   pm_strcat(hpkt.edbuf, "\"");
173                   found = true;
174                   break;
175                }
176             }
177             if (!found) {
178                sendit(NULL, "No find for type=%d in second loop\n", i);
179             }
180          } else if (i == M_SAVED) {
181             /* Saved is not set by default, users must explicitly use it
182              * on the configuration line
183              */
184             pm_strcat(hpkt.edbuf, ",\"Saved\"");
185          }
186       }
187    }
188    pm_strcat(hpkt.edbuf, "]");
189 }
190
191 bool display_global_item(HPKT &hpkt)
192 {
193    bool found = true;
194
195    if (hpkt.ritem->handler == store_res) {
196       display_res(hpkt);
197    } else if (hpkt.ritem->handler == store_str ||
198               hpkt.ritem->handler == store_name ||
199               hpkt.ritem->handler == store_password ||
200               hpkt.ritem->handler == store_strname ||
201               hpkt.ritem->handler == store_dir) {
202       display_string_pair(hpkt);
203    } else if (hpkt.ritem->handler == store_int32 ||
204               hpkt.ritem->handler == store_pint32 ||
205               hpkt.ritem->handler == store_size32) {
206       display_int32_pair(hpkt);
207    } else if (hpkt.ritem->handler == store_size64 ||
208               hpkt.ritem->handler == store_int64 ||
209               hpkt.ritem->handler == store_time ||
210               hpkt.ritem->handler == store_speed) {
211       display_int64_pair(hpkt);
212    } else if (hpkt.ritem->handler == store_bool) {
213       display_bool_pair(hpkt);
214    } else if (hpkt.ritem->handler == store_msgs) {
215       display_msgs(hpkt);
216    } else if (hpkt.ritem->handler == store_bit) {
217       display_bit_pair(hpkt);
218    } else if (hpkt.ritem->handler == store_alist_res) {
219       found = display_alist_res(hpkt); /* In some cases, the list is null... */
220    } else if (hpkt.ritem->handler == store_alist_str) {
221       found = display_alist_str(hpkt); /* In some cases, the list is null... */
222    } else {
223       found = false;
224    }
225
226    return found;
227 }
228
229 /*
230  * Called here for each store_msgs resource
231  */
232 void display_msgs(HPKT &hpkt)
233 {
234    MSGS *msgs = (MSGS *)hpkt.ritem->value;  /* Message res */
235    DEST *dest;   /* destination chain */
236    int first = true;
237
238    if (!hpkt.in_store_msg) {
239       hpkt.in_store_msg = true;
240       sendit(NULL, "\n    \"Destinations\": [");
241    }
242    for (dest=msgs->dest_chain; dest; dest=dest->next) {
243       if (dest->dest_code == hpkt.ritem->code) {
244          if (!first) sendit(NULL, ",");
245          first = false;
246          edit_msg_types(hpkt, dest);
247          switch (hpkt.ritem->code) {
248          /* Output only message types */
249          case MD_STDOUT:
250          case MD_STDERR:
251          case MD_SYSLOG:
252          case MD_CONSOLE:
253          case MD_CATALOG:
254             sendit(NULL, "\n      {\n        \"Type\": \"%s\","
255                          "\n        \"MsgTypes\": %s\n      }",
256                hpkt.ritem->name, hpkt.edbuf);
257             break;
258          /* Output MsgTypes, Where */
259          case MD_DIRECTOR:
260          case MD_FILE:
261          case MD_APPEND:
262             sendit(NULL, "\n      {\n        \"Type\": \"%s\","
263                          "\n        \"MsgTypes\": %s,\n",
264                hpkt.ritem->name, hpkt.edbuf);
265             sendit(NULL, "        \"Where\": [%s]\n      }",
266                quote_where(hpkt.edbuf, dest->where));
267             break;
268          /* Now we edit MsgTypes, Where, and Command */
269          case MD_MAIL:
270          case MD_OPERATOR:
271          case MD_MAIL_ON_ERROR:
272          case MD_MAIL_ON_SUCCESS:
273             sendit(NULL, "\n      {\n        \"Type\": \"%s\","
274                          "\n        \"MsgTypes\": %s,\n",
275                hpkt.ritem->name, hpkt.edbuf);
276             sendit(NULL, "        \"Where\": [%s],\n",
277                quote_where(hpkt.edbuf, dest->where));
278             sendit(NULL, "        \"Command\": %s\n      }",
279                quote_string(hpkt.edbuf, dest->mail_cmd));
280             break;
281          }
282       }
283    }
284 }
285
286 /*
287  * Called here if the ITEM_LAST is set in flags,
288  *  that means there are no more items to examine
289  *  for this resource and that we can close any
290  *  open json list.
291  */
292 void display_last(HPKT &hpkt)
293 {
294    if (hpkt.in_store_msg) {
295       hpkt.in_store_msg = false;
296       sendit(NULL, "\n    ]");
297    }
298 }
299
300 void display_alist(HPKT &hpkt)
301 {
302    edit_alist(hpkt);
303    sendit(NULL, "%s", hpkt.edbuf);
304 }
305
306 bool display_alist_str(HPKT &hpkt)
307 {
308    hpkt.list = (alist *)(*(hpkt.ritem->value));
309    if (!hpkt.list) {
310       return false;
311    }
312    sendit(NULL, "\n    \"%s\":", hpkt.ritem->name);
313    display_alist(hpkt);
314    return true;
315 }
316
317 bool display_alist_res(HPKT &hpkt)
318 {
319    bool f = true;
320    alist *list;
321    RES *res;
322
323    list = (alist *)(*(hpkt.ritem->value));
324    if (!list) {
325       return false;
326    }
327    sendit(NULL, "\n    \"%s\":", hpkt.ritem->name);
328    sendit(NULL, " [");
329    foreach_alist(res, list) {
330       if (!f) {
331          sendit(NULL, ", ");
332       }
333       sendit(NULL, "%s", quote_string(hpkt.edbuf, res->name));
334       f = false;
335    }
336    sendit(NULL, "]");
337    return true;
338 }
339
340 void display_res(HPKT &hpkt)
341 {
342    RES *res;
343
344    res = (RES *)*hpkt.ritem->value;
345    sendit(NULL, "\n    \"%s\": %s", hpkt.ritem->name,
346       quote_string(hpkt.edbuf, res->name));
347 }
348
349 void display_string_pair(HPKT &hpkt)
350 {
351    sendit(NULL, "\n    \"%s\": %s", hpkt.ritem->name,
352       quote_string(hpkt.edbuf, *hpkt.ritem->value));
353 }
354
355 void display_int32_pair(HPKT &hpkt)
356 {
357    char ed1[50];
358    sendit(NULL, "\n    \"%s\": %s", hpkt.ritem->name,
359       edit_int64(*(int32_t *)hpkt.ritem->value, ed1));
360 }
361
362 void display_int64_pair(HPKT &hpkt)
363 {
364    char ed1[50];
365    sendit(NULL, "\n    \"%s\": %s", hpkt.ritem->name,
366       edit_int64(*(int64_t *)hpkt.ritem->value, ed1));
367 }
368
369 void display_bool_pair(HPKT &hpkt)
370 {
371    sendit(NULL, "\n    \"%s\": %s", hpkt.ritem->name,
372       ((*(bool *)(hpkt.ritem->value)) == 0)?"false":"true");
373 }
374
375 void display_bit_pair(HPKT &hpkt)
376 {
377    sendit(NULL, "\n    \"%s\": %s", hpkt.ritem->name,
378       ((*(uint32_t *)(hpkt.ritem->value) & hpkt.ritem->code)
379          == 0)?"false":"true");
380 }
381
382 bool byte_is_set(char *byte, int num)
383 {
384    int i;
385    bool found = false;
386    for (i=0; i<num; i++) {
387       if (byte[i]) {
388          found = true;
389          break;
390       }
391    }
392    return found;
393 }
394
395 void display_bit_array(char *array, int num)
396 {
397    int i;
398    bool first = true;
399    sendit(NULL, " [");
400    for (i=0; i<num; i++) {
401       if (bit_is_set(i, array)) {
402          if (!first) sendit(NULL, ", ");
403          first = false;
404          sendit(NULL, "%d", i);
405       }
406    }
407    sendit(NULL, "]");
408 }