Imported Upstream version 2.5.1p3
[debian/amanda] / recover-src / set_commands.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998, 2000 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: set_commands.c,v 1.26.2.1 2006/12/22 15:10:27 martinea Exp $
28  *
29  * implements the "set" commands in amrecover
30  */
31
32 #include "amanda.h"
33 #include "util.h"
34 #include "amrecover.h"
35
36 #ifdef SAMBA_CLIENT
37 extern unsigned short samba_extract_method;
38 #endif /* SAMBA_CLIENT */
39
40 /* sets a date, mapping given date into standard form if needed */
41 int
42 set_date(
43     char *      date)
44 {
45     char *cmd = NULL;
46     char *qdisk_path;
47
48     clear_dir_list();
49
50     cmd = stralloc2("DATE ", date);
51     if (converse(cmd) == -1)
52         exit(1);
53
54     /* if a host/disk/directory is set, then check if that directory
55        is still valid at the new date, and if not set directory to
56        mount_point */
57     if (disk_path != NULL) {
58         qdisk_path = quote_string(disk_path);
59         cmd = newstralloc2(cmd, "OISD ", qdisk_path);
60         amfree(qdisk_path);
61         if (exchange(cmd) == -1)
62             exit(1);
63         if (server_happy())
64         {
65             suck_dir_list_from_server();
66         }
67         else
68         {
69             printf("No index records for cwd on new date\n");
70             printf("Setting cwd to mount point\n");
71             disk_path = newstralloc(disk_path, "/");    /* fake it */
72             clear_dir_list();
73         }
74     }
75     amfree(cmd);
76     return 0;
77 }
78
79
80 void
81 set_host(
82     const char *host)
83 {
84     char *cmd = NULL;
85     struct hostent *hp;
86     char **hostp;
87     int found_host = 0;
88
89     if (is_extract_list_nonempty())
90     {
91         printf("Must clear extract list before changing host\n");
92         return;
93     }
94
95     cmd = stralloc2("HOST ", host);
96     if (converse(cmd) == -1)
97         exit(1);
98     if (server_happy())
99     {
100         found_host = 1;
101     }
102     else
103     {
104         /*
105          * Try converting the given host to a fully qualified name
106          * and then try each of the aliases.
107          */
108         if ((hp = gethostbyname(host)) != NULL) {
109             host = hp->h_name;
110             printf("Trying host %s ...\n", host);
111             cmd = newstralloc2(cmd, "HOST ", host);
112             if (converse(cmd) == -1)
113                 exit(1);
114             if(server_happy())
115             {
116                 found_host = 1;
117             }
118             else
119             {
120                 for (hostp = hp->h_aliases; (host = *hostp) != NULL; hostp++)
121                 {
122                     printf("Trying host %s ...\n", host);
123                     cmd = newstralloc2(cmd, "HOST ", host);
124                     if (converse(cmd) == -1)
125                         exit(1);
126                     if(server_happy())
127                     {
128                         found_host = 1;
129                         break;
130                     }
131                 }
132             }
133         }
134     }
135     if(found_host)
136     {
137         dump_hostname = newstralloc(dump_hostname, host);
138         amfree(disk_name);
139         amfree(mount_point);
140         amfree(disk_path);
141         clear_dir_list();
142     }
143     amfree(cmd);
144 }
145
146 void
147 list_host(void)
148 {
149     char *cmd = NULL;
150
151     cmd = stralloc("LISTHOST");
152     if (converse(cmd) == -1)
153         exit(1);
154     amfree(cmd);
155 }
156
157 void
158 set_disk(
159     char *      dsk,
160     char *      mtpt)
161 {
162     char *cmd = NULL;
163     char *qdsk;
164
165     if (is_extract_list_nonempty())
166     {
167         printf("Must clear extract list before changing disk\n");
168         return;
169     }
170
171     /* if mount point specified, check it is valid */
172     if ((mtpt != NULL) && (*mtpt != '/'))
173     {
174         printf("Mount point \"%s\" invalid - must start with /\n", mtpt);
175         return;
176     }
177
178     clear_dir_list();
179     qdsk = quote_string(dsk);
180     cmd = stralloc2("DISK ", qdsk);
181     amfree(qdsk);
182     if (converse(cmd) == -1)
183         exit(1);
184     amfree(cmd);
185
186     if (!server_happy())
187         return;
188
189     disk_name = newstralloc(disk_name, dsk);
190     if (mtpt == NULL)
191     {
192         /* mount point not specified */
193         if (*dsk == '/')
194         {
195             /* disk specified by mount point, hence use it */
196             mount_point = newstralloc(mount_point, dsk);
197         }
198         else
199         {
200             /* device name given, use '/' because nothing better */
201             mount_point = newstralloc(mount_point, "/");
202         }
203     }
204     else
205     {
206         /* mount point specified */
207         mount_point = newstralloc(mount_point, mtpt);
208     }
209
210     /* set the working directory to the mount point */
211     /* there is the possibility that there are no index records for the
212        disk for the given date, hence setting the directory to the
213        mount point will fail. Preempt this by checking first so we can write
214        a more informative message. */
215     if (exchange("OISD /") == -1)
216         exit(1);
217     if (server_happy())
218     {
219         disk_path = newstralloc(disk_path, "/");
220         suck_dir_list_from_server();    /* get list of directory contents */
221     }
222     else
223     {
224         printf("No index records for disk for specified date\n");
225         printf("If date correct, notify system administrator\n");
226         disk_path = newstralloc(disk_path, "/");        /* fake it */
227         clear_dir_list();
228     }
229 }
230
231 void
232 list_disk(
233     char *      amdevice)
234 {
235     char *cmd = NULL;
236     char *qamdevice;
237
238     if(amdevice) {
239         qamdevice = quote_string(amdevice);
240         cmd = stralloc2("LISTDISK ", qamdevice);
241         amfree(qamdevice);
242         if (converse(cmd) == -1)
243             exit(1);
244         amfree(cmd);
245     }
246     else {
247         cmd = stralloc("LISTDISK");
248         if (converse(cmd) == -1)
249             exit(1);
250         amfree(cmd);
251     }
252 }
253
254 void
255 cd_glob(
256     char *      glob)
257 {
258     char *regex;
259     char *regex_path;
260     char *s;
261
262     char *path_on_disk = NULL;
263
264     if (disk_name == NULL) {
265         printf("Must select disk before changing directory\n");
266         return;
267     }
268
269     regex = glob_to_regex(glob);
270     dbprintf(("cd_glob (%s) -> %s\n", glob, regex));
271     if ((s = validate_regexp(regex)) != NULL) {
272         printf("\"%s\" is not a valid shell wildcard pattern: ", glob);
273         puts(s);
274         amfree(regex);
275         return;
276     }
277     /*
278      * glob_to_regex() anchors the beginning of the pattern with ^,
279      * but we will be tacking it onto the end of the current directory
280      * in add_file, so strip that off.  Also, it anchors the end with
281      * $, but we need to match a trailing /, add it if it is not there
282      */
283     regex_path = stralloc(regex + 1);
284     amfree(regex);
285     if(regex_path[strlen(regex_path) - 2] != '/' ) {
286         regex_path[strlen(regex_path) - 1] = '\0';
287         strappend(regex_path, "/$");
288     }
289
290     /* convert path (assumed in cwd) to one on disk */
291     if (strcmp(disk_path, "/") == 0)
292         path_on_disk = stralloc2("/", regex_path);
293     else {
294         char *clean_disk_path = clean_regex(disk_path);
295         path_on_disk = vstralloc(clean_disk_path, "/", regex_path, NULL);
296         amfree(clean_disk_path);
297     }
298
299     cd_dir(path_on_disk, glob);
300
301     amfree(regex_path);
302     amfree(path_on_disk);
303 }
304
305 void
306 cd_regex(
307     char *      regex)
308 {
309     char *s;
310
311     char *path_on_disk = NULL;
312
313     if (disk_name == NULL) {
314         printf("Must select disk before changing directory\n");
315         return;
316     }
317
318     if ((s = validate_regexp(regex)) != NULL) {
319         printf("\"%s\" is not a valid regular expression: ", regex);
320         puts(s);
321         return;
322     }
323
324     /* convert path (assumed in cwd) to one on disk */
325     if (strcmp(disk_path, "/") == 0)
326         path_on_disk = stralloc2("/", regex);
327     else {
328         char *clean_disk_path = clean_regex(disk_path);
329         path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
330         amfree(clean_disk_path);
331     }
332
333     cd_dir(path_on_disk, regex);
334
335     amfree(path_on_disk);
336 }
337
338 void
339 cd_dir(
340     char *      path_on_disk,
341     char *      default_dir)
342 {
343     char *path_on_disk_slash = NULL;
344     char *dir = NULL;
345
346     int nb_found;
347     size_t i;
348
349     DIR_ITEM *ditem;
350
351     path_on_disk_slash = stralloc2(path_on_disk, "/");
352
353     nb_found = 0;
354
355     for (ditem=get_dir_list(); ditem!=NULL && nb_found <= 1; 
356                                ditem=get_next_dir_item(ditem))
357     {
358         if (match(path_on_disk, ditem->path)
359             || match(path_on_disk_slash, ditem->path))
360         {
361             i = strlen(ditem->path);
362             if((i > 0 && ditem->path[i-1] == '/')
363                || (i > 1 && ditem->path[i-2] == '/' && ditem->path[i-1] == '.'))
364             {   /* It is a directory */
365                 char *dir1, *dir2;
366                 nb_found++;
367                 dir = newstralloc(dir,ditem->path);
368                 if(dir[strlen(dir)-1] == '/')
369                     dir[strlen(dir)-1] = '\0'; /* remove last / */
370                 /* remove everything before the last / */
371                 dir1 = rindex(dir,'/');
372                 if (dir1) {
373                     dir1++;
374                     dir2 = stralloc(dir1);
375                     amfree(dir);
376                     dir = dir2;
377                 }
378             }
379         }
380     }
381     amfree(path_on_disk_slash);
382
383     if(nb_found==0) {
384         set_directory(default_dir);
385     }
386     else if(nb_found==1) {
387         set_directory(dir);
388     }
389     else {
390         printf("Too many directory\n");
391     }
392     amfree(dir);
393 }
394
395 void
396 set_directory(
397     char *      dir)
398 {
399     char *cmd = NULL;
400     char *new_dir = NULL;
401     char *qnew_dir;
402     char *dp, *de;
403     char *ldir = NULL;
404
405     /* do nothing if "." */
406     if(strcmp(dir,".")==0) {
407         show_directory();               /* say where we are */
408         return;
409         /*NOTREACHED*/
410     }
411
412     if (disk_name == NULL) {
413         printf("Must select disk before setting directory\n");
414         return;
415         /*NOTREACHED*/
416     }
417
418     ldir = stralloc(dir);
419     clean_pathname(ldir);
420
421     /* convert directory into absolute path relative to disk mount point */
422     if (ldir[0] == '/')
423     {
424         /* absolute path specified, must start with mount point */
425         if (strcmp(mount_point, "/") == 0)
426         {
427             new_dir = stralloc(ldir);
428         }
429         else
430         {
431             if (strncmp(mount_point, ldir, strlen(mount_point)) != 0)
432             {
433                 printf("Invalid directory - Can't cd outside mount point \"%s\"\n",
434                        mount_point);
435                 amfree(ldir);
436                 return;
437                 /*NOTREACHED*/
438             }
439             new_dir = stralloc(ldir+strlen(mount_point));
440             if (strlen(new_dir) == 0) {
441                 new_dir = newstralloc(new_dir, "/");
442                                         /* i.e. ldir == mount_point */
443             }
444         }
445     }
446     else
447     {
448         new_dir = stralloc(disk_path);
449         dp = ldir;
450         /* strip any leading ..s */
451         while (strncmp(dp, "../", 3) == 0)
452         {
453             de = strrchr(new_dir, '/'); /* always at least 1 */
454             if (de == new_dir)
455             {
456                 /* at top of disk */
457                 *(de + 1) = '\0';
458                 dp = dp + 3;
459             }
460             else
461             {
462                 *de = '\0';
463                 dp = dp + 3;
464             }
465         }
466         if (strcmp(dp, "..") == 0) {
467             if (strcmp(new_dir, "/") == 0) {
468                 /* at top of disk */
469                 printf("Invalid directory - Can't cd outside mount point \"%s\"\n",
470                        mount_point);
471                 /*@ignore@*/
472                 amfree(new_dir);
473                 /*@end@*/
474                 amfree(ldir);
475                 return;
476                 /*NOTREACHED*/
477             }
478             de = strrchr(new_dir, '/'); /* always at least 1 */
479             if (de == new_dir)
480             {
481                 /* at top of disk */
482                 *(de+1) = '\0';
483             }
484             else
485             {
486                 *de = '\0';
487             }
488         } else {
489             /*@ignore@*/
490             if (strcmp(new_dir, "/") != 0) {
491                 strappend(new_dir, "/");
492             }
493             strappend(new_dir, ldir);
494             /*@end@*/
495         }
496     }
497
498     qnew_dir = quote_string(new_dir);
499     cmd = stralloc2("OISD ", qnew_dir);
500     amfree(qnew_dir);
501     if (exchange(cmd) == -1) {
502         exit(1);
503         /*NOTREACHED*/
504     }
505     amfree(cmd);
506
507     if (server_happy())
508     {
509         disk_path = newstralloc(disk_path, new_dir);
510         suck_dir_list_from_server();    /* get list of directory contents */
511         show_directory();               /* say where we moved to */
512     }
513     else
514     {
515         printf("Invalid directory - %s\n", dir);
516     }
517
518     /*@ignore@*/
519     amfree(new_dir);
520     amfree(ldir);
521     /*@end@*/
522 }
523
524
525 /* prints the current working directory */
526 void
527 show_directory(void)
528 {
529     if (mount_point == NULL || disk_path == NULL)
530         printf("Must select disk first\n");
531     else if (strcmp(mount_point, "/") == 0)
532         printf("%s\n", disk_path);
533     else if (strcmp(disk_path, "/") == 0)
534         printf("%s\n", mount_point);
535     else
536         printf("%s%s\n", mount_point, disk_path);
537 }
538
539
540 /* set the tape server and device */
541 void
542 set_tape(
543     char *      tape)
544 {
545     char *tapedev = strchr(tape, ':');
546
547     if (tapedev)
548     {
549         if (tapedev != tape) {
550             if((strchr(tapedev+1, ':') == NULL) &&
551                (strncmp(tape, "null:", 5) == 0 ||
552                 strncmp(tape, "rait:", 5) == 0 ||
553                 strncmp(tape, "file:", 5) == 0 ||
554                 strncmp(tape, "tape:", 5) == 0)) {
555                 tapedev = tape;
556             }
557             else {
558                 *tapedev = '\0';
559                 tape_server_name = newstralloc(tape_server_name, tape);
560                 ++tapedev;
561             }
562         } else { /* reset server_name if start with : */
563             amfree(tape_server_name);
564             ++tapedev;
565         }
566     } else
567         tapedev = tape;
568     
569     if (tapedev[0])
570     {
571         if (strcmp(tapedev, "default") == 0)
572             amfree(tape_device_name);
573         else
574             tape_device_name = newstralloc(tape_device_name, tapedev);
575     }
576
577     if (tape_device_name)
578         printf ("Using tape \"%s\"", tape_device_name);
579     else
580         printf ("Using default tape");
581
582     if (tape_server_name)
583         printf (" from server %s.\n", tape_server_name);
584     else
585         printf (".\nTape server unspecified, assumed to be %s.\n",
586                 server_name);
587 }
588
589 void
590 set_mode(
591     int         mode)
592 {
593 #ifdef SAMBA_CLIENT
594   if (mode == SAMBA_SMBCLIENT) {
595     printf ("SAMBA dumps will be extracted using smbclient\n");
596     samba_extract_method = SAMBA_SMBCLIENT;
597   } else {
598     if (mode == SAMBA_TAR) {
599       printf ("SAMBA dumps will be extracted as TAR dumps\n");
600       samba_extract_method = SAMBA_TAR;
601     }
602   }
603 #else
604   (void)mode;   /* Quiet unused parameter warning */
605 #endif /* SAMBA_CLIENT */
606 }
607
608 void
609 show_mode(void) 
610 {
611 #ifdef SAMBA_CLIENT
612   printf ("SAMBA dumps are extracted ");
613
614   if (samba_extract_method == SAMBA_TAR) {
615     printf (" as TAR dumps\n");
616   } else {
617     printf ("using smbclient\n");
618   }
619 #endif /* SAMBA_CLIENT */
620 }