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