Imported Upstream version 3.3.3
[debian/amanda] / recover-src / display_commands.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of U.M. not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  U.M. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  *
17  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Authors: the Amanda Development Team.  Its members are listed in a
25  * file named AUTHORS, in the root directory of this distribution.
26  */
27 /*
28  * $Id: display_commands.c,v 1.22 2006/07/05 19:42:17 martinea Exp $
29  *
30  * implements the directory-display related commands in amrecover
31  */
32
33 #include "amanda.h"
34 #include "amrecover.h"
35 #include "util.h"
36
37 gboolean translate_mode = TRUE;
38
39 DIR_ITEM *get_dir_list(void);
40 DIR_ITEM *get_next_dir_item(DIR_ITEM *this);
41
42 void clear_dir_list(void);
43 void free_dir_item(DIR_ITEM *item);
44 static int add_dir_list_item(char *date,
45                                 int level,
46                                 char *tape,
47                                 off_t fileno,
48                                 char *path);
49 void list_disk_history(void);
50 void suck_dir_list_from_server(void);
51 void list_directory(void);
52
53 static DIR_ITEM *dir_list = NULL;
54
55 DIR_ITEM *
56 get_dir_list(void)
57 {
58     return dir_list;
59 }
60
61 DIR_ITEM *
62 get_next_dir_item(
63     DIR_ITEM *  this)
64 {
65     /*@ignore@*/
66     return this->next;
67     /*@end@*/
68 }
69
70
71 void
72 clear_dir_list(void)
73 {
74     free_dir_item(dir_list); /* Frees all items from dir_list to end of list */
75     dir_list = NULL;
76 }
77
78 void
79 free_dir_item(
80     DIR_ITEM *  item)
81 {
82     DIR_ITEM *next;
83
84     while (item != NULL) {
85         next = item->next;
86         amfree(item->date);
87         amfree(item->tape);
88         amfree(item->path);
89         amfree(item->tpath);
90         amfree(item);
91         item = next;
92     }
93 }
94
95 /* add item to list if path not already on list */
96 static int
97 add_dir_list_item(
98     char *      date,
99     int         level,
100     char *      tape,
101     off_t       fileno,
102     char *      path)
103 {
104     DIR_ITEM *next;
105
106     dbprintf(_("add_dir_list_item: Adding \"%s\" \"%d\" \"%s\" \"%lld\" \"%s\"\n"),
107               date, level, tape, (long long)fileno, path);
108
109     next = (DIR_ITEM *)alloc(sizeof(DIR_ITEM));
110     memset(next, 0, sizeof(DIR_ITEM));
111
112     next->date = stralloc(date);
113     next->level = level;
114     next->tape = stralloc(tape);
115     next->fileno = fileno;
116     next->path = stralloc(path);
117     next->tpath = translate_octal(g_strdup(path));
118
119     next->next = dir_list;
120     dir_list = next;
121
122     return 0;
123 }
124
125
126 void
127 list_disk_history(void)
128 {
129     if (converse("DHST") == -1)
130         exit(1);
131 }
132
133
134 void
135 suck_dir_list_from_server(void)
136 {
137     char *cmd = NULL;
138     char *err = NULL;
139     int i;
140     char *l = NULL;
141     char *date;
142     int level = 0;
143     off_t fileno = (off_t)-1;
144     char *tape, *tape_undo, tape_undo_ch = '\0';
145     char *dir, *qdir;
146     char *disk_path_slash = NULL;
147     char *disk_path_slash_dot = NULL;
148     char *s;
149     int ch;
150     char *qdisk_path;
151
152     if (disk_path == NULL) {
153         g_printf(_("Directory must be set before getting listing\n"));
154         return;
155     } else if(strcmp(disk_path, "/") == 0) {
156         disk_path_slash = stralloc(disk_path);
157     } else {
158         disk_path_slash = stralloc2(disk_path, "/");
159     }
160
161     clear_dir_list();
162
163     qdisk_path = quote_string(disk_path);
164     cmd = stralloc2("OLSD ", qdisk_path);
165     amfree(qdisk_path);
166     if (send_command(cmd) == -1) {
167         amfree(cmd);
168         amfree(disk_path_slash);
169         exit(1);
170     }
171     amfree(cmd);
172     /* skip preamble */
173     if ((i = get_reply_line()) == -1) {
174         amfree(disk_path_slash);
175         exit(1);
176     }
177     if (i == 0)                         /* assume something wrong! */
178     {
179         amfree(disk_path_slash);
180         l = reply_line();
181         g_printf("%s\n", l);
182         return;
183     }
184     disk_path_slash_dot = stralloc2(disk_path_slash, ".");
185     amfree(cmd);
186     amfree(err);
187     tape_undo = NULL;
188     /* skip the last line -- duplicate of the preamble */
189     while ((i = get_reply_line()) != 0)
190     {
191         if (i == -1) {
192             amfree(disk_path_slash_dot);
193             amfree(disk_path_slash);
194             exit(1);
195         }
196         if(err) {
197             if(cmd == NULL) {
198                 if(tape_undo) *tape_undo = tape_undo_ch;
199                 tape_undo = NULL;
200                 cmd = stralloc(l);      /* save for the error report */
201             }
202             continue;                   /* throw the rest of the lines away */
203         }
204         l = reply_line();
205         if (!server_happy())
206         {
207             g_printf("%s\n", l);
208             continue;
209         }
210         s = l;
211         if (strncmp_const_skip(l, "201-", s, ch) != 0) {
212             err = _("bad reply: not 201-");
213             continue;
214         }
215         ch = *s++;
216         skip_whitespace(s, ch);
217         if(ch == '\0') {
218             err = _("bad reply: missing date field");
219             continue;
220         }
221         date = s - 1;
222         skip_non_whitespace(s, ch);
223         *(s - 1) = '\0';
224
225         skip_whitespace(s, ch);
226         if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
227             err = _("bad reply: cannot parse level field");
228             continue;
229         }
230         skip_integer(s, ch);
231
232         skip_whitespace(s, ch);
233         if(ch == '\0') {
234             err = _("bad reply: missing tape field");
235             continue;
236         }
237         tape = s - 1;
238         skip_quoted_string(s, ch);
239         tape_undo = s - 1;
240         tape_undo_ch = *tape_undo;
241         *tape_undo = '\0';
242         tape = unquote_string(tape);
243
244         if(am_has_feature(indexsrv_features, fe_amindexd_fileno_in_OLSD)) {
245             long long fileno_ = (long long)0;
246             skip_whitespace(s, ch);
247             if(ch == '\0' || sscanf(s - 1, "%lld", &fileno_) != 1) {
248                 err = _("bad reply: cannot parse fileno field");
249                 continue;
250             }
251             fileno = (off_t)fileno_;
252             skip_integer(s, ch);
253         }
254         else {
255             fileno = (off_t)-1;
256         }
257
258         skip_whitespace(s, ch);
259         if(ch == '\0') {
260             err = _("bad reply: missing directory field");
261             continue;
262         }
263         qdir = s - 1;
264         dir = unquote_string(qdir);
265
266         /* add a '.' if it a the entry for the current directory */
267         if((strcmp(disk_path,dir)==0) || (strcmp(disk_path_slash,dir)==0)) {
268             amfree(dir);
269             dir = stralloc(disk_path_slash_dot);
270         }
271         add_dir_list_item(date, level, tape, fileno, dir);
272         amfree(tape);
273         amfree(dir);
274     }
275     amfree(disk_path_slash_dot);
276     amfree(disk_path_slash);
277     if(!server_happy()) {
278         puts(reply_line());
279     } else if(err) {
280         if(*err) {
281             puts(err);
282         }
283         if (cmd)
284             puts(cmd);
285         clear_dir_list();
286     }
287     amfree(cmd);
288 }
289
290
291 void
292 list_directory(void)
293 {
294     size_t i;
295     DIR_ITEM *item;
296     FILE *fp;
297     char *pager;
298     char *pager_command;
299     char *quoted;
300
301     if (disk_path == NULL) {
302         g_printf(_("Must select a disk before listing files; use the setdisk command.\n"));
303         return;
304     }
305
306     if ((pager = getenv("PAGER")) == NULL)
307     {
308         pager = "more";
309     }
310     /*
311      * Set up the pager command so if the pager is terminated, we do
312      * not get a SIGPIPE back.
313      */
314     pager_command = stralloc2(pager, " ; /bin/cat > /dev/null");
315     if ((fp = popen(pager_command, "w")) == NULL)
316     {
317         g_printf(_("Warning - can't pipe through %s\n"), pager);
318         fp = stdout;
319     }
320     amfree(pager_command);
321     i = strlen(disk_tpath);
322     if (i != 1)
323         i++;                            /* so disk_tpath != "/" */
324     for (item = get_dir_list(); item != NULL; item=get_next_dir_item(item)) {
325         quoted = quote_string(item->tpath + i);
326         g_fprintf(fp, "%s %s\n", item->date, quoted);
327         amfree(quoted);
328     }
329     apclose(fp);
330 }