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 */
72 disk_tpath = newstralloc(disk_tpath, "/"); /* fake it */
86 struct hostent *hp = NULL;
89 char *uqhost = unquote_string(host);
91 if (is_extract_list_nonempty())
93 g_printf(_("Must clear extract list before changing host\n"));
99 * The idea here is to try as many permutations of the hostname
100 * as we can imagine. The server will reject anything it doesn't
104 cmd = stralloc2("HOST ", uqhost);
105 if (converse(cmd) == -1)
111 * Try converting the given host to a fully qualified, canonical
115 if ((hp = gethostbyname(uqhost)) != NULL) {
117 g_printf(_("Trying host %s ...\n"), host);
118 cmd = newstralloc2(cmd, "HOST ", host);
119 if (converse(cmd) == -1)
127 * Since we have them, try any CNAMEs that were traversed from uqhost
128 * to the canonical name (this assumes gethostbyname was called above)
132 for (hostp = hp->h_aliases; (host = *hostp) != NULL; hostp++)
134 g_printf(_("Trying host %s ...\n"), host);
135 cmd = newstralloc2(cmd, "HOST ", host);
136 if (converse(cmd) == -1)
147 /* Try looking up the canonical name of the host */
152 result = resolve_hostname(uqhost, 0, NULL, &canonname);
153 if (result == 0 && canonname) {
155 g_printf(_("Trying host %s ...\n"), host);
156 cmd = newstralloc2(cmd, "HOST ", host);
157 if (converse(cmd) == -1)
165 dump_hostname = newstralloc(dump_hostname, host);
181 cmd = stralloc("LISTHOST");
182 if (converse(cmd) == -1)
197 if (is_extract_list_nonempty())
199 g_printf(_("Must clear extract list before changing disk\n"));
203 /* if mount point specified, check it is valid */
205 uqmtpt = unquote_string(mtpt);
207 g_printf(_("Mount point \"%s\" invalid - must start with /\n"), uqmtpt);
214 uqdsk = unquote_string(dsk);
215 qdsk = quote_string(uqdsk);
216 cmd = stralloc2("DISK ", qdsk);
218 if (converse(cmd) == -1)
222 if (!server_happy()) {
228 disk_name = newstralloc(disk_name, uqdsk);
231 /* mount point not specified */
234 /* disk specified by mount point, hence use it */
235 mount_point = newstralloc(mount_point, uqdsk);
239 /* device name given, use '/' because nothing better */
240 mount_point = newstralloc(mount_point, "/");
245 /* mount point specified */
246 mount_point = newstralloc(mount_point, uqmtpt);
249 /* set the working directory to the mount point */
250 /* there is the possibility that there are no index records for the
251 disk for the given date, hence setting the directory to the
252 mount point will fail. Preempt this by checking first so we can write
253 a more informative message. */
254 if (exchange("OISD /") == -1)
258 disk_path = newstralloc(disk_path, "/");
259 disk_tpath = newstralloc(disk_tpath, "/");
260 suck_dir_list_from_server(); /* get list of directory contents */
264 g_printf(_("No index records for disk for specified date\n"));
265 g_printf(_("If date correct, notify system administrator\n"));
266 disk_path = newstralloc(disk_path, "/"); /* fake it */
267 disk_tpath = newstralloc(disk_tpath, "/"); /* fake it */
273 if (am_has_feature(indexsrv_features, fe_amindexd_DLE)) {
277 cmd = stralloc("DLE");
278 if (exchange(cmd) == -1)
285 dle_str = reply_line();
286 if (BSTRNCMP(dle_str+4, "NODLE") == 0) {
289 dle_str = unquote_string(dle_str+4);
290 dump_dle = amxml_parse_node_CHAR(dle_str, &errmsg);
301 char *qamdevice, *uqamdevice;
304 uqamdevice = unquote_string(amdevice);
305 qamdevice = quote_string(uqamdevice);
306 cmd = stralloc2("LISTDISK ", qamdevice);
309 if (converse(cmd) == -1)
314 cmd = stralloc("LISTDISK");
315 if (converse(cmd) == -1)
321 static GSList *prop_values = NULL;
329 char *property_name, *pn;
331 pn = unquote_string(name);
332 property_name = amandaify_property_name(pn);
336 g_hash_table_remove(proplist, property_name);
339 prop = g_hash_table_lookup(proplist, property_name);
343 prop = malloc(sizeof(property_t));
347 g_hash_table_insert(proplist, stralloc(property_name), prop);
350 /* add prop_values to prop->values */
352 prop->values = prop_values;
357 for(pv = prop_values; pv != NULL; pv = pv->next) {
358 prop->values = g_slist_append(prop->values, pv->data);
360 g_slist_free(prop_values);
363 amfree(property_name);
371 prop_values = g_slist_prepend(prop_values, unquote_string(value));
375 /* A GHFunc (callback for g_hash_table_foreach) */
376 static void list_one_property(
379 gpointer user_data_p G_GNUC_UNUSED)
381 char *property_s = key_p;
383 property_t *property = value_p;
387 qproperty = quote_string_always(property_s);
388 printf("property %s", qproperty);
390 for (value = property->values; value != NULL; value = value->next) {
391 qvalue = quote_string_always((char*)value->data);
392 printf(" %s", qvalue);
402 g_hash_table_foreach(proplist, list_one_property, NULL);
404 printf("No property set\n");
412 char *uqdir = unquote_string(dir);
413 if (chdir(uqdir) == -1) {
430 char *tpath_on_disk = NULL;
432 if (disk_name == NULL) {
433 g_printf(_("Must select disk before changing directory\n"));
437 uqglob = unquote_string(glob);
438 regex = glob_to_regex(uqglob);
439 dbprintf(_("cd_glob (%s) -> %s\n"), uqglob, regex);
440 if ((s = validate_regexp(regex)) != NULL) {
441 g_printf(_("\"%s\" is not a valid shell wildcard pattern: "), glob);
448 * glob_to_regex() anchors the beginning of the pattern with ^,
449 * but we will be tacking it onto the end of the current directory
450 * in add_file, so strip that off. Also, it anchors the end with
451 * $, but we need to match a trailing /, add it if it is not there
453 regex_path = stralloc(regex + 1);
455 if(regex_path[strlen(regex_path) - 2] != '/' ) {
456 regex_path[strlen(regex_path) - 1] = '\0';
457 strappend(regex_path, "/$");
460 /* convert path (assumed in cwd) to one on disk */
461 if (strcmp(disk_path, "/") == 0)
462 tpath_on_disk = stralloc2("/", regex_path);
464 char *clean_disk_tpath = clean_regex(disk_tpath, 0);
465 tpath_on_disk = vstralloc(clean_disk_tpath, "/", regex_path, NULL);
466 amfree(clean_disk_tpath);
469 result = cd_dir(tpath_on_disk, uqglob, verbose);
472 amfree(tpath_on_disk);
489 char *tpath_on_disk = NULL;
491 if (disk_name == NULL) {
492 g_printf(_("Must select disk before changing directory\n"));
496 uq_orig_regex = unquote_string(regex);
497 uqregex = stralloc(uq_orig_regex);
499 /* Add a terminating '/' if it is not there, maybe before a '$' */
500 len_uqregex = strlen(uqregex);
501 if (uqregex[len_uqregex-1] == '$') {
502 if (uqregex[len_uqregex-2] != '/') {
503 uqregex[len_uqregex-1] = '\0';
504 strappend(uqregex, "/$");
506 } else if (uqregex[len_uqregex-1] != '/') {
507 //uqregex[len_uqregex-1] = '\0';
508 strappend(uqregex, "/");
510 if ((s = validate_regexp(uqregex)) != NULL) {
511 g_printf(_("\"%s\" is not a valid regular expression: "), uq_orig_regex);
513 amfree(uq_orig_regex);
518 /* convert path (assumed in cwd) to one on disk */
519 if (strcmp(disk_path, "/") == 0)
520 tpath_on_disk = stralloc2("/", uqregex);
522 char *clean_disk_tpath = clean_regex(disk_tpath, 0);
523 tpath_on_disk = vstralloc(clean_disk_tpath, "/", regex, NULL);
524 amfree(clean_disk_tpath);
527 result = cd_dir(tpath_on_disk, uq_orig_regex, verbose);
529 amfree(tpath_on_disk);
531 amfree(uq_orig_regex);
550 if ((s = 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 */