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.
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.
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.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: set_commands.c,v 1.26 2006/07/05 13:14:58 martinea Exp $
30 * implements the "set" commands in amrecover
36 #include "amrecover.h"
39 extern unsigned short samba_extract_method;
41 /* sets a date, mapping given date into standard form if needed */
51 cmd = stralloc2("DATE ", date);
52 if (converse(cmd) == -1)
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
58 if (disk_path != NULL) {
59 qdisk_path = quote_string(disk_path);
60 cmd = newstralloc2(cmd, "OISD ", qdisk_path);
62 if (exchange(cmd) == -1)
66 suck_dir_list_from_server();
70 g_printf(_("No index records for cwd on new date\n"));
71 g_printf(_("Setting cwd to mount point\n"));
72 disk_path = newstralloc(disk_path, "/"); /* fake it */
73 disk_tpath = newstralloc(disk_tpath, "/"); /* fake it */
87 struct hostent *hp = NULL;
90 char *uqhost = unquote_string(host);
92 if (is_extract_list_nonempty())
94 g_printf(_("Must clear extract list before changing host\n"));
100 * The idea here is to try as many permutations of the hostname
101 * as we can imagine. The server will reject anything it doesn't
105 cmd = stralloc2("HOST ", uqhost);
106 if (converse(cmd) == -1)
112 * Try converting the given host to a fully qualified, canonical
116 if ((hp = gethostbyname(uqhost)) != NULL) {
118 g_printf(_("Trying host %s ...\n"), host);
119 cmd = newstralloc2(cmd, "HOST ", host);
120 if (converse(cmd) == -1)
128 * Since we have them, try any CNAMEs that were traversed from uqhost
129 * to the canonical name (this assumes gethostbyname was called above)
133 for (hostp = hp->h_aliases; (host = *hostp) != NULL; hostp++)
135 g_printf(_("Trying host %s ...\n"), host);
136 cmd = newstralloc2(cmd, "HOST ", host);
137 if (converse(cmd) == -1)
148 /* Try looking up the canonical name of the host */
153 result = resolve_hostname(uqhost, 0, NULL, &canonname);
154 if (result == 0 && canonname) {
156 g_printf(_("Trying host %s ...\n"), host);
157 cmd = newstralloc2(cmd, "HOST ", host);
158 if (converse(cmd) == -1)
166 dump_hostname = newstralloc(dump_hostname, host);
182 cmd = stralloc("LISTHOST");
183 if (converse(cmd) == -1)
198 if (is_extract_list_nonempty())
200 g_printf(_("Must clear extract list before changing disk\n"));
204 /* if mount point specified, check it is valid */
206 uqmtpt = unquote_string(mtpt);
208 g_printf(_("Mount point \"%s\" invalid - must start with /\n"), uqmtpt);
215 uqdsk = unquote_string(dsk);
216 qdsk = quote_string(uqdsk);
217 cmd = stralloc2("DISK ", qdsk);
219 if (converse(cmd) == -1)
223 if (!server_happy()) {
229 disk_name = newstralloc(disk_name, uqdsk);
232 /* mount point not specified */
235 /* disk specified by mount point, hence use it */
236 mount_point = newstralloc(mount_point, uqdsk);
240 /* device name given, use '/' because nothing better */
241 mount_point = newstralloc(mount_point, "/");
246 /* mount point specified */
247 mount_point = newstralloc(mount_point, uqmtpt);
250 /* set the working directory to the mount point */
251 /* there is the possibility that there are no index records for the
252 disk for the given date, hence setting the directory to the
253 mount point will fail. Preempt this by checking first so we can write
254 a more informative message. */
255 if (exchange("OISD /") == -1)
259 disk_path = newstralloc(disk_path, "/");
260 disk_tpath = newstralloc(disk_tpath, "/");
261 suck_dir_list_from_server(); /* get list of directory contents */
265 g_printf(_("No index records for disk for specified date\n"));
266 g_printf(_("If date correct, notify system administrator\n"));
267 disk_path = newstralloc(disk_path, "/"); /* fake it */
268 disk_tpath = newstralloc(disk_tpath, "/"); /* fake it */
274 if (am_has_feature(indexsrv_features, fe_amindexd_DLE)) {
278 cmd = stralloc("DLE");
279 if (exchange(cmd) == -1)
286 dle_str = reply_line();
287 if (BSTRNCMP(dle_str+4, "NODLE") == 0) {
290 dle_str = unquote_string(dle_str+4);
291 dump_dle = amxml_parse_node_CHAR(dle_str, &errmsg);
302 char *qamdevice, *uqamdevice;
305 uqamdevice = unquote_string(amdevice);
306 qamdevice = quote_string(uqamdevice);
307 cmd = stralloc2("LISTDISK ", qamdevice);
310 if (converse(cmd) == -1)
315 cmd = stralloc("LISTDISK");
316 if (converse(cmd) == -1)
322 static GSList *prop_values = NULL;
330 char *property_name, *pn;
332 pn = unquote_string(name);
333 property_name = amandaify_property_name(pn);
337 g_hash_table_remove(proplist, property_name);
340 prop = g_hash_table_lookup(proplist, property_name);
344 prop = malloc(sizeof(property_t));
348 g_hash_table_insert(proplist, stralloc(property_name), prop);
351 /* add prop_values to prop->values */
353 prop->values = prop_values;
358 for(pv = prop_values; pv != NULL; pv = pv->next) {
359 prop->values = g_slist_append(prop->values, pv->data);
361 g_slist_free(prop_values);
364 amfree(property_name);
372 prop_values = g_slist_prepend(prop_values, unquote_string(value));
376 /* A GHFunc (callback for g_hash_table_foreach) */
377 static void list_one_property(
380 gpointer user_data_p G_GNUC_UNUSED)
382 char *property_s = key_p;
384 property_t *property = value_p;
388 qproperty = quote_string_always(property_s);
389 printf("property %s", qproperty);
391 for (value = property->values; value != NULL; value = value->next) {
392 qvalue = quote_string_always((char*)value->data);
393 printf(" %s", qvalue);
403 g_hash_table_foreach(proplist, list_one_property, NULL);
405 printf("No property set\n");
413 char *uqdir = unquote_string(dir);
414 if (chdir(uqdir) == -1) {
431 char *tpath_on_disk = NULL;
433 if (disk_name == NULL) {
434 g_printf(_("Must select disk before changing directory\n"));
438 uqglob = unquote_string(glob);
439 regex = glob_to_regex(uqglob);
440 dbprintf(_("cd_glob (%s) -> %s\n"), uqglob, regex);
441 if ((s = validate_regexp(regex)) != NULL) {
442 g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), glob);
449 * glob_to_regex() anchors the beginning of the pattern with ^,
450 * but we will be tacking it onto the end of the current directory
451 * in add_file, so strip that off. Also, it anchors the end with
452 * $, but we need to match a trailing /, add it if it is not there
454 regex_path = stralloc(regex + 1);
456 if(regex_path[strlen(regex_path) - 2] != '/' ) {
457 regex_path[strlen(regex_path) - 1] = '\0';
458 strappend(regex_path, "/$");
461 /* convert path (assumed in cwd) to one on disk */
462 if (strcmp(disk_path, "/") == 0)
463 tpath_on_disk = stralloc2("/", regex_path);
465 char *clean_disk_tpath = clean_regex(disk_tpath, 0);
466 tpath_on_disk = vstralloc(clean_disk_tpath, "/", regex_path, NULL);
467 amfree(clean_disk_tpath);
470 result = cd_dir(tpath_on_disk, uqglob, verbose);
473 amfree(tpath_on_disk);
490 char *tpath_on_disk = NULL;
492 if (disk_name == NULL) {
493 g_printf(_("Must select disk before changing directory\n"));
497 uq_orig_regex = unquote_string(regex);
498 uqregex = stralloc(uq_orig_regex);
500 /* Add a terminating '/' if it is not there, maybe before a '$' */
501 len_uqregex = strlen(uqregex);
502 if (uqregex[len_uqregex-1] == '$') {
503 if (uqregex[len_uqregex-2] != '/') {
504 uqregex[len_uqregex-1] = '\0';
505 strappend(uqregex, "/$");
507 } else if (uqregex[len_uqregex-1] != '/') {
508 //uqregex[len_uqregex-1] = '\0';
509 strappend(uqregex, "/");
511 if ((s = validate_regexp(uqregex)) != NULL) {
512 g_printf(_("\"%s\" is not a valid regular expression: "), uq_orig_regex);
514 amfree(uq_orig_regex);
519 /* convert path (assumed in cwd) to one on disk */
520 if (strcmp(disk_path, "/") == 0)
521 tpath_on_disk = stralloc2("/", uqregex);
523 char *clean_disk_tpath = clean_regex(disk_tpath, 0);
524 tpath_on_disk = vstralloc(clean_disk_tpath, "/", regex, NULL);
525 amfree(clean_disk_tpath);
528 result = cd_dir(tpath_on_disk, uq_orig_regex, verbose);
530 amfree(tpath_on_disk);
532 amfree(uq_orig_regex);
550 if (validate_regexp(tpath_on_disk) != NULL) {
551 result = set_directory(default_dir, verbose);
557 for (ditem=get_dir_list(); ditem!=NULL && nb_found <= 1;
558 ditem=get_next_dir_item(ditem))
560 if (match(tpath_on_disk, ditem->tpath))
562 i = strlen(ditem->tpath);
563 if((i > 0 && ditem->tpath[i-1] == '/')
564 || (i > 1 && ditem->tpath[i-2] == '/' && ditem->tpath[i-1] == '.'))
565 { /* It is a directory */
568 dir = newstralloc(dir,ditem->path);
569 if(dir[strlen(dir)-1] == '/')
570 dir[strlen(dir)-1] = '\0'; /* remove last / */
571 /* remove everything before the last / */
572 dir1 = strrchr(dir,'/');
575 dir2 = stralloc(dir1);
584 result = set_directory(default_dir, verbose);
586 else if(nb_found==1) {
587 result = set_directory(dir, verbose);
590 g_printf(_("Too many directories matching '%s'\n"), default_dir);
597 /* dir is relative to dir_path or absolute with mount_point */
604 char *new_dir = NULL;
610 /* do nothing if "." */
611 if(strcmp(dir,".")==0) {
612 show_directory(); /* say where we are */
617 if (disk_name == NULL) {
618 g_printf(_("Must select disk before setting directory\n"));
623 ldir = stralloc(dir);
624 clean_pathname(ldir);
626 /* convert directory into absolute path relative to disk mount point */
629 /* absolute path specified, must start with mount point */
630 if (strcmp(mount_point, "/") == 0)
632 new_dir = stralloc(ldir);
636 if (strncmp(mount_point, ldir, strlen(mount_point)) != 0)
638 g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
644 new_dir = stralloc(ldir+strlen(mount_point));
645 if (strlen(new_dir) == 0) {
646 new_dir = newstralloc(new_dir, "/");
647 /* i.e. ldir == mount_point */
653 new_dir = stralloc(disk_path);
655 /* strip any leading ..s */
656 while (strncmp(dp, "../", 3) == 0)
658 de = strrchr(new_dir, '/'); /* always at least 1 */
671 if (strcmp(dp, "..") == 0) {
672 if (strcmp(new_dir, "/") == 0) {
674 g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
683 de = strrchr(new_dir, '/'); /* always at least 1 */
695 if (strcmp(new_dir, "/") != 0) {
696 strappend(new_dir, "/");
698 strappend(new_dir, ldir);
703 qnew_dir = quote_string(new_dir);
704 cmd = stralloc2("OISD ", qnew_dir);
706 if (exchange(cmd) == -1) {
714 disk_path = newstralloc(disk_path, new_dir);
716 disk_tpath = translate_octal(g_strdup(disk_path));
717 suck_dir_list_from_server(); /* get list of directory contents */
719 show_directory(); /* say where we moved to */
724 g_printf(_("Invalid directory - %s\n"), dir);
737 /* prints the current working directory */
741 if (mount_point == NULL || disk_path == NULL)
742 g_printf(_("Must select disk first\n"));
743 else if (strcmp(mount_point, "/") == 0)
744 g_printf("%s\n", disk_tpath);
745 else if (strcmp(disk_path, "/") == 0)
746 g_printf("%s\n", mount_point);
748 g_printf("%s%s\n", mount_point, disk_tpath);
752 /* set the tape server and device (deprecated version) */
757 char *uqtape = unquote_string(tape);
758 char *tapedev = strchr(uqtape, ':');
761 g_printf(_("NOTE: 'settape' is deprecated; use setdevice instead.\n"));
765 /* This command is deprecated because this parsing is going to fall
766 * behind the list of available device names at some point, or to shadow
767 * an interesting hostname (wouldn't 'tape' be a good name for a
769 if (tapedev != uqtape) {
770 if((strchr(tapedev+1, ':') == NULL) &&
771 (strncmp_const(uqtape, "null:") == 0 ||
772 strncmp_const(uqtape, "rait:") == 0 ||
773 strncmp_const(uqtape, "file:") == 0 ||
774 strncmp_const(uqtape, "s3:") == 0 ||
775 strncmp_const(uqtape, "tape:") == 0)) {
780 host = stralloc(uqtape);
791 if (strcmp(tapedev, "default") == 0)
795 /* call out to the new version */
796 set_device(host, tapedev);
802 /* set the tape server and device, for real */
809 tape_server_name = newstralloc(tape_server_name, host);
811 amfree(tape_server_name);
814 tape_device_name = newstralloc(tape_device_name, device);
816 amfree(tape_device_name);
818 /* print the current status */
819 if (tape_device_name)
820 g_printf (_("Using tape \"%s\""), tape_device_name);
822 g_printf (_("Using default tape"));
824 if (tape_server_name)
825 g_printf (_(" from server %s.\n"), tape_server_name);
827 g_printf (_(".\nTape server unspecified, assumed to be %s.\n"),
836 if (translate == NULL) {
837 translate_mode = TRUE;
838 } else if (strcasecmp(translate, "yes") == 0 ||
839 strcasecmp(translate, "true") == 0 ||
840 strcasecmp(translate, "on") == 0) {
841 translate_mode = TRUE;
843 translate_mode = FALSE;
845 suck_dir_list_from_server(); /* get list of directory contents */
852 if (mode == SAMBA_SMBCLIENT) {
853 g_printf (_("SAMBA dumps will be extracted using smbclient\n"));
854 samba_extract_method = SAMBA_SMBCLIENT;
856 if (mode == SAMBA_TAR) {
857 g_printf (_("SAMBA dumps will be extracted as TAR dumps\n"));
858 samba_extract_method = SAMBA_TAR;
867 g_printf (_("SAMBA dumps are extracted "));
869 if (samba_extract_method == SAMBA_TAR) {
870 g_printf (_(" as TAR dumps\n"));
872 g_printf (_("using smbclient\n"));
874 #endif /* SAMBA_CLIENT */