~ubuntu-branches/ubuntu/gutsy/dvd+rw-tools/gutsy

« back to all changes in this revision

Viewing changes to growisofs.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2004-09-14 11:10:28 UTC
  • Revision ID: james.westby@ubuntu.com-20040914111028-barbf1stmvtng0s7
Tags: upstream-5.19.4.9.7
Import upstream version 5.19.4.9.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * growisofs 5.19 by Andy Polyakov <appro@fy.chalmers.se>.
 
3
 *
 
4
 * Use-it-on-your-own-risk, GPL bless...
 
5
 *
 
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.
 
11
 *
 
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...
 
16
 *
 
17
 * For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/.
 
18
 *
 
19
 * Revision history:
 
20
 *
 
21
 * 1.1:
 
22
 * - flush cache before copying volume descriptors;
 
23
 * 2.0:
 
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
 
28
 *   kernel;
 
29
 * 2.1:
 
30
 * - mkisofs_pid typo;
 
31
 * 2.2:
 
32
 * - uninitialized in_device variable;
 
33
 * - -help option;
 
34
 * 3.0:
 
35
 * - support for DVD+R;
 
36
 * 3.1:
 
37
 * - -Z fails if a file system is present and stdin is not a tty;
 
38
 * 3.2:
 
39
 * - support for image burning (needed for DVD+R as you can't use dd);
 
40
 * 3.3:
 
41
 * - 'growisofs -Z /dev/scdN image.iso' is too confusing, implement
 
42
 *   'growisofs -Z /dev/scdN=image.iso' instead;
 
43
 * 4.0:
 
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;
 
50
 * 4.1:
 
51
 * - uninitialized errno at exit from -Z /dev/scdN=image.iso;
 
52
 * 4.2:
 
53
 * - don't print initial bogus progress indicator values;
 
54
 * - apparently some firmwares exhibit ambiguity in DVD+R disc
 
55
 *   finalizing code;
 
56
 * 5.0:
 
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;
 
60
 * 5.1:
 
61
 * - support for writing speed control;
 
62
 * 5.2:
 
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
 
67
 *   none interactively;
 
68
 * - brown-bag bug in "LONG WRITE IN PROGRESS" handling code fixed;
 
69
 * 5.3:
 
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;
 
79
 * 5.4:
 
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.
 
86
 * 5.5:
 
87
 * - fix for ENOENT at unmount, I should have called myself with execlp,
 
88
 *   not execl;
 
89
 * - security: chdir("/") in set-root-uid assistant;
 
90
 * - use /proc/mounts instead of MOUNTED (a.k.a. /etc/mtab) in Linux
 
91
 *   umount code;
 
92
 * 5.6:
 
93
 * - unconditional exit in set-root-uid assistant, mostly for aesthetic
 
94
 *   reasons;
 
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
 
98
 *   procedure);
 
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;
 
118
 * 5.7:
 
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
 
124
 *   late);
 
125
 * 5.8:
 
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
 
130
 *   port to FreeBSD;
 
131
 * - FreeBSD support contributed by Matthew Dillon;
 
132
 * - volume descriptors from second session were discarded in
 
133
 *   Restricted Overwrite since 5.6;
 
134
 * 5.9:
 
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"
 
138
 *   for DAO;
 
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;
 
147
 * 5.10:
 
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
 
159
 *   to mkisofs binary;
 
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
 
164
 *   at exit;
 
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;
 
177
 * 5.11:
 
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
 
184
 *   conservative one;
 
185
 * 5.12:
 
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;
 
202
 * 5.13:
 
203
 * - workarounds for Panasonic/MATSUSHITA DVD-RAM LF-D310;
 
204
 * - Solaris: media load upon start-up;
 
205
 * 5.14:
 
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
 
211
 *   dry-run mode;
 
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;
 
227
 * 5.15:
 
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
 
254
 *   case);
 
255
 * - -speed option in DVD+ context is enabled, upon release tested with
 
256
 *   Plextor PX-708A;
 
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"
 
259
 *   rewritable media;
 
260
 * 5.16:
 
261
 * - brown-bag bug in "LONG WRITE IN PROGRESS" code path;
 
262
 * 5.17:
 
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;
 
278
 * 5.18:
 
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;
 
284
 * 5.19:
 
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
 
289
 *   PX-708A;
 
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;
 
294
 */
 
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));   \
 
300
} while (0)
 
301
 
 
302
#define _LARGEFILE_SOURCE 
 
303
#define _LARGEFILE64_SOURCE
 
304
#define _FILE_OFFSET_BITS 64
 
305
#if defined(__linux)
 
306
/* ... and "engage" glibc large file support */
 
307
#ifndef _GNU_SOURCE
 
308
#define _GNU_SOURCE
 
309
#endif
 
310
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
 
311
#define off64_t  off_t
 
312
#define stat64   stat
 
313
#define fstat64  fstat
 
314
#define open64   open
 
315
#define pread64  pread
 
316
#define pwrite64 pwrite
 
317
#define lseek64  lseek
 
318
#endif
 
319
 
 
320
#include <stdio.h>
 
321
#include <unistd.h>
 
322
#include <stdlib.h>
 
323
#include <time.h>
 
324
#include <errno.h>
 
325
#include <string.h>
 
326
#include <sys/types.h>
 
327
#include <sys/stat.h>
 
328
#include <fcntl.h>
 
329
#include <sys/wait.h>
 
330
#include <sys/mman.h>
 
331
#include <signal.h>
 
332
#include <poll.h>
 
333
#include <assert.h>
 
334
#include <sys/time.h>
 
335
 
 
336
#define FATAL_START(err)        (0x80|(err))
 
337
#ifndef EMEDIUMTYPE
 
338
#define EMEDIUMTYPE     EINVAL
 
339
#endif
 
340
#ifndef ENOMEDIUM
 
341
#define ENOMEDIUM       ENODEV
 
342
#endif
 
343
 
 
344
typedef ssize_t (*pwrite64_t)(int,const void *,size_t,off64_t);
 
345
/*
 
346
 * Symbols from growisofs_mmc.cpp
 
347
 */
 
348
/*
 
349
 * These might terminate the program if error appears fatal.
 
350
 * The return value is therefore is always sane and suitable
 
351
 * for assignment.
 
352
 */
 
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);
 
356
/*
 
357
 * These never terminate the program.
 
358
 * Pay attention to the return value.
 
359
 */
 
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);
 
364
 
 
365
/* simplified */
 
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];
 
372
};
 
373
 
 
374
#define CD_BLOCK        ((off64_t)2048)
 
375
#define VOLDESC_OFF     16
 
376
#define DVD_BLOCK       (32*1024)
 
377
 
 
378
static unsigned int from_733 (unsigned char *s)
 
379
{ unsigned int ret=0;
 
380
    ret |= s[0];
 
381
    ret |= s[1]<<8;
 
382
    ret |= s[2]<<16;
 
383
    ret |= s[3]<<24;
 
384
  return ret;
 
385
}
 
