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