Imported Upstream version 3.1.0
[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 "match.h"
34 #include "util.h"
35 #include "amrecover.h"
36 #include "amxml.h"
37
38 extern unsigned short samba_extract_method;
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             g_printf(_("No index records for cwd on new date\n"));
70             g_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 = NULL;
86     char **hostp;
87     int found_host = 0;
88     char *uqhost = unquote_string(host);
89
90     if (is_extract_list_nonempty())
91     {
92         g_printf(_("Must clear extract list before changing host\n"));
93         amfree(uqhost);
94         return;
95     }
96
97     /*
98      * The idea here is to try as many permutations of the hostname
99      * as we can imagine.  The server will reject anything it doesn't
100      * recognize.
101      */
102
103     cmd = stralloc2("HOST ", uqhost);
104     if (converse(cmd) == -1)
105         exit(1);
106     if (server_happy())
107         found_host = 1;
108
109     /*
110      * Try converting the given host to a fully qualified, canonical
111      * name.
112      */
113     if (!found_host) {
114         if ((hp = gethostbyname(uqhost)) != NULL) {
115             host = hp->h_name;
116             g_printf(_("Trying host %s ...\n"), host);
117             cmd = newstralloc2(cmd, "HOST ", host);
118             if (converse(cmd) == -1)
119                 exit(1);
120             if(server_happy())
121                 found_host = 1;
122         }
123     }
124
125     /*
126      * Since we have them, try any CNAMEs that were traversed from uqhost
127      * to the canonical name (this assumes gethostbyname was called above)
128      */
129     if (!found_host) {
130         if (hp) {
131             for (hostp = hp->h_aliases; (host = *hostp) != NULL; hostp++)
132             {
133                 g_printf(_("Trying host %s ...\n"), host);
134                 cmd = newstralloc2(cmd, "HOST ", host);
135                 if (converse(cmd) == -1)
136                     exit(1);
137                 if(server_happy())
138                 {
139                     found_host = 1;
140                     break;
141                 }
142             }
143         }
144     }
145
146     /* Try looking up the canonical name of the host */
147     if (!found_host) {
148         char *canonname;
149         int result;
150
151         result = resolve_hostname(uqhost, 0, NULL, &canonname);
152         if (result == 0 && canonname) {
153             host = canonname;
154             g_printf(_("Trying host %s ...\n"), host);
155             cmd = newstralloc2(cmd, "HOST ", host);
156             if (converse(cmd) == -1)
157                 exit(1);
158             if(server_happy())
159                 found_host = 1;
160         }
161     }
162
163     if(found_host) {
164         dump_hostname = newstralloc(dump_hostname, host);
165         amfree(disk_name);
166         amfree(mount_point);
167         amfree(disk_path);
168         clear_dir_list();
169     }
170     amfree(cmd);
171     amfree(uqhost);
172 }
173
174 void
175 list_host(void)
176 {
177     char *cmd = NULL;
178
179     cmd = stralloc("LISTHOST");
180     if (converse(cmd) == -1)
181         exit(1);
182     amfree(cmd);
183 }
184
185 void
186 set_disk(
187     char *      dsk,
188     char *      mtpt)
189 {
190     char *cmd = NULL;
191     char *qdsk;
192     char *uqdsk;
193     char *uqmtpt = NULL;
194
195     if (is_extract_list_nonempty())
196     {
197         g_printf(_("Must clear extract list before changing disk\n"));
198         return;
199     }
200
201     /* if mount point specified, check it is valid */
202     if (mtpt != NULL) {
203         uqmtpt = unquote_string(mtpt);
204         if (*mtpt != '/') {
205             g_printf(_("Mount point \"%s\" invalid - must start with /\n"), uqmtpt);
206             amfree(uqmtpt);
207             return;
208         }
209     }
210
211     clear_dir_list();
212     uqdsk = unquote_string(dsk);
213     qdsk = quote_string(uqdsk);
214     cmd = stralloc2("DISK ", qdsk);
215     amfree(qdsk);
216     if (converse(cmd) == -1)
217         exit(1);
218     amfree(cmd);
219
220     if (!server_happy()) {
221         amfree(uqmtpt);
222         amfree(uqdsk);
223         return;
224     }
225
226     disk_name = newstralloc(disk_name, uqdsk);
227     if (mtpt == NULL)
228     {
229         /* mount point not specified */
230         if (*uqdsk == '/')
231         {
232             /* disk specified by mount point, hence use it */
233             mount_point = newstralloc(mount_point, uqdsk);
234         }
235         else
236         {
237             /* device name given, use '/' because nothing better */
238             mount_point = newstralloc(mount_point, "/");
239         }
240     }
241     else
242     {
243         /* mount point specified */
244         mount_point = newstralloc(mount_point, uqmtpt);
245     }
246
247     /* set the working directory to the mount point */
248     /* there is the possibility that there are no index records for the
249        disk for the given date, hence setting the directory to the
250        mount point will fail. Preempt this by checking first so we can write
251        a more informative message. */
252     if (exchange("OISD /") == -1)
253         exit(1);
254     if (server_happy())
255     {
256         disk_path = newstralloc(disk_path, "/");
257         suck_dir_list_from_server();    /* get list of directory contents */
258     }
259     else
260     {
261         g_printf(_("No index records for disk for specified date\n"));
262         g_printf(_("If date correct, notify system administrator\n"));
263         disk_path = newstralloc(disk_path, "/");        /* fake it */
264         clear_dir_list();
265     }
266     amfree(uqmtpt);
267     amfree(uqdsk);
268
269     if (am_has_feature(indexsrv_features, fe_amindexd_DLE)) {
270         char *dle_str;
271         char *errmsg = NULL;
272
273         cmd = stralloc("DLE");
274         if (exchange(cmd) == -1)
275             exit(1);
276         amfree(cmd);
277
278         if (!server_happy())
279             return;
280
281         dle_str = reply_line();
282         if (BSTRNCMP(dle_str+4, "NODLE") == 0) {
283             dump_dle = NULL;
284         } else {
285             dle_str = unquote_string(dle_str+4);
286             dump_dle = amxml_parse_node_CHAR(dle_str, &errmsg);
287             amfree(dle_str);
288         }
289     }
290 }
291
292 void
293 list_disk(
294     char *      amdevice)
295 {
296     char *cmd = NULL;
297     char *qamdevice, *uqamdevice;
298
299     if(amdevice) {
300         uqamdevice = unquote_string(amdevice);
301         qamdevice = quote_string(uqamdevice);
302         cmd = stralloc2("LISTDISK ", qamdevice);
303         amfree(uqamdevice);
304         amfree(qamdevice);
305         if (converse(cmd) == -1)
306             exit(1);
307         amfree(cmd);
308     }
309     else {
310         cmd = stralloc("LISTDISK");
311         if (converse(cmd) == -1)
312             exit(1);
313         amfree(cmd);
314     }
315 }
316
317 static GSList *prop_values = NULL;
318
319 void
320 set_property_name(
321     char *name,
322     int   append)
323 {
324     property_t *prop;
325     char       *property_name, *pn;
326
327     pn = unquote_string(name);
328     property_name = amandaify_property_name(pn);
329     amfree(pn);
330
331     if (!append) {
332         g_hash_table_remove(proplist, property_name);
333         prop = NULL;
334     } else {
335         prop = g_hash_table_lookup(proplist, property_name);
336     }
337     
338     if (!prop) {
339         prop = malloc(sizeof(property_t));
340         prop->append = 0;
341         prop->priority = 1;
342         prop->values = NULL;
343         g_hash_table_insert(proplist, stralloc(property_name), prop);
344     }
345
346     /* add prop_values to prop->values */
347     if (!prop->values) {
348         prop->values = prop_values;
349         prop_values = NULL;
350     } else {
351         GSList *pv;
352
353         for(pv = prop_values; pv != NULL; pv = pv->next) {
354             prop->values = g_slist_append(prop->values, pv->data);
355         }
356         g_slist_free(prop_values);
357         prop_values = NULL;
358     }
359     amfree(property_name);
360 }
361
362 void
363 add_property_value(
364     char *value)
365 {
366     if (value) {
367         prop_values = g_slist_prepend(prop_values, unquote_string(value));
368     }
369 }
370
371 /* A GHFunc (callback for g_hash_table_foreach) */
372 static void list_one_property(
373     gpointer key_p,
374     gpointer value_p,
375     gpointer user_data_p G_GNUC_UNUSED)
376 {
377     char       *property_s = key_p;
378     char       *qproperty;
379     property_t *property = value_p;
380     GSList     *value;
381     char       *qvalue;
382
383     qproperty = quote_string_always(property_s);
384     printf("property %s", qproperty);
385     amfree(qproperty);
386     for (value = property->values; value != NULL; value = value->next) {
387         qvalue = quote_string_always((char*)value->data);
388         printf(" %s", qvalue);
389         amfree(qvalue);
390     }
391     printf("\n");
392 }
393
394 void
395 list_property(void)
396 {
397     if (proplist) {
398         g_hash_table_foreach(proplist, list_one_property, NULL);
399     } else {
400         printf("No property set\n");
401     }
402 }
403
404 void
405 local_cd(
406     char *dir)
407 {
408     char *uqdir = unquote_string(dir);
409     if (chdir(uqdir) == -1) {
410         perror(uqdir);
411     }
412     amfree(uqdir);
413 }
414
415 int
416 cd_glob(
417     char *      glob,
418     int         verbose)
419 {
420     char *regex;
421     char *regex_path;
422     char *s;
423     char *uqglob;
424     int   result;
425
426     char *path_on_disk = NULL;
427
428     if (disk_name == NULL) {
429         g_printf(_("Must select disk before changing directory\n"));
430         return 0;
431     }
432
433     uqglob = unquote_string(glob);
434     regex = glob_to_regex(uqglob);
435     dbprintf(_("cd_glob (%s) -> %s\n"), uqglob, regex);
436     if ((s = validate_regexp(regex)) != NULL) {
437         g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), glob);
438         puts(s);
439         amfree(regex);
440         amfree(uqglob);
441         return 0;
442     }
443     /*
444      * glob_to_regex() anchors the beginning of the pattern with ^,
445      * but we will be tacking it onto the end of the current directory
446      * in add_file, so strip that off.  Also, it anchors the end with
447      * $, but we need to match a trailing /, add it if it is not there
448      */
449     regex_path = stralloc(regex + 1);
450     amfree(regex);
451     if(regex_path[strlen(regex_path) - 2] != '/' ) {
452         regex_path[strlen(regex_path) - 1] = '\0';
453         strappend(regex_path, "/$");
454     }
455
456     /* convert path (assumed in cwd) to one on disk */
457     if (strcmp(disk_path, "/") == 0)
458         path_on_disk = stralloc2("/", regex_path);
459     else {
460         char *clean_disk_path = clean_regex(disk_path, 0);
461         path_on_disk = vstralloc(clean_disk_path, "/", regex_path, NULL);
462         amfree(clean_disk_path);
463     }
464
465     result = cd_dir(path_on_disk, uqglob, verbose);
466
467     amfree(regex_path);
468     amfree(path_on_disk);
469     amfree(uqglob);
470
471     return result;
472 }
473
474 int
475 cd_regex(
476     char *      regex,
477     int         verbose)
478 {
479     char *s;
480     char *uq_orig_regex;
481     char *uqregex;
482     int  len_uqregex;
483     int  result;
484
485     char *path_on_disk = NULL;
486
487     if (disk_name == NULL) {
488         g_printf(_("Must select disk before changing directory\n"));
489         return 0;
490     }
491
492     uq_orig_regex = unquote_string(regex);
493     uqregex = stralloc(uq_orig_regex);
494
495     /* Add a terminating '/' if it is not there, maybe before a '$' */
496     len_uqregex = strlen(uqregex);
497     if (uqregex[len_uqregex-1] == '$') {
498         if (uqregex[len_uqregex-2] != '/') {
499             uqregex[len_uqregex-1] = '\0';
500             strappend(uqregex, "/$");
501         }
502     } else if (uqregex[len_uqregex-1] != '/') {
503         //uqregex[len_uqregex-1] = '\0';
504         strappend(uqregex, "/");
505     }
506     if ((s = validate_regexp(uqregex)) != NULL) {
507         g_printf(_("\"%s\" is not a valid regular expression: "), uq_orig_regex);
508         amfree(uqregex);
509         amfree(uq_orig_regex);
510         puts(s);
511         return 0;
512     }
513
514     /* convert path (assumed in cwd) to one on disk */
515     if (strcmp(disk_path, "/") == 0)
516         path_on_disk = stralloc2("/", uqregex);
517     else {
518         char *clean_disk_path = clean_regex(disk_path, 0);
519         path_on_disk = vstralloc(clean_disk_path, "/", regex, NULL);
520         amfree(clean_disk_path);
521     }
522
523     result = cd_dir(path_on_disk, uq_orig_regex, verbose);
524
525     amfree(path_on_disk);
526     amfree(uqregex);
527     amfree(uq_orig_regex);
528
529     return result;
530 }
531
532 int
533 cd_dir(
534     char *      path_on_disk,
535     char *      default_dir,
536     int         verbose)
537 {
538     char *dir = NULL;
539     char *s;
540     int nb_found;
541     int result;
542     size_t i;
543
544     DIR_ITEM *ditem;
545
546     if ((s = validate_regexp(path_on_disk)) != NULL) {
547         result = set_directory(default_dir, verbose);
548         return result;
549     }
550
551     nb_found = 0;
552
553     for (ditem=get_dir_list(); ditem!=NULL && nb_found <= 1; 
554                                ditem=get_next_dir_item(ditem))
555     {
556         if (match(path_on_disk, ditem->path))
557         {
558             i = strlen(ditem->path);
559             if((i > 0 && ditem->path[i-1] == '/')
560                || (i > 1 && ditem->path[i-2] == '/' && ditem->path[i-1] == '.'))
561             {   /* It is a directory */
562                 char *dir1, *dir2;
563                 nb_found++;
564                 dir = newstralloc(dir,ditem->path);
565                 if(dir[strlen(dir)-1] == '/')
566                     dir[strlen(dir)-1] = '\0'; /* remove last / */
567                 /* remove everything before the last / */
568                 dir1 = strrchr(dir,'/');
569                 if (dir1) {
570                     dir1++;
571                     dir2 = stralloc(dir1);
572                     amfree(dir);
573                     dir = dir2;
574                 }
575             }
576         }
577     }
578
579     if(nb_found==0) {
580         result = set_directory(default_dir, verbose);
581     }
582     else if(nb_found==1) {
583         result = set_directory(dir, verbose);
584     }
585     else {
586         g_printf(_("Too many directories matching '%s'\n"), default_dir);
587         result = 0;
588     }
589     amfree(dir);
590     return result;
591 }
592
593 int
594 set_directory(
595     char *      dir,
596     int         verbose)
597 {
598     char *cmd = NULL;
599     char *new_dir = NULL;
600     char *qnew_dir;
601     char *dp, *de;
602     char *ldir = NULL;
603     int   result;
604
605     /* do nothing if "." */
606     if(strcmp(dir,".")==0) {
607         show_directory();               /* say where we are */
608         return 1;
609         /*NOTREACHED*/
610     }
611
612     if (disk_name == NULL) {
613         g_printf(_("Must select disk before setting directory\n"));
614         return 0;
615         /*NOTREACHED*/
616     }
617
618     ldir = stralloc(dir);
619     clean_pathname(ldir);
620
621     /* convert directory into absolute path relative to disk mount point */
622     if (ldir[0] == '/')
623     {
624         /* absolute path specified, must start with mount point */
625         if (strcmp(mount_point, "/") == 0)
626         {
627             new_dir = stralloc(ldir);
628         }
629         else
630         {
631             if (strncmp(mount_point, ldir, strlen(mount_point)) != 0)
632             {
633                 g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
634                        mount_point);
635                 amfree(ldir);
636                 return 0;
637                 /*NOTREACHED*/
638             }
639             new_dir = stralloc(ldir+strlen(mount_point));
640             if (strlen(new_dir) == 0) {
641                 new_dir = newstralloc(new_dir, "/");
642                                         /* i.e. ldir == mount_point */
643             }
644         }
645     }
646     else
647     {
648         new_dir = stralloc(disk_path);
649         dp = ldir;
650         /* strip any leading ..s */
651         while (strncmp(dp, "../", 3) == 0)
652         {
653             de = strrchr(new_dir, '/'); /* always at least 1 */
654             if (de == new_dir)
655             {
656                 /* at top of disk */
657                 *(de + 1) = '\0';
658                 dp = dp + 3;
659             }
660             else
661             {
662                 *de = '\0';
663                 dp = dp + 3;
664             }
665         }
666         if (strcmp(dp, "..") == 0) {
667             if (strcmp(new_dir, "/") == 0) {
668                 /* at top of disk */
669                 g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
670                        mount_point);
671                 /*@ignore@*/
672                 amfree(new_dir);
673                 /*@end@*/
674                 amfree(ldir);
675                 return 0;
676                 /*NOTREACHED*/
677             }
678             de = strrchr(new_dir, '/'); /* always at least 1 */
679             if (de == new_dir)
680             {
681                 /* at top of disk */
682                 *(de+1) = '\0';
683             }
684             else
685             {
686                 *de = '\0';
687             }
688         } else {
689             /*@ignore@*/
690             if (strcmp(new_dir, "/") != 0) {
691                 strappend(new_dir, "/");
692             }
693             strappend(new_dir, ldir);
694             /*@end@*/
695         }
696     }
697
698     qnew_dir = quote_string(new_dir);
699     cmd = stralloc2("OISD ", qnew_dir);
700     amfree(qnew_dir);
701     if (exchange(cmd) == -1) {
702         exit(1);
703         /*NOTREACHED*/
704     }
705     amfree(cmd);
706
707     if (server_happy())
708     {
709         disk_path = newstralloc(disk_path, new_dir);
710         suck_dir_list_from_server();    /* get list of directory contents */
711         if (verbose)
712             show_directory();           /* say where we moved to */
713         result = 1;
714     }
715     else
716     {
717         g_printf(_("Invalid directory - %s\n"), dir);
718         result = 0;
719     }
720
721     /*@ignore@*/
722     amfree(new_dir);
723     amfree(ldir);
724     /*@end@*/
725
726     return result;
727 }
728
729
730 /* prints the current working directory */
731 void
732 show_directory(void)
733 {
734     if (mount_point == NULL || disk_path == NULL)
735         g_printf(_("Must select disk first\n"));
736     else if (strcmp(mount_point, "/") == 0)
737         g_printf("%s\n", disk_path);
738     else if (strcmp(disk_path, "/") == 0)
739         g_printf("%s\n", mount_point);
740     else
741         g_printf("%s%s\n", mount_point, disk_path);
742 }
743
744
745 /* set the tape server and device (deprecated version) */
746 void
747 set_tape(
748     char *      tape)
749 {
750     char *uqtape = unquote_string(tape);
751     char *tapedev = strchr(uqtape, ':');
752     char *host = NULL;
753
754     g_printf(_("NOTE: 'settape' is deprecated; use setdevice instead.\n"));
755
756     if (tapedev)
757     {
758         /* This command is deprecated because this parsing is going to fall 
759          * behind the list of available device names at some point, or to shadow
760          * an interesting hostname (wouldn't 'tape' be a good name for a 
761          * tape server?) */
762         if (tapedev != uqtape) {
763             if((strchr(tapedev+1, ':') == NULL) &&
764                (strncmp_const(uqtape, "null:") == 0 ||
765                 strncmp_const(uqtape, "rait:") == 0 ||
766                 strncmp_const(uqtape, "file:") == 0 ||
767                 strncmp_const(uqtape, "s3:") == 0 ||
768                 strncmp_const(uqtape, "tape:") == 0)) {
769                 tapedev = uqtape;
770             }
771             else {
772                 *tapedev = '\0';
773                 host = stralloc(uqtape);
774                 ++tapedev;
775             }
776         } else {
777             ++tapedev;
778         }
779     } else
780         tapedev = uqtape;
781     
782     if (tapedev[0])
783     {
784         if (strcmp(tapedev, "default") == 0)
785             tapedev = NULL;
786     }
787
788     /* call out to the new version */
789     set_device(host, tapedev);
790
791     amfree(host);
792     amfree(uqtape);
793 }
794
795 /* set the tape server and device, for real */
796 void
797 set_device(
798     char *      host,
799     char *      device)
800 {
801     if (host)
802         tape_server_name = newstralloc(tape_server_name, host);
803     else
804         amfree(tape_server_name);
805
806     if (device)
807         tape_device_name = newstralloc(tape_device_name, device);
808     else
809         amfree(tape_device_name);
810
811     /* print the current status */
812     if (tape_device_name)
813         g_printf (_("Using tape \"%s\""), tape_device_name);
814     else
815         g_printf (_("Using default tape"));
816
817     if (tape_server_name)
818         g_printf (_(" from server %s.\n"), tape_server_name);
819     else
820         g_printf (_(".\nTape server unspecified, assumed to be %s.\n"),
821                 server_name);
822 }
823
824 void
825 set_mode(
826     int         mode)
827 {
828   if (mode == SAMBA_SMBCLIENT) {
829     g_printf (_("SAMBA dumps will be extracted using smbclient\n"));
830     samba_extract_method = SAMBA_SMBCLIENT;
831   } else {
832     if (mode == SAMBA_TAR) {
833       g_printf (_("SAMBA dumps will be extracted as TAR dumps\n"));
834       samba_extract_method = SAMBA_TAR;
835     }
836   }
837 }
838
839 void
840 show_mode(void) 
841 {
842 #ifdef SAMBA_CLIENT
843   g_printf (_("SAMBA dumps are extracted "));
844
845   if (samba_extract_method == SAMBA_TAR) {
846     g_printf (_(" as TAR dumps\n"));
847   } else {
848     g_printf (_("using smbclient\n"));
849   }
850 #endif /* SAMBA_CLIENT */
851 }