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