]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_query.c
561b335fdc2b2885e0ddb048c5b59dabe2a9185a
[bacula/bacula] / bacula / src / dird / ua_query.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 Director -- User Agent Database Query Commands
22  *
23  *     Kern Sibbald, December MMI
24  *
25  */
26
27 #include "bacula.h"
28 #include "dird.h"
29
30 extern DIRRES *director;
31
32 static POOLMEM *substitute_prompts(UAContext *ua,
33                        POOLMEM *query, char **prompt, int nprompt);
34
35 /*
36  * Read a file containing SQL queries and prompt
37  *  the user to select which one.
38  *
39  *   File format:
40  *   #  => comment
41  *   :prompt for query
42  *   *prompt for subst %1
43  *   *prompt for subst %2
44  *   ...
45  *   SQL statement possibly terminated by ;
46  *   :next query prompt
47  */
48 int query_cmd(UAContext *ua, const char *cmd)
49 {
50    FILE *fd = NULL;
51    POOLMEM *query = get_pool_memory(PM_MESSAGE);
52    char line[1000];
53    int i, len;
54    int item = 0;
55    long val;
56    char *prompt[9];
57    int nprompt = 0;;
58    char *query_file = director->query_file;
59    bool must_prompt = true;
60
61    if (!open_client_db(ua)) {
62       goto bail_out;
63    }
64    if ((fd=fopen(query_file, "rb")) == NULL) {
65       berrno be;
66       ua->error_msg(_("Could not open %s: ERR=%s\n"), query_file,
67          be.bstrerror());
68       goto bail_out;
69    }
70
71    start_prompt(ua, _("Available queries:\n"));
72    while (fgets(line, sizeof(line), fd) != NULL) {
73       if (line[0] == ':') {
74          strip_trailing_junk(line);
75          add_prompt(ua, line+1);
76       }
77    }
78    if (ua->argc >= 2) {
79        errno = 0;
80        val = strtol(ua->argk[1], NULL, 10) - 1;
81        if (val < 0) {
82           errno = 1;
83        }
84        if (errno != 0) {
85           ua->error_msg(_("Invalid command line query item specified.\n"));
86           must_prompt = true;
87        } else {
88           item = val;
89           must_prompt = false;
90       }
91    }
92    if (must_prompt && (item=do_prompt(ua, "", _("Choose a query"), NULL, 0)) < 0) {
93       goto bail_out;
94    }
95    rewind(fd);
96    i = -1;
97    while (fgets(line, sizeof(line), fd) != NULL) {
98       if (line[0] == ':') {
99          i++;
100       }
101       if (i == item) {
102          break;
103       }
104    }
105    if (i != item) {
106       ua->error_msg(_("Could not find query.\n"));
107       goto bail_out;
108    }
109    query[0] = 0;
110    for (i=0; i<9; i++) {
111       prompt[i] = NULL;
112    }
113    while (fgets(line, sizeof(line), fd) != NULL) {
114       if (line[0] == '#') {
115          continue;
116       }
117       if (line[0] == ':') {
118          break;
119       }
120       strip_trailing_junk(line);
121       len = strlen(line);
122       if (line[0] == '*') {            /* prompt */
123          if (nprompt >= 9) {
124             ua->error_msg(_("Too many prompts in query, max is 9.\n"));
125          } else {
126             line[len++] = ' ';
127             line[len] = 0;
128             prompt[nprompt++] = bstrdup(line+1);
129             continue;
130          }
131       }
132       if (*query != 0) {
133          pm_strcat(query, " ");
134       }
135       pm_strcat(query, line);
136       if (line[len-1] != ';') {
137          continue;
138       }
139       line[len-1] = 0;             /* zap ; */
140       if (query[0] != 0) {
141          query = substitute_prompts(ua, query, prompt, nprompt);
142          Dmsg1(100, "Query2=%s\n", query);
143          if (query[0] == '!') {
144             db_list_sql_query(ua->jcr, ua->db, query+1, prtit, ua, 0, VERT_LIST);
145          } else if (!db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST)) {
146             ua->send_msg("%s\n", query);
147          }
148          query[0] = 0;
149       }
150    } /* end while */
151
152    if (query[0] != 0) {
153       query = substitute_prompts(ua, query, prompt, nprompt);
154       Dmsg1(100, "Query2=%s\n", query);
155          if (query[0] == '!') {
156             db_list_sql_query(ua->jcr, ua->db, query+1, prtit, ua, 0, VERT_LIST);
157          } else if (!db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST)) {
158             ua->error_msg("%s\n", query);
159          }
160    }
161
162 bail_out:
163    if (fd) {
164       fclose(fd);
165    }
166    free_pool_memory(query);
167    for (i=0; i<nprompt; i++) {
168       free(prompt[i]);
169    }
170    return 1;
171 }
172
173 static POOLMEM *substitute_prompts(UAContext *ua,
174                        POOLMEM *query, char **prompt, int nprompt)
175 {
176    char *p, *q, *o;
177    POOLMEM *new_query;
178    int i, n, len, olen;
179    char *subst[9];
180
181    if (nprompt == 0) {
182       return query;
183    }
184    for (i=0; i<9; i++) {
185       subst[i] = NULL;
186    }
187    new_query = get_pool_memory(PM_FNAME);
188    o = new_query;
189    for (q=query; (p=strchr(q, '%')); ) {
190       if (p) {
191         olen = o - new_query;
192         new_query = check_pool_memory_size(new_query, olen + p - q + 10);
193         o = new_query + olen;
194          while (q < p) {              /* copy up to % */
195             *o++ = *q++;
196          }
197          p++;
198          switch (*p) {
199          case '1':
200          case '2':
201          case '3':
202          case '4':
203          case '5':
204          case '6':
205          case '7':
206          case '8':
207          case '9':
208             n = (int)(*p) - (int)'1';
209             if (prompt[n]) {
210                if (!subst[n]) {
211                   if (!get_cmd(ua, prompt[n])) {
212                      q += 2;
213                      break;
214                   }
215                }
216                len = strlen(ua->cmd);
217                p = (char *)malloc(len * 2 + 1);
218                db_escape_string(ua->jcr, ua->db, p, ua->cmd, len);
219                subst[n] = p;
220                olen = o - new_query;
221                new_query = check_pool_memory_size(new_query, olen + strlen(p) + 10);
222                o = new_query + olen;
223                while (*p) {
224                   *o++ = *p++;
225                }
226             } else {
227                ua->error_msg(_("Warning prompt %d missing.\n"), n+1);
228             }
229             q += 2;
230             break;
231          case '%':
232             *o++ = '%';
233             q += 2;
234             break;
235          default:
236             *o++ = '%';
237             q++;
238             break;
239          }
240       }
241    }
242    olen = o - new_query;
243    new_query = check_pool_memory_size(new_query, olen + strlen(q) + 10);
244    o = new_query + olen;
245    while (*q) {
246       *o++ = *q++;
247    }
248    *o = 0;
249    for (i=0; i<9; i++) {
250       if (subst[i]) {
251          free(subst[i]);
252       }
253    }
254    free_pool_memory(query);
255    return new_query;
256 }
257
258 /*
259  * Get general SQL query for Catalog
260  */
261 int sqlquery_cmd(UAContext *ua, const char *cmd)
262 {
263    POOL_MEM query(PM_MESSAGE);
264    int len;
265    const char *msg;
266
267    if (!open_new_client_db(ua)) {
268       return 1;
269    }
270    *query.c_str() = 0;
271
272    ua->send_msg(_("Entering SQL query mode.\n"
273 "Terminate each query with a semicolon.\n"
274 "Terminate query mode with a blank line.\n"));
275    msg = _("Enter SQL query: ");
276    while (get_cmd(ua, msg)) {
277       len = strlen(ua->cmd);
278       Dmsg2(400, "len=%d cmd=%s:\n", len, ua->cmd);
279       if (len == 0) {
280          break;
281       }
282       if (*query.c_str() != 0) {
283          pm_strcat(query, " ");
284       }
285       pm_strcat(query, ua->cmd);
286       if (ua->cmd[len-1] == ';') {
287          ua->cmd[len-1] = 0;          /* zap ; */
288          /* Submit query */
289          db_list_sql_query(ua->jcr, ua->db, query.c_str(), prtit, ua, 1, HORZ_LIST);
290          *query.c_str() = 0;         /* start new query */
291          msg = _("Enter SQL query: ");
292       } else {
293          msg = _("Add to SQL query: ");
294       }
295    }
296    ua->send_msg(_("End query mode.\n"));
297    return 1;
298 }