Imported Upstream version 2.6.1p2
[debian/amanda] / server-src / amtape.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 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: amtape.c,v 1.47 2006/07/25 18:27:57 martinea Exp $
28  *
29  * tape changer interface program
30  */
31 #include "amanda.h"
32 #include "conffile.h"
33 #include "tapefile.h"
34 #include "taperscan.h"
35 #include "clock.h"
36 #include "changer.h"
37 #include "version.h"
38 #include "device.h"
39 #include "timestamp.h"
40
41 /* local functions */
42 static void usage(void);
43 int main(int argc, char **argv);
44 static void reset_changer(int argc, char **argv);
45 static void eject_tape(int argc, char **argv);
46 static void clean_tape(int argc, char **argv);
47 static void load_slot(int argc, char **argv);
48 static void load_label(int argc, char **argv);
49 static void show_slots(int argc, char **argv);
50 static void show_current(int argc, char **argv);
51 static void amtape_taper_scan(int argc, char **argv);
52 static void show_device(int argc, char **argv);
53 static int loadlabel_slot(void *ud, int rc, char *slotstr, char *device);
54 int show_init(void *ud, int rc, int ns, int bk, int s);
55 static int show_slots_slot(void *ud, int rc, char *slotstr, char *device);
56
57 static const struct {
58     const char *name;
59     void (*fn)(int, char **);
60     const char *usage;
61 } cmdtab[] = {
62     { "reset", reset_changer,
63         T_("reset                Reset changer to known state") },
64     { "eject", eject_tape,
65         T_("eject                Eject current tape from drive") },
66     { "clean", clean_tape,
67         T_("clean                Clean the drive") },
68     { "show", show_slots,
69         T_("show                 Show contents of all slots") },
70     { "current", show_current,
71         T_("current              Show contents of current slot") },
72     { "slot" , load_slot,
73         T_("slot <slot #>        load tape from slot <slot #>") },
74     { "slot" , load_slot,
75         T_("slot current         load tape from current slot") },
76     { "slot" , load_slot,
77         T_("slot next            load tape from next slot") },
78     { "slot" , load_slot,
79         T_("slot advance         advance to next slot but do not load") },
80     { "slot" , load_slot,
81         T_("slot first           load tape from first slot") },
82     { "label", load_label,
83         T_("label <label>        find and load labeled tape") },
84     { "taper", amtape_taper_scan,
85         T_("taper                perform taper's scan alg.") },
86     { "device", show_device,
87         T_("device               show current tape device") },
88     { "update", show_slots,
89         T_("update               update the label matchingdatabase")},
90 };
91 #define NCMDS   (int)(sizeof(cmdtab) / sizeof(cmdtab[0]))
92
93 static void
94 usage(void)
95 {
96     int i;
97
98     g_fprintf(stderr, _("Usage: amtape%s <conf> <command> {<args>} [-o configoption]*\n"), versionsuffix());
99     g_fprintf(stderr, _("\tValid commands are:\n"));
100     for (i = 0; i < NCMDS; i++)
101         g_fprintf(stderr, "\t\t%s\n", _(cmdtab[i].usage));
102     exit(1);
103 }
104
105 int
106 main(
107     int         argc,
108     char **     argv)
109 {
110     char *conf_tapelist;
111     int i;
112     int have_changer;
113     config_overwrites_t *cfg_ovr = NULL;
114
115     /*
116      * Configure program for internationalization:
117      *   1) Only set the message locale for now.
118      *   2) Set textdomain for all amanda related programs to "amanda"
119      *      We don't want to be forced to support dozens of message catalogs.
120      */  
121     setlocale(LC_MESSAGES, "C");
122     textdomain("amanda"); 
123
124     safe_fd(-1, 0);
125     safe_cd();
126
127     set_pname("amtape");
128
129     /* Don't die when child closes pipe */
130     signal(SIGPIPE, SIG_IGN);
131
132     dbopen(DBG_SUBDIR_SERVER);
133
134     erroutput_type = ERR_INTERACTIVE;
135
136     cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
137     if(argc < 3) usage();
138
139     config_init(CONFIG_INIT_EXPLICIT_NAME, argv[1]);
140     apply_config_overwrites(cfg_ovr);
141
142     if (config_errors(NULL) >= CFGERR_WARNINGS) {
143         config_print_errors();
144         if (config_errors(NULL) >= CFGERR_ERRORS) {
145             g_critical(_("errors processing config file"));
146         }
147     }
148
149     check_running_as(RUNNING_AS_DUMPUSER);
150
151     dbrename(get_config_name(), DBG_SUBDIR_SERVER);
152
153     conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST));
154     if (read_tapelist(conf_tapelist)) {
155         error(_("could not load tapelist \"%s\""), conf_tapelist);
156         /*NOTREACHED*/
157     }
158     amfree(conf_tapelist);
159
160     if((have_changer = changer_init()) == 0) {
161         error(_("no tpchanger specified in \"%s\""), get_config_filename());
162         /*NOTREACHED*/
163     } else if (have_changer != 1) {
164         error(_("changer initialization failed: %s"), strerror(errno));
165         /*NOTREACHED*/
166     }
167
168     /* switch on command name */
169
170     argc -= 2; argv += 2;
171     for (i = 0; i < NCMDS; i++)
172         if (strcmp(argv[0], cmdtab[i].name) == 0) {
173             (*cmdtab[i].fn)(argc, argv);
174             break;
175         }
176     if (i == NCMDS) {
177         g_fprintf(stderr, _("%s: unknown command \"%s\"\n"), get_pname(), argv[0]);
178         usage();
179     }
180
181     amfree(changer_resultstr);
182
183     dbclose();
184     return 0;
185 }
186
187 /* ---------------------------- */
188
189 static void
190 reset_changer(G_GNUC_UNUSED int argc,
191               G_GNUC_UNUSED char ** argv) {
192     char *slotstr = NULL;
193
194     switch(changer_reset(&slotstr)) {
195     case 0:
196         g_fprintf(stderr, _("%s: changer is reset, slot %s is loaded.\n"),
197                 get_pname(), slotstr);
198         break;
199     case 1:
200         g_fprintf(stderr, _("%s: changer is reset, but slot %s not loaded: %s\n"),
201                 get_pname(), slotstr, changer_resultstr);
202         break;
203     default:
204         error(_("could not reset changer: %s"), changer_resultstr);
205         /*NOTREACHED*/
206     }
207     amfree(slotstr);
208 }
209
210
211 /* ---------------------------- */
212 static void
213 clean_tape(G_GNUC_UNUSED int    argc,
214            G_GNUC_UNUSED char ** argv) {
215     char *devstr = NULL;
216
217     if(changer_clean(&devstr) == 0) {
218         g_fprintf(stderr, _("%s: device %s is clean.\n"), get_pname(), devstr);
219     } else {
220         g_fprintf(stderr, _("%s: device %s not clean: %s\n"),
221                 get_pname(), devstr ? devstr : "??", changer_resultstr);
222     }
223     amfree(devstr);
224 }
225
226
227 /* ---------------------------- */
228 static void
229 eject_tape(G_GNUC_UNUSED int    argc,
230            G_GNUC_UNUSED char ** argv) {
231     char *slotstr = NULL;
232
233     if(changer_eject(&slotstr) == 0) {
234         g_fprintf(stderr, _("%s: slot %3s is ejected.\n"), get_pname(), slotstr);
235     } else {
236         g_fprintf(stderr, _("%s: slot %3s not ejected: %s\n"),
237                 get_pname(), slotstr ? slotstr : "??", changer_resultstr);
238     }
239     amfree(slotstr);
240 }
241
242
243 /* ---------------------------- */
244
245 static void
246 load_slot(
247     int         argc,
248     char **     argv)
249 {
250     char *slotstr = NULL, *devicename = NULL;
251     Device * device;
252
253     if(argc != 2)
254         usage();
255
256     device_api_init();
257
258     if (strcmp(argv[1], "advance") == 0) {
259         argv[1] = "next";
260     }
261
262     if(changer_loadslot(argv[1], &slotstr, &devicename)) {
263         error(_("could not load slot %s: %s"), slotstr, changer_resultstr);
264         /*NOTREACHED*/
265     }
266
267     device = device_open(devicename);
268     g_assert(device != NULL);
269     if (device->status != DEVICE_STATUS_SUCCESS) {
270         g_fprintf(stderr,
271                 _("%s: could not open device %s: %s"), get_pname(),
272                 devicename, device_error(device));
273     }
274     g_object_unref(device);
275
276     g_fprintf(stderr, _("%s: changed to slot %s on %s\n"), get_pname(), slotstr, devicename);
277     amfree(slotstr);
278     amfree(devicename);
279 }
280
281
282 /* ---------------------------- */
283
284 /* This initalizes the ChangerStatus structure for all commands that
285    use changer_find; namely, show_slots, load_label, and
286    show_current. */
287 static int 
288 scan_init(G_GNUC_UNUSED void * data, int rc, G_GNUC_UNUSED int numslots,
289           G_GNUC_UNUSED int backwards, G_GNUC_UNUSED int searchable) {
290     if(rc != 0) {
291         error(_("could not get changer info: %s"), changer_resultstr);
292         /*NOTREACHED*/
293     }
294
295     return 0;
296 }
297
298 static int scan_init_print(void * data, int rc, int numslots,
299                          int backwards, int searchable) {
300     
301     g_fprintf(stderr, _("%s: scanning all %d slots in tape-changer rack:\n"),
302             get_pname(), numslots);
303
304     return scan_init(data, rc, numslots, backwards, searchable);
305 }
306
307 typedef struct {
308     gboolean found;
309     char *searchlabel;
310 } LabelChangerStatus;
311
312 /* This is the 'user_slot' callback for the 'load label' command. */
313 static int
314 loadlabel_slot(
315     void *      ud,
316     int         rc,
317     char *      slotstr,
318     char *      device_name)
319 {
320     LabelChangerStatus * status = ud;
321     Device * device;
322     DeviceStatusFlags device_status;
323
324     if (rc > 1) {
325         error(_("could not load slot %s: %s"), slotstr, changer_resultstr);
326         g_assert_not_reached();
327     } else if (rc == 1) {
328         g_fprintf(stderr, _("%s: slot %3s: %s\n"),
329                 get_pname(), slotstr, changer_resultstr);
330         return 0;
331     }
332
333     device = device_open(device_name);
334     g_assert(device != NULL);
335     if (device->status != DEVICE_STATUS_SUCCESS) {
336         g_fprintf(stderr, _("%s: slot %3s: Could not open device: %s.\n"),
337                   get_pname(), slotstr, device_error(device));
338         return 0;
339     }
340
341     if (!device_configure(device, TRUE)) {
342         g_fprintf(stderr, _("%s: slot %3s: Could not configure device: %s.\n"),
343                   get_pname(), slotstr, device_error(device));
344         return 0;
345     }
346
347     device_status = device_read_label(device);
348     if (device_status != DEVICE_STATUS_SUCCESS) {
349         g_fprintf(stderr, _("%s: slot %3s: %s\n"),
350                   get_pname(), slotstr, device_error_or_status(device));
351         g_object_unref(device);
352         return 0;
353     }
354     
355     g_fprintf(stderr, _("%s: slot %3s: time %-14s label %s"),
356             get_pname(), slotstr, device->volume_time, device->volume_label);
357
358     if(strcmp(device->volume_label, status->searchlabel) != 0) {
359         g_fprintf(stderr, _(" (wrong tape)\n"));
360         g_object_unref(device);
361         return 0;
362     } else {
363         g_fprintf(stderr, _(" (exact label match)\n"));
364         g_object_unref(device);
365         status->found = 1;
366         return 1;
367     }
368
369     g_assert_not_reached();
370 }
371
372 /* This does the 'load label' command. */
373 static void
374 load_label(
375     int         argc,
376     char **     argv)
377 {
378     LabelChangerStatus status;
379
380     if(argc != 2)
381         usage();
382     
383     device_api_init();
384
385     status.searchlabel = argv[1];
386
387     g_fprintf(stderr, _("%s: scanning for tape with label %s\n"),
388             get_pname(), status.searchlabel);
389
390     status.found = 0;
391
392     changer_find(&status, scan_init, loadlabel_slot, status.searchlabel);
393
394     if(status.found)
395         g_fprintf(stderr, _("%s: label %s is now loaded.\n"),
396                 get_pname(), status.searchlabel);
397     else
398         g_fprintf(stderr, _("%s: could not find label %s in tape rack.\n"),
399                 get_pname(), status.searchlabel);
400 }
401
402
403 /* ---------------------------- */
404
405 /* This is the user_slot function for "amtape show". */
406 static int
407 show_slots_slot(G_GNUC_UNUSED void * data, int rc, char * slotstr,
408                 char * device_name)
409 {
410     Device * device;
411
412     if(rc > 1) {
413         error(_("could not load slot %s: %s"), slotstr, changer_resultstr);
414         g_assert_not_reached();
415     }
416
417     if(rc == 1) {
418         g_fprintf(stderr, _("slot %s: %s\n"), slotstr, changer_resultstr);
419         return 0;
420     }
421
422     device = device_open(device_name);
423     g_assert(device != NULL);
424     if (device->status != DEVICE_STATUS_SUCCESS) {
425         g_fprintf(stderr, _("%s: slot %3s: Could not open device: %s.\n"),
426                   get_pname(), slotstr, device_error(device));
427     } else {
428         DeviceStatusFlags device_status;
429
430         if (!device_configure(device, TRUE)) {
431             g_fprintf(stderr, _("%s: slot %3s: %s\n"),
432                       get_pname(), slotstr, device_error_or_status(device));
433         }
434
435         device_status = device_read_label(device);
436
437         if (device_status != DEVICE_STATUS_SUCCESS) {
438             g_fprintf(stderr, _("%s: slot %3s: %s\n"),
439                       get_pname(), slotstr, device_error_or_status(device));
440         } else {
441             g_fprintf(stderr, _("slot %3s: time %-14s label %s\n"),
442                     slotstr, device->volume_time, device->volume_label);
443
444             /* update the changer db */
445             changer_label(slotstr, device->volume_label);
446         }
447     }
448
449     if (device != NULL)
450         g_object_unref(device);
451
452     return 0;
453 }
454
455 static void
456 show_current(int argc, G_GNUC_UNUSED char ** argv) {
457     if(argc != 1)
458         usage();
459
460     device_api_init();
461
462     g_fprintf(stderr, _("%s: scanning current slot in tape-changer rack:\n"),
463             get_pname());
464     changer_current(NULL, scan_init, show_slots_slot);
465 }
466
467 static void
468 show_slots(int argc, G_GNUC_UNUSED char ** argv) {
469     if(argc != 1)
470         usage();
471
472     device_api_init();
473     changer_find(NULL, scan_init_print, show_slots_slot, NULL);
474 }
475
476
477 /* ---------------------------- */
478
479 static void
480 amtape_taper_scan(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char ** argv) {
481     char *label = NULL;
482     char * searchlabel;
483     tape_t * tp;
484     char *timestamp = NULL;
485     char *tapedev = NULL;
486     int result;
487
488     device_api_init();
489     
490     g_fprintf(stderr, _("%s: scanning for "), get_pname());
491
492     tp = lookup_last_reusable_tape(0);
493     if (tp == NULL) {
494         searchlabel = NULL;
495     } else {
496         searchlabel = stralloc(tp->label);
497         g_fprintf(stderr, _("tape label %s or "), searchlabel);
498     }
499     g_fprintf(stderr, _("a new tape.\n"));
500
501     result = taper_scan(searchlabel, &label, &timestamp, &tapedev, NULL,
502                         FILE_taperscan_output_callback, stderr, NULL, NULL);
503
504     if (result < 0) {
505         g_fprintf(stderr, _("Could not find a  non-active Amanda tape.\n"));
506         if (label) {
507             g_fprintf(stderr, _("Tape with label `%s' is now loaded.\n"), label);
508         }
509     } else if (result == 3) {
510         g_fprintf(stderr, _("New tape loaded, it will be labelled `%s'.\n"),
511                   label);
512     } else {
513         g_fprintf(stderr, _("Tape with label `%s' is now loaded.\n"), label);
514     }
515
516     amfree(searchlabel);
517     amfree(label);
518     amfree(timestamp);
519     amfree(tapedev);
520 }
521
522 /* ---------------------------- */
523
524 static void
525 show_device(G_GNUC_UNUSED int   argc,
526             G_GNUC_UNUSED char ** argv) {
527     char *slot = NULL, *device = NULL;
528     
529     if(changer_loadslot(_("current"), &slot, &device)) {
530         error(_("could not load current slot: %s\n"), changer_resultstr);
531         /*NOTREACHED*/
532     }
533
534     g_printf("%s\n", device);
535     amfree(slot);
536     amfree(device);
537 }