b04dcff2732460737404b2c7e831dcc6c8ec90ad
[debian/amanda] / server-src / amlabel.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998, 2000 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: amlabel.c,v 1.53.2.2 2007/02/06 14:07:44 martinea Exp $
28  *
29  * write an Amanda label on a tape
30  */
31 #include "amanda.h"
32 #include "conffile.h"
33 #include "tapefile.h"
34 #include "tapeio.h"
35 #include "changer.h"
36
37 #ifdef HAVE_LIBVTBLC
38 #include <vtblc.h>
39 #endif /* HAVE_LIBVTBLC */
40
41 /* local functions */
42
43 int main(int argc, char **argv);
44 void usage(void);
45
46 void
47 usage(void)
48 {
49     fprintf(stderr, "Usage: %s [-f] <conf> <label> [slot <slot-number>] [-o configoption]*\n",
50             get_pname());
51     exit(1);
52 }
53
54 int
55 main(
56     int         argc,
57     char **     argv)
58 {
59     char *conffile;
60     char *conf_tapelist;
61     char *outslot = NULL;
62     char *errstr = NULL, *label, *oldlabel=NULL, *tapename = NULL;
63     char *labelstr, *slotstr;
64     char *olddatestamp=NULL;
65     char *conf_tapelist_old;
66     unsigned long malloc_hist_1, malloc_size_1;
67     unsigned long malloc_hist_2, malloc_size_2;
68 #ifdef HAVE_LINUX_ZFTAPE_H
69     int fd = -1;
70     int isa_zftape;
71 #endif /* HAVE_LINUX_ZFTAPE_H */
72     int have_changer;
73     int force, tape_ok;
74     tapetype_t *tape;
75     size_t tt_blocksize_kb;
76     int slotcommand;
77     uid_t uid_me;
78     uid_t uid_dumpuser;
79     char *dumpuser;
80     struct passwd *pw;
81     int    new_argc;
82     char **new_argv;
83
84 #ifdef HAVE_LIBVTBLC
85     int vtbl_no      = -1;
86     char *datestr    = NULL;
87     char *rawtapedev = NULL;
88     int first_seg, last_seg;
89 #endif /* HAVE_LIBVTBLC */
90
91     safe_fd(-1, 0);
92     safe_cd();
93
94     set_pname("amlabel");
95
96     dbopen(DBG_SUBDIR_SERVER);
97
98     /* Don't die when child closes pipe */
99     signal(SIGPIPE, SIG_IGN);
100
101     malloc_size_1 = malloc_inuse(&malloc_hist_1);
102
103     erroutput_type = ERR_INTERACTIVE;
104
105     parse_server_conf(argc, argv, &new_argc, &new_argv);
106
107     if(new_argc > 1 && strcmp(new_argv[1],"-f") == 0)
108          force=1;
109     else force=0;
110
111     if(new_argc != 3+force && new_argc != 5+force)
112         usage();
113
114     config_name = new_argv[1+force];
115     label = new_argv[2+force];
116
117     if(new_argc == 5+force) {
118         if(strcmp(new_argv[3+force], "slot"))
119             usage();
120         slotstr = new_argv[4+force];
121         slotcommand = 1;
122     } else {
123         slotstr = "current";
124         slotcommand = 0;
125     }
126
127     config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
128     conffile = stralloc2(config_dir, CONFFILE_NAME);
129     if (read_conffile(conffile)) {
130         error("errors processing config file \"%s\"", conffile);
131         /*NOTREACHED*/
132     }
133
134     dbrename(config_name, DBG_SUBDIR_SERVER);
135
136     report_bad_conf_arg();
137
138     conf_tapelist = getconf_str(CNF_TAPELIST);
139     if (*conf_tapelist == '/') {
140         conf_tapelist = stralloc(conf_tapelist);
141     } else {
142         conf_tapelist = stralloc2(config_dir, conf_tapelist);
143     }
144     if (read_tapelist(conf_tapelist)) {
145         error("could not load tapelist \"%s\"", conf_tapelist);
146         /*NOTREACHED*/
147     }
148
149     uid_me = getuid();
150     uid_dumpuser = uid_me;
151     dumpuser = getconf_str(CNF_DUMPUSER);
152
153     if ((pw = getpwnam(dumpuser)) == NULL) {
154         error("cannot look up dump user \"%s\"", dumpuser);
155         /*NOTREACHED*/
156     }
157     uid_dumpuser = pw->pw_uid;
158     if ((pw = getpwuid(uid_me)) == NULL) {
159         error("cannot look up my own uid %ld", (long)uid_me);
160         /*NOTREACHED*/
161     }
162     if (uid_me != uid_dumpuser) {
163         error("running as user \"%s\" instead of \"%s\"",
164               pw->pw_name, dumpuser);
165         /*NOTREACHED*/
166     }
167
168     labelstr = getconf_str(CNF_LABELSTR);
169
170     if(!match(labelstr, label)) {
171         error("label %s doesn't match labelstr \"%s\"", label, labelstr);
172         /*NOTREACHED*/
173     }
174
175     if((lookup_tapelabel(label))!=NULL) {
176         if(!force) {
177             error("label %s already on a tape\n",label);
178             /*NOTREACHED*/
179         }
180     }
181     tape = lookup_tapetype(getconf_str(CNF_TAPETYPE));
182     tt_blocksize_kb = (size_t)tapetype_get_blocksize(tape);
183
184     if((have_changer = changer_init()) == 0) {
185         if(slotcommand) {
186             fprintf(stderr,
187              "%s: no tpchanger specified in \"%s\", so slot command invalid\n",
188                     new_argv[0], conffile);
189             usage();
190         }
191         tapename = getconf_str(CNF_TAPEDEV);
192         if (tapename == NULL) {
193             error("No tapedev specified");
194         } else {
195             tapename = stralloc(tapename);
196         }
197 #ifdef HAVE_LIBVTBLC
198         rawtapedev = stralloc(getconf_str(CNF_RAWTAPEDEV));
199 #endif /* HAVE_LIBVTBLC */
200     } else if(have_changer != 1) {
201         error("changer initialization failed: %s", strerror(errno));
202         /*NOTREACHED*/
203     } else {
204         if(changer_loadslot(slotstr, &outslot, &tapename)) {
205             error("could not load slot \"%s\": %s", slotstr, changer_resultstr);
206             /*NOTREACHED*/
207         }
208
209         printf("labeling tape in slot %s (%s):\n", outslot, tapename);
210     }
211
212 #ifdef HAVE_LINUX_ZFTAPE_H
213     isa_zftape = is_zftape(tapename);
214     if (isa_zftape) {
215         if((fd = tape_open(tapename, O_WRONLY)) == -1) {
216             errstr = newstralloc2(errstr, "amlabel: ",
217                                   (errno == EACCES) ? "tape is write-protected"
218                                   : strerror(errno));
219             error(errstr);
220             /*NOTREACHED*/
221         }
222     }
223 #endif /* HAVE_LINUX_ZFTAPE_H */
224
225     printf("rewinding"); fflush(stdout);
226
227 #ifdef HAVE_LINUX_ZFTAPE_H
228     if (isa_zftape) {
229         if(tapefd_rewind(fd) == -1) {
230             putchar('\n');
231             error(strerror(errno));
232             /*NOTREACHED*/
233         }
234     }
235     else
236 #endif /* HAVE_LINUX_ZFTAPE_H */
237     if((errstr = tape_rewind(tapename)) != NULL) {
238         putchar('\n');
239         error(errstr);
240         /*NOTREACHED*/
241     }
242
243     tape_ok=1;
244     printf(", reading label");fflush(stdout);
245     if((errstr = tape_rdlabel(tapename, &olddatestamp, &oldlabel)) != NULL) {
246         printf(", %s\n",errstr);
247         tape_ok=1;
248     }
249     else {
250         /* got an amanda tape */
251         printf(" %s",oldlabel);
252         if(strcmp(oldlabel, FAKE_LABEL) != 0
253            && match(labelstr, oldlabel) == 0) {
254             printf(", tape is in another amanda configuration");
255             if(!force)
256                 tape_ok=0;
257         }
258         else {
259             if((lookup_tapelabel(oldlabel)) != NULL) {
260                 printf(", tape is active");
261                 if(!force)
262                     tape_ok=0;
263             }
264         }
265         printf("\n");
266     }
267     amfree(oldlabel);
268     amfree(olddatestamp);
269         
270     printf("rewinding"); fflush(stdout);
271
272 #ifdef HAVE_LINUX_ZFTAPE_H
273     if (isa_zftape) {
274         if(tapefd_rewind(fd) == -1) {
275             putchar('\n');
276             error(strerror(errno));
277             /*NOTREACHED*/
278         }
279     }
280     else
281 #endif /* HAVE_LINUX_ZFTAPE_H */
282     if((errstr = tape_rewind(tapename)) != NULL) {
283         putchar('\n');
284         error(errstr);
285         /*NOTREACHED*/
286     }
287
288     if(tape_ok) {
289         printf(", writing label %s", label); fflush(stdout);
290
291 #ifdef HAVE_LINUX_ZFTAPE_H
292         if (isa_zftape) {
293             errstr = tapefd_wrlabel(fd, "X", label,
294                                     (tt_blocksize_kb * 1024));
295             if(errstr != NULL) {
296                 putchar('\n');
297                 error(errstr);
298                 /*NOTREACHED*/
299             }
300         }
301         else
302 #endif /* HAVE_LINUX_ZFTAPE_H */
303         errstr = tape_wrlabel(tapename, "X", label,
304                               (tt_blocksize_kb * 1024));
305         if(errstr != NULL) {
306             putchar('\n');
307             error(errstr);
308             /*NOTREACHED*/
309         }
310
311 #ifdef HAVE_LINUX_ZFTAPE_H
312         if (isa_zftape) {
313             tapefd_weof(fd, (off_t)1);
314         }
315 #endif /* HAVE_LINUX_ZFTAPE_H */
316
317 #ifdef HAVE_LINUX_ZFTAPE_H
318         if (isa_zftape) {
319             errstr = tapefd_wrendmark(fd, "X",
320                                       (tt_blocksize_kb * 1024));
321             if(errstr != NULL) {
322                 putchar('\n');
323                 error(errstr);
324                 /*NOTREACHED*/
325             }
326         }
327         else
328 #endif /* HAVE_LINUX_ZFTAPE_H */
329         errstr = tape_wrendmark(tapename, "X",
330                                 (tt_blocksize_kb * 1024));
331         if(errstr != NULL) {
332             putchar('\n');
333             error(errstr);
334             /*NOTREACHED*/
335         }
336
337 #ifdef HAVE_LINUX_ZFTAPE_H
338         if (isa_zftape) {
339             tapefd_weof(fd, (off_t)1);
340
341             printf(",\nrewinding"); fflush(stdout); 
342      
343             if(tapefd_rewind(fd) == -1) { 
344                 putchar('\n'); 
345                 error(strerror(errno)); 
346                 /*NOTREACHED*/
347             } 
348             close(fd);
349 #ifdef HAVE_LIBVTBLC
350             /* update volume table */
351             printf(", updating volume table"); fflush(stdout);
352     
353             if ((fd = raw_tape_open(rawtapedev, O_RDWR)) == -1) {
354                 if(errno == EACCES) {
355                     errstr = newstralloc(errstr,
356                                          "updating volume table: raw tape device is write protected");
357                 } else {
358                     errstr = newstralloc2(errstr,
359                                           "updating volume table: ", strerror(errno));
360                 }
361                 putchar('\n');
362                 error(errstr);
363                 /*NOTREACHED*/
364             }
365             /* read volume table */
366             if ((num_volumes = read_vtbl(fd, volumes, vtbl_buffer,
367                                          &first_seg, &last_seg)) == -1 ) {
368                 errstr = newstralloc2(errstr,
369                                       "reading volume table: ", strerror(errno));
370                 putchar('\n');
371                 error(errstr);
372                 /*NOTREACHED*/
373             }
374             /* set date and volume label for first entry */
375             vtbl_no = 0;
376             datestr = NULL; 
377             if (set_date(datestr, volumes, num_volumes, vtbl_no)){
378                 errstr = newstralloc2(errstr,
379                                       "setting date for entry 1: ", strerror(errno));
380                 putchar('\n');
381                 error(errstr);
382                 /*NOTREACHED*/
383             }
384             if(set_label(label, volumes, num_volumes, vtbl_no)){
385                 errstr = newstralloc2(errstr,
386                                       "setting label for entry 1: ", strerror(errno));
387                 putchar('\n');
388                 error(errstr);
389                 /*NOTREACHED*/
390             }
391             /* set date and volume label for last entry */
392             vtbl_no = 1;
393             datestr = NULL; 
394             if (set_date(datestr, volumes, num_volumes, vtbl_no)){
395                 errstr = newstralloc2(errstr,
396                                       "setting date for entry 2: ", strerror(errno));
397                 putchar('\n');
398                 error(errstr);
399                 /*NOTREACHED*/
400             }
401             if(set_label("AMANDA Tape End", volumes, num_volumes, vtbl_no)){
402                 errstr = newstralloc2(errstr,
403                                       "setting label for entry 2: ", strerror(errno));
404                 putchar('\n');
405                 error(errstr);
406                 /*NOTREACHED*/
407             }
408             /* write volume table back */
409             if (write_vtbl(fd, volumes, vtbl_buffer, num_volumes, first_seg,
410                            op_mode == trunc)) {
411                 errstr = newstralloc2(errstr,
412                                       "writing volume table: ", strerror(errno));
413                 putchar('\n');
414                 error(errstr);
415                 /*NOTREACHED*/
416             }  
417             close(fd);
418 #endif /* HAVE_LIBVTBLC */
419         }
420 #endif /* HAVE_LINUX_ZFTAPE_H */
421
422         if (tape_ok) {
423             printf(", checking label"); fflush(stdout);
424
425             if((errstr = tape_rdlabel(tapename, &olddatestamp, &oldlabel)) != NULL) {
426                 putchar('\n');
427                 if (strcmp(errstr, "not an amanda tape") != 0) {
428                     error(errstr);
429                     /*NOTREACHED*/
430                 }
431                 error("no label found, are you sure %s is non-rewinding?",
432                       tapename);
433                 /*NOTREACHED*/
434             }
435
436             if (strcmp("X", olddatestamp) != 0 ||
437                 (strcmp(oldlabel, FAKE_LABEL) != 0
438                  && strcmp(label, oldlabel) != 0)) {
439                 putchar('\n');
440                 error("read label %s back, timestamp %s (expected X), what now?",
441                       oldlabel, olddatestamp);
442                 /*NOTREACHED*/
443             }
444             amfree(oldlabel);
445             amfree(olddatestamp);
446
447             /* write tape list */
448
449             /* make a copy */
450             conf_tapelist_old = stralloc2(conf_tapelist, ".amlabel");
451             if(write_tapelist(conf_tapelist_old)) {
452                 error("couldn't write tapelist: %s", strerror(errno));
453                 /*NOTREACHED*/
454             }
455             amfree(conf_tapelist_old);
456
457             /* XXX add cur_tape number to tape list structure */
458             remove_tapelabel(label);
459             add_tapelabel("0", label);
460             if(write_tapelist(conf_tapelist)) {
461                 error("couldn't write tapelist: %s", strerror(errno));
462                 /*NOTREACHED*/
463             }
464
465             if (have_changer) {
466                 changer_label(outslot, label);
467             }
468         } /* write tape list */
469         printf(", done.\n");
470     } else {
471         printf("\ntape not labeled\n");
472     }
473
474     clear_tapelist();
475     free_new_argv(new_argc, new_argv);
476     free_server_config();
477     amfree(outslot);
478     amfree(tapename);
479     amfree(conffile);
480     amfree(conf_tapelist);
481     amfree(config_dir);
482     config_name=NULL;
483     dbclose();
484
485     malloc_size_2 = malloc_inuse(&malloc_hist_2);
486
487     if(malloc_size_1 != malloc_size_2) {
488         malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
489     }
490
491     return 0;
492 }