2
* growisofs 5.19 by Andy Polyakov <appro@fy.chalmers.se>.
4
* Use-it-on-your-own-risk, GPL bless...
6
* This front-end to mkisofs(8) was originally developed to facilitate
7
* appending of data to ISO9660 volumes residing on random write access
8
* DVD media such as DVD+RW, DVD-RAM, as well as plain files/iso images.
9
* At later stages even support for multi-session recording to DVD
10
* write-once media such as DVD+R and DVD-R was added.
12
* As for growing random access volumes. The idea is very simple. The
13
* program appends new data as it was added to a multisession media and
14
* then copies the new volume descriptor(s) to the beginning of media
15
* thus effectively updating the root catalog reference...
17
* For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/.
22
* - flush cache before copying volume descriptors;
24
* - support for /dev/raw*;
25
* - support for set-root-uid operation (needed for /dev/raw*);
26
* - support for first "session" burning (needed for "poor-man");
27
* - "poor-man" support for those who don't want to recompile the
32
* - uninitialized in_device variable;
35
* - support for DVD+R;
37
* - -Z fails if a file system is present and stdin is not a tty;
39
* - support for image burning (needed for DVD+R as you can't use dd);
41
* - 'growisofs -Z /dev/scdN image.iso' is too confusing, implement
42
* 'growisofs -Z /dev/scdN=image.iso' instead;
44
* - transport C++-fication for better portability;
45
* - support for -dvd-compat option (improved DVD+R/RW compatibility);
46
* - -dvd-video implies -dvd-compat;
47
* - support for SONY DRU-500A;
48
* - progress indicator for -Z /dev/scdN=image.iso;
49
* - agressive -poor-man-ing;
51
* - uninitialized errno at exit from -Z /dev/scdN=image.iso;
53
* - don't print initial bogus progress indicator values;
54
* - apparently some firmwares exhibit ambiguity in DVD+R disc
57
* - enforced 32K write strategy (needed for DVD-R[W]);
58
* - support for DVD-RW Restricted Overwrite Mode;
59
* - support for DVD-R[W] Sequential Mode;
61
* - support for writing speed control;
63
* - re-make it work under Linux 2.2 kernel;
64
* - progress indicator to display recording velocity;
65
* - code to protect against overburns;
66
* - undocumented -use-the-force-luke flag to overwrite the media
68
* - brown-bag bug in "LONG WRITE IN PROGRESS" handling code fixed;
70
* - Pioneer workarounds/fix-ups, most notably DVR-x05 doesn't seem
71
* to digest immediate "SYNC CACHE";
72
* - support for DVD-RW Quick Format, upon release verified to work
73
* with Pioneer DVR-x05;
74
* - bug in DVD+RW overburn "protection" code fixed;
75
* - media reload is moved here from dvd+rw-format;
76
* - refuse to burn if session starts close to or beyond 4GB limit
77
* (limitation of Linux isofs implementation);
78
* - dry_run check is postponed all the way till the first write;
80
* - split first write to two to avoid "empty DMA table?" in kernel log;
81
* - setup_fds is introduced to assist ports to another platforms;
82
* - set-root-uid assistant code directly at entry point (see main());
83
* - OpenBSD/NetBSD support added, it's worth noting that unlike 3.3
84
* port by Maarten Hofman, it's /dev/rcd?c which is expected to be
85
* passed as argument, not /dev/cd?c.
87
* - fix for ENOENT at unmount, I should have called myself with execlp,
89
* - security: chdir("/") in set-root-uid assistant;
90
* - use /proc/mounts instead of MOUNTED (a.k.a. /etc/mtab) in Linux
93
* - unconditional exit in set-root-uid assistant, mostly for aesthetic
95
* - support for DVD-RW DAO recordings (whenever Pioneer-ish Quick
96
* Format is not an option, DAO should fill in for it, as it's the
97
* only recording strategy applicable after *minimal* blanking
99
* - support for SG_IO pass-through interface, or in other words
100
* support for Linux 2>=5;
101
* - 'growisofs -M /dev/cdrom=/dev/zero', this is basically a counter-
102
* intuitive kludge assigned to fill up multi-session write-once
103
* media for better compatibility with DVD-ROM/-Video units, to keep
104
* it mountable [in the burner unit] volume descriptors from previous
105
* session are copied to the new session;
106
* - disable -dvd-compat with -M option and DVD+R, advice to fill up
107
* the media as above instead;
108
* - postpone Write Page setup all the way till after dry_run check;
109
* - if recording to write-once media is terminated by external event,
110
* leave the session opened, so that the recording can be resumed
111
* (though no promises about final results are made, it's just that
112
* leaving it open makes more sense than to close the session);
113
* - ask unit to perform OPC if READ DISC INFORMATION doesn't return
114
* any OPC descriptors;
115
* - get rid of redundant Quick Grow in Restricted Overwrite;
116
* - Solaris 2.x support is merged, it's volume manager aware, i.e.
117
* you can run it with or without volume manager;
119
* - Solaris USB workaround;
120
* - 15 min timeout for FLUSH CACHE in DVD-RW DAO;
121
* - revalidate recording speed;
122
* - load media upon start-up (Linux used to auto-close tray upon open,
123
* but not the others, which is why this functionality is added so
126
* - elder Ricoh firmwares seem to report events differently, which
127
* triggered growisofs and dvd+rw-format to end-less loop at startup
128
* [event handling was introduced in 5.6 for debugging purposes];
129
* - int ioctl_fd is transformed to void *ioctl_handle to facilitate
131
* - FreeBSD support contributed by Matthew Dillon;
132
* - volume descriptors from second session were discarded in
133
* Restricted Overwrite since 5.6;
135
* - some [SONY] firmwares make it impossible to tell apart minimally
136
* and fully blanked media, so we need a way to engage DAO manually
137
* [in DVD-RW]... let's treat multiple -dvd-compat options as "cry"
139
* - refuse to finalize even DVD-R media with -M flag (advise to fill
140
* it up with -M /dev/cdrom=/dev/zero too), apparently DVD-units
141
* [or is it just SONY?] also "misplace" legacy lead-out in the same
142
* manner as DVD+units;
143
* - oops! DAO hung at >4MB buffer because of sign overflow;
144
* - couple of human-readable error messages in poor_mans_pwrite64;
145
* - work around Plextor firmware deficiency which [also] manifests as
146
* end-less loop upon startup;
148
* - increase timeout for OPC, NEC multi-format derivatives might
149
* require more time to fulfill the OPC procedure;
150
* - extended syntax for -use-the-force-luke option, it's now possible
151
* to engage DVD-R[W] dummy mode by -use-the-force-luke=[tty,]dummy
152
* for example, where "tty" substitutes for the original non-extended
153
* option meaning, see the source for more easter eggs;
154
* - FreeBSD: compile-time option to pass -M /dev/fd/0 to mkisofs to
155
* make life easier for those who mount devfs, but not fdescfs;
156
* - eliminate potential race conditions;
157
* - avoid end-less loop if no media was in upon tray load;
158
* - interpret value of MKISOFS environment variable as absolute path
160
* - to facilitate for GUI front-ends return different exit codes, most
161
* notably exit value of 128|errno denotes a fatal error upon program
162
* startup [messages worth popping up in a separate modal dialog
163
* perhaps?], errno - fatal error during recording and 1 - warnings
165
* - to facilitate for GUI front-ends auto-format blank DVD+RW media;
166
* - Linux: fix for failure to copy volume descriptors when DVD-RW
167
* Restricted Overwrite procedure is applied to patched kernel;
168
* - FreeBSD: growisofs didn't close tray upon startup nor did the rest
169
* of the tools work with open tray;
170
* - bark at -o option and terminate execution, the "problem" was that
171
* users seem to misspell -overburn once in a while, in which case it
172
* was passed down to mkisofs and an iso-image was dumped to current
173
* working directory instead of media;
174
* - generalize -M /dev/cdrom=file.iso option, but if file.iso is not
175
* /dev/zero, insist on sane -C argument to be passed prior -M and
176
* double-verify the track starting address;
178
* - authorship statement in -version output;
179
* - make speed_factor floating point and print "Current Write Speed"
180
* factor for informational purposes;
181
* - Pioneer DVR-x06 exhibited degraded performance when recording DVD+;
182
* - Pioneer DVR-x06 failed to complete DVD+ recording gracefully;
183
* - alter set-root-uid behaviour under Linux from "PAM-junky" to more
186
* - single Pioneer DVR-x06 user reported that very small fraction of
187
* his recordings get terminted with "LONG WRITE IN PROGRESS," even
188
* though growisofs explicitly reserves for this condition... It
189
* turned out that at those rare occasions unit reported a lot of free
190
* buffer space, which growisofs treated as error condition. It's not
191
* clear if it's firmware deficiency, but growisofs reserves even for
192
* this apparently rare condition now.
193
* - [major] issue with MODE SENSE/SELECT on SANYO derivatives, such as
194
* Optorite, is addressed;
195
* - Linux can't open(2) a socket by /dev/fd/N, replace it with dup(2);
196
* - more relaxed command line option parsing and simultaneously a
197
* zealous check to make sure that no mkisofs options are passed
198
* along with -[ZM] /dev/cdrom=image;
199
* - report I/O error if input stream was less than 64K;
200
* - -M /dev/cdrom=/dev/zero didn't relocate the lead-out in DVD-RW
201
* Restricted Overwrite;
203
* - workarounds for Panasonic/MATSUSHITA DVD-RAM LF-D310;
204
* - Solaris: media load upon start-up;
206
* - LG GSA-4040B failed to auto-format DVD+RW blanks;
207
* - '| growisofs -Z /dev/cdrom=/dev/fd/0' failed with "already carries
208
* isofs" even when running interactively, so I check on /dev/tty
209
* instead of isatty(0);
210
* - error output was confusing when overburn condition was raised in
212
* - more sane default drain buffer size to minimize system load when
213
* unit fails to return usable buffer utilization statistics under
214
* "LONG WRITE IN PROGRESS" condition;
215
* - progress indicator process was orphaned if -Z /dev/cdrom=file.iso
216
* terminated prematurely;
217
* - -overburn -Z /dev/cdrom=file.iso printed two "ignored" messages;
218
* - Solaris: use large-file API in setup_fds;
219
* - HP-UX: HP-UX support is contributed by HP;
220
* - block signals in the beginning of recording, formally it shouldn't
221
* be necessary, but is apparently needed for some units (is it?);
222
* - prepare code for -speed even in DVD+ context, need a test-case...
223
* - TEAC DV-W50D and Lite-On LDW-811S failed to set recording velocity,
224
* deploy GET PERFORMANCE/SET STREAMING commands;
225
* - Lite-On LDW-811S returns 0s in Write Speed descriptors in page 2A,
226
* this would cause a problem if DVD+ speed control was implemented;
228
* - confusing output when DAO mode is manually engaged and DVD-RW media
229
* is minimally blanked;
230
* - complement -use-the-force-luke=dao[:size] to arrange for piping
231
* non-iso images in DAO mode (size is to be expressed in 2KB chunks);
232
* - Pioneer DVR-x06 apparently needs larger timeout to avoid "the LUN
233
* appears to be stuck" message in the beginning of DAO recording;
234
* - HP-UX: fix-up umount code;
235
* - HP-UX: make sure user doesn't pass /dev/rscsi/cXtYlZ, they should
236
* stick to /dev/rdsk/cXtYdZ;
237
* - implement -use-the-force-luke=seek:N -Z /dev/dvd=image to arrange
238
* for 'builtin_dd if=image of=/dev/dvd obs=32k seek=N/16' (note that
239
* N is expected to be expressed in 2KB chunks);
240
* - skip overwrite check for blank media to avoid read errors at start,
241
* which reportedly may cause bus reset in some configurations;
242
* - make get_mmc_profile load media, explicit media load used to be on
243
* per platform basis, while it doesn't have to;
244
* - postpone handle_events till after dry-run checkpoint;
245
* - error reporting revised;
246
* - Optorite seems to insist on resuming suspended DVD+RW format, at
247
* least it's apparently the only way to get *reliable* results
248
* (formally this contradicts specification, which explicitly states
249
* that format is to be resumed automatically and transparently);
250
* - FreeBSD: FreeBSD 5-CURRENT since 2003-08-24, including 5.2 fails
251
* to pull sense data automatically, at least for ATAPI transport,
252
* so I reach for it myself (it's apparently a kernel bug, which
253
* eventually will be fixed, but I keep the workaround code just in
255
* - -speed option in DVD+ context is enabled, upon release tested with
257
* - make builtin_dd print amount of transferred data, together with
258
* -use-the-force-luke=seek:N it's easier to maintain "tar-formatted"
261
* - brown-bag bug in "LONG WRITE IN PROGRESS" code path;
263
* - Linux: fix for /proc/sys/dev/cdrom/check_media set to 1;
264
* - HP-UX: INQUIRY buffer is required to be 128 bytes. Well, "required"
265
* is wrong word in this context, as it's apparently a kernel bug
266
* addressed in PHKL_30038 (HPUX 11.11) and PHKL_30039 (HPUX 11.23).
267
* This "change" affects all dvd+rw-tools, but I don't bump their
268
* version numbers for this, as it's an "ugly" workaround for an
269
* *external* problem;
270
* - switch to GET PERFORMANCE even for current write speed (most
271
* notably required for NEC and derivatives);
272
* - the above change required adaptations for Pioneer and LG units,
273
* which don't/fail to provide current write speed through GET
274
* PERFORMANCE despite the fact that the command is mandatory;
275
* - HP-UX: retain root privileges in setup_fds, SIOC_IO requires them;
276
* - fix for COMMAND SEQUENCE ERROR in the beginning of DVD-recording;
277
* - drop privileges prior mkisofs -version;
279
* - refuse to run if ${SUDO_COMMAND} is set;
280
* - minimize amount of compiler warnings on 64-bit platforms;
281
* - skip count-down if no_tty_check is set;
282
* - -use-the-force-luke=tracksize:size option by suggestion from K3b;
283
* - Linux: fix for "Bad file descriptor" with DVD+RW kernel patch;
285
* - IRIX: IRIX 6.x port is added;
286
* - Solaris: get rid of media reload, which made it possible to improve
287
* volume manager experience as well;
288
* - address speed verification issues with NEC ND-2500 and Plextor
290
* - make DVD-RAM work in "poor-man" mode;
291
* - average write speed report at the end of recording;
292
* - LG GSA-4081B fails to "SET STREAMING" with "LBA OUT OF RANGE" for
293
* DVD+RW media, but not e.g. DVD-R;
295
#define PRINT_VERSION(cmd) do { \
296
char *s=strrchr((cmd),'/'); \
297
s ? s++ : (s=(cmd)); \
298
printf ("* %.*sgrowisofs by <appro@fy.chalmers.se>,"\
299
" version 5.19,\n",(int)(s-(cmd)),(cmd)); \
302
#define _LARGEFILE_SOURCE
303
#define _LARGEFILE64_SOURCE
304
#define _FILE_OFFSET_BITS 64
306
/* ... and "engage" glibc large file support */
310
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
311
#define off64_t off_t
313
#define fstat64 fstat
315
#define pread64 pread
316
#define pwrite64 pwrite
317
#define lseek64 lseek
326
#include <sys/types.h>
327
#include <sys/stat.h>
329
#include <sys/wait.h>
330
#include <sys/mman.h>
334
#include <sys/time.h>
336
#define FATAL_START(err) (0x80|(err))
338
#define EMEDIUMTYPE EINVAL
341
#define ENOMEDIUM ENODEV
344
typedef ssize_t (*pwrite64_t)(int,const void *,size_t,off64_t);
346
* Symbols from growisofs_mmc.cpp
349
* These might terminate the program if error appears fatal.
350
* The return value is therefore is always sane and suitable
353
int get_mmc_profile (void *fd);
354
int plusminus_r_C_parm (void *fd,char *C_parm);
355
pwrite64_t poor_mans_setup (void *fd,off64_t leadout);
357
* These never terminate the program.
358
* Pay attention to the return value.
360
int media_reload (char *file,struct stat *ref);
361
int fumount (int fd);
362
off64_t get_capacity (void *fd);
363
int poor_man_rewritable (void *fd,void *buf);
366
struct iso_primary_descriptor {
367
unsigned char type [1];
368
unsigned char id [5];
369
unsigned char void1 [80-5-1];
370
unsigned char volume_space_size [8];
371
unsigned char void2 [2048-80-8];
374
#define CD_BLOCK ((off64_t)2048)
375
#define VOLDESC_OFF 16
376
#define DVD_BLOCK (32*1024)
378
static unsigned int from_733 (unsigned char *s)
379
{ unsigned int ret=0;
387
static void to_733 (unsigned char *s,unsigned int val)
388
{ s[0] = (val) & 0xFF;
389
s[1] = (val>>8) & 0xFF;
390
s[2] = (val>>16) & 0xFF;
391
s[3] = (val>>24) & 0xFF;
392
s[4] = (val>>24) & 0xFF;
393
s[5] = (val>>16) & 0xFF;
394
s[6] = (val>>8) & 0xFF;
398
static pwrite64_t pwrite64_method = pwrite64;
400
* Page-aligned 2*DVD_BLOCK=64KB large buffer, second 32KB contain
401
* "next" session volume descriptors that were written in the beginning
402
* of current recording...
404
static char *the_buffer;
406
* id_fd is passed to mkisofs, out_fd - to pwrite and ioctl_fd - to ioctl.
408
static int in_fd=-1,out_fd=-1;
410
#ifndef INVALID_HANDLE
411
#define INVALID_HANDLE ((void *)-1)
413
static void *ioctl_handle=INVALID_HANDLE;
414
#define ioctl_fd ((long)ioctl_handle)
416
static int poor_man=-1, zero_image=0, quiet=1,
417
overburn=0, no_tty_check=0, dry_run=0, dao_size=0;
419
int dvd_compat=0, test_write=0, no_reload=0, mmc_profile=0;
420
double speed_factor=0.0;
427
#include <linux/cdrom.h>
428
#include <sys/ioctl.h>
429
#include <linux/raw.h>
431
char *find_raw_device(struct stat64 *sb)
432
{ int i,rawctl,dev_major,dev_minor;
434
struct raw_config_request req;
435
static char rawdevname[24] = "";
437
if (!S_ISBLK(sb->st_mode)) return NULL;
439
dev_major = major (sb->st_rdev);
440
dev_minor = minor (sb->st_rdev);
442
if ((rawctl=open ("/dev/rawctl",O_RDONLY)) < 0) return NULL;
446
if (ioctl(rawctl,RAW_GETBIND,&req) < 0) break;
447
if (req.block_major == dev_major && req.block_minor == dev_minor)
448
{ sprintf (rawdevname,"/dev/raw/raw%d",i);
458
char *setup_fds (char *device)
464
* I ignore return values from set{re}uid calls because if
465
* they fail we have no privileges to care about and should
466
* just proceed anyway...
471
* Get real, but preserve saved uid. I count that user is
472
* logged on console and therefore owns the 'device' [this
473
* is a PAM's resposibility to arrange].
475
setreuid ((uid_t)-1,uid);
478
* More "traditional" set-root-uid behaviour. I assume that if
479
* administrator has installed growisofs set-root-uid, then
480
* [s]he consciously wanted to grant access to /dev/scdN to
481
* everybody, not just console user.
485
if ((in_fd = open64 (device,O_RDONLY)) < 0)
486
if (!(errno == ENOMEDIUM || errno == EMEDIUMTYPE) ||
487
(in_fd = open64 (device,O_RDONLY|O_NONBLOCK)) < 0)
488
fprintf (stderr,":-( unable to open64(\"%s\",O_RDONLY): ",device),
489
perror (NULL), exit (FATAL_START(errno));
492
setreuid ((uid_t)-1,uid);
495
if (fstat64(in_fd,&sb) < 0)
496
fprintf (stderr,":-( unable to stat64(\"%s\"): ",device),
497
perror (NULL), exit (FATAL_START(errno));
499
if (!S_ISBLK(sb.st_mode))
500
{ setuid(uid); /* drop all privileges */
501
close (in_fd); /* reopen as mortal */
502
if ((in_fd = open64 (device,O_RDONLY)) < 0)
503
fprintf (stderr,":-( unable to re-open64(\"%s\",O_RDONLY): ",
505
perror (NULL), exit (FATAL_START(errno));
507
if ((out_fd = open64 (device,O_RDWR)) < 0)
508
fprintf (stderr,":-( unable to open64(\"%s\",O_RDWR): ",device),
509
perror (NULL), exit (FATAL_START(errno));
510
if (fstat64(out_fd,&sc) < 0)
511
fprintf (stderr,":-( unable to stat64(\"%s\"): ",device),
512
perror (NULL), exit (FATAL_START(errno));
513
if (sb.st_dev!=sc.st_dev || sb.st_ino!=sc.st_ino)
514
fprintf (stderr,":-( %s: race condition detected!\n",device),
515
exit(FATAL_START(EPERM));
518
if (ioctl_handle!=INVALID_HANDLE)
519
close (ioctl_fd), ioctl_handle = INVALID_HANDLE;
520
setuid (uid); /* drop all privileges */
524
ioctl_handle=(void *)(long)dup(in_fd);
527
* get_mmc_profile terminates the program if ioctl_handle is
530
mmc_profile = get_mmc_profile (ioctl_handle);
532
/* Consume media_changed flag */
533
if (ioctl (ioctl_fd,CDROM_MEDIA_CHANGED,CDSL_CURRENT) < 0)
534
{ fprintf (stderr,":-( %s: CD_ROM_MEDIA_CHANGED ioctl failed: ",
536
perror (NULL), exit (FATAL_START(errno));
539
switch (mmc_profile&0xFFFF)
540
{ case 0x11: /* DVD-R */
541
case 0x13: /* DVD-RW Restricted Overwrite */
542
case 0x14: /* DVD-RW Sequential */
543
case 0x1B: /* DVD+R */
547
setuid (uid); /* drop all privileges */
548
return ioctl_device=device;
549
case 0x1A: /* DVD+RW */
550
case 0x12: /* DVD-RAM */
551
if (poor_man>0) goto open_poor_man;
554
fprintf (stderr,":-( %s: media is not recognized as "
555
"recordable DVD: %X\n",device,mmc_profile);
556
exit (FATAL_START(EMEDIUMTYPE));
560
* Attempt to locate /dev/raw/raw*
564
setreuid((uid_t)-1,0); /* get root for a /dev/raw sake */
566
if ((odevice=find_raw_device (&sb))) /* /dev/raw */
567
{ if ((out_fd=open64 (odevice,O_RDWR)) < 0)
568
{ if (errno == EROFS) /* must be unpatched kernel */
571
fprintf (stderr,":-( unable to open64(\"%s\",O_RDWR): ",
573
perror (NULL), exit (FATAL_START(errno));
578
if ((mmc_profile&0xFFFF) == 0x12) goto open_rw; /* DVD-RAM */
579
else goto open_poor_man;
582
#elif defined(__OpenBSD__) || defined(__NetBSD__)
584
char *setup_fds (char *device)
585
{ uid_t uid=getuid();
589
* We might be entering as euid=root!
591
if ((in_fd = open (device,O_RDONLY)) < 0)
592
fprintf (stderr,":-( unable to open(\"%s\",O_RDONLY): ",device),
593
perror (NULL), exit (FATAL_START(errno));
595
if (fstat (in_fd,&sb) < 0)
596
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
597
perror (NULL), exit (FATAL_START(errno));
599
if (!S_ISCHR(sb.st_mode))
600
{ if (S_ISBLK(sb.st_mode) && !strncmp (device,"/dev/cd",7))
601
{ fprintf (stderr,":-) you most likely want to use /dev/r%s instead!\n",
603
if (isatty(0) && !dry_run) poll(NULL,0,5000);
605
setuid(uid); /* drop all privileges */
606
close (in_fd); /* reopen as mortal */
607
if ((in_fd = open (device,O_RDONLY)) < 0)
608
fprintf (stderr,":-( unable to reopen(\"%s\",O_RDONLY): ",device),
609
perror (NULL), exit (FATAL_START(errno));
611
if ((out_fd = open (device,O_RDWR)) < 0)
612
fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",device),
613
perror (NULL), exit (FATAL_START(errno));
617
ioctl_handle = INVALID_HANDLE;
618
setuid (uid); /* drop all privileges */
623
* Still as euid=root! But note that get_mmc_profile makes sure it's
624
* an MMC device, as it terminates the program if the unit doesn't
625
* reply to GET CONFIGURATON. In combination with following switch
626
* this means that if installed set-root-uid, growisofs grants
627
* access to DVD burner(s), but not to any other device.
629
ioctl_handle = (void *)(long)open (device,O_RDWR); /* O_RDWR is a must for SCIOCCOMMAND */
630
if (ioctl_handle == INVALID_HANDLE)
631
{ fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",device),
634
fprintf (stderr," is its block counterpart mounted?\n");
635
exit (FATAL_START(errno));
637
if (fstat(ioctl_fd,&sc) < 0)
638
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
639
perror (NULL), exit (FATAL_START(errno));
640
if (sb.st_dev!=sc.st_dev || sb.st_ino!=sc.st_ino)
641
fprintf (stderr,":-( %s: race condition detected!\n",device),
642
exit(FATAL_START(EPERM));
644
mmc_profile = get_mmc_profile (ioctl_handle);
645
switch (mmc_profile&0xFFFF)
646
{ case 0x11: /* DVD-R */
647
case 0x13: /* DVD-RW Restricted Overwrite */
648
case 0x14: /* DVD-RW Sequential */
649
case 0x1B: /* DVD+R */
650
case 0x1A: /* DVD+RW */
653
out_fd = dup(ioctl_fd);
654
setuid (uid); /* drop all privileges */
655
return ioctl_device=device;
656
case 0x12: /* DVD-RAM */
657
if (poor_man>0) goto open_poor_man;
658
out_fd = dup(ioctl_fd);
661
fprintf (stderr,":-( %s: media is not recognized as "
662
"recordable DVD: %X\n",device,mmc_profile);
663
exit (FATAL_START(EMEDIUMTYPE));
665
/* not actually reached */
670
#elif defined(__FreeBSD__)
672
#include <sys/cdio.h>
674
#include <cam/scsi/scsi_pass.h>
677
#define ioctl_fd (((struct cam_device *)ioctl_handle)->fd)
679
#define PASS_STDIN_TO_MKISOFS
681
char *setup_fds (char *device)
682
{ uid_t uid=getuid();
685
char pass[32]; /* periph_name is 16 chars long */
686
struct cam_device *cam;
690
* We might be entering as euid=root!
692
if ((in_fd = open (device,O_RDONLY)) < 0)
693
fprintf (stderr,":-( unable to open(\"%s\",O_RDONLY): ",device),
694
perror (NULL), exit (FATAL_START(errno));
696
if (fstat (in_fd,&sb) < 0)
697
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
698
perror (NULL), exit (FATAL_START(errno));
700
if (!S_ISCHR(sb.st_mode))
701
{ setuid(uid); /* drop all privileges */
702
close (in_fd); /* reopen as mortal */
703
if ((in_fd = open (device,O_RDONLY)) < 0)
704
fprintf (stderr,":-( unable to reopen(\"%s\",O_RDONLY): ",device),
705
perror (NULL), exit (FATAL_START(errno));
707
if ((out_fd = open (device,O_RDWR)) < 0)
708
fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",device),
709
perror (NULL), exit (FATAL_START(errno));
710
if (fstat(out_fd,&sc) < 0)
711
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
712
perror (NULL), exit (FATAL_START(errno));
713
if (sb.st_dev!=sc.st_dev || sb.st_ino!=sc.st_ino)
714
fprintf (stderr,":-( %s: race condition detected!\n",device),
715
exit(FATAL_START(EPERM));
718
if (ioctl_handle && ioctl_handle != INVALID_HANDLE)
719
cam_close_device (ioctl_handle);
720
ioctl_handle = INVALID_HANDLE;
721
setuid (uid); /* drop all privileges */
726
* Still as euid=root! But note that get_mmc_profile makes sure it's
727
* an MMC device, as it terminates the program if the unit doesn't
728
* reply to GET CONFIGURATON. In combination with following switch
729
* this means that if installed set-root-uid, growisofs grants
730
* access to DVD burner(s), but not to any other device.
733
for (once=1;1;once--)
734
{ memset (&ccb,0,sizeof(ccb));
735
ccb.ccb_h.func_code = XPT_GDEVLIST;
736
if (ioctl (in_fd,CAMGETPASSTHRU,&ccb) < 0)
737
{ if (errno==ENXIO && once)
738
{ if (ioctl (in_fd,CDIOCCLOSE)==0) continue; }
739
fprintf (stderr,":-( unable to CAMGETPASSTHRU for %s: ",device),
740
perror (NULL), exit (FATAL_START(errno));
745
sprintf (pass,"/dev/%.15s%u",ccb.cgdl.periph_name,ccb.cgdl.unit_number);
746
cam = cam_open_pass (pass,O_RDWR,NULL);
748
{ fprintf (stderr,":-( unable to cam_open_pass(\"%s\",O_RDWR): ",pass),
750
exit (FATAL_START(errno));
753
ioctl_handle = (void *)cam;
755
mmc_profile = get_mmc_profile (ioctl_handle);
756
switch (mmc_profile&0xFFFF)
757
{ case 0x11: /* DVD-R */
758
case 0x13: /* DVD-RW Restricted Overwrite */
759
case 0x14: /* DVD-RW Sequential */
760
case 0x1B: /* DVD+R */
761
case 0x1A: /* DVD+RW */
764
out_fd = dup(in_fd); /* it's ignored in poor_man ... */
765
setuid (uid); /* drop all privileges */
766
return ioctl_device=cam->device_path;
767
case 0x12: /* DVD-RAM */
768
if (poor_man>0) goto open_poor_man;
771
fprintf (stderr,":-( %s: media is not recognized as "
772
"recordable DVD: %X\n",device,mmc_profile);
773
exit (FATAL_START(EMEDIUMTYPE));
779
#elif defined(__sun) || defined(sun)
782
#include <sys/cdio.h>
784
char *setup_fds (char *device)
785
{ uid_t uid=getuid();
789
if ((v=volmgt_running()))
790
{ char *file=NULL,*volname;
793
* I leak some memory here, but I don't care...
795
if ((volname=volmgt_symname (device)))
796
file=media_findname (volname);
798
file=media_findname (device);
800
if (file) device=file;
805
* We might be entering as euid=root!
807
if ((in_fd = open64 (device,O_RDONLY)) < 0)
808
if (errno != ENXIO ||
809
(in_fd = open64 (device,O_RDONLY|O_NONBLOCK)) < 0)
810
fprintf (stderr,":-( unable to open(\"%s\",O_RDONLY): ",device),
811
perror (NULL), exit (FATAL_START(errno));
813
if (fstat64 (in_fd,&sb) < 0)
814
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
815
perror (NULL), exit (FATAL_START(errno));
817
if (!S_ISCHR(sb.st_mode))
819
if (S_ISBLK(sb.st_mode) && (s=strstr (device,"/dsk/")))
820
{ fprintf (stderr,":-) you most likely want to use %.*s/r%s instead!\n",
821
(int)(s-device),device,s+1);
822
if (isatty(0) && !dry_run) poll(NULL,0,5000);
824
setuid(uid); /* drop all privileges */
825
close (in_fd); /* reopen as mortal */
826
if ((in_fd = open64 (device,O_RDONLY)) < 0)
827
fprintf (stderr,":-( unable to reopen(\"%s\",O_RDONLY): ",device),
828
perror (NULL), exit (FATAL_START(errno));
830
if ((out_fd = open64 (device,O_RDWR)) < 0)
831
fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",device),
832
perror (NULL), exit (FATAL_START(errno));
833
if (fstat64(out_fd,&sc) < 0)
834
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
835
perror (NULL), exit (FATAL_START(errno));
836
if (sb.st_dev!=sc.st_dev || sb.st_ino!=sc.st_ino)
837
fprintf (stderr,":-( %s: race condition detected!\n",device),
838
exit(FATAL_START(EPERM));
841
ioctl_handle = INVALID_HANDLE;
842
setuid (uid); /* drop all privileges */
847
* Still as euid=root! But note that get_mmc_profile makes sure it's
848
* an MMC device, as it terminates the program if the unit doesn't
849
* reply to GET CONFIGURATON. In combination with following switch
850
* this means that if installed set-root-uid, growisofs grants
851
* access to DVD burner(s), but not to any other device.
853
ioctl_handle = (void *)(long)dup (in_fd);
856
if (ioctl(ioctl_handle,CDROMSTART)<0 && errno==ENXIO)
857
media_load(ioctl_handle);
860
mmc_profile = get_mmc_profile (ioctl_handle);
861
switch (mmc_profile&0xFFFF)
862
{ case 0x11: /* DVD-R */
863
case 0x12: /* DVD-RAM */
864
case 0x13: /* DVD-RW Restricted Overwrite */
865
case 0x14: /* DVD-RW Sequential */
866
case 0x1B: /* DVD+R */
867
case 0x1A: /* DVD+RW */
869
out_fd = dup(ioctl_fd);
870
#if 0 /* 'man uscsi' maintains that root privileges are required upon
871
* issue of USCSI ioctl, we therefore can't drop them...
873
setuid (uid); /* drop all privileges */
875
return ioctl_device=device;
877
fprintf (stderr,":-( %s: media is not recognized as "
878
"recordable DVD: %X\n",device,mmc_profile);
879
exit (FATAL_START(EMEDIUMTYPE));
885
#elif defined(__hpux)
888
# define SCTL_SANITY_CHECK SCTL_MAJOR-1
889
# if SCTL_SANITY_CHECK<=0
892
# undef SCTL_SANITY_CHECK
896
#error "SCTL_MAJOR is undefined or not sane."
899
#include <sys/mknod.h>
900
#include <sys/diskio.h>
902
#define seteuid(x) setreuid((uid_t)-1,x)
905
#define CANNOT_PASS_DEV_FD_N_TO_MKISOFS
907
--- ./multi.c.orig Wed Dec 25 15:15:24 2002
908
+++ ./multi.c Tue Nov 11 17:12:27 2003
909
@@ -1067,3 +1067,13 @@
910
open_merge_image(path)
915
+ if (sscanf (path,"/dev/fd/%u",&fd) == 1) {
916
+ int fdd = dup(fd); /* validate file descriptor */
917
+ if (fdd < 0) return -1;
919
+ in_image = fdopen (fd,"rb");
920
+ return in_image ? 0 : -1;
925
#ifdef CANNOT_PASS_DEV_FD_N_TO_MKISOFS
926
char *get_M_parm (int fd, char *device)
932
if (fstat (fd,&sb)==0 && S_ISCHR(sb.st_mode))
933
{ m = minor (sb.st_rdev);
934
sprintf (ctl,"%d,%d,%d",(m>>16)&0xFF,(m>>12)&0xF,(m>>8)&0xF);
942
char *setup_fds (char *device)
943
{ uid_t uid=getuid();
946
static char rscsi [32];
947
disk_describe_type ddt;
950
* We might be entering as euid=root!
952
if ((in_fd = open64 (device,O_RDONLY)) < 0)
953
fprintf (stderr,":-( unable to open(\"%s\",O_RDONLY): ",device),
954
perror (NULL), exit (FATAL_START(errno));
956
if (fstat64 (in_fd,&sb) < 0)
957
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
958
perror (NULL), exit (FATAL_START(errno));
960
if (!S_ISCHR(sb.st_mode))
962
if (S_ISBLK(sb.st_mode) && (s=strstr (device,"/dsk/")))
963
{ fprintf (stderr,":-) you most likely want to use %.*s/r%s instead!\n",
964
(int)(s-device),device,s+1);
965
if (isatty(0) && !dry_run) poll(NULL,0,5000);
967
setuid(uid); /* drop all privileges */
968
close (in_fd); /* reopen as mortal */
969
if ((in_fd = open64 (device,O_RDONLY)) < 0)
970
fprintf (stderr,":-( unable to reopen(\"%s\",O_RDONLY): ",device),
971
perror (NULL), exit (FATAL_START(errno));
973
if ((out_fd = open64 (device,O_RDWR)) < 0)
974
fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",device),
975
perror (NULL), exit (FATAL_START(errno));
976
if (fstat64(out_fd,&sc) < 0)
977
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
978
perror (NULL), exit (FATAL_START(errno));
979
if (sb.st_dev!=sc.st_dev || sb.st_ino!=sc.st_ino)
980
fprintf (stderr,":-( %s: race condition detected!\n",device),
981
exit(FATAL_START(EPERM));
984
ioctl_handle = INVALID_HANDLE;
985
setuid (uid); /* drop all privileges */
990
* Still as euid=root! But note that get_mmc_profile makes sure it's
991
* an MMC device, as it terminates the program if the unit doesn't
992
* reply to GET CONFIGURATON. In combination with following switch
993
* this means that if installed set-root-uid, growisofs grants
994
* access to DVD burner(s), but not to any other device.
999
/* Make sure user isn't using /dev/rscsi/cXtYlZ... */
1001
if (ioctl (in_fd,DIOC_DESCRIBE,&ddt) != 0)
1003
if (major(sb.st_rdev) == SCTL_MAJOR)
1005
fprintf (stderr,":-( stick to /dev/rdsk/c%xt%x%c%x!\n",
1006
(m>>16)&0xFF,(m>>12)&0xF,'d',(m>>8)&0xF),
1007
exit(FATAL_START(EINVAL));
1010
* Even though /dev/rdsk/cXtYdZ accepts SIOC_IO as well, we have to
1011
* use /dev/rscsi/cXtYlZ for pass-through access in order to avoid
1012
* command replay by upper "class" driver...
1014
sprintf (rscsi,"/dev/rscsi/c%xt%x%c%x",
1015
(m>>16)&0xFF,(m>>12)&0xF,'l',(m>>8)&0xF);
1016
ioctl_handle = (void *)(long)open64 (rscsi,O_RDONLY);
1017
if (ioctl_handle == INVALID_HANDLE)
1018
{ fprintf (stderr,":-( unable to open(\"%s\",O_RDONLY): ",rscsi),
1020
if (errno == ENOENT)
1021
fprintf (stderr,":-! consider "
1022
"'mknod %s c %d 0x%06x; chmod 0600 %s'\n",
1023
rscsi,SCTL_MAJOR,(m&0xFFFF00)|2,rscsi);
1024
exit (FATAL_START(errno));
1026
if (fstat64 (ioctl_fd,&sc) < 0)
1027
fprintf (stderr,":-( unable to stat(\"%s\"): ",rscsi),
1028
perror (NULL), exit (FATAL_START(errno));
1029
/* Make sure we land on same SCSI ID... */
1030
if ((m&0xFFFF00) != (minor(sc.st_rdev)&0xFFFF00))
1031
fprintf (stderr,":-( SCSI ID mismatch: %06x!=%06x\n",
1032
m,minor(sc.st_rdev)),
1033
exit(FATAL_START(EPERM));
1035
mmc_profile = get_mmc_profile (ioctl_handle);
1036
switch (mmc_profile&0xFFFF)
1037
{ case 0x11: /* DVD-R */
1038
case 0x12: /* DVD-RAM */
1039
case 0x13: /* DVD-RW Restricted Overwrite */
1040
case 0x14: /* DVD-RW Sequential */
1041
case 0x1B: /* DVD+R */
1042
case 0x1A: /* DVD+RW */
1044
out_fd = dup(ioctl_fd);
1045
#if 0 /* HP-UX requires root privileges upon SIOC_IO ioctl */
1046
setuid (uid); /* drop all privileges */
1048
return ioctl_device=rscsi;
1050
fprintf (stderr,":-( %s: media is not recognized as "
1051
"recordable DVD: %X\n",device,mmc_profile);
1052
exit (FATAL_START(EMEDIUMTYPE));
1059
* PA-RISC HP-UX doesn't have /dev/zero:-(
1061
static fd_set _dev_zero;
1063
static int open64_zero(const char *pathname, int flags)
1065
if (strcmp(pathname,"/dev/zero"))
1066
return open64 (pathname,flags);
1067
else if ((fd=open ("/dev/null",flags)) >= 0)
1068
FD_SET (fd,&_dev_zero);
1072
static ssize_t read_zero (int fd, void *buf, size_t count)
1073
{ if (!FD_ISSET(fd,&_dev_zero)) return read (fd,buf,count);
1074
memset (buf,0,count); return count;
1077
static int close_zero (int fd)
1078
{ int ret=close (fd);
1079
if (ret>=0 && FD_ISSET(fd,&_dev_zero)) FD_CLR (fd,&_dev_zero);
1083
static int dup2_zero (int oldfd, int newfd)
1085
ret = dup2 (oldfd,newfd);
1087
{ if (FD_ISSET(oldfd,&_dev_zero)) FD_SET (ret,&_dev_zero);
1088
else FD_CLR (ret,&_dev_zero);
1092
#define open64 open64_zero
1093
#define read read_zero
1094
#define close close_zero
1095
#define dup2 dup2_zero
1097
#elif defined(__sgi)
1099
#include <sys/attributes.h>
1100
#include <sys/param.h>
1103
char *setup_fds (char *device)
1104
{ uid_t uid=getuid();
1105
struct stat64 sb,sc;
1106
char hw_path[MAXPATHLEN],*s;
1107
int hw_len=sizeof(hw_path)-1;
1108
int bus=0,tgt=4,lun=0; /* default config for O2 */
1109
static char rscsi[64];
1112
* We might be entering as euid=root!
1114
if ((in_fd = open64 (device,O_RDONLY)) < 0)
1115
{ if (errno==EIO) goto tray_might_be_open;
1116
fprintf (stderr,":-( unable to open(\"%s\",O_RDONLY): ",device),
1117
perror (NULL), exit (FATAL_START(errno));
1120
if (fstat64 (in_fd,&sb) < 0)
1121
fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
1122
perror (NULL), exit (FATAL_START(errno));
1124
if (!S_ISCHR(sb.st_mode))
1125
{ if (S_ISBLK(sb.st_mode) && !strncmp (device,"/dev/dsk",7))
1126
{ fprintf (stderr,":-) you most likely want to use "
1127
"/dev/r%s instead!\n",device+5);
1128
if (isatty(0) && !dry_run) poll(NULL,0,5000);
1131
setuid(uid); /* drop all privileges */
1132
close (in_fd); /* reopen as mortal */
1133
if ((in_fd = open64 (device,O_RDONLY)) < 0)
1134
fprintf (stderr,":-( unable to reopen(\"%s\",O_RDONLY): ",device),
1135
perror (NULL), exit (FATAL_START(errno));
1136
if ((out_fd = open64 (device,O_RDWR)) < 0)
1137
fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",device),
1138
perror (NULL), exit (FATAL_START(errno));
1142
ioctl_handle = INVALID_HANDLE;
1143
setuid (uid); /* drop all privileges */
1148
* Still as euid=root! But note that get_mmc_profile makes sure it's
1149
* an MMC device, as it terminates the program if the unit doesn't
1150
* reply to GET CONFIGURATON. In combination with following switch
1151
* this means that if installed set-root-uid, growisofs grants
1152
* access to DVD burner(s), but not to any other device.
1157
if ((in_fd<0) ? attr_get (device,"_devname",hw_path,&hw_len,0) :
1158
attr_getf (in_fd,"_devname",hw_path,&hw_len,0) )
1159
fprintf (stderr,":-( unable to obtain hw_path for \"%s\": ",device),
1160
perror (NULL), exit (FATAL_START(errno));
1161
if (hw_len>=sizeof(hw_path)) hw_len=sizeof(hw_path)-1; /* paranoia */
1162
hw_path[hw_len]='\0';
1164
if ((s=strstr(hw_path,"/scsi_ctlr/")))
1165
sscanf (s,"/scsi_ctlr/%d/target/%d/lun/%d/",&bus,&tgt,&lun);
1167
/* Make sure user is using /dev/rdsk/dksXdYlZvol... */
1168
if ((s=strstr(hw_path,"/disk/volume/char"))==NULL)
1170
fprintf (stderr,":-( stick to /dev/rdsk/dks%dd%dl%dvol!\n",
1173
fprintf (stderr,":-( stick to /dev/rdsk/dks%dd%dvol!\n",
1175
exit(FATAL_START(EINVAL));
1178
memcpy (s,"/scsi",6);
1179
ioctl_handle = (void *)(long)open64 (hw_path,O_RDWR);
1180
if (ioctl_handle == INVALID_HANDLE)
1181
fprintf (stderr,":-( unable to open(\"%s\",O_RDWR): ",hw_path),
1182
perror (NULL), exit (FATAL_START(errno));
1183
if (fstat64 (ioctl_fd,&sc) < 0)
1184
fprintf (stderr,":-( unable to stat(\"%s\"): ",hw_path),
1185
perror (NULL), exit (FATAL_START(errno));
1186
memcpy (s,"/disk/volume/char",6);
1188
mmc_profile = get_mmc_profile (ioctl_handle);
1189
switch (mmc_profile&0xFFFF)
1190
{ case 0x11: /* DVD-R */
1191
case 0x13: /* DVD-RW Restricted Overwrite */
1192
case 0x14: /* DVD-RW Sequential */
1193
case 0x1B: /* DVD+R */
1194
case 0x1A: /* DVD+RW */
1197
out_fd = dup (ioctl_fd);
1198
if (in_fd<0 && (in_fd=open64 (hw_path,O_RDONLY))<0)
1199
/* hope for the best? */ ;
1200
setuid (uid); /* drop all privileges */
1201
mediad_get_exclusiveuse (hw_path,"growisofs");
1202
if (mediad_last_error ()==RMED_NOERROR)
1203
putenv ("MEDIAD_GOT_EXCLUSIVEUSE="); /* kludge... */
1204
sprintf (rscsi,"/dev/scsi/sc%dd%dl%d",bus,tgt,lun);
1205
return ioctl_device=rscsi; /* might be bogus... */
1206
case 0x12: /* DVD-RAM */
1207
/* Some of latest tentative IRIX releases seem to
1208
* implement DVD-RAM writing at dksc level, but I'm
1209
* not sure which one. So I just fall down to poor-man,
1210
* at least for now... */
1214
fprintf (stderr,":-( %s: media is not recognized as "
1215
"recordable DVD: %X\n",device,mmc_profile);
1216
exit (FATAL_START(EMEDIUMTYPE));
1218
/* not actually reached */
1224
#error "Unsupported OS"
1227
int setup_C_parm (char *C_parm,struct iso_primary_descriptor *descr)
1228
{ int next_session=-1,profile=mmc_profile&0xFFFF;
1230
if (!poor_man || profile==0x1A || profile==0x13 || profile==0x12)
1231
{ next_session = from_733(descr->volume_space_size);
1232
/* pad to closest 32K boundary */
1236
sprintf (C_parm,"16,%u",next_session);
1238
else if (profile==0x1B || profile==0x11 || profile==0x14)
1239
next_session=plusminus_r_C_parm (ioctl_handle,C_parm);
1241
return next_session;
1244
int builtin_dd (int infd,int outfd,off64_t outoff)
1248
off64_t capacity=0,tracksize=0,startoff=outoff;
1249
pid_t pid=(pid_t)-1,ppid=getpid();
1250
volatile struct { time_t zero; off64_t current,final; } *progress;
1252
if ((fd=mkstemp (s=strdup("/tmp/dvd+rw.XXXXXX"))) < 0)
1253
fprintf (stderr,":-( unable to mkstemp(\"%s\")",s),
1254
exit(FATAL_START(errno));
1256
ftruncate(fd,sizeof(*progress));
1259
progress = (void *)mmap (NULL,sizeof(*progress),PROT_READ|PROT_WRITE,
1260
MAP_SHARED,fd,(off_t)0);
1262
if (progress == MAP_FAILED)
1263
fprintf (stderr,":-( unable to anonymously mmap %lu?\n",
1265
perror (NULL), exit(FATAL_START(errno));
1267
if (fstat64 (infd,&sb))
1268
perror (":-( unable to fstat64"), exit(FATAL_START(errno));
1270
if (ioctl_handle!=INVALID_HANDLE)
1271
capacity = get_capacity (ioctl_handle);
1274
progress->current=outoff;
1275
if (dao_size || S_ISREG(sb.st_mode))
1276
{ tracksize = dao_size ? (dao_size*CD_BLOCK) : sb.st_size;
1277
progress->final=outoff+tracksize;
1278
if (capacity && progress->final > capacity)
1279
{ fprintf (stderr,":-( %s: %lld blocks are free, "
1280
"%lld to be written!\n",
1282
(capacity-outoff)/2048,tracksize/2048);
1284
fprintf (stderr,":-! ignoring...\n");
1286
close(infd), close(outfd),
1287
exit (FATAL_START(ENOSPC));
1290
else progress->final=0;
1292
if (!dry_run && quiet<=0 && (pid=fork()) == 0)
1293
{ double ratio,velocity,slept;
1295
off64_t lastcurrent=outoff,current;
1300
while (kill (ppid,0)==0)
1301
{ gettimeofday (&tv,NULL); slept = tv.tv_usec/1e6+tv.tv_sec;
1303
gettimeofday (&tv,NULL); slept -= tv.tv_usec/1e6+tv.tv_sec;
1304
if (progress->zero==0 || !nfirst++) continue;
1305
if ((current = progress->current) > outoff)
1306
{ delta = time (NULL) - progress->zero;
1307
ratio = (double)(progress->final-outoff) /
1308
(double)(current-outoff);
1309
delta *= ratio - 1.0;
1310
velocity=(current-lastcurrent)/(-slept*1024*1385);
1311
fprintf (stdout,"%10lld/%lld (%4.1f%%) @%.1fx, "
1312
"remaining %d:%02d\n",
1313
current,progress->final,100.0/ratio,
1314
velocity,delta/60,delta%60);
1315
lastcurrent=current;
1318
fprintf (stdout,"%10lld/%lld (%4.1f%%) @0x, remaining ??:??\n",
1319
current,progress->final,0.0);
1322
exit(0); /* not [normally] reached */
1325
/* suck in first 64K and examine ISO9660 Primary Descriptor if present */
1327
while ((n=read (infd,the_buffer+off,2*DVD_BLOCK-off)) > 0)
1329
if (off == 2*DVD_BLOCK)
1330
{ if (!memcmp(the_buffer+DVD_BLOCK,"\1CD001",6))
1331
{ struct iso_primary_descriptor *descr;
1333
descr=(struct iso_primary_descriptor *)(the_buffer+DVD_BLOCK);
1337
{ tracksize=from_733(descr->volume_space_size)*CD_BLOCK;
1338
if (capacity && (outoff+tracksize) > capacity)
1339
{ fprintf (stderr,":-( %s: %lld blocks are free, "
1340
"%lld to be written\n",
1342
(capacity-outoff)/2048,
1345
fprintf (stderr,":-! ignoring...\n");
1347
close(infd), close(outfd),
1348
exit(FATAL_START(ENOSPC));
1350
{ n = -1; errno = FATAL_START(ENOSPC);
1355
/* else already checked for overburn condition */
1357
else if (capacity > outoff)
1359
unsigned int ts = (tracksize=capacity-outoff)/2048;
1361
while (i<16 && descr->type[0] != (unsigned char)255)
1362
to_733 (descr->volume_space_size,ts),
1366
{ fprintf (stderr,":-( capacity is undefined or insane?\n");
1367
n = -1; errno = FATAL_START(EINVAL);/* ... or whatever */
1371
else if (outoff && zero_image)
1372
{ fprintf (stderr,":-( no volume descriptors found "
1373
"in previous session?\n");
1374
n = -1; errno = FATAL_START(ENOTDIR); /* ... or whatever */
1378
if (dry_run) close(infd), close(outfd), exit(0);
1382
* See commentary section in growisofs_mmc.cpp for
1383
* further details on poor_mans_setup
1385
pwrite64_method = poor_mans_setup (ioctl_handle,
1388
if (!progress->final)
1389
{ if (tracksize) progress->final = outoff+tracksize;
1390
else progress->final = capacity;
1392
if (capacity && progress->final>capacity)
1393
progress->final = capacity;
1395
progress->zero=time(NULL);
1397
/* Write two 32KB chunks, not one 64KB... */
1398
if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff))
1400
{ if (n>0) errno = FATAL_START(EIO);
1401
else if (n==0) errno = FATAL_START(ENOSPC);
1405
outoff += DVD_BLOCK;
1406
progress->current=outoff;
1408
if ((n=(*pwrite64_method) (outfd,the_buffer+DVD_BLOCK,DVD_BLOCK,outoff))
1410
{ if (n>0) errno = EIO;
1411
else if (n==0) errno = ENOSPC;
1415
outoff += DVD_BLOCK;
1416
progress->current=outoff;
1423
/* yeah, really kludgy, shuffling file descriptor like that... */
1425
close(infd), infd=open64 ("/dev/zero",O_RDONLY);
1429
* From now on only the first 32K of the_buffer are used!
1431
while ((n=read (infd,the_buffer+off,DVD_BLOCK-off)) > 0)
1433
if (off == DVD_BLOCK)
1435
if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff))
1437
{ if (n>0) errno = EIO;
1438
else if (n==0) errno = ENOSPC;
1442
outoff += DVD_BLOCK;
1443
progress->current=outoff;
1446
if (off) /* pad to the closest 32K is needed */
1447
{ memset (the_buffer+off,0,DVD_BLOCK-off);
1448
if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff))
1450
{ if (n>0) errno = EIO;
1451
else if (n==0) errno = ENOSPC;
1454
outoff += DVD_BLOCK;
1457
printf ("builtin_dd: %lld*2KB out @ average %.1fx1385KBps\n",
1458
(outoff-startoff)/2048,
1459
((outoff-startoff)/(1024.0*1385.0))/(time(NULL)-progress->zero));
1461
{ int saved_errno=errno;
1463
if (pid!=(pid_t)-1) kill (pid,SIGTERM), waitpid (pid,NULL,0);
1465
errno = outoff ? saved_errno : (n--?saved_errno:FATAL_START(EIO));
1471
void pipe_mkisofs_up (char *mkisofs_argv[],int infd,int outfd,off64_t outoff)
1472
{ pid_t mkisofs_pid;
1473
int fildes[2],ret,n;
1475
if (pipe (fildes) < 0)
1476
perror (":-( unable to create pipe"), exit(FATAL_START(errno));
1478
if ((mkisofs_pid=fork ()) == (pid_t)-1)
1479
perror (":-( unable to fork mkisofs"), exit(FATAL_START(errno));
1480
else if (mkisofs_pid == 0)
1481
{ dup2 (fildes[1],1);
1484
close (outfd); /* redundant:-) */
1486
#ifdef PASS_STDIN_TO_MKISOFS
1491
if ((n=fcntl (infd,F_GETFD))<0) n=0;
1492
fcntl (infd,F_SETFD,n&~FD_CLOEXEC);
1494
* If platform-specific setup_fds did not drop privileges,
1495
* do it now. I ignore return value because if it fails,
1496
* then privileges were dropped already.
1499
execvp (mkisofs_argv[0],mkisofs_argv);
1500
fprintf (stderr,":-( unable to execute %s: ",mkisofs_argv[0]),
1501
perror (NULL), exit (FATAL_START(errno));
1506
n=builtin_dd(fildes[0],outfd,outoff);
1508
if (n==0) /* mkisofs must have finished, consume the exit code */
1509
{ if ((waitpid (mkisofs_pid,&ret,0)) == -1)
1510
perror (":-( waitpid failed"), exit (errno);
1512
if (!WIFEXITED(ret) || WEXITSTATUS(ret)!=0)
1513
fprintf (stderr,":-( mkisofs has failed: %d\n",WEXITSTATUS(ret)),
1518
errno = err&0x7F; /* they might be passing FATAL_START */
1519
perror (":-( write failed"), exit (err);
1524
* This may not be larger than 32KB!
1527
#define IVDs_SIZE (sizeof(struct iso_primary_descriptor)*MAX_IVDs)
1529
int main (int argc, char *argv[])
1531
char *in_device=NULL,*out_device=NULL,*in_image=NULL,*env;
1533
int i,n,warn_for_isofs=0;
1534
char **mkisofs_argv,C_parm[24],M_parm_[16],*M_parm=M_parm_;
1535
int mkisofs_argc,growisofs_argc;
1536
int next_session=-1,alleged_next_session=-1,new_size;
1537
struct iso_primary_descriptor *descr;
1539
if (getenv ("SUDO_COMMAND"))
1540
{ fprintf (stderr,":-( %s is being executed under sudo, "
1541
"aborting!\n",argv[0]);
1542
fprintf (stderr," See NOTES paragraph in growisofs "
1543
"manual page for further details.\n");
1544
exit(FATAL_START(EACCES));
1547
* This is a set-root-uid "entry point" for listed operations. User
1548
* can't trick this code to unmount arbitrary file system, as [s]he
1549
* has to pass opened file descriptor to the mounted device. As for
1550
* file descriptor passed by this program itself, I rely upon the
1551
* fact that it was appropriately audited at open time in platform-
1552
* specific setup_fds above...
1554
if (*argv[0] == '-')
1559
if (argc != 3) exit (EINVAL);
1561
if (!strcmp(argv[0],"-umount"))
1562
{ if (fumount (fd)) exit (errno);
1565
else if (!strcmp(argv[0],"-reload"))
1566
{ if (fstat (fd,&fdst) < 0)
1567
perror (":-( unable to fstat"), exit (1);
1571
if (media_reload (argv[2],&fdst))
1572
perror (":-( unable to reload tray"), exit (1);
1578
/* mmap buffer so that we can use it with /dev/raw/rawN */
1579
#if defined(MAP_ANONYMOUS) && !(defined(__sun) || defined(sun))
1580
the_buffer = mmap (NULL,2*DVD_BLOCK,PROT_READ|PROT_WRITE,
1581
MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
1585
if ((fd=open ("/dev/zero",O_RDWR)) < 0)
1586
perror (":-( unable to open \"/dev/zero\"?"),
1587
exit(FATAL_START(errno));
1588
the_buffer = mmap (NULL,2*DVD_BLOCK,PROT_READ|PROT_WRITE,
1593
if (the_buffer == MAP_FAILED)
1594
fprintf (stderr,":-( unable to anonymously mmap %d: ",2*DVD_BLOCK),
1595
perror (NULL), exit (FATAL_START(errno));
1597
mkisofs_argv = malloc ((argc+3)*sizeof(char *));
1598
if (mkisofs_argv == NULL)
1599
fprintf (stderr,":-( unable to allocate %lu bytes: ",
1600
(argc+3)*sizeof(char *)),
1601
perror (NULL), exit (FATAL_START(errno));
1603
env = getenv ("MKISOFS");
1604
mkisofs_argv[0] = (env?env:"mkisofs"), mkisofs_argc = 1;
1607
_argc=argc, _argv=argv;
1609
for (i=1;i<argc;i++)
1610
{ int len=strlen(argv[i]);
1614
if (argv[i][0] == '-')
1615
{ opt = argv[i] + ((argv[i][1]=='-')?(len--,1):0);
1616
if (argv[i][1] == 'M')
1617
{ if (len > 2) in_device = argv[i]+2;
1618
else in_device = argv[++i];
1621
else if (!strncmp(opt,"-prev-session",13))
1622
{ if (len > 13) in_device = opt+13;
1623
else in_device = argv[++i];
1626
else if (argv[i][1] == 'Z')
1627
{ if (len > 2) in_device = argv[i]+2;
1628
else in_device = argv[++i];
1631
else if (!strncmp(opt,"-zero-session",13))
1632
{ if (len > 13) in_device = opt+13;
1633
else in_device = argv[++i];
1636
else if (!strcmp(opt,"-poor-man"))
1637
{ if (poor_man<0) poor_man = 1;
1640
else if (!strncmp(opt,"-speed",6))
1642
if (len>6) (s=strchr(opt,'='))?s++:s;
1644
if (s) speed_factor=atof(s);
1645
if (speed_factor<=0)
1646
fprintf (stderr,"-speed=%.1f: insane speed factor.\n",
1648
exit(FATAL_START(EINVAL));
1651
else if (!strcmp(opt,"-dvd-compat"))
1652
{ if (poor_man<0) poor_man = 1;
1656
else if (!strcmp(opt,"-overburn"))
1660
else if (argv[i][1] == 'o')
1661
{ if (!strchr(argv[i]+2,'-')) /* somewhat opportunistic... */
1662
fprintf (stderr,"%s: -o[output] option "
1663
"is not permitted.\n",argv[0]),
1664
exit(FATAL_START(EINVAL));
1666
else if (!strncmp(opt,"-use-the-force-luke",19))
1667
{ char *s=strchr (opt,'='),*o;
1669
if (s == NULL) /* backward compatibility */
1673
if (strstr(s,"tty")) no_tty_check = 1;
1674
if (strstr(s,"dummy")) test_write = 1;
1675
if (strstr(s,"notray")) no_reload = 1;
1676
if (strstr(s,"moi"))
1677
{ quiet=-1; mkisofs_argv[mkisofs_argc++] = "-quiet"; }
1678
if ((o=strstr(s,"dao")))
1679
{ dvd_compat += 256;
1680
/* vvvvvvvvvvv tracksize option takes precedence! */
1681
if (dao_size==0 && (o[3]==':' || o[3]=='='))
1682
{ dao_size=strtol(o+4,0,0);
1684
fprintf (stderr,":-( insane dao%c%d option\n",
1686
exit(FATAL_START(EINVAL));
1689
if ((o=strstr(s,"tracksize")))
1690
{ if (o[9]==':' || o[9]=='=')
1691
{ dao_size=strtol(o+10,0,0);
1693
fprintf (stderr,":-( insane tracksize%c%d option\n",
1695
exit(FATAL_START(EINVAL));
1698
if ((o=strstr(s,"seek")) && next_session<0)
1699
{ if (o[4]==':' || o[4]=='=')
1700
{ next_session=strtol(o+5,0,0);
1701
if (next_session%16)
1702
fprintf (stderr,":-( insane seek%c%d option\n",
1704
exit(FATAL_START(EINVAL));
1710
else if (!strcmp(opt,"-dvd-video"))
1711
{ if (poor_man<0) poor_man = 1;
1712
dvd_compat++, growisofs_argc++;
1714
else if (!strcmp(opt,"-quiet"))
1715
quiet++, growisofs_argc++;
1716
else if (argv[i][1] == 'C' || !strncmp(opt,"-cdrecord-params",16))
1717
{ char *s=argv[i+1];
1719
if (argv[i][1]=='C' && len>2) s=argv[i]+2;
1721
if (sscanf (s,"%d,%d",&i1,&i2) == 2)
1722
alleged_next_session=i2;
1725
else if (argv[i][1] == '#' || !strcmp(opt,"-dry-run"))
1729
else if (argv[i][1] == '?' || !strcmp(opt,"-help"))
1730
{ PRINT_VERSION (argv[0]);
1731
printf ("- usage: %s [-dvd-compat] [-overburn] [-speed=1] \\\n"
1732
" -[ZM] /dev/cdrom <mkisofs options>\n",argv[0]);
1733
printf (" for <mkisofs options> see 'mkisofs %s'\n",opt);
1734
exit (FATAL_START(EINVAL));
1736
else if (strstr (opt,"-version"))
1737
{ PRINT_VERSION (argv[0]);
1738
printf (" front-ending to %s: ",mkisofs_argv[0]);
1741
execlp (mkisofs_argv[0],mkisofs_argv[0],"-version",NULL);
1742
fprintf (stderr,"\n- %s: unable to execute %s: ",
1743
argv[0],mkisofs_argv[0]),
1744
perror (NULL), exit (FATAL_START(errno));
1748
if (dev_found && in_device)
1749
{ if (*in_device == '=') in_device++;
1751
if (1 || dev_found == 'Z')
1752
{ if ((in_image = strchr(in_device,'=')))
1753
{ uid_t euid=geteuid();
1755
seteuid (getuid()); /* get real for parsing -[ZM] a=b */
1760
if (access (in_device,F_OK)==0 || errno!=ENOENT)
1763
in_image=strchr(in_image+1,'=');
1767
fprintf (stderr,":-( \"%s\": unexpected errno:",
1769
perror (NULL), exit (FATAL_START(errno));
1774
if (sscanf(in_image,"/dev/fd/%u",&imgfd) == 1)
1775
imgfd = dup (imgfd); /* validate descriptor */
1777
imgfd = open64(in_image,O_RDONLY);
1780
fprintf (stderr,":-( unable to open64(\"%s\","
1781
"O_RDONLY): ",in_image),
1782
perror (NULL), exit(FATAL_START(errno));
1784
if (!strcmp(in_image,"/dev/zero"))
1788
seteuid (euid); /* revert to saved [set-]uid */
1793
* Sets up in_fd, out_fd, ioctl_handle and poor_man variable.
1794
* This procedure is platform-specific. If the program
1795
* has to be installed set-root-uid, then this procedure
1796
* is the one to drop privileges [if appropriate].
1798
out_device=setup_fds (in_device);
1800
*(long *)the_buffer=0; /* redundant:-) */
1801
if (mmc_profile&0x10000) /* blank media */
1804
{ n=pread64 (in_fd,the_buffer,2048,VOLDESC_OFF*CD_BLOCK);
1805
if (n==0) errno=EIO; /* end-of-file reached? */
1807
if (n!=2048 && dev_found=='M')
1808
perror (":-( unable to pread64(2) primary volume descriptor"),
1809
fprintf (stderr," you most likely want to use -Z option.\n"),
1810
exit (FATAL_START(errno));
1812
if (dev_found == 'M')
1813
{ if (memcmp (the_buffer,"\1CD001",6))
1814
fprintf (stderr,":-( %s doesn't look like isofs...\n",
1815
in_device), exit(FATAL_START(EMEDIUMTYPE));
1817
next_session=setup_C_parm(C_parm,
1818
(struct iso_primary_descriptor *)the_buffer);
1822
{ off64_t off=(atoi(C_parm)-16)*CD_BLOCK;
1824
dup2(in_fd,imgfd); /* kludge! */
1825
if (lseek64 (imgfd,off,SEEK_SET) == (off64_t)-1)
1826
fprintf (stderr,":-( %s: unable to lseek(%lld): ",
1828
perror (NULL), exit(FATAL_START(errno));
1829
} else if (alleged_next_session!=next_session)
1830
fprintf (stderr,"%s: -C argument is %s.\n",
1831
argv[0],alleged_next_session>=0?
1832
"insane":"undefined"),
1833
exit(FATAL_START(EINVAL));
1835
else if (next_session > (0x200000-0x5000)) /* 4GB/2K-40MB/2K */
1836
fprintf (stderr,":-( next session would cross 4GB boundary, "
1838
exit (FATAL_START(ENOSPC));
1840
mkisofs_argv[mkisofs_argc++] = "-C";
1841
mkisofs_argv[mkisofs_argc++] = C_parm;
1842
#ifdef CANNOT_PASS_DEV_FD_N_TO_MKISOFS
1843
# ifdef PASS_STDIN_TO_MKISOFS
1846
M_parm = get_M_parm (in_fd,in_device);
1849
# ifdef PASS_STDIN_TO_MKISOFS
1850
M_parm = "/dev/fd/0";
1852
sprintf (M_parm,"/dev/fd/%d",in_fd);
1855
mkisofs_argv[mkisofs_argc++] = "-M";
1856
mkisofs_argv[mkisofs_argc++] = M_parm;
1857
len = 3 + strlen(C_parm) + 3 + strlen(M_parm);
1858
growisofs_argc += 4;
1861
{ if (!memcmp (the_buffer,"\1CD001",6))
1863
if (next_session<0) next_session = 0;
1868
{ mkisofs_argv[mkisofs_argc++] = argv[i]; }
1871
if (in_device == NULL)
1872
fprintf (stderr,"%s: previous \"session\" device is not specified, "
1873
"do use -M or -Z option\n",argv[0]),
1874
exit (FATAL_START(EINVAL));
1877
{ if (mkisofs_argc==1)
1878
fprintf (stderr,"%s: no mkisofs options specified, "
1879
"aborting...\n",argv[0]),
1880
exit (FATAL_START(EINVAL));
1882
else if ((mkisofs_argc-growisofs_argc)>1)
1883
fprintf (stderr,"%s: no mkisofs options are permitted with =, "
1884
"aborting...\n",argv[0]),
1885
exit (FATAL_START(EINVAL));
1887
mkisofs_argv[mkisofs_argc] = NULL;
1889
assert (next_session!=-1);
1891
assert (out_fd!=-1);
1893
/* never finalize disc at multi-sessioning DVD�R recordings... */
1894
{ int profile = mmc_profile&0xFFFF;
1895
if (next_session>0 &&
1896
(profile==0x1B || profile==0x11)) dvd_compat=0;
1897
/* ... except when filling the media up:-) */
1898
if (next_session>0 && zero_image) dvd_compat=1;
1902
{ int fd=open("/dev/tty",O_RDONLY);
1905
{ if (isatty (fd)) warn_for_isofs |= 2;
1908
else if (isatty (0)) warn_for_isofs |= 2;
1910
if (no_tty_check || (warn_for_isofs&2))
1911
fprintf (stderr,"WARNING: %s already carries isofs!\n",in_device),
1912
printf ("About to execute '");
1914
fprintf (stderr,"FATAL: %s already carries isofs!\n",in_device),
1915
exit(FATAL_START(EBUSY));
1918
printf ("Executing '");
1921
printf ("builtin_dd if=%s of=%s obs=32k seek=%u",
1922
in_image,out_device,next_session/16);
1924
{ for (i=0;i<mkisofs_argc;i++) printf ("%s ",mkisofs_argv[i]);
1925
printf ("| builtin_dd of=%s obs=32k seek=%u",
1926
out_device,next_session/16);
1931
if ((warn_for_isofs&2) && !dry_run && !no_tty_check)
1932
{ fprintf (stderr,"Sleeping for 5 sec...\a"), poll (NULL,0,1000);
1933
fprintf (stderr,"\b\b\b\b\b\b\b\b4 sec...\a"), poll (NULL,0,1000);
1934
fprintf (stderr,"\b\b\b\b\b\b\b\b3 sec...\a"), poll (NULL,0,1000);
1935
fprintf (stderr,"\b\b\b\b\b\b\b\b2 sec...\a"), poll (NULL,0,1000);
1936
fprintf (stderr,"\b\b\b\b\b\b\b\b1 sec...\a"), poll (NULL,0,1000);
1937
fprintf (stderr,"\b\b\b\b\b\b\b\b0 sec...\r");
1940
#define CLOSEONEXEC(fd) do { int f; \
1941
if ((f=fcntl ((fd),F_GETFD)) < 0) f=0; \
1942
fcntl ((fd),F_SETFD,f|FD_CLOEXEC); } while (0)
1944
CLOSEONEXEC(out_fd);
1945
CLOSEONEXEC(ioctl_fd);
1948
if (!dry_run && (poor_man || next_session==0)) /* unmount media */
1952
if ((pid=fork()) == (pid_t)-1)
1953
perror (":-( unable to fork -umount"), exit (FATAL_START(errno));
1955
/* pass through set-root-uid if any */
1959
if ((rval=fcntl (in_fd,F_GETFD))<0) rval=0;
1960
fcntl (in_fd,F_SETFD,rval&~FD_CLOEXEC);
1962
sprintf (str,"%d",in_fd);
1963
execlp (argv[0],"-umount",str,in_device,NULL);
1964
exit (FATAL_START(errno));
1967
{ rpid = waitpid (pid,&rval,0);
1968
if (rpid == (pid_t)-1 || (rpid != pid && (errno=ECHILD,1)))
1969
{ if (errno==EINTR) continue;
1970
else perror (":-( waipid failed"),
1971
exit(FATAL_START(errno));
1973
if (WIFSTOPPED(rval)) continue;
1975
if (WIFEXITED(rval)) errno=WEXITSTATUS(rval);
1981
fprintf (stderr,":-( %s: unable to proceed with recording: ",
1984
fprintf (stderr,"device is mounted\n"),
1986
fprintf (stderr,"unable to unmount\n"),
1988
exit (FATAL_START(errno));
1990
fprintf (stderr,":-( unable to umount %s: ",in_device);
1991
perror (""), exit (FATAL_START(errno));
1996
{ out_device=in_device;
1997
if (!ioctl_device) ioctl_device=out_device;
1999
switch (mmc_profile&0xFFFF)
2000
{ case 0x11: /* DVD-R Sequential */
2001
case 0x12: /* DVD-RAM */
2002
case 0x13: /* DVD-RW Restricted Overwrite */
2003
case 0x14: /* DVD-RW Sequential */
2004
case 0x1A: /* DVD+RW */
2005
case 0x1B: /* DVD+R */
2008
fprintf (stderr,":-( %s: mounted media doesn't appear to be "
2009
"DVD�RW or DVD�R\n",out_device),
2010
exit(FATAL_START(EMEDIUMTYPE));
2017
if (builtin_dd (imgfd,out_fd,next_session*CD_BLOCK) < 0)
2019
errno = err&0x7F; /* they might be passing FATAL_START */
2020
perror (":-( write failed"), exit (err);
2027
pipe_mkisofs_up (mkisofs_argv,in_fd,out_fd,next_session*CD_BLOCK);
2030
* Recall that second 32KB written in this session are still
2031
* in the upper half of the_buffer! And now note that
2032
* poor_man_rewritable() fills the first 32KB with volume
2033
* descriptor set from beginning of the volume, if appropriate
2034
* that is! The latter is a workaround hook for DVD-RW Restricted
2035
* Overwrite interfering with DVD+RW kernel patch... Is this mode
2036
* ugly or is it ugly? G-r-r-r...
2038
if (next_session!=0 &&
2039
(!poor_man || poor_man_rewritable (ioctl_handle,the_buffer)))
2041
descr = (struct iso_primary_descriptor *)the_buffer;
2043
if (memcmp (descr+16,"\1CD001",6))
2044
fprintf (stderr,":-( %s:%d doesn't look like isofs!\n",
2045
out_device,next_session),
2046
exit ((errno=EMEDIUMTYPE));
2048
fprintf (stderr,"%s: copying volume descriptor(s)\n",
2049
poor_man?ioctl_device:out_device);
2051
new_size = from_733(descr[16].volume_space_size) + next_session;
2053
if (!poor_man && (errno=0, pread64 (out_fd,descr,DVD_BLOCK,
2054
VOLDESC_OFF*CD_BLOCK)) != DVD_BLOCK)
2055
errno=errno?errno:EIO,
2056
perror (":-( unable to pread64(2) volume descriptors set"),
2059
memcpy (descr+0,descr+16,sizeof(struct iso_primary_descriptor));
2060
to_733(descr[0].volume_space_size,new_size);
2063
* copy secondary volume descriptor(s) which are expected to
2064
* appear in the very same order.
2066
for (i=1;i<MAX_IVDs;i++)
2067
{ if (descr[16+i].type[0] == (unsigned char)255) break;
2068
if (memcmp (descr[16+i].id,"CD001",5)) break;
2070
if (descr[16+i].type[0] != descr[i].type[0])
2071
{ fprintf (stderr,":-? volume descriptor mismatch, did you "
2072
"use same mkisofs options?\n");
2075
memcpy (descr+i,descr+16+i,sizeof(struct iso_primary_descriptor));
2076
to_733(descr[i].volume_space_size,new_size);
2079
if ((*pwrite64_method) (out_fd,descr,DVD_BLOCK,
2080
VOLDESC_OFF*CD_BLOCK) != DVD_BLOCK)
2081
perror (":-( unable to pwrite64(2) volume descriptors set"),