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