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