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