386
 
 
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;
 
395
    s[7] = (val)     & 0xFF;
 
396
}
 
397
 
 
398
static pwrite64_t pwrite64_method = pwrite64;
 
399
/*
 
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...
 
403
 */
 
404
static char *the_buffer;
 
405
/*
 
406
 * id_fd is passed to mkisofs, out_fd - to pwrite and ioctl_fd - to ioctl.
 
407
 */
 
408
static int    in_fd=-1,out_fd=-1;
 
409
 
 
410
#ifndef INVALID_HANDLE
 
411
#define INVALID_HANDLE ((void *)-1)
 
412
#endif
 
413
static void   *ioctl_handle=INVALID_HANDLE;
 
414
#define ioctl_fd ((long)ioctl_handle)
 
415
 
 
416
static int      poor_man=-1, zero_image=0, quiet=1,
 
417
                overburn=0, no_tty_check=0, dry_run=0, dao_size=0;
 
418
 
 
419
int    dvd_compat=0, test_write=0, no_reload=0, mmc_profile=0;
 
420
double speed_factor=0.0;
 
421
char  *ioctl_device;
 
422
int    _argc;
 
423
char **_argv;
 
424
 
 
425
#if defined(__linux)
 
426
 
 
427
#include <linux/cdrom.h>
 
428
#include <sys/ioctl.h>
 
429
#include <linux/raw.h>
 
430
 
 
431
char *find_raw_device(struct stat64 *sb)
 
432
{ int   i,rawctl,dev_major,dev_minor;
 
433
  char  *ret=NULL;
 
434
  struct raw_config_request req;
 
435
  static char rawdevname[24] = "";
 
436
 
 
437
    if (!S_ISBLK(sb->st_mode)) return NULL;
 
438
 
 
439
    dev_major = major (sb->st_rdev);
 
440
    dev_minor = minor (sb->st_rdev);
 
441
 
 
442
    if ((rawctl=open ("/dev/rawctl",O_RDONLY)) < 0) return NULL;
 
443
 
 
444
    for (i=1;i<256;i++)
 
445
    {   req.raw_minor = i;
 
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);
 
449
            ret = rawdevname;
 
450
            break;
 
451
        }
 
452
    }
 
453
    close (rawctl);
 
454
 
 
455
  return ret;
 
456
}
 
457
 
 
458
char *setup_fds (char *device)
 
459
{ char *odevice;
 
460
  uid_t uid=getuid();
 
461
  struct stat64 sb,sc;
 
462
 
 
463
    /*
 
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...
 
467
     */
 
468
#if 0
 
469
#define GET_REAL
 
470
    /*
 
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].
 
474
     */
 
475
    setreuid ((uid_t)-1,uid);
 
476
#else
 
477
    /*
 
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.
 
482
     */
 
483
#endif
 
484
 
 
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));
 
490
 
 
491
#ifdef GET_REAL
 
492
    setreuid ((uid_t)-1,uid);
 
493
#endif
 
494
 
 
495
    if (fstat64(in_fd,&sb) < 0)
 
496
        fprintf (stderr,":-( unable to stat64(\"%s\"): ",device),
 
497
        perror (NULL), exit (FATAL_START(errno));
 
498
 
 
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): ",
 
504
                            device),
 
505
            perror (NULL), exit (FATAL_START(errno));
 
506
      open_rw:
 
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));
 
516
      opened_rw:
 
517
        poor_man = 0;
 
518
        if (ioctl_handle!=INVALID_HANDLE)
 
519
            close (ioctl_fd), ioctl_handle = INVALID_HANDLE;
 
520
        setuid (uid);           /* drop all privileges */
 
521
        return device;
 
522
    }
 
523
 
 
524
    ioctl_handle=(void *)(long)dup(in_fd);
 
525
 
 
526
    /*
 
527
     * get_mmc_profile terminates the program if ioctl_handle is
 
528
     * not an MMC unit...
 
529
     */
 
530
    mmc_profile = get_mmc_profile (ioctl_handle);
 
531
 
 
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: ",
 
535
                        device),
 
536
        perror (NULL), exit (FATAL_START(errno));
 
537
    }
 
538
 
 
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                        */
 
544
        open_poor_man:
 
545
            poor_man = 1;
 
546
            out_fd = dup(in_fd);
 
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;
 
552
            break;
 
553
        default:
 
554
            fprintf (stderr,":-( %s: media is not recognized as "
 
555
                            "recordable DVD: %X\n",device,mmc_profile);
 
556
            exit (FATAL_START(EMEDIUMTYPE));
 
557
    }
 
558
 
 
559
    /*
 
560
     * Attempt to locate /dev/raw/raw*
 
561
     */
 
562
#ifdef GET_REAL
 
563
#undef GET_REAL
 
564
    setreuid((uid_t)-1,0);      /* get root for a /dev/raw sake */
 
565
#endif
 
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 */
 
569
                goto open_poor_man;
 
570
            else
 
571
                fprintf (stderr,":-( unable to open64(\"%s\",O_RDWR): ",
 
572
                                odevice),
 
573
                perror (NULL), exit (FATAL_START(errno));
 
574
        }
 
575
        device=odevice;
 
576
        goto opened_rw;
 
577
    }
 
578
    if ((mmc_profile&0xFFFF) == 0x12)   goto open_rw;   /* DVD-RAM */
 
579
    else                                goto open_poor_man;
 
580
}
 
581
 
 
582
#elif defined(__OpenBSD__) || defined(__NetBSD__)
 
583
 
 
584
char *setup_fds (char *device)
 
585
{ uid_t uid=getuid();
 
586
  struct stat sb,sc;
 
587
 
 
588
    /*
 
589
     * We might be entering as euid=root!
 
590
     */
 
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));
 
594
 
 
595
    if (fstat (in_fd,&sb) < 0)
 
596
        fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
 
597
        perror (NULL), exit (FATAL_START(errno));
 
598
 
 
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",
 
602
                            device+5);
 
603
            if (isatty(0) && !dry_run) poll(NULL,0,5000);
 
604
        }
 
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));
 
610
      open_rw:
 
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));
 
614
      opened_rw:
 
615
        poor_man = 0;
 
616
        close (ioctl_fd);
 
617
        ioctl_handle = INVALID_HANDLE;
 
618
        setuid (uid);   /* drop all privileges  */
 
619
        return device;
 
620
    }
 
621
 
 
622
    /*
 
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.
 
628
     */
 
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),
 
632
        perror (NULL);
 
633
        if (errno == EBUSY)
 
634
            fprintf (stderr,"    is its block counterpart mounted?\n");
 
635
        exit (FATAL_START(errno));
 
636
    }
 
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));
 
643
 
 
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                       */
 
651
        open_poor_man:
 
652
            poor_man = 1;
 
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);
 
659
            goto opened_rw;
 
660
        default:
 
661
            fprintf (stderr,":-( %s: media is not recognized as "
 
662
                            "recordable DVD: %X\n",device,mmc_profile);
 
