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