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