663
            exit (FATAL_START(EMEDIUMTYPE));
 
664
    }
 
665
    /* not actually reached */
 
666
    setuid(uid);
 
667
    goto open_rw;
 
668
}
 
669
 
 
670
#elif defined(__FreeBSD__)
 
671
 
 
672
#include <sys/cdio.h>
 
673
#include <camlib.h>
 
674
#include <cam/scsi/scsi_pass.h>
 
675
 
 
676
#undef  ioctl_fd
 
677
#define ioctl_fd (((struct cam_device *)ioctl_handle)->fd)
 
678
 
 
679
#define PASS_STDIN_TO_MKISOFS
 
680
 
 
681
char *setup_fds (char *device)
 
682
{ uid_t         uid=getuid();
 
683
  struct stat   sb,sc;
 
684
  union ccb     ccb;
 
685
  char          pass[32]; /* periph_name is 16 chars long */
 
686
  struct cam_device *cam;
 
687
  int           once=1;
 
688
 
 
689
    /*
 
690
     * We might be entering as euid=root!
 
691
     */
 
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));
 
695
 
 
696
    if (fstat (in_fd,&sb) < 0)
 
697
        fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
 
698
        perror (NULL), exit (FATAL_START(errno));
 
699
 
 
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));
 
706
      open_rw:
 
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));
 
716
      opened_rw:
 
717
        poor_man = 0;
 
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  */
 
722
        return device;
 
723
    }
 
724
 
 
725
    /*
 
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.
 
731
     */
 
732
 
 
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));
 
741
        }
 
742
        break;
 
743
    }
 
744
 
 
745
    sprintf (pass,"/dev/%.15s%u",ccb.cgdl.periph_name,ccb.cgdl.unit_number);
 
746
    cam = cam_open_pass (pass,O_RDWR,NULL);
 
747
    if (cam == NULL)
 
748
    {   fprintf (stderr,":-( unable to cam_open_pass(\"%s\",O_RDWR): ",pass),
 
749
        perror (NULL);
 
750
        exit (FATAL_START(errno));
 
751
    }
 
752
 
 
753
    ioctl_handle = (void *)cam;
 
754
 
 
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                       */
 
762
        open_poor_man:
 
763
            poor_man = 1;
 
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;
 
769
            break;
 
770
        default:
 
771
            fprintf (stderr,":-( %s: media is not recognized as "
 
772
                            "recordable DVD: %X\n",device,mmc_profile);
 
773
            exit (FATAL_START(EMEDIUMTYPE));
 
774
    }
 
775
    setuid(uid);
 
776
    goto open_rw;
 
777
}
 
778
 
 
779
#elif defined(__sun) || defined(sun)
 
780
 
 
781
#include <volmgt.h>
 
782
#include <sys/cdio.h>
 
783
 
 
784
char *setup_fds (char *device)
 
785
{ uid_t uid=getuid();
 
786
  struct stat64 sb,sc;
 
787
  int v;
 
788
 
 
789
    if ((v=volmgt_running()))
 
790
    { char *file=NULL,*volname;
 
791
 
 
792
        /*
 
793
         * I leak some memory here, but I don't care...
 
794
         */
 
795
        if ((volname=volmgt_symname (device)))
 
796
            file=media_findname (volname);
 
797
        else
 
798
            file=media_findname (device);
 
799
 
 
800
        if (file) device=file;
 
801
        else      v=0;
 
802
    }
 
803
 
 
804
    /*
 
805
     * We might be entering as euid=root!
 
806
     */
 
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));
 
812
 
 
813
    if (fstat64 (in_fd,&sb) < 0)
 
814
        fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
 
815
        perror (NULL), exit (FATAL_START(errno));
 
816
 
 
817
    if (!S_ISCHR(sb.st_mode))
 
818
    { char *s;
 
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);
 
823
        }
 
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));
 
829
      open_rw:
 
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));
 
839
        poor_man = 0;
 
840
        close (ioctl_fd);
 
841
        ioctl_handle = INVALID_HANDLE;
 
842
        setuid (uid);   /* drop all privileges  */
 
843
        return device;
 
844
    }
 
845
 
 
846
    /*
 
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.
 
852
     */
 
853
    ioctl_handle = (void *)(long)dup (in_fd);
 
854
 
 
855
#if 0
 
856
    if (ioctl(ioctl_handle,CDROMSTART)<0 && errno==ENXIO)
 
857
        media_load(ioctl_handle);
 
858
#endif
 
859
 
 
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                       */
 
868
            poor_man = 1;
 
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...
 
872
             */
 
873
            setuid (uid);       /* drop all privileges  */
 
874
#endif
 
875
            return ioctl_device=device;
 
876
        default:
 
877
            fprintf (stderr,":-( %s: media is not recognized as "
 
878
                            "recordable DVD: %X\n",device,mmc_profile);
 
879
            exit (FATAL_START(EMEDIUMTYPE));
 
880
    }
 
881
    setuid(uid);
 
882
    goto open_rw;
 
883
}
 
884
 
 
885
#elif defined(__hpux)
 
886
 
 
887
#ifdef SCTL_MAJOR
 
888
#  define SCTL_SANITY_CHECK SCTL_MAJOR-1
 
889
#  if SCTL_SANITY_CHECK<=0
 
890
#    undef SCTL_MAJOR
 
891
#  endif
 
892
#  undef SCTL_SANITY_CHECK
 
893
#endif
 
894
 
 
895
#ifndef SCTL_MAJOR
 
896
#error "SCTL_MAJOR is undefined or not sane."
 
897
#endif
 
898
 
 
899
#include <sys/mknod.h>
 
900
#include <sys/diskio.h>
 
901
 
 
902
#define seteuid(x)      setreuid((uid_t)-1,x)
 
903
 
 
904
#if 1
 
905
#define CANNOT_PASS_DEV_FD_N_TO_MKISOFS
 
906
#elif 0
 
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)
 
911
        char    *path;
 
912
 {
 
913
+       int fd;
 
914
+
 
915
+       if (sscanf (path,"/dev/fd/%u",&fd) == 1) {
 
916
+               int fdd = dup(fd);      /* validate file descriptor */
 
917
+               if (fdd < 0) return -1;
 
918
+               close (fdd);
 
919
+               in_image = fdopen (fd,"rb");
 
920
+               return in_image ? 0 : -1;
 
921
+       }
 
922
+
 
923
#endif
 
924
 
 
925
#ifdef CANNOT_PASS_DEV_FD_N_TO_MKISOFS
 
926
char *get_M_parm (int fd, char *device)
 
927
{ struct stat sb;
 
928
  dev_t m;
 
929
  char *ret=device;
 
930
  static char ctl[16];
 
931
 
 
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);
 
935
        ret = ctl;
 
936
    }
 
937
 
 
938
  return ret;
 
939
}
 
940
#endif
 
941
 
 
942
char *setup_fds (char *device)
 
