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