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