943
{ uid_t uid=getuid();
 
944
  struct stat64 sb,sc;
 
945
  dev_t  m;
 
946
  static char rscsi [32];
 
947
  disk_describe_type ddt;
 
948
 
 
949
    /*
 
950
     * We might be entering as euid=root!
 
951
     */
 
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));
 
955
 
 
956
    if (fstat64 (in_fd,&sb) < 0)
 
957
        fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
 
958
        perror (NULL), exit (FATAL_START(errno));
 
959
 
 
960
    if (!S_ISCHR(sb.st_mode))
 
961
    { char *s;
 
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);
 
966
        }
 
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));
 
972
      open_rw:
 
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));
 
982
        poor_man = 0;
 
983
        close (ioctl_fd);
 
984
        ioctl_handle = INVALID_HANDLE;
 
985
        setuid (uid);   /* drop all privileges  */
 
986
        return device;
 
987
    }
 
988
 
 
989
    /*
 
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.
 
995
     */
 
996
 
 
997
    m=minor(sb.st_rdev);
 
998
 
 
999
    /* Make sure user isn't using /dev/rscsi/cXtYlZ... */
 
1000
#if 1
 
1001
    if (ioctl (in_fd,DIOC_DESCRIBE,&ddt) != 0)
 
1002
#else
 
1003
    if (major(sb.st_rdev) == SCTL_MAJOR)
 
1004
#endif
 
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));
 
1008
 
 
1009
    /*
 
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...
 
1013
     */
 
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),
 
1019
        perror (NULL);
 
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));
 
1025
    }
 
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));
 
1034
 
 
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                       */
 
1043
            poor_man = 1;
 
1044
            out_fd = dup(ioctl_fd);
 
1045
#if 0       /* HP-UX requires root privileges upon SIOC_IO ioctl */
 
1046
            setuid (uid);       /* drop all privileges  */
 
1047
#endif
 
1048
            return ioctl_device=rscsi;
 
1049
        default:
 
1050
            fprintf (stderr,":-( %s: media is not recognized as "
 
1051
                            "recordable DVD: %X\n",device,mmc_profile);
 
1052
            exit (FATAL_START(EMEDIUMTYPE));
 
1053
    }
 
1054
    setuid(uid);
 
1055
    goto open_rw;
 
1056
}
 
1057
 
 
1058
/*
 
1059
 * PA-RISC HP-UX doesn't have /dev/zero:-(
 
1060
 */
 
1061
static fd_set _dev_zero;
 
1062
 
 
1063
static int open64_zero(const char *pathname, int flags)
 
1064
{ int fd;
 
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);
 
1069
  return fd;    
 
1070
}
 
1071
 
 
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;
 
1075
}
 
1076
 
 
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);
 
1080
  return ret;
 
1081
}
 
1082
 
 
1083
static int dup2_zero (int oldfd, int newfd)
 
1084
{ int ret;
 
1085
    ret = dup2 (oldfd,newfd);
 
1086
    if (ret >= 0)
 
1087
    {   if (FD_ISSET(oldfd,&_dev_zero)) FD_SET (ret,&_dev_zero);
 
1088
        else                            FD_CLR (ret,&_dev_zero);
 
1089
    }
 
1090
  return ret;
 
1091
}
 
1092
#define open64  open64_zero
 
1093
#define read    read_zero
 
1094
#define close   close_zero
 
1095
#define dup2    dup2_zero
 
1096
 
 
1097
#elif defined(__sgi)
 
1098
 
 
1099
#include <sys/attributes.h>
 
1100
#include <sys/param.h>
 
1101
#include <mediad.h>
 
1102
 
 
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];
 
1110
 
 
1111
    /*
 
1112
     * We might be entering as euid=root!
 
1113
     */
 
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));
 
1118
    }
 
1119
 
 
1120
    if (fstat64 (in_fd,&sb) < 0)
 
1121
        fprintf (stderr,":-( unable to stat(\"%s\"): ",device),
 
1122
        perror (NULL), exit (FATAL_START(errno));
 
1123
 
 
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);
 
1129
        }
 
1130
      open_rw:
 
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));
 
1139
      opened_rw:
 
1140
        poor_man = 0;
 
1141
        close (ioctl_fd);
 
1142
        ioctl_handle = INVALID_HANDLE;
 
1143
        setuid (uid);   /* drop all privileges  */
 
1144
        return device;
 
1145
    }
 
1146
 
 
1147
    /*
 
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.
 
1153
     */
 
1154
 
 
1155
  tray_might_be_open:
 
1156
 
 
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';
 
1163
 
 
1164
    if ((s=strstr(hw_path,"/scsi_ctlr/")))
 
1165
        sscanf (s,"/scsi_ctlr/%d/target/%d/lun/%d/",&bus,&tgt,&lun);
 
1166
 
 
1167
    /* Make sure user is using /dev/rdsk/dksXdYlZvol... */
 
1168
    if ((s=strstr(hw_path,"/disk/volume/char"))==NULL)
 
1169
    {   if (lun)
 
1170
            fprintf (stderr,":-( stick to /dev/rdsk/dks%dd%dl%dvol!\n",
 
1171
                            bus,tgt,lun);
 
1172
        else
 
1173
            fprintf (stderr,":-( stick to /dev/rdsk/dks%dd%dvol!\n",
 
1174
                            bus,tgt);
 
1175
        exit(FATAL_START(EINVAL));
 
1176
    }
 
1177
 
 
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);
 
1187
 
 
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                       */
 
1195
        open_poor_man:
 
1196
            poor_man = 1;
 
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... */
 
1211
            goto open_poor_man;
 
1212
            break;
 
1213
        default:
 
1214
            fprintf (stderr,":-( %s: media is not recognized as "
 
1215
                            "recordable DVD: %X\n",device,mmc_profile);
 
1216
            exit (FATAL_START(EMEDIUMTYPE));
 
1217
    }
 
1218
    /* not actually reached */
 
1219
    setuid(uid);
 
1220
    goto open_rw;
 
1221
}
 
1222
 
 
1223
#else
 
1224
#error "Unsupported OS"
 
1225
#endif
 
1226
 
 
1227
int setup_C_parm (char *C_parm,struct iso_primary_descriptor *descr)
 
1228
{ int next_session=-1,profile=mmc_profile&0xFFFF;
 
1229
 
 
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 */
 
1233
        next_session += 15;
 
1234
        next_session /= 16;
 
1235
        next_session *= 16;
 
1236
        sprintf (C_parm,"16,%u",next_session);
 
1237
    }
 
1238
    else if (profile==0x1B || profile==0x11 || profile==0x14)
 
1239
        next_session=plusminus_r_C_parm (ioctl_handle,C_parm);
 
1240
 
 
1241
  return next_session;
 
1242
}
 
1243
 
 
1244
int builtin_dd (int infd,int outfd,off64_t outoff)
 
