651e6b6ec4d91bc007c689390d514758084dded9
[debian/amanda] / server-src / amlabel.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: amlabel.c,v 1.53 2006/07/25 18:27:57 martinea Exp $
28  *
29  * write an Amanda label on a tape
30  */
31 #include "amanda.h"
32 #include "conffile.h"
33 #include "tapefile.h"
34 #include "changer.h"
35 #include <device.h>
36 #include <timestamp.h>
37 #include <taperscan.h>
38
39 /* local functions */
40
41 int main(int argc, char **argv);
42
43 static void usage(void) {
44     g_fprintf(stderr, _("Usage: %s [-f] <conf> <label> [slot <slot-number>] [-o configoption]*\n"),
45             get_pname());
46     exit(1);
47 }
48
49 static void print_read_label_status_error(ReadLabelStatusFlags status) {
50     char ** status_strv;
51
52     if (status == READ_LABEL_STATUS_SUCCESS)
53         return;
54
55     status_strv = g_flags_nick_to_strv(status,
56                                        READ_LABEL_STATUS_FLAGS_TYPE);
57     g_assert(g_strv_length(status_strv) > 0);
58     if (g_strv_length(status_strv) == 1) {
59         g_printf("Error was %s.\n", *status_strv);
60     } else {
61         char * status_list = g_english_strjoinv(status_strv, "or");
62         g_printf("Error was one of %s.\n", status_list);
63         amfree(status_list);
64     }
65     g_strfreev(status_strv);
66 }
67
68 int
69 main(
70     int         argc,
71     char **     argv)
72 {
73     char *conf_tapelist;
74     char *outslot = NULL;
75     char *label, *tapename = NULL;
76     char *labelstr, *slotstr;
77     char *conf_tapelist_old;
78     int have_changer;
79     int force, tape_ok;
80     tapetype_t *tape;
81     size_t tt_blocksize_kb;
82     int slotcommand;
83     Device * device;
84     ReadLabelStatusFlags label_status;
85     char *cfg_opt = NULL;
86     config_overwrites_t *cfg_ovr = NULL;
87
88     /*
89      * Configure program for internationalization:
90      *   1) Only set the message locale for now.
91      *   2) Set textdomain for all amanda related programs to "amanda"
92      *      We don't want to be forced to support dozens of message catalogs.
93      */  
94     setlocale(LC_MESSAGES, "C");
95     textdomain("amanda"); 
96
97     safe_fd(-1, 0);
98     safe_cd();
99
100     set_pname("amlabel");
101
102     dbopen(DBG_SUBDIR_SERVER);
103     device_api_init();
104
105     /* Don't die when child closes pipe */
106     signal(SIGPIPE, SIG_IGN);
107
108     malloc_size_1 = malloc_inuse(&malloc_hist_1);
109
110     erroutput_type = ERR_INTERACTIVE;
111
112     cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
113
114     if(argc > 1 && strcmp(argv[1],"-f") == 0)
115          force=1;
116     else force=0;
117
118     if(argc != 3+force && argc != 5+force)
119         usage();
120
121     cfg_opt = argv[1+force];
122     label = argv[2+force];
123
124     if(argc == 5+force) {
125         if(strcmp(argv[3+force], "slot"))
126             usage();
127         slotstr = argv[4+force];
128         slotcommand = 1;
129     } else {
130         slotstr = "current";
131         slotcommand = 0;
132     }
133
134     config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_FATAL,
135                 cfg_opt);
136     apply_config_overwrites(cfg_ovr);
137
138     check_running_as(RUNNING_AS_DUMPUSER);
139
140     dbrename(config_name, DBG_SUBDIR_SERVER);
141
142     conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST));
143     if (read_tapelist(conf_tapelist)) {
144         error(_("could not load tapelist \"%s\""), conf_tapelist);
145         /*NOTREACHED*/
146     }
147
148     labelstr = getconf_str(CNF_LABELSTR);
149
150     if(!match(labelstr, label)) {
151         error(_("label %s doesn't match labelstr \"%s\""), label, labelstr);
152         /*NOTREACHED*/
153     }
154
155     if((lookup_tapelabel(label))!=NULL) {
156         if(!force) {
157             error(_("label %s already on a tape\n"),label);
158             /*NOTREACHED*/
159         }
160     }
161     tape = lookup_tapetype(getconf_str(CNF_TAPETYPE));
162     tt_blocksize_kb = (size_t)tapetype_get_blocksize(tape);
163
164     if((have_changer = changer_init()) == 0) {
165         if(slotcommand) {
166             g_fprintf(stderr,
167              _("%s: no tpchanger specified in \"%s\", so slot command invalid\n"),
168                     argv[0], config_filename);
169             usage();
170         }
171         tapename = getconf_str(CNF_TAPEDEV);
172         if (tapename == NULL) {
173             error(_("No tapedev specified"));
174         }
175     } else if(have_changer != 1) {
176         error(_("changer initialization failed: %s"), strerror(errno));
177         /*NOTREACHED*/
178     } else {
179         if(changer_loadslot(slotstr, &outslot, &tapename)) {
180             error(_("could not load slot \"%s\": %s"), slotstr, changer_resultstr);
181             /*NOTREACHED*/
182         }
183     }
184 #endif /* HAVE_LINUX_ZFTAPE_H */
185
186         g_printf(_("labeling tape in slot %s (%s):\n"), outslot, tapename);
187     }
188
189     tape_ok=1;
190     g_printf("Reading label...\n");fflush(stdout);
191     device = device_open(tapename);
192     if (device == NULL) {
193         error("Could not open device %s.\n", tapename);
194     }
195     
196     device_set_startup_properties_from_config(device);
197     label_status = device_read_label(device);
198
199     if (label_status & READ_LABEL_STATUS_VOLUME_UNLABELED) {
200         g_printf("Found an unlabeled tape.\n");
201     } else if (label_status != READ_LABEL_STATUS_SUCCESS) {
202         g_printf("Reading the tape label failed: \n  ");
203         print_read_label_status_error(label_status);
204         tape_ok = 0;
205     } else {
206         /* got an amanda tape */
207         g_printf(_("Found Amanda tape %s"),device->volume_label);
208         if(match(labelstr, device->volume_label) == 0) {
209             g_printf(_(", but it is not from configuration %s."), config_name);
210             if(!force)
211                 tape_ok=0;
212         } else {
213             if((lookup_tapelabel(device->volume_label)) != NULL) {
214                 g_printf(_(", tape is active"));
215                 if(!force)
216                     tape_ok=0;
217             }
218         }
219         g_printf("\n");
220     }
221
222     if(tape_ok) {
223         char *timestamp = NULL;
224
225         g_printf(_("Writing label %s..\n"), label); fflush(stdout);
226         
227         timestamp = get_undef_timestamp();
228         if (!device_start(device, ACCESS_WRITE, label, timestamp)) {
229             error(_("Error writing label.\n"));
230             g_assert_not_reached();
231         } else if (!device_finish(device)) {
232             error(_("Error closing device.\n"));
233             g_assert_not_reached();
234         }
235         amfree(timestamp);
236
237         g_printf(_("Checking label...\n")); fflush(stdout);
238
239         label_status = device_read_label(device);
240         if (label_status != READ_LABEL_STATUS_SUCCESS) {
241             g_printf("Checking the tape label failed: \n  ");
242             print_read_label_status_error(label_status);
243             exit(EXIT_FAILURE);
244         } else if (device->volume_label == NULL) {
245             error(_("no label found.\n"));
246             g_assert_not_reached();
247         } else if (strcmp(device->volume_label, label) != 0) {
248             error(_("Read back a different label: Got %s, but expected %s\n"),
249                   device->volume_label, label);
250             g_assert_not_reached();
251         } else if (get_timestamp_state(device->volume_time) !=
252                    TIME_STATE_UNDEF) {
253             error(_("Read the right label, but the wrong timestamp: "
254                     "Got %s, expected X.\n"), device->volume_time);
255             g_assert_not_reached();
256         }
257         
258         /* write tape list */
259         
260         /* make a copy */
261         conf_tapelist_old = stralloc2(conf_tapelist, ".amlabel");
262         if(write_tapelist(conf_tapelist_old)) {
263             error(_("couldn't write tapelist: %s"), strerror(errno));
264             /*NOTREACHED*/
265         }
266         amfree(conf_tapelist_old);
267         
268         /* XXX add cur_tape number to tape list structure */
269         remove_tapelabel(label);
270         add_tapelabel("0", label);
271         if(write_tapelist(conf_tapelist)) {
272             error(_("couldn't write tapelist: %s"), strerror(errno));
273             /*NOTREACHED*/
274         }
275         
276         g_printf(_("Success!\n"));
277     } else {
278         g_printf(_("\ntape not labeled\n"));
279     }
280     
281     g_object_unref(device);
282     device = NULL;
283
284     clear_tapelist();
285     amfree(outslot);
286     amfree(conf_tapelist);
287     config_name=NULL;
288     dbclose();
289
290     return 0;
291 }