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-2013 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 *
get_dir_list(void)56 get_dir_list(void)
57 {
58     return dir_list;
59 }
60 
61 DIR_ITEM *
get_next_dir_item(DIR_ITEM * this)62 get_next_dir_item(
63     DIR_ITEM *	this)
64 {
65     /*@ignore@*/
66     return this->next;
67     /*@end@*/
68 }
69 
70 
71 void
clear_dir_list(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
free_dir_item(DIR_ITEM * item)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
add_dir_list_item(char * date,int level,char * tape,off_t fileno,char * path)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
list_disk_history(void)127 list_disk_history(void)
128 {
129     if (converse("DHST") == -1)
130 	exit(1);
131 }
132 
133 
134 void
suck_dir_list_from_server(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
list_directory(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 }
331