1245
{ char          *s;
 
1246
  int            n,off,fd;
 
1247
  struct stat64  sb;
 
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;
 
1251
 
 
1252
    if ((fd=mkstemp (s=strdup("/tmp/dvd+rw.XXXXXX"))) < 0)
 
1253
        fprintf (stderr,":-( unable to mkstemp(\"%s\")",s),
 
1254
        exit(FATAL_START(errno));
 
1255
 
 
1256
    ftruncate(fd,sizeof(*progress));
 
1257
    unlink(s), free(s);
 
1258
 
 
1259
    progress = (void *)mmap (NULL,sizeof(*progress),PROT_READ|PROT_WRITE,
 
1260
                        MAP_SHARED,fd,(off_t)0);
 
1261
    close (fd);
 
1262
    if (progress == MAP_FAILED)
 
1263
        fprintf (stderr,":-( unable to anonymously mmap %lu?\n",
 
1264
                        sizeof(*progress)),
 
1265
        perror (NULL), exit(FATAL_START(errno));
 
1266
 
 
1267
    if (fstat64 (infd,&sb))
 
1268
        perror (":-( unable to fstat64"), exit(FATAL_START(errno));
 
1269
 
 
1270
    if (ioctl_handle!=INVALID_HANDLE)
 
1271
        capacity = get_capacity (ioctl_handle);
 
1272
 
 
1273
    progress->zero=0;
 
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",
 
1281
                            ioctl_device,
 
1282
                            (capacity-outoff)/2048,tracksize/2048);
 
1283
            if (overburn)
 
1284
                fprintf (stderr,":-! ignoring...\n");
 
1285
            else
 
1286
                close(infd), close(outfd),
 
1287
                exit (FATAL_START(ENOSPC));
 
1288
        }
 
1289
    }
 
1290
    else progress->final=0;
 
1291
 
 
1292
    if (!dry_run && quiet<=0 && (pid=fork()) == 0)
 
1293
    { double            ratio,velocity,slept;
 
1294
      int               delta,nfirst=0;
 
1295
      off64_t           lastcurrent=outoff,current;
 
1296
      struct timeval    tv;
 
1297
 
 
1298
        close (infd);
 
1299
        close (outfd);
 
1300
        while (kill (ppid,0)==0)
 
1301
        {   gettimeofday (&tv,NULL); slept =  tv.tv_usec/1e6+tv.tv_sec;
 
1302
            poll (NULL,0,3333);
 
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;
 
1316
            }
 
1317
            else
 
1318
                fprintf (stdout,"%10lld/%lld (%4.1f%%) @0x, remaining ??:??\n",
 
1319
                                current,progress->final,0.0);
 
1320
            fflush (stdout);
 
1321
        }
 
1322
        exit(0); /* not [normally] reached */
 
1323
    }
 
1324
 
 
1325
    /* suck in first 64K and examine ISO9660 Primary Descriptor if present */
 
1326
    off = 0;
 
1327
    while ((n=read (infd,the_buffer+off,2*DVD_BLOCK-off)) > 0)
 
1328
    {   off += n;
 
1329
        if (off == 2*DVD_BLOCK)
 
1330
        {   if (!memcmp(the_buffer+DVD_BLOCK,"\1CD001",6))
 
1331
            { struct iso_primary_descriptor *descr;
 
1332
 
 
1333
                descr=(struct iso_primary_descriptor *)(the_buffer+DVD_BLOCK);
 
1334
 
 
1335
                if (!zero_image)
 
1336
                {   if (tracksize==0)
 
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",
 
1341
                                            ioctl_device,
 
1342
                                            (capacity-outoff)/2048,
 
1343
                                            tracksize/2048);
 
1344
                            if (overburn)
 
1345
                                fprintf (stderr,":-! ignoring...\n");
 
1346
                            else if (dry_run)
 
1347
                                close(infd), close(outfd),
 
1348
                                exit(FATAL_START(ENOSPC));
 
1349
                            else
 
1350
                            {   n = -1; errno = FATAL_START(ENOSPC);
 
1351
                                goto out;
 
1352
                            }
 
1353
                        }
 
1354
                    }
 
1355
                    /* else already checked for overburn condition */
 
1356
                }
 
1357
                else if (capacity > outoff)
 
1358
                { int i=0;
 
1359
                  unsigned int ts = (tracksize=capacity-outoff)/2048;
 
1360
 
 
1361
                    while (i<16 && descr->type[0] != (unsigned char)255)
 
1362
                        to_733 (descr->volume_space_size,ts),
 
1363
                        descr++, i++;
 
1364
                }
 
1365
                else
 
1366
                {   fprintf (stderr,":-( capacity is undefined or insane?\n");
 
1367
                    n = -1; errno = FATAL_START(EINVAL);/* ... or whatever */
 
1368
                    goto out;
 
1369
                }
 
1370
            }
 
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 */
 
1375
                goto out;
 
1376
            }
 
1377
 
 
1378
            if (dry_run) close(infd), close(outfd), exit(0);
 
1379
 
 
1380
            if (poor_man)
 
1381
                /*
 
1382
                 * See commentary section in growisofs_mmc.cpp for
 
1383
                 * further details on poor_mans_setup
 
1384
                 */
 
1385
                pwrite64_method = poor_mans_setup (ioctl_handle,
 
1386
                                                   outoff+tracksize);
 
1387
 
 
1388
            if (!progress->final)
 
1389
            {   if (tracksize)  progress->final = outoff+tracksize;
 
1390
                else            progress->final = capacity;
 
1391
            }
 
1392
            if (capacity && progress->final>capacity)
 
1393
                progress->final = capacity;
 
1394
 
 
1395
            progress->zero=time(NULL);
 
1396
 
 
1397
            /* Write two 32KB chunks, not one 64KB... */
 
1398
            if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff))
 
1399
                        != DVD_BLOCK)
 
1400
            {   if (n>0)        errno = FATAL_START(EIO);
 
1401
                else if (n==0)  errno = FATAL_START(ENOSPC);
 
1402
                n = -1;
 
1403
                goto out;
 
1404
            }
 
1405
            outoff += DVD_BLOCK;
 
1406
            progress->current=outoff;
 
1407
 
 
1408
            if ((n=(*pwrite64_method) (outfd,the_buffer+DVD_BLOCK,DVD_BLOCK,outoff))
 
1409
                        != DVD_BLOCK)
 
1410
            {   if (n>0)        errno = EIO;
 
1411
                else if (n==0)  errno = ENOSPC;
 
1412
                n = -1;
 
1413
                goto out;
 
1414
            }
 
1415
            outoff += DVD_BLOCK;
 
1416
            progress->current=outoff;
 
1417
 
 
1418
            break;
 
1419
        }
 
1420
    }
 
1421
    if (n<=0) goto out;
 
1422
 
 
1423
    /* yeah, really kludgy, shuffling file descriptor like that... */
 
1424
    if (zero_image)
 
1425
        close(infd), infd=open64 ("/dev/zero",O_RDONLY);
 
1426
 
 
1427
    off = 0;
 
1428
    /*
 
1429
     * From now on only the first 32K of the_buffer are used!
 
1430
     */
 
1431
    while ((n=read (infd,the_buffer+off,DVD_BLOCK-off)) > 0)
 
