4 static unsigned flags
= 0;
7 static void set_status(int st
)
8 { if (st
> status
) status
= st
; }
9 static void vgripe_syserr(int st
, int err
, const char *fmt
, va_list ap
)
10 { vmoan_syserr(err
, fmt
, ap
); set_status(st
); }
11 static void vgripe(int st
, const char *fmt
, va_list ap
)
12 { vgripe_syserr(st
, 0, fmt
, ap
); }
14 static void gripe_syserr(int st
, int err
, const char *fmt
, ...)
17 va_start(ap
, fmt
); vgripe_syserr(st
, err
, fmt
, ap
); va_end(ap
);
19 PRINTF_LIKE(2, 3) static void gripe(int st
, const char *fmt
, ...)
20 { va_list ap
; va_start(ap
, fmt
); vgripe(st
, fmt
, ap
); va_end(ap
); }
22 static int carefully_read(int fd
, off_t off
,
23 void *p
, size_t sz
, const char *file
)
28 if (lseek(fd
, off
, SEEK_SET
) < 0)
29 { gripe_syserr(2, errno
, "failed to seek in `%s'", file
); return (-1); }
34 { gripe_syserr(2, errno
, "failed to read `%s'", file
); return (-1); }
36 { gripe(2, "unexpected end-of-file reading `%s'", file
); return (-1); }
42 typedef uint_least32_t u32
;
43 #define Pu32 PRIuLEAST32
45 static u32
load32(const unsigned char *p
)
47 return (((u32
)p
[0] << 0) | ((u32
)p
[1] << 8) |
48 ((u32
)p
[2] << 16) | ((u32
)p
[3] << 24));
53 static int check_anchor_header(const unsigned char *b
, secaddr addr
,
54 unsigned f
, const char *file
)
61 gripe(1, "anchor descriptor not found at `%s' sector %"PRIuSEC
"",
66 for (i
= 0, t
= 0; i
< 16; i
++) if (i
!= 4) t
+= b
[i
];
70 gripe(1, "bad anchor descriptor header checksum (%u /= %u) "
71 "at `%s' sector %"PRIuSEC
"", (unsigned)b
[4], t
, file
, addr
);
79 gripe(1, "bad sector number in anchor descriptor "
80 "(%"PRIuSEC
" /= %"PRIuSEC
") in `%s'",
89 static int all_zero_p(const unsigned char *p
, size_t sz
)
98 static void check_img(const char *file
)
101 unsigned char b
[SECTORSZ
], bb
[SECTORSZ
];
107 if (open_dvd(file
, (flags
&F_FIX
) ? O_RDWR
: O_RDONLY
, &fd
, 0))
108 { set_status(2); goto end
; }
109 blksz
= SECTORSZ
; volsz
= device_size(fd
, file
, &blksz
);
110 if (SECTORSZ
!= 2048)
111 { gripe(2, "device sector size %d /= 2048", blksz
); goto end
; }
112 if (volsz
%SECTORSZ
) {
113 gripe(2, "bad length for `%s' -- not whole number of sectors", file
);
116 end
= volsz
/SECTORSZ
;
118 if (carefully_read(fd
, 256*SECTORSZ
, b
, SECTORSZ
, file
) ||
119 check_anchor_header(b
, 256, CAHF_GRIPE
| CAHF_FULL
, file
))
122 for (i
= 1; i
< 32768; i
++) {
123 if (carefully_read(fd
, (off_t
)(end
- i
)*SECTORSZ
, bb
, SECTORSZ
, file
))
125 if (bb
[0] || !all_zero_p(bb
, SECTORSZ
)) goto nonzero
;
127 gripe(1, "too many trailing zero sectors: "
128 "couldn't find backup anchor descriptor in `%s'", file
);
133 if (bb
[0] == 2 && !check_anchor_header(bb
, end
- j
, 0, file
))
137 gripe(1, "failed to find backup anchor descriptor in `%s'", file
);
140 if (carefully_read(fd
, (off_t
)(end
- j
)*SECTORSZ
, bb
, SECTORSZ
, file
))
144 gripe(1, "found backup anchor descriptor at sector %"PRIuSEC
" "
145 " = %"PRIuSEC
" from end, = %"PRIuSEC
" from trailing zeros",
146 end
- j
, j
, j
- i
+ 1);
150 if (check_anchor_header(bb
, end
- i
, CAHF_GRIPE
| CAHF_FULL
, file
))
153 if (MEMCMP(b
+ 16, != , bb
+ 16, SECTORSZ
- 16)) {
154 gripe(1, "backup anchor descriptor in sector %"PRIuSEC
" "
155 "doesn't match primary in sector 256 of `%s'",
162 gripe(1, "%u trailing zero sectors in `%s'", i
- 1, file
);
164 if (ftruncate(fd
, (off_t
)(end
- i
+ 1)*SECTORSZ
))
165 gripe_syserr(2, errno
,
166 "failed to truncate `%s' to %"PRIuSEC
" sectors",
169 moan("removed %u trailing zero sectors from `%s'", i
- 1, file
);
174 if (fd
!= -1) close(fd
);
177 static void usage(FILE *fp
)
178 { fprintf(fp
, "usage: %s [-x] IMG ...\n", prog
); }
180 int main(int argc
, char *argv
[])
188 opt
= getopt(argc
, argv
, "hx"); if (opt
< 0) break;
190 case 'h': usage(stdout
); exit(0);
191 case 'x': flags
|= F_FIX
; break;
192 default: f
|= f_bogus
; break;
195 if (optind
>= argc
) f
|= f_bogus
;
196 if (f
&f_bogus
) { usage(stderr
); exit(2); }
197 setlocale(LC_ALL
, "");
198 progress_init(&progress
);
199 for (i
= optind
; i
< argc
; i
++) check_img(argv
[i
]);
200 progress_free(&progress
);