Imported Upstream version 2.6.1p2
[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 int
50 main(
51     int         argc,
52     char **     argv)
53 {
54     char *conf_tapelist;
55     char *outslot = NULL;
56     char *label, *tapename = NULL;
57     char *labelstr, *slotstr;
58     char *conf_tapelist_old;
59     int have_changer;
60     int force, tape_ok;
61     tapetype_t *tape;
62     size_t tt_blocksize_kb;
63     int slotcommand;
64     Device * device;
65     DeviceStatusFlags device_status;
66     char *cfg_opt = NULL;
67     config_overwrites_t *cfg_ovr = NULL;
68
69     /*
70      * Configure program for internationalization:
71      *   1) Only set the message locale for now.
72      *   2) Set textdomain for all amanda related programs to "amanda"
73      *      We don't want to be forced to support dozens of message catalogs.
74      */  
75     setlocale(LC_MESSAGES, "C");
76     textdomain("amanda"); 
77
78     safe_fd(-1, 0);
79     safe_cd();
80
81     set_pname("amlabel");
82
83     dbopen(DBG_SUBDIR_SERVER);
84     device_api_init();
85
86     /* Don't die when child closes pipe */
87     signal(SIGPIPE, SIG_IGN);
88
89     erroutput_type = ERR_INTERACTIVE;
90
91     cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
92
93     if(argc > 1 && strcmp(argv[1],"-f") == 0)
94          force=1;
95     else force=0;
96
97     if(argc != 3+force && argc != 5+force)
98         usage();
99
100     cfg_opt = argv[1+force];
101     label = argv[2+force];
102
103     if(argc == 5+force) {
104         if(strcmp(argv[3+force], "slot"))
105             usage();
106         slotstr = argv[4+force];
107         slotcommand = 1;
108     } else {
109         slotstr = "current";
110         slotcommand = 0;
111     }
112
113     config_init(CONFIG_INIT_EXPLICIT_NAME, cfg_opt);
114     apply_config_overwrites(cfg_ovr);
115
116     if (config_errors(NULL) >= CFGERR_WARNINGS) {
117         config_print_errors();
118         if (config_errors(NULL) >= CFGERR_ERRORS) {
119             g_critical(_("errors processing config file"));
120         }
121     }
122
123     check_running_as(RUNNING_AS_DUMPUSER);
124
125     dbrename(get_config_name(), DBG_SUBDIR_SERVER);
126
127     conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST));
128     if (read_tapelist(conf_tapelist)) {
129         error(_("could not load tapelist \"%s\""), conf_tapelist);
130         /*NOTREACHED*/
131     }
132
133     labelstr = getconf_str(CNF_LABELSTR);
134
135     if(!match(labelstr, label)) {
136         error(_("label %s doesn't match labelstr \"%s\""), label, labelstr);
137         /*NOTREACHED*/
138     }
139
140     if((lookup_tapelabel(label))!=NULL) {
141         if(!force) {
142             error(_("label %s already on a tape\n"),label);
143             /*NOTREACHED*/
144         }
145     }
146     tape = lookup_tapetype(getconf_str(CNF_TAPETYPE));
147     tt_blocksize_kb = (size_t)tapetype_get_blocksize(tape);
148
149     if((have_changer = changer_init()) == 0) {
150         if(slotcommand) {
151             g_fprintf(stderr,
152              _("%s: no tpchanger specified in \"%s\", so slot command invalid\n"),
153                     argv[0], get_config_filename());
154             usage();
155         }
156         tapename = getconf_str(CNF_TAPEDEV);
157         if (tapename == NULL) {
158             error(_("No tapedev specified"));
159         }
160     } else if(have_changer != 1) {
161         error(_("changer initialization failed: %s"), strerror(errno));
162         /*NOTREACHED*/
163     } else {
164         if(changer_loadslot(slotstr, &outslot, &tapename)) {
165             error(_("could not load slot \"%s\": %s"), slotstr, changer_resultstr);
166             /*NOTREACHED*/
167         }
168
169         g_printf(_("labeling tape in slot %s (%s):\n"), outslot, tapename);
170     }
171
172     tape_ok=1;
173     g_printf("Reading label...\n");fflush(stdout);
174     device = device_open(tapename);
175     g_assert(device != NULL);
176     if (device->status != DEVICE_STATUS_SUCCESS) {
177         error("Could not open device %s: %s.\n", tapename,
178               device_error(device));
179     }
180
181     if (!device_configure(device, TRUE)) {
182         error("Could not configure device %s: %s.\n", tapename,
183               device_error(device));
184     }
185
186     device_status = device_read_label(device);
187
188     if (device_status & DEVICE_STATUS_VOLUME_UNLABELED) {
189         /* if there's no header, then the tape was truly empty; otherwise, there
190          * was *something* on the tape, so let's be careful and require a force */
191         if (!device->volume_header || device->volume_header->type == F_EMPTY) {
192             g_printf("Found an empty tape.\n");
193         } else {
194             g_printf("Found a non-Amanda tape.\n");
195             if(!force)
196                 tape_ok=0;
197         }
198     } else if (device_status != DEVICE_STATUS_SUCCESS) {
199         g_printf("Reading the tape label failed: %s.\n",
200                  device_error_or_status(device));
201         tape_ok = 0;
202     } else {
203         /* got an amanda tape */
204         g_printf(_("Found Amanda tape %s"),device->volume_label);
205         if(match(labelstr, device->volume_label) == 0) {
206             g_printf(_(", but it is not from configuration %s."),
207                      get_config_name());
208             if(!force)
209                 tape_ok=0;
210         } else {
211             if((lookup_tapelabel(device->volume_label)) != NULL) {
212                 g_printf(_(", tape is active"));
213                 if(!force)
214                     tape_ok=0;
215             }
216         }
217         g_printf("\n");
218     }
219
220     if(tape_ok) {
221         char *timestamp = NULL;
222
223         g_printf(_("Writing label %s..\n"), label); fflush(stdout);
224         
225         timestamp = get_undef_timestamp();
226         if (!device_start(device, ACCESS_WRITE, label, timestamp)) {
227             error(_("Error writing label: %s.\n"),
228                   device_error(device));
229             g_assert_not_reached();
230         } else if (!device_finish(device)) {
231             error(_("Error closing device: %s.\n"),
232                   device_error(device));
233             g_assert_not_reached();
234         }
235         amfree(timestamp);
236
237         g_printf(_("Checking label...\n")); fflush(stdout);
238
239         device_status = device_read_label(device);
240         if (device_status != DEVICE_STATUS_SUCCESS) {
241             g_printf(_("Checking the tape label failed: %s.\n"),
242                      device_error_or_status(device));
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, NULL);
271         if(write_tapelist(conf_tapelist)) {
272             error(_("couldn't write tapelist: %s"), strerror(errno));
273             /*NOTREACHED*/
274         }
275
276         if (have_changer && changer_label(outslot, label) != 0) {
277             error(_("couldn't update barcode database for slot %s, label %s\n"), outslot, label);
278             /*NOTREACHED*/
279         }
280
281         g_printf(_("Success!\n"));
282     } else {
283         g_printf(_("\ntape not labeled\n"));
284         exit(EXIT_FAILURE);
285     }
286     
287     g_object_unref(device);
288     device = NULL;
289
290     clear_tapelist();
291     amfree(outslot);
292     amfree(conf_tapelist);
293     dbclose();
294
295     return 0;
296 }