1432
    {   off += n;
 
1433
        if (off == DVD_BLOCK)
 
1434
        {   off = 0;
 
1435
            if ((n=(*pwrite64_method) (outfd,the_buffer,DVD_BLOCK,outoff))
 
1436
                        != DVD_BLOCK)
 
1437
            {   if (n>0)        errno = EIO;
 
1438
                else if (n==0)  errno = ENOSPC;
 
1439
                n = -1;
 
1440
                break;
 
1441
            }
 
1442
            outoff += DVD_BLOCK;
 
1443
            progress->current=outoff;
 
1444
        }
 
1445
    }
 
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))
 
1449
                        != DVD_BLOCK)
 
1450
        {    if (n>0)           errno = EIO;
 
1451
             else if (n==0)     errno = ENOSPC;
 
1452
             n = -1;
 
1453
        }
 
1454
        outoff += DVD_BLOCK;
 
1455
    }
 
1456
 
 
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));
 
1460
out:
 
1461
    { int saved_errno=errno;
 
1462
 
 
1463
        if (pid!=(pid_t)-1) kill (pid,SIGTERM), waitpid (pid,NULL,0);
 
1464
 
 
1465
        errno = outoff ? saved_errno : (n--?saved_errno:FATAL_START(EIO));
 
1466
    }
 
1467
 
 
1468
  return n;
 
1469
}
 
1470
 
 
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;
 
1474
 
 
1475
    if (pipe (fildes) < 0)
 
1476
        perror (":-( unable to create pipe"), exit(FATAL_START(errno));
 
1477
 
 
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);
 
1482
        close (fildes[0]);
 
1483
        close (fildes[1]);
 
1484
        close (outfd);  /* redundant:-) */
 
1485
 
 
1486
#ifdef PASS_STDIN_TO_MKISOFS
 
1487
        dup2(infd,0);
 
1488
        close(infd);
 
1489
        infd=0;
 
1490
#endif
 
1491
        if ((n=fcntl (infd,F_GETFD))<0) n=0;
 
1492
        fcntl (infd,F_SETFD,n&~FD_CLOEXEC);
 
1493
        /*
 
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.
 
1497
         */
 
1498
        setuid(getuid());
 
1499
        execvp (mkisofs_argv[0],mkisofs_argv);
 
1500
        fprintf (stderr,":-( unable to execute %s: ",mkisofs_argv[0]),
 
1501
        perror (NULL), exit (FATAL_START(errno));
 
1502
    }
 
1503
 
 
1504
    close (fildes[1]);
 
1505
 
 
1506
    n=builtin_dd(fildes[0],outfd,outoff);
 
1507
 
 
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);
 
1511
 
 
1512
        if (!WIFEXITED(ret) || WEXITSTATUS(ret)!=0)
 
1513
            fprintf (stderr,":-( mkisofs has failed: %d\n",WEXITSTATUS(ret)),
 
1514
            exit (1);
 
1515
    }
 
1516
    else if (n<0)
 
1517
    { int err = errno;
 
1518
        errno = err&0x7F;       /* they might be passing FATAL_START */
 
1519
        perror (":-( write failed"), exit (err);
 
1520
    }
 
1521
}
 
1522
 
 
1523
/*
 
1524
 * This may not be larger than 32KB!
 
1525
 */
 
1526
#define MAX_IVDs        16
 
1527
#define IVDs_SIZE       (sizeof(struct iso_primary_descriptor)*MAX_IVDs)
 
1528
 
 
1529
int main (int argc, char *argv[])
 
1530
{ int  imgfd=-1;
 
1531
  char *in_device=NULL,*out_device=NULL,*in_image=NULL,*env;
 
1532
  char dev_found;
 
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;
 
1538
 
 
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));
 
1545
    }
 
1546
    /*
 
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...
 
1553
     */
 
1554
    if (*argv[0] == '-')
 
1555
    { int fd;
 
1556
      struct stat fdst;
 
1557
 
 
1558
        chdir ("/");
 
1559
        if (argc != 3)  exit (EINVAL);
 
1560
        fd=atoi (argv[1]);
 
1561
        if (!strcmp(argv[0],"-umount"))
 
1562
        {   if (fumount (fd)) exit (errno);
 
1563
            exit (0);
 
1564
        }
 
1565
        else if (!strcmp(argv[0],"-reload"))
 
1566
        {   if (fstat (fd,&fdst) < 0)
 
1567
                perror (":-( unable to fstat"), exit (1);
 
1568
 
 
1569
            close (fd);
 
1570
 
 
1571
            if (media_reload (argv[2],&fdst))
 
1572
                perror (":-( unable to reload tray"), exit (1);
 
1573
            exit (0);
 
1574
        }
 
1575
        exit(1);
 
1576
    }
 
1577
 
 
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);
 
1582
#else
 
1583
    { int fd;
 
1584
 
 
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,
 
1589
                        MAP_PRIVATE,fd,0);
 
1590
        close (fd);
 
1591
    }
 
1592
#endif
 
1593
    if (the_buffer == MAP_FAILED)
 
1594
        fprintf (stderr,":-( unable to anonymously mmap %d: ",2*DVD_BLOCK),
 
1595
        perror (NULL), exit (FATAL_START(errno));
 
1596
 
 
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));
 
1602
 
 
1603
    env = getenv ("MKISOFS");
 
1604
    mkisofs_argv[0] = (env?env:"mkisofs"), mkisofs_argc = 1;
 
1605
    growisofs_argc=0;
 
1606
 
 
1607
    _argc=argc, _argv=argv;
 
1608
 
 
1609
    for (i=1;i<argc;i++)
 
1610
    { int len=strlen(argv[i]);
 
1611
      char *opt;
 
1612
 
 
1613
        dev_found = '\0';
 
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];
 
1619
                dev_found = 'M';
 
1620
            }
 
1621
            else if (!strncmp(opt,"-prev-session",13))
 
1622
            {   if (len > 13) in_device = opt+13;
 
1623
                else          in_device = argv[++i];
 
1624
                dev_found = 'M';
 
1625
            }
 
1626
            else if (argv[i][1] == 'Z')
 
1627
            {   if (len > 2) in_device = argv[i]+2;
 
1628
                else         in_device = argv[++i];
 
1629
                dev_found = 'Z';
 
1630
            }
 
1631
            else if (!strncmp(opt,"-zero-session",13))
 
1632
            {   if (len > 13) in_device = opt+13;
 
1633
                else          in_device = argv[++i];
 
1634
                dev_found = 'Z';
 
1635
            }
 
1636
            else if (!strcmp(opt,"-poor-man"))
 
1637
            {   if (poor_man<0) poor_man = 1;
 
1638
                continue;
 
1639
            }
 
1640
            else if (!strncmp(opt,"-speed",6))
 
