Imported Upstream version 2.5.2p1
[debian/amanda] / server-src / cmdline.c
1 /*
2  * Copyright (c) 2005 Zmanda Inc.  All Rights Reserved.
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  * 
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  * 
18  * Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  *
21  * Author: Dustin J. Mitchell <dustin@zmanda.com>
22  */
23 /*
24  * $Id$
25  *
26  * Utility routines for handling command lines.
27  */
28
29 #include <ctype.h>
30 #include "amanda.h"
31 #include "cmdline.h"
32 #include "holding.h"
33
34 dumpspec_t *
35 dumpspec_new(
36     char *host, 
37     char *disk, 
38     char *datestamp)
39 {
40     dumpspec_t *rv;
41
42     rv = calloc(1, sizeof(*rv));
43     if (!rv) return NULL;
44     if (host) rv->host = stralloc(host);
45     if (disk) rv->disk = stralloc(disk);
46     if (datestamp) rv->datestamp = stralloc(datestamp);
47
48     return rv;
49 }
50
51 void
52 dumpspec_free(
53     dumpspec_t *dumpspec)
54 {
55     if (!dumpspec) return;
56     if (dumpspec->host) free(dumpspec->host);
57     if (dumpspec->disk) free(dumpspec->disk);
58     if (dumpspec->datestamp) free(dumpspec->datestamp);
59     free(dumpspec);
60 }
61
62 void
63 dumpspec_free_list(
64     dumpspec_list_t *dumpspec_list)
65 {
66     dumpspec_t *dumpspec = (dumpspec_t *)dumpspec_list;
67     dumpspec_t *next;
68
69     while (dumpspec) {
70         next = dumpspec->next;
71         dumpspec_free(dumpspec);
72         dumpspec = next;
73     }
74 }
75
76 dumpspec_list_t *
77 cmdline_parse_dumpspecs(
78     int argc,
79     char **argv)
80 {
81     dumpspec_t *dumpspec = NULL, *t;
82     char *errstr;
83     char *name;
84     int optind = 0;
85     enum { ARG_GET_HOST, ARG_GET_DISK, ARG_GET_DATE } arg_state = ARG_GET_HOST;
86
87     while (optind < argc) {
88         name = argv[optind++];
89         switch (arg_state) {
90             case ARG_GET_HOST:
91                 if (name[0] != '\0'
92                     && (errstr=validate_regexp(name)) != NULL) {
93                     fprintf(stderr, _("%s: bad hostname regex \"%s\": %s\n"),
94                                     get_pname(), name, errstr);
95                     goto error;
96                 }
97                 t = dumpspec_new(name, NULL, NULL);
98                 t->next = (dumpspec_t *)dumpspec;
99                 dumpspec = t;
100                 arg_state = ARG_GET_DISK;
101                 break;
102
103             case ARG_GET_DISK:
104                 if (name[0] != '\0'
105                     && (errstr=validate_regexp(name)) != NULL) {
106                     fprintf(stderr, _("%s: bad diskname regex \"%s\": %s\n"),
107                                     get_pname(), name, errstr);
108                     goto error;
109                 }
110                 dumpspec->disk = stralloc(name);
111                 arg_state = ARG_GET_DATE;
112                 break;
113
114             case ARG_GET_DATE:
115                 if (name[0] != '\0'
116                     && (errstr=validate_regexp(name)) != NULL) {
117                     fprintf(stderr, _("%s: bad datestamp regex \"%s\": %s\n"),
118                                     get_pname(), name, errstr);
119                     goto error;
120                 }
121                 dumpspec->datestamp = stralloc(name);
122                 arg_state = ARG_GET_HOST;
123                 break;
124         }
125     }
126
127     if (dumpspec == NULL) 
128         dumpspec = dumpspec_new("", "", "");
129     return (dumpspec_list_t *)dumpspec;
130
131 error:
132     dumpspec_free_list((dumpspec_list_t *)dumpspec);
133     return NULL;
134 }
135
136 char *
137 cmdline_format_dumpspec(
138     dumpspec_t *dumpspec)
139 {
140     if (!dumpspec) return NULL;
141     return cmdline_format_dumpspec_components(
142         dumpspec->host,
143         dumpspec->disk,
144         dumpspec->datestamp);
145 }
146
147 /* Quote str for shell interpretation, being conservative.
148  * Any non-alphanumeric charcacters other than '.' and '/'
149  * trigger surrounding single quotes, and single quotes and
150  * backslashes within those single quotes are escaped.
151  */
152 static char *
153 quote_dumpspec_string(char *str)
154 {
155     char *rv;
156     char *p, *q;
157     int len = 0;
158     int need_single_quotes = 0;
159
160     for (p = str; *p; p++) {
161         if (!isalnum(*p) && *p != '.' && *p != '/') need_single_quotes=1;
162         if (*p == '\'' || *p == '\\') len++; /* extra byte for '\' */
163         len++;
164     }
165     if (need_single_quotes) len += 2;
166
167     q = rv = malloc(len+1);
168     if (need_single_quotes) *(q++) = '\'';
169     for (p = str; *p; p++) {
170         if (*p == '\'' || *p == '\\') *(q++) = '\\';
171         *(q++) = *p;
172     }
173     if (need_single_quotes) *(q++) = '\'';
174     *(q++) = '\0';
175
176     return rv;
177 }
178
179 char *
180 cmdline_format_dumpspec_components(
181     char *host,
182     char *disk,
183     char *datestamp)
184 {
185     char *rv = NULL;
186
187     host = host? quote_dumpspec_string(host):NULL;
188     disk = disk? quote_dumpspec_string(disk):NULL;
189     datestamp = datestamp? quote_dumpspec_string(datestamp):NULL;
190
191     if (host) {
192         rv = host;
193         if (disk) {
194             rv = newvstralloc(rv, rv, " ", disk, NULL);
195             amfree(disk);
196             if (datestamp) {
197                 rv = newvstralloc(rv, rv, " ", datestamp, NULL);
198                 amfree(datestamp);
199             }
200         }
201     }
202     if (disk) amfree(disk);
203     if (datestamp) amfree(datestamp);
204
205     return rv;
206 }
207
208 sl_t *
209 cmdline_match_holding(
210     dumpspec_list_t *dumpspec_list)
211 {
212     char *host;
213     char *disk;
214     char *datestamp;
215     filetype_t filetype;
216     dumpspec_t *de;
217     sl_t *holding_files;
218     sle_t *he;
219     sl_t *matching_files = new_sl();
220
221     holding_set_verbosity(0);
222     holding_files = holding_get_files(NULL, NULL, 1);
223
224     for (he = holding_files->first; he != NULL; he = he->next) {
225         filetype = holding_file_read_header(he->name, &host, &disk, NULL, &datestamp);
226         if (filetype != F_DUMPFILE) continue;
227         for (de = (dumpspec_t *)dumpspec_list; de != NULL; de = de->next) {
228             if (de->host && !match_host(de->host, host)) continue;
229             if (de->disk && !match_disk(de->disk, disk)) continue;
230             if (de->datestamp && !match_datestamp(de->datestamp, datestamp)) continue;
231             matching_files = insert_sort_sl(matching_files, he->name);
232             break;
233         }
234     }
235
236     return matching_files;
237 }