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