1641
            { char *s;
 
1642
                if (len>6)      (s=strchr(opt,'='))?s++:s;
 
1643
                else            s=argv[++i];
 
1644
                if (s)          speed_factor=atof(s);
 
1645
                if (speed_factor<=0)
 
1646
                    fprintf (stderr,"-speed=%.1f: insane speed factor.\n",
 
1647
                                    speed_factor),
 
1648
                    exit(FATAL_START(EINVAL));
 
1649
                continue;
 
1650
            }
 
1651
            else if (!strcmp(opt,"-dvd-compat"))
 
1652
            {   if (poor_man<0) poor_man = 1;
 
1653
                dvd_compat++;
 
1654
                continue;
 
1655
            }
 
1656
            else if (!strcmp(opt,"-overburn"))
 
1657
            {   overburn = 1;
 
1658
                continue;
 
1659
            }
 
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));
 
1665
            }
 
1666
            else if (!strncmp(opt,"-use-the-force-luke",19))
 
1667
            { char *s=strchr (opt,'='),*o;
 
1668
 
 
1669
                if (s == NULL)  /* backward compatibility */
 
1670
                    no_tty_check = 1;
 
1671
                else
 
1672
                {   s++;
 
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);
 
1683
                            if (dao_size%16)
 
1684
                                fprintf (stderr,":-( insane dao%c%d option\n",
 
1685
                                                o[3],dao_size),
 
1686
                                exit(FATAL_START(EINVAL));
 
1687
                        }
 
1688
                    }
 
1689
                    if ((o=strstr(s,"tracksize")))
 
1690
                    {   if (o[9]==':' || o[9]=='=')
 
1691
                        {   dao_size=strtol(o+10,0,0);
 
1692
                            if (dao_size%16)
 
1693
                                fprintf (stderr,":-( insane tracksize%c%d option\n",
 
1694
                                                o[9],dao_size),
 
1695
                                exit(FATAL_START(EINVAL));
 
1696
                        }
 
1697
                    }
 
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",
 
1703
                                                o[4],next_session),
 
1704
                                exit(FATAL_START(EINVAL));
 
1705
                        }
 
1706
                    }
 
1707
                }
 
1708
                continue;
 
1709
            }
 
1710
            else if (!strcmp(opt,"-dvd-video"))
 
1711
            {   if (poor_man<0) poor_man = 1;
 
1712
                dvd_compat++,   growisofs_argc++;
 
1713
            }
 
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];
 
1718
              int   i1,i2;
 
1719
                if (argv[i][1]=='C' && len>2)   s=argv[i]+2;
 
1720
                else                            i++;
 
1721
                if (sscanf (s,"%d,%d",&i1,&i2) == 2)
 
1722
                    alleged_next_session=i2;
 
1723
                continue;
 
1724
            }
 
1725
            else if (argv[i][1] == '#' || !strcmp(opt,"-dry-run"))
 
1726
            {   dry_run = 1;
 
1727
                continue;
 
1728
            }
 
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));
 
1735
            }
 
1736
            else if (strstr (opt,"-version"))
 
1737
            {   PRINT_VERSION (argv[0]);
 
1738
                printf ("  front-ending to %s: ",mkisofs_argv[0]);
 
1739
                fflush (stdout);
 
1740
                setuid(getuid());
 
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));
 
1745
            }
 
1746
        }
 
1747
 
 
1748
        if (dev_found && in_device)
 
1749
        {   if (*in_device == '=') in_device++;
 
1750
 
 
1751
            if (1 || dev_found == 'Z')
 
1752
            {   if ((in_image = strchr(in_device,'=')))
 
1753
                { uid_t euid=geteuid();
 
1754
 
 
1755
                    seteuid (getuid()); /* get real for parsing -[ZM] a=b */
 
1756
 
 
1757
                    while (in_image)
 
1758
                    {   *in_image='\0';
 
1759
                        errno=0;
 
1760
                        if (access (in_device,F_OK)==0 || errno!=ENOENT)
 
1761
                            break;
 
1762
                        *in_image='=',
 
1763
                        in_image=strchr(in_image+1,'=');
 
1764
                    }
 
1765
 
 
1766
                    if (errno)
 
1767
                        fprintf (stderr,":-( \"%s\": unexpected errno:",
 
1768
                                        in_device),
 
1769
                        perror (NULL), exit (FATAL_START(errno));
 
1770
 
 
1771
                    if (in_image)
 
1772
                    {   in_image++;
 
1773
 
 
1774
                        if (sscanf(in_image,"/dev/fd/%u",&imgfd) == 1)
 
1775
                            imgfd = dup (imgfd); /* validate descriptor */
 
1776
                        else
 
1777
                            imgfd = open64(in_image,O_RDONLY);
 
1778
 
 
1779
                        if (imgfd < 0)
 
1780
                            fprintf (stderr,":-( unable to open64(\"%s\","
 
1781
                                            "O_RDONLY): ",in_image),
 
1782
                            perror (NULL), exit(FATAL_START(errno));
 
1783
 
 
1784
                        if (!strcmp(in_image,"/dev/zero"))
 
1785
                            zero_image=1;
 
1786
                    }
 
1787
 
 
1788
                    seteuid (euid);     /* revert to saved [set-]uid */
 
1789
                }
 
1790
            }
 
1791
 
 
1792
            /*
 
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].
 
1797
             */
 
1798
            out_device=setup_fds (in_device);
 
1799
 
 
1800
            *(long *)the_buffer=0;      /* redundant:-) */
 
1801
            if (mmc_profile&0x10000)    /* blank media  */
 
1802
                n=0, errno=EIO;
 
1803
            else
 
1804
            {   n=pread64 (in_fd,the_buffer,2048,VOLDESC_OFF*CD_BLOCK);
 
1805
                if (n==0) errno=EIO;    /* end-of-file reached? */
 
1806
            }
 
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));
 
1811
 
 
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));
 
1816
 
 
1817
                next_session=setup_C_parm(C_parm,
 
1818
                                (struct iso_primary_descriptor *)the_buffer);
 
1819
 
 
1820
                if (imgfd>=0)
 
1821
                {   if (zero_image)
 
1822
                    { off64_t off=(atoi(C_parm)-16)*CD_BLOCK;
 
1823
 
 
1824
                        dup2(in_fd,imgfd);      /* kludge! */
 
1825
                        if (lseek64 (imgfd,off,SEEK_SET) == (off64_t)-1)
 
1826
                            fprintf (stderr,":-( %s: unable to lseek(%lld): ",
 
1827
                                            in_device,off),
 
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));
 
1834
                }
 
1835
                else if (next_session > (0x200000-0x5000)) /* 4GB/2K-40MB/2K */
 
1836
                    fprintf (stderr,":-( next session would cross 4GB boundary, "
 
1837
                                    "aborting...\n"),
 
1838
                    exit (FATAL_START(ENOSPC));
 
1839
 
 
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
 
1844
                M_parm = "-";
 
1845
# else
 
1846
                M_parm = get_M_parm (in_fd,in_device);
 
1847
# endif
 
1848
#else
 
1849
# ifdef PASS_STDIN_TO_MKISOFS
 
