Imported Upstream version 2.5.1
[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 "tapeio.h"
36 #include "clock.h"
37 #include "changer.h"
38 #include "version.h"
39
40 /* local functions */
41 void usage(void);
42 int main(int argc, char **argv);
43 void reset_changer(int argc, char **argv);
44 void eject_tape(int argc, char **argv);
45 void clean_tape(int argc, char **argv);
46 void load_slot(int argc, char **argv);
47 void load_label(int argc, char **argv);
48 void show_slots(int argc, char **argv);
49 void show_current(int argc, char **argv);
50 void update_labeldb (int argc, char **argv);
51 void amtape_taper_scan(int argc, char **argv);
52 void show_device(int argc, char **argv);
53 int update_one_slot (void *ud, int rc, char *slotstr, char *device);
54 int loadlabel_slot(void *ud, int rc, char *slotstr, char *device);
55 int show_init(void *ud, int rc, int ns, int bk, int s);
56 int show_init_all(void *ud, int rc, int ns, int bk, int s);
57 int show_init_current(void *ud, int rc, int ns, int bk, int s);
58 int show_slot(void *ud, int rc, char *slotstr, char *device);
59
60 static const struct {
61     const char *name;
62     void (*fn)(int, char **);
63     const char *usage;
64 } cmdtab[] = {
65     { "reset", reset_changer,
66         "reset                Reset changer to known state" },
67     { "eject", eject_tape,
68         "eject                Eject current tape from drive" },
69     { "clean", clean_tape,
70         "clean                Clean the drive" },
71     { "show", show_slots,
72         "show                 Show contents of all slots" },
73     { "current", show_current,
74         "current              Show contents of current slot" },
75     { "slot" , load_slot,
76         "slot <slot #>        load tape from slot <slot #>" },
77     { "slot" , load_slot,
78         "slot current         load tape from current slot" },
79     { "slot" , load_slot,
80         "slot prev            load tape from previous slot" },
81     { "slot" , load_slot,
82         "slot next            load tape from next slot" },
83     { "slot" , load_slot,
84         "slot advance         advance to next slot but do not load" },
85     { "slot" , load_slot,
86         "slot first           load tape from first slot" },
87     { "slot" , load_slot,
88         "slot last            load tape from last slot" },
89     { "label", load_label,
90         "label <label>        find and load labeled tape" },
91     { "taper", amtape_taper_scan,
92         "taper                perform taper's scan alg." },
93     { "device", show_device,
94         "device               show current tape device" },
95     { "update", update_labeldb,
96         "update               update the label matchingdatabase"},
97 };
98 #define NCMDS   (int)(sizeof(cmdtab) / sizeof(cmdtab[0]))
99
100 void
101 usage(void)
102 {
103     int i;
104
105     fprintf(stderr, "Usage: amtape%s <conf> <command>\n", versionsuffix());
106     fprintf(stderr, "\tValid commands are:\n");
107     for (i = 0; i < NCMDS; i++)
108         fprintf(stderr, "\t\t%s\n", cmdtab[i].usage);
109     exit(1);
110 }
111
112 int
113 main(
114     int         argc,
115     char **     argv)
116 {
117     char *conffile;
118     char *conf_tapelist;
119     char *argv0 = argv[0];
120     unsigned long malloc_hist_1, malloc_size_1;
121     unsigned long malloc_hist_2, malloc_size_2;
122     int i;
123     int have_changer;
124     uid_t uid_me;
125     uid_t uid_dumpuser;
126     char *dumpuser;
127     struct passwd *pw;
128
129     safe_fd(-1, 0);
130     safe_cd();
131
132     set_pname("amtape");
133
134     /* Don't die when child closes pipe */
135     signal(SIGPIPE, SIG_IGN);
136
137     dbopen(DBG_SUBDIR_SERVER);
138
139     malloc_size_1 = malloc_inuse(&malloc_hist_1);
140
141     erroutput_type = ERR_INTERACTIVE;
142
143     if(argc < 3) usage();
144
145     config_name = argv[1];
146
147     config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
148     conffile = stralloc2(config_dir, CONFFILE_NAME);
149     if (read_conffile(conffile)) {
150         error("errors processing config file \"%s\"", conffile);
151         /*NOTREACHED*/
152     }
153
154     dbrename(config_name, DBG_SUBDIR_SERVER);
155
156     conf_tapelist = getconf_str(CNF_TAPELIST);
157     if (*conf_tapelist == '/') {
158         conf_tapelist = stralloc(conf_tapelist);
159     } else {
160         conf_tapelist = stralloc2(config_dir, conf_tapelist);
161     }
162     if (read_tapelist(conf_tapelist)) {
163         error("could not load tapelist \"%s\"", conf_tapelist);
164         /*NOTREACHED*/
165     }
166     amfree(conf_tapelist);
167
168     uid_me = getuid();
169     uid_dumpuser = uid_me;
170     dumpuser = getconf_str(CNF_DUMPUSER);
171
172     if ((pw = getpwnam(dumpuser)) == NULL) {
173         error("cannot look up dump user \"%s\"", dumpuser);
174         /*NOTREACHED*/
175     }
176     uid_dumpuser = pw->pw_uid;
177     if ((pw = getpwuid(uid_me)) == NULL) {
178         error("cannot look up my own uid %ld", (long)uid_me);
179         /*NOTREACHED*/
180     }
181     if (uid_me != uid_dumpuser) {
182         error("running as user \"%s\" instead of \"%s\"",
183               pw->pw_name, dumpuser);
184         /*NOTREACHED*/
185     }
186
187     if((have_changer = changer_init()) == 0) {
188         error("no tpchanger specified in \"%s\"", conffile);
189         /*NOTREACHED*/
190     } else if (have_changer != 1) {
191         error("changer initialization failed: %s", strerror(errno));
192         /*NOTREACHED*/
193     }
194
195     /* switch on command name */
196
197     argc -= 2; argv += 2;
198     for (i = 0; i < NCMDS; i++)
199         if (strcmp(argv[0], cmdtab[i].name) == 0) {
200             (*cmdtab[i].fn)(argc, argv);
201             break;
202         }
203     if (i == NCMDS) {
204         fprintf(stderr, "%s: unknown command \"%s\"\n", argv0, argv[0]);
205         usage();
206     }
207
208     amfree(changer_resultstr);
209     amfree(conffile);
210     amfree(config_dir);
211
212     malloc_size_2 = malloc_inuse(&malloc_hist_2);
213
214     if(malloc_size_1 != malloc_size_2) {
215         malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
216     }
217
218     dbclose();
219     return 0;
220 }
221
222 /* ---------------------------- */
223
224 void
225 reset_changer(
226     int         argc,
227     char **     argv)
228 {
229     char *slotstr = NULL;
230
231     (void)argc; /* Quiet unused parameter warning */
232     (void)argv; /* Quiet unused parameter warning */
233
234     switch(changer_reset(&slotstr)) {
235     case 0:
236         fprintf(stderr, "%s: changer is reset, slot %s is loaded.\n",
237                 get_pname(), slotstr);
238         break;
239     case 1:
240         fprintf(stderr, "%s: changer is reset, but slot %s not loaded: %s\n",
241                 get_pname(), slotstr, changer_resultstr);
242         break;
243     default:
244         error("could not reset changer: %s", changer_resultstr);
245         /*NOTREACHED*/
246     }
247     amfree(slotstr);
248 }
249
250
251 /* ---------------------------- */
252 void
253 clean_tape(
254     int         argc,
255     char **     argv)
256 {
257     char *devstr = NULL;
258
259     (void)argc; /* Quiet unused parameter warning */
260     (void)argv; /* Quiet unused parameter warning */
261
262     if(changer_clean(&devstr) == 0) {
263         fprintf(stderr, "%s: device %s is clean.\n", get_pname(), devstr);
264     } else {
265         fprintf(stderr, "%s: device %s not clean: %s\n",
266                 get_pname(), devstr ? devstr : "??", changer_resultstr);
267     }
268     amfree(devstr);
269 }
270
271
272 /* ---------------------------- */
273 void
274 eject_tape(
275     int         argc,
276     char **     argv)
277 {
278     char *slotstr = NULL;
279
280     (void)argc; /* Quiet unused parameter warning */
281     (void)argv; /* Quiet unused parameter warning */
282
283     if(changer_eject(&slotstr) == 0) {
284         fprintf(stderr, "%s: slot %s is ejected.\n", get_pname(), slotstr);
285     } else {
286         fprintf(stderr, "%s: slot %s not ejected: %s\n",
287                 get_pname(), slotstr ? slotstr : "??", changer_resultstr);
288     }
289     amfree(slotstr);
290 }
291
292
293 /* ---------------------------- */
294
295 void
296 load_slot(
297     int         argc,
298     char **     argv)
299 {
300     char *slotstr = NULL, *devicename = NULL;
301     char *errstr;
302     int is_advance;
303
304     if(argc != 2)
305         usage();
306
307     is_advance = (strcmp(argv[1], "advance") == 0);
308     if(changer_loadslot(argv[1], &slotstr, &devicename)) {
309         error("could not load slot %s: %s", slotstr, changer_resultstr);
310         /*NOTREACHED*/
311     }
312     if(! is_advance && (errstr = tape_rewind(devicename)) != NULL) {
313         fprintf(stderr,
314                 "%s: could not rewind %s: %s", get_pname(), devicename, errstr);
315         amfree(errstr);
316     }
317
318     fprintf(stderr, "%s: changed to slot %s", get_pname(), slotstr);
319     if(! is_advance) {
320         fprintf(stderr, " on %s", devicename);
321     }
322     fputc('\n', stderr);
323     amfree(slotstr);
324     amfree(devicename);
325 }
326
327
328 /* ---------------------------- */
329
330 int nslots, backwards, found, got_match, tapedays;
331 char *datestamp;
332 char *label = NULL, *first_match_label = NULL, *first_match = NULL;
333 char *searchlabel, *labelstr;
334 tape_t *tp;
335 static int scan_init(void *ud, int rc, int ns, int bk, int s);
336
337 static int 
338 scan_init(
339     void *      ud,
340     int         rc,
341     int         ns,
342     int         bk,
343     int         s)
344 {
345     (void)ud;   /* Quiet unused parameter warning */
346     (void)s;    /* Quiet unused parameter warning */
347
348     if(rc) {
349         error("could not get changer info: %s", changer_resultstr);
350         /*NOTREACHED*/
351     }
352
353     nslots = ns;
354     backwards = bk;
355
356     return 0;
357 }
358
359 int
360 loadlabel_slot(
361     void *      ud,
362     int         rc,
363     char *      slotstr,
364     char *      device)
365 {
366     char *errstr;
367
368     (void)ud;   /* Quiet unused parameter warning */
369
370     if(rc > 1) {
371         error("could not load slot %s: %s", slotstr, changer_resultstr);
372         /*NOTREACHED*/
373     }
374     else if(rc == 1)
375         fprintf(stderr, "%s: slot %s: %s\n",
376                 get_pname(), slotstr, changer_resultstr);
377     else if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL)
378         fprintf(stderr, "%s: slot %s: %s\n", get_pname(), slotstr, errstr);
379     else {
380         fprintf(stderr, "%s: slot %s: date %-8s label %s",
381                 get_pname(), slotstr, datestamp, label);
382         if(strcmp(label, FAKE_LABEL) != 0
383            && strcmp(label, searchlabel) != 0)
384             fprintf(stderr, " (wrong tape)\n");
385         else {
386             fprintf(stderr, " (exact label match)\n");
387             if((errstr = tape_rewind(device)) != NULL) {
388                 fprintf(stderr,
389                         "%s: could not rewind %s: %s",
390                         get_pname(), device, errstr);
391                 amfree(errstr);
392             }
393             found = 1;
394             amfree(datestamp);
395             amfree(label);
396             return 1;
397         }
398     }
399     amfree(datestamp);
400     amfree(label);
401     return 0;
402 }
403
404 void
405 load_label(
406     int         argc,
407     char **     argv)
408 {
409     if(argc != 2)
410         usage();
411
412     searchlabel = argv[1];
413
414     fprintf(stderr, "%s: scanning for tape with label %s\n",
415             get_pname(), searchlabel);
416
417     found = 0;
418
419     changer_find(NULL, scan_init, loadlabel_slot, searchlabel);
420
421     if(found)
422         fprintf(stderr, "%s: label %s is now loaded.\n",
423                 get_pname(), searchlabel);
424     else
425         fprintf(stderr, "%s: could not find label %s in tape rack.\n",
426                 get_pname(), searchlabel);
427 }
428
429
430 /* ---------------------------- */
431
432 int
433 show_init(
434     void *      ud,
435     int         rc,
436     int         ns,
437     int         bk,
438     int         s)
439 {
440     (void)ud;   /* Quiet unused parameter warning */
441     (void)s;    /* Quiet unused parameter warning */
442
443     if(rc) {
444         error("could not get changer info: %s", changer_resultstr);
445         /*NOTREACHED*/
446     }
447
448     nslots = ns;
449     backwards = bk;
450     return 0;
451 }
452
453 int
454 show_init_all(
455     void *      ud,
456     int         rc,
457     int         ns,
458     int         bk,
459     int         s)
460 {
461     int ret = show_init(NULL, rc, ns, bk, s);
462
463     (void)ud;   /* Quiet unused parameter warning */
464
465     fprintf(stderr, "%s: scanning all %d slots in tape-changer rack:\n",
466             get_pname(), nslots);
467     return ret;
468 }
469
470 int
471 show_init_current(
472     void *      ud,
473     int         rc,
474     int         ns,
475     int         bk,
476     int         s)
477 {
478     int ret = show_init(NULL, rc, ns, bk, s);
479
480     (void)ud;   /* Quiet unused parameter warning */
481
482     fprintf(stderr, "%s: scanning current slot in tape-changer rack:\n",
483             get_pname());
484     return ret;
485 }
486
487 int
488 show_slot(
489     void *      ud,
490     int         rc,
491     char *      slotstr,
492     char *      device)
493 {
494     char *errstr;
495
496     (void)ud;   /* Quiet unused parameter warning */
497
498     if(rc > 1) {
499         error("could not load slot %s: %s", slotstr, changer_resultstr);
500         /*NOTREACHED*/
501     }
502     else if(rc == 1) {
503         fprintf(stderr, "slot %s: %s\n", slotstr, changer_resultstr);
504     }
505     else if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL) {
506         fprintf(stderr, "slot %s: %s\n", slotstr, errstr);
507         amfree(errstr);
508     } else {
509         fprintf(stderr, "slot %s: date %-8s label %s\n",
510                 slotstr, datestamp, label);
511     }
512     amfree(datestamp);
513     amfree(label);
514     return 0;
515 }
516
517 void
518 show_current(
519     int         argc,
520     char **     argv)
521 {
522     (void)argv; /* Quiet unused parameter warning */
523
524     if(argc != 1)
525         usage();
526
527     changer_current(NULL, show_init_current, show_slot);
528 }
529
530 void
531 show_slots(
532     int         argc,
533     char **     argv)
534 {
535     (void)argv; /* Quiet unused parameter warning */
536
537     if(argc != 1)
538         usage();
539
540     changer_find(NULL, show_init_all, show_slot, NULL);
541 }
542
543
544 /* ---------------------------- */
545
546 void
547 amtape_taper_scan(
548     int         argc,
549     char **     argv)
550 {
551     char *device = NULL;
552     char *label = NULL;
553
554     (void)argc; /* Quiet unused parameter warning */
555     (void)argv; /* Quiet unused parameter warning */
556
557     if((tp = lookup_last_reusable_tape(0)) == NULL)
558         searchlabel = NULL;
559     else
560         searchlabel = stralloc(tp->label);
561
562     tapedays    = getconf_int(CNF_TAPECYCLE);
563     labelstr    = getconf_str(CNF_LABELSTR);
564     found = 0;
565     got_match = 0;
566
567     fprintf(stderr, "%s: scanning for ", get_pname());
568     if(searchlabel) fprintf(stderr, "tape label %s or ", searchlabel);
569     fprintf(stderr, "a new tape.\n");
570
571     taper_scan(searchlabel, &label, &datestamp,&device, FILE_taperscan_output_callback, stderr);
572
573     fprintf(stderr, "%s: label %s is now loaded.\n",
574             get_pname(), label);
575
576     amfree(label);
577     amfree(datestamp);
578     amfree(device);
579 }
580
581 /* ---------------------------- */
582
583 void
584 show_device(
585     int         argc,
586     char **     argv)
587 {
588     char *slot = NULL, *device = NULL;
589
590     (void)argc; /* Quiet unused parameter warning */
591     (void)argv; /* Quiet unused parameter warning */
592
593     if(changer_loadslot("current", &slot, &device)) {
594         error("Could not load current slot.\n");
595         /*NOTREACHED*/
596     }
597
598     printf("%s\n", device);
599     amfree(slot);
600     amfree(device);
601 }
602
603 /* ---------------------------- */
604
605 int
606 update_one_slot(
607     void *      ud,
608     int         rc,
609     char *      slotstr,
610     char *      device)
611 {
612     char *errstr = NULL;
613     char *datestamp = NULL;
614     char *label = NULL;
615
616     (void)ud;   /* Quiet unused parameter warning */
617
618     if(rc > 1)
619         error("could not load slot %s: %s", slotstr, changer_resultstr);
620     else if(rc == 1)
621         fprintf(stderr, "slot %s: %s\n", slotstr, changer_resultstr);
622     else if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL)
623         fprintf(stderr, "slot %s: %s\n", slotstr, errstr);
624     else {
625         fprintf(stderr, "slot %s: date %-8s label %s\n",
626                 slotstr, datestamp, label);
627         changer_label(slotstr, label);
628     }
629     amfree(errstr);
630     amfree(datestamp);
631     amfree(label);
632     return 0;
633 }
634
635 void
636 update_labeldb(
637     int         argc,
638     char **     argv)
639 {
640     (void)argv; /* Quiet unused parameter warning */
641
642     if(argc != 1)
643         usage();
644
645     changer_find(NULL, show_init_all, update_one_slot, NULL);
646 }