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