1850
                M_parm = "/dev/fd/0";
 
1851
# else
 
1852
                sprintf (M_parm,"/dev/fd/%d",in_fd);
 
1853
# endif
 
1854
#endif
 
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;
 
1859
            }
 
1860
            else
 
1861
            {   if (!memcmp (the_buffer,"\1CD001",6))
 
1862
                    warn_for_isofs = 1;
 
1863
                if (next_session<0) next_session = 0;
 
1864
                continue;
 
1865
            }
 
1866
        }
 
1867
        else
 
1868
        {   mkisofs_argv[mkisofs_argc++] = argv[i];   }
 
1869
    }
 
1870
 
 
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));
 
1875
 
 
1876
    if (imgfd<0)
 
1877
    {   if (mkisofs_argc==1)
 
1878
            fprintf (stderr,"%s: no mkisofs options specified, "
 
1879
                            "aborting...\n",argv[0]),
 
1880
            exit (FATAL_START(EINVAL));
 
1881
    }
 
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));
 
1886
 
 
1887
    mkisofs_argv[mkisofs_argc] = NULL;
 
1888
 
 
1889
    assert (next_session!=-1);
 
1890
    assert (in_fd!=-1);
 
1891
    assert (out_fd!=-1);
 
1892
 
 
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;
 
1899
    }
 
1900
 
 
1901
    if (warn_for_isofs)
 
1902
    { int fd=open("/dev/tty",O_RDONLY);
 
1903
 
 
1904
        if (fd>=0)
 
1905
        {   if (isatty (fd)) warn_for_isofs |= 2;
 
1906
            close (fd);
 
1907
        }
 
1908
        else if (isatty (0)) warn_for_isofs |= 2;
 
1909
 
 
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 '");
 
1913
        else
 
1914
            fprintf (stderr,"FATAL: %s already carries isofs!\n",in_device),
 
1915
            exit(FATAL_START(EBUSY));
 
1916
    }
 
1917
    else
 
1918
        printf ("Executing '");
 
1919
 
 
1920
    if (imgfd>=0)
 
1921
        printf ("builtin_dd if=%s of=%s obs=32k seek=%u",
 
1922
                in_image,out_device,next_session/16);
 
1923
    else
 
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);
 
1927
    }
 
1928
    printf ("'\n");
 
1929
    fflush (stdout);
 
1930
 
 
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");
 
1938
    }
 
1939
 
 
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)
 
1943
    CLOSEONEXEC(in_fd);
 
1944
    CLOSEONEXEC(out_fd);
 
1945
    CLOSEONEXEC(ioctl_fd);
 
1946
#undef CLOSEONEXEC
 
1947
 
 
1948
    if (!dry_run && (poor_man || next_session==0))      /* unmount media */
 
1949
    {   pid_t rpid,pid;
 
1950
        int   rval;
 
1951
 
 
1952
        if ((pid=fork()) == (pid_t)-1)
 
1953
            perror (":-( unable to fork -umount"), exit (FATAL_START(errno));
 
1954
 
 
1955
        /* pass through set-root-uid if any */
 
1956
        if (pid == 0)
 
1957
        {   char str[12];
 
1958
 
 
1959
            if ((rval=fcntl (in_fd,F_GETFD))<0) rval=0;
 
1960
            fcntl (in_fd,F_SETFD,rval&~FD_CLOEXEC);
 
1961
 
 
1962
            sprintf (str,"%d",in_fd);
 
1963
            execlp (argv[0],"-umount",str,in_device,NULL);
 
1964
            exit (FATAL_START(errno));
 
1965
        }
 
1966
        while (1)
 
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));
 
1972
            }
 
1973
            if (WIFSTOPPED(rval))       continue;
 
1974
            errno=0;
 
1975
            if (WIFEXITED(rval))        errno=WEXITSTATUS(rval);
 
1976
            else                        errno=ECHILD;
 
1977
            break;
 
1978
        }
 
1979
        if (errno)
 
1980
        {   if (errno==EBUSY)
 
1981
                fprintf (stderr,":-( %s: unable to proceed with recording: ",
 
1982
                            in_device),
 
1983
#ifdef __hpux
 
1984
                fprintf (stderr,"device is mounted\n"),
 
1985
#else
 
1986
                fprintf (stderr,"unable to unmount\n"),
 
1987
#endif
 
1988
                exit (FATAL_START(errno));
 
1989
            else
 
1990
                fprintf (stderr,":-( unable to umount %s: ",in_device);
 
1991
            perror (""), exit (FATAL_START(errno));
 
1992
        }
 
1993
    }
 
1994
 
 
1995
    if (poor_man)
 
1996
    {   out_device=in_device;
 
1997
        if (!ioctl_device) ioctl_device=out_device;
 
1998
 
 
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                        */
 
2006
                break;
 
2007
            default:
 
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));
 
2011
                break;
 
2012
        }
 
2013
    }
 
2014
 
 
2015
    if (imgfd>=0)
 
2016
    {   quiet--;
 
2017
        if (builtin_dd (imgfd,out_fd,next_session*CD_BLOCK) < 0)
 
2018
        { int err = errno;
 
2019
            errno = err&0x7F;     /* they might be passing FATAL_START */
 
2020
            perror (":-( write failed"), exit (err);
 
2021
        }
 
2022
        errno = 0;
 
2023
        exit (0);
 
2024
        /* NOT REACHED */
 
2025
    }
 
2026
 
 
2027
    pipe_mkisofs_up (mkisofs_argv,in_fd,out_fd,next_session*CD_BLOCK);
 
2028
 
 
2029
    /*
 
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...
 
2037
     */
 
2038
    if (next_session!=0 &&
 
2039
        (!poor_man || poor_man_rewritable (ioctl_handle,the_buffer)))
 
2040
    {
 
2041
        descr = (struct iso_primary_descriptor *)the_buffer;
 
2042
 
 
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));
 
2047
 
 
2048
        fprintf (stderr,"%s: copying volume descriptor(s)\n",
 
2049
                        poor_man?ioctl_device:out_device);
 
2050
 
 
2051
        new_size = from_733(descr[16].volume_space_size) + next_session;
 
2052
 
 
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"),
 
2057
            exit (errno);
 
2058
 
 
2059
        memcpy (descr+0,descr+16,sizeof(struct iso_primary_descriptor));
 
2060
        to_733(descr[0].volume_space_size,new_size);
 
2061
 
 
2062
        /*
 
2063
         * copy secondary volume descriptor(s) which are expected to
 
2064
         * appear in the very same order.
 
2065
         */
 
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;
 
2069
 
 
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");
 
2073
                break;
 
2074
            }
 
2075
            memcpy (descr+i,descr+16+i,sizeof(struct iso_primary_descriptor));
 
2076
            to_733(descr[i].volume_space_size,new_size);
 
2077
        }
 
2078
 
 
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"),
 
2082
            exit (errno);
 
2083
    }
 
2084
 
 
2085
    errno = 0;
 
2086
    exit (0);
 
2087
}