2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998, 2000 University of Maryland at College Park
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.
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.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: set_commands.c,v 1.26 2006/07/05 13:14:58 martinea Exp $
29 * implements the "set" commands in amrecover
35 #include "amrecover.h"
38 extern unsigned short samba_extract_method;
40 /* sets a date, mapping given date into standard form if needed */
50 cmd = stralloc2("DATE ", date);
51 if (converse(cmd) == -1)
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
57 if (disk_path != NULL) {
58 qdisk_path = quote_string(disk_path);
59 cmd = newstralloc2(cmd, "OISD ", qdisk_path);
61 if (exchange(cmd) == -1)
65 suck_dir_list_from_server();
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 */
85 struct hostent *hp = NULL;
88 char *uqhost = unquote_string(host);
90 if (is_extract_list_nonempty())
92 g_printf(_("Must clear extract list before changing host\n"));
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
103 cmd = stralloc2("HOST ", uqhost);
104 if (converse(cmd) == -1)
110 * Try converting the given host to a fully qualified, canonical
114 if ((hp = gethostbyname(uqhost)) != NULL) {
116 g_printf(_("Trying host %s ...\n"), host);
117 cmd = newstralloc2(cmd, "HOST ", host);
118 if (converse(cmd) == -1)
126 * Since we have them, try any CNAMEs that were traversed from uqhost
127 * to the canonical name (this assumes gethostbyname was called above)
131 for (hostp = hp->h_aliases; (host = *hostp) != NULL; hostp++)
133 g_printf(_("Trying host %s ...\n"), host);
134 cmd = newstralloc2(cmd, "HOST ", host);
135 if (converse(cmd) == -1)
146 /* Try looking up the canonical name of the host */
151 result = resolve_hostname(uqhost, 0, NULL, &canonname);
152 if (result == 0 && canonname) {
154 g_printf(_("Trying host %s ...\n"), host);
155 cmd = newstralloc2(cmd, "HOST ", host);
156 if (converse(cmd) == -1)
164 dump_hostname = newstralloc(dump_hostname, host);
179 cmd = stralloc("LISTHOST");
180 if (converse(cmd) == -1)
195 if (is_extract_list_nonempty())
197 g_printf(_("Must clear extract list before changing disk\n"));
201 /* if mount point specified, check it is valid */
203 uqmtpt = unquote_string(mtpt);
205 g_printf(_("Mount point \"%s\" invalid - must start with /\n"), uqmtpt);
212 uqdsk = unquote_string(dsk);
213 qdsk = quote_string(uqdsk);
214 cmd = stralloc2("DISK ", qdsk);
216 if (converse(cmd) == -1)
220 if (!server_happy()) {
226 disk_name = newstralloc(disk_name, uqdsk);
229 /* mount point not specified */
232 /* disk specified by mount point, hence use it */
233 mount_point = newstralloc(mount_point, uqdsk);
237 /* device name given, use '/' because nothing better */
238 mount_point = newstralloc(mount_point, "/");
243 /* mount point specified */
244 mount_point = newstralloc(mount_point, uqmtpt);
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)
256 disk_path = newstralloc(disk_path, "/");
257 suck_dir_list_from_server(); /* get list of directory contents */
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 */
269 if (am_has_feature(indexsrv_features, fe_amindexd_DLE)) {
273 cmd = stralloc("DLE");
274 if (exchange(cmd) == -1)
281 dle_str = reply_line();
282 if (BSTRNCMP(dle_str+4, "NODLE") == 0) {
285 dle_str = unquote_string(dle_str+4);
286 dump_dle = amxml_parse_node_CHAR(dle_str, &errmsg);
297 char *qamdevice, *uqamdevice;
300 uqamdevice = unquote_string(amdevice);
301 qamdevice = quote_string(uqamdevice);
302 cmd = stralloc2("LISTDISK ", qamdevice);
305 if (converse(cmd) == -1)
310 cmd = stralloc("LISTDISK");
311 if (converse(cmd) == -1)
317 static GSList *prop_values = NULL;
325 char *property_name, *pn;
327 pn = unquote_string(name);
328 property_name = amandaify_property_name(pn);
332 g_hash_table_remove(proplist, property_name);
335 prop = g_hash_table_lookup(proplist, property_name);
339 prop = malloc(sizeof(property_t));
343 g_hash_table_insert(proplist, stralloc(property_name), prop);
346 /* add prop_values to prop->values */
348 prop->values = prop_values;
353 for(pv = prop_values; pv != NULL; pv = pv->next) {
354 prop->values = g_slist_append(prop->values, pv->data);
356 g_slist_free(prop_values);
359 amfree(property_name);
367 prop_values = g_slist_prepend(prop_values, unquote_string(value));
371 /* A GHFunc (callback for g_hash_table_foreach) */
372 static void list_one_property(
375 gpointer user_data_p G_GNUC_UNUSED)
377 char *property_s = key_p;
379 property_t *property = value_p;
383 qproperty = quote_string_always(property_s);
384 printf("property %s", qproperty);
386 for (value = property->values; value != NULL; value = value->next) {
387 qvalue = quote_string_always((char*)value->data);
388 printf(" %s", qvalue);
398 g_hash_table_foreach(proplist, list_one_property, NULL);
400 printf("No property set\n");
408 char *uqdir = unquote_string(dir);
409 if (chdir(uqdir) == -1) {
426 char *path_on_disk = NULL;
428 if (disk_name == NULL) {
429 g_printf(_("Must select disk before changing directory\n"));
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);
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
449 regex_path = stralloc(regex + 1);
451 if(regex_path[strlen(regex_path) - 2] != '/' ) {
452 regex_path[strlen(regex_path) - 1] = '\0';
453 strappend(regex_path, "/$");
456 /* convert path (assumed in cwd) to one on disk */
457 if (strcmp(disk_path, "/") == 0)
458 path_on_disk = stralloc2("/", regex_path);
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);
465 result = cd_dir(path_on_disk, uqglob, verbose);
468 amfree(path_on_disk);
485 char *path_on_disk = NULL;
487 if (disk_name == NULL) {
488 g_printf(_("Must select disk before changing directory\n"));
492 uq_orig_regex = unquote_string(regex);
493 uqregex = stralloc(uq_orig_regex);
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, "/$");
502 } else if (uqregex[len_uqregex-1] != '/') {
503 //uqregex[len_uqregex-1] = '\0';
504 strappend(uqregex, "/");
506 if ((s = validate_regexp(uqregex)) != NULL) {
507 g_printf(_("\"%s\" is not a valid regular expression: "), uq_orig_regex);
509 amfree(uq_orig_regex);
514 /* convert path (assumed in cwd) to one on disk */
515 if (strcmp(disk_path, "/") == 0)
516 path_on_disk = stralloc2("/", uqregex);
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);
523 result = cd_dir(path_on_disk, uq_orig_regex, verbose);
525 amfree(path_on_disk);
527 amfree(uq_orig_regex);
546 if ((s = validate_regexp(path_on_disk)) != NULL) {
547 result = set_directory(default_dir, verbose);
553 for (ditem=get_dir_list(); ditem!=NULL && nb_found <= 1;
554 ditem=get_next_dir_item(ditem))
556 if (match(path_on_disk, ditem->path))
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 */
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,'/');
571 dir2 = stralloc(dir1);
580 result = set_directory(default_dir, verbose);
582 else if(nb_found==1) {
583 result = set_directory(dir, verbose);
586 g_printf(_("Too many directories matching '%s'\n"), default_dir);
599 char *new_dir = NULL;
605 /* do nothing if "." */
606 if(strcmp(dir,".")==0) {
607 show_directory(); /* say where we are */
612 if (disk_name == NULL) {
613 g_printf(_("Must select disk before setting directory\n"));
618 ldir = stralloc(dir);
619 clean_pathname(ldir);
621 /* convert directory into absolute path relative to disk mount point */
624 /* absolute path specified, must start with mount point */
625 if (strcmp(mount_point, "/") == 0)
627 new_dir = stralloc(ldir);
631 if (strncmp(mount_point, ldir, strlen(mount_point)) != 0)
633 g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
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 */
648 new_dir = stralloc(disk_path);
650 /* strip any leading ..s */
651 while (strncmp(dp, "../", 3) == 0)
653 de = strrchr(new_dir, '/'); /* always at least 1 */
666 if (strcmp(dp, "..") == 0) {
667 if (strcmp(new_dir, "/") == 0) {
669 g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
678 de = strrchr(new_dir, '/'); /* always at least 1 */
690 if (strcmp(new_dir, "/") != 0) {
691 strappend(new_dir, "/");
693 strappend(new_dir, ldir);
698 qnew_dir = quote_string(new_dir);
699 cmd = stralloc2("OISD ", qnew_dir);
701 if (exchange(cmd) == -1) {
709 disk_path = newstralloc(disk_path, new_dir);
710 suck_dir_list_from_server(); /* get list of directory contents */
712 show_directory(); /* say where we moved to */
717 g_printf(_("Invalid directory - %s\n"), dir);
730 /* prints the current working directory */
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);
741 g_printf("%s%s\n", mount_point, disk_path);
745 /* set the tape server and device (deprecated version) */
750 char *uqtape = unquote_string(tape);
751 char *tapedev = strchr(uqtape, ':');
754 g_printf(_("NOTE: 'settape' is deprecated; use setdevice instead.\n"));
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
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)) {
773 host = stralloc(uqtape);
784 if (strcmp(tapedev, "default") == 0)
788 /* call out to the new version */
789 set_device(host, tapedev);
795 /* set the tape server and device, for real */
802 tape_server_name = newstralloc(tape_server_name, host);
804 amfree(tape_server_name);
807 tape_device_name = newstralloc(tape_device_name, device);
809 amfree(tape_device_name);
811 /* print the current status */
812 if (tape_device_name)
813 g_printf (_("Using tape \"%s\""), tape_device_name);
815 g_printf (_("Using default tape"));
817 if (tape_server_name)
818 g_printf (_(" from server %s.\n"), tape_server_name);
820 g_printf (_(".\nTape server unspecified, assumed to be %s.\n"),
828 if (mode == SAMBA_SMBCLIENT) {
829 g_printf (_("SAMBA dumps will be extracted using smbclient\n"));
830 samba_extract_method = SAMBA_SMBCLIENT;
832 if (mode == SAMBA_TAR) {
833 g_printf (_("SAMBA dumps will be extracted as TAR dumps\n"));
834 samba_extract_method = SAMBA_TAR;
843 g_printf (_("SAMBA dumps are extracted "));
845 if (samba_extract_method == SAMBA_TAR) {
846 g_printf (_(" as TAR dumps\n"));
848 g_printf (_("using smbclient\n"));
850 #endif /* SAMBA_CLIENT */