1 /*
2 * BD/DVD�RW/-RAM format 7.1 by Andy Polyakov <appro@fy.chalmers.se>.
3 *
4 * Use-it-on-your-own-risk, GPL bless...
5 *
6 * For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/.
7 *
8 * Revision history:
9 *
10 * 2.0:
11 * - deploy "IMMED" bit in "FORMAT UNIT";
12 * 2.1:
13 * - LP64 fix;
14 * - USB workaround;
15 * 3.0:
16 * - C++-fication for better portability;
17 * - SYSV signals for better portability;
18 * - -lead-out option for improved DVD+RW compatibility;
19 * - tested with SONY DRU-500A;
20 * 4.0:
21 * - support for DVD-RW formatting and blanking, tool name becomes
22 * overloaded...
23 * 4.1:
24 * - re-make it work under Linux 2.2 kernel;
25 * 4.2:
26 * - attempt to make DVD-RW Quick Format truly quick, upon release
27 * is verified to work with Pioneer DVR-x05;
28 * - media reload is moved to growisofs where is actually belongs;
29 * 4.3:
30 * - -blank to imply -force;
31 * - reject -blank in DVD+RW context and -lead-out in DVD-RW;
32 * 4.4:
33 * - support for -force=full in DVD-RW context;
34 * - ask unit to perform OPC if READ DISC INFORMATION doesn't return
35 * any OPC descriptors;
36 * 4.5:
37 * - increase timeout for OPC, NEC multi-format derivatives might
38 * require more time to fulfill the OPC procedure;
39 * 4.6:
40 * - -force to ignore error from READ DISC INFORMATION;
41 * - -force was failing under FreeBSD with 'unable to unmount';
42 * - undocumented -gui flag to ease progress indicator parsing for
43 * GUI front-ends;
44 * 4.7:
45 * - when formatting DVD+RW, Pioneer DVR-x06 remained unaccessible for
46 * over 2 minutes after dvd+rw-format exited and user was frustrated
47 * to poll the unit himself, now dvd+rw-format does it for user;
48 * 4.8:
49 * - DVD-RW format fails if preceeded by dummy recording;
50 * - make sure we talk to MMC unit, be less intrusive;
51 * - unify error reporting;
52 * - permit for -lead-out even for blank DVD+RW, needed(?) for SANYO
53 * derivatives;
54 * 4.9:
55 * - permit for DVD-RW blank even if format descriptors are not present;
56 * 4.10:
57 * - add support for DVD-RAM;
58 * 6.0:
59 * - versioning harmonization;
60 * - WIN32 port;
61 * - Initial DVD+RW Double Layer support;
62 * - Ignore "WRITE PROTECTED" error in OPC;
63 * 6.1:
64 * - � localization;
65 * - Treat only x73xx OPC errors as fatal;
66 * 7.0:
67 * - Blu-ray Disc support;
68 * - Mac OS X 10>=2 support;
69 * 7.1:
70 * - refine x73xx error treatment;
71 */
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75
76 #if defined(__unix) || defined(__unix__)
77 #include <sys/types.h>
78 #include <sys/stat.h>
79 #include <fcntl.h>
80 #include <unistd.h>
81 #include <sys/mman.h>
82 #include <signal.h>
83 #include <setjmp.h>
84 #include <sys/wait.h>
85 #endif
86
87 #include "transport.hxx"
88
usage(char * prog)89 static void usage (char *prog)
90 { fprintf (stderr,"- usage: %s [-force[=full]] [-lead-out|-blank[=full]]\n"
91 " [-ssa[=none|default|max|XXXm]] /dev/dvd\n",prog),
92 exit(1);
93 }
94
95 #ifdef _WIN32
96 #include <process.h>
97
98 # if defined(__GNUC__)
99 # define __shared__ __attribute__((section(".shared"),shared))
100 # elif defined(_MSC_VER)
101 # define __shared__
102 # pragma data_seg(".shared")
103 # pragma comment(linker,"/section:.shared,rws")
104 # endif
105 static volatile int shared_progress_indicator __shared__ = 0;
106 # if defined(_MSC_VER)
107 # pragma data_seg()
108 # endif
109
110 static volatile int *progress = &shared_progress_indicator;
111 static HANDLE Process = NULL;
112
GoBackground(DWORD code)113 BOOL WINAPI GoBackground (DWORD code)
114 { if (*progress)
115 { FreeConsole(); /* detach from console upon ctrl-c or window close */
116 return TRUE;
117 }
118 return FALSE;
119 }
120
KillForeground(void)121 void KillForeground (void)
122 { fprintf(stderr,"\n");
123 TerminateProcess(Process,0);
124 }
125 #else
126 static volatile int *progress;
127 #endif
128
129 static const char *gui_action=NULL;
130 static const char *str = "|/-\\",*backspaces="\b\b\b\b\b\b\b\b\b\b";
131
132 #if defined(__unix) || defined(__unix__)
alarm_handler(int no)133 extern "C" void alarm_handler (int no)
134 { static int i=0,len=1,old_progress=0;
135 int new_progress = *progress;
136
137 if (gui_action)
138 { fprintf (stderr,"* %s %.1f%%\n",gui_action,
139 100.0*new_progress/65536.0);
140 alarm(3);
141 return;
142 }
143
144 if (new_progress != old_progress)
145 len = fprintf (stderr,"%.*s%.1f%%",len,backspaces,
146 100.0*new_progress/65536.0) - len,
147 old_progress = new_progress;
148 else
149 fprintf (stderr,"\b%c",str[i]),
150 i++, i&=3;
151
152 alarm(1);
153 }
154 #endif
155
main(int argc,char * argv[])156 int main (int argc, char *argv[])
157 { unsigned char formats[260],dinfo[32],inq[128];
158 char *dev=NULL,*p;
159 unsigned int capacity,lead_out,mmc_profile,err;
160 int len,i;
161 int force=0,full=0,compat=0,blank=0,ssa=0,do_opc=0,gui=0,
162 blu_ray=0,not_pow=0;
163 #ifdef _WIN32
164 DWORD ppid;
165 char filename[MAX_PATH],*progname;
166
167 /*
168 * Foreground process spawns itself and simply waits for shared
169 * progress indicator to increment...
170 */
171 if (sscanf(argv[0],":%u:",&ppid) != 1)
172 { int i=0,len=1,old_progress=0,new_progress;
173
174 sprintf (filename,":%u:",GetCurrentProcessId());
175 progname = argv[0];
176 argv[0] = filename;
177 Process = (HANDLE)_spawnv (_P_NOWAIT,progname,argv);
178 if (Process == (HANDLE)-1)
179 perror("_spawnv"), ExitProcess(errno);
180
181 while(1)
182 { if (WaitForSingleObject(Process,1000) == WAIT_OBJECT_0)
183 { ppid = 0; /* borrow DWORD variable */
184 GetExitCodeProcess(Process,&ppid);
185 ExitProcess(ppid);
186 }
187
188 new_progress = *progress;
189 if (new_progress != old_progress)
190 len = fprintf (stderr,"%.*s%.1f%%",len,backspaces,
191 100.0*new_progress/65536.0) - len,
192 old_progress = new_progress;
193 else if (new_progress)
194 fprintf (stderr,"\b%c",str[i]),
195 i++, i&=3;
196 }
197 }
198
199 /*
200 * ... while background process does *all* the job...
201 */
202 Process = OpenProcess (PROCESS_TERMINATE,FALSE,ppid);
203 if (Process == NULL)
204 perror("OpenProcess"), ExitProcess(errno);
205
206 atexit (KillForeground);
207 SetConsoleCtrlHandler (GoBackground,TRUE);
208
209 GetModuleFileName (NULL,filename,sizeof(filename));
210 progname = strrchr(filename,'\\');
211 if (progname) argv[0] = progname+1;
212 else argv[0] = filename;
213 #elif defined(__unix) || defined(__unix__)
214 pid_t pid;
215
216 { int fd;
217 char *s;
218
219 if ((fd=mkstemp (s=strdup("/tmp/dvd+rw-format.XXXXXX"))) < 0)
220 fprintf (stderr,":-( unable to mkstemp(\"%s\")",s),
221 exit(1);
222
223 ftruncate(fd,sizeof(*progress));
224 unlink(s);
225
226 progress = (int *)mmap(NULL,sizeof(*progress),PROT_READ|PROT_WRITE,
227 MAP_SHARED,fd,0);
228 close (fd);
229 if (progress == MAP_FAILED)
230 perror (":-( unable to mmap anonymously"),
231 exit(1);
232 }
233 *progress = 0;
234
235 if ((pid=fork()) == (pid_t)-1)
236 perror (":-( unable to fork()"),
237 exit(1);
238
239 if (pid)
240 { struct sigaction sa;
241
242 sigaction (SIGALRM,NULL,&sa);
243 sa.sa_flags &= ~SA_RESETHAND;
244 sa.sa_flags |= SA_RESTART;
245 sa.sa_handler = alarm_handler;
246 sigaction (SIGALRM,&sa,NULL);
247 alarm(1);
248 while ((waitpid(pid,&i,0) != pid) && !WIFEXITED(i)) ;
249 if (WEXITSTATUS(i) == 0) fprintf (stderr,"\n");
250 exit (0);
251 }
252 #endif
253
254 fprintf (stderr,"* BD/DVD%sRW/-RAM format utility by <appro@fy.chalmers.se>, "
255 "version 7.1.\n",plusminus_locale());
256
257 for (i=1;i<argc;i++) {
258 if (*argv[i] == '-')
259 if (argv[i][1] == 'f') // -format|-force
260 { force = 1;
261 if ((p=strchr(argv[i],'=')) && p[1]=='f') full=1;
262 }
263 else if (argv[i][1] == 'l') // -lead-out
264 force = compat = 1;
265 else if (argv[i][1] == 'b') // -blank
266 { blank=0x11;
267 if ((p=strchr(argv[i],'=')) && p[1]=='f') blank=0x10;
268 force=1;
269 }
270 else if (argv[i][1] == 'p') // -pow
271 { not_pow=1; // minus pow
272 }
273 else if (argv[i][1] == 's') // -ssa|-spare
274 { force=ssa=1;
275 if ((p=strchr(argv[i],'=')))
276 { if (p[1]=='n') ssa=-1; // =none
277 else if (p[3]=='n') ssa=1; // =min
278 else if (p[1]=='d') ssa=2; // =default
279 else if (p[3]=='x') ssa=3; // =max
280 else if (p[1]=='.' || (p[1]>='0' && p[1]<='9'))
281 { char *s=NULL;
282 double a=strtod(p+1,&s);
283
284 if (s)
285 { if (*s=='g' || *s=='G') a *= 1e9;
286 else if (*s=='m' || *s=='M') a *= 1e6;
287 else if (*s=='k' || *s=='K') a *= 1e3;
288 }
289 ssa = (int)(a/2e3); // amount of 2K
290 }
291 else ssa=0; // invalid?
292 }
293 }
294 else if (argv[i][1] == 'g') gui=1;
295 else usage(argv[0]);
296 #ifdef _WIN32
297 else if (argv[i][1] == ':')
298 #else
299 else if (*argv[i] == '/')
300 #endif
301 dev = argv[i];
302 else
303 usage (argv[0]);
304 }
305
306 if (dev==NULL) usage (argv[0]);
307
308 Scsi_Command cmd;
309
310 if (!cmd.associate(dev))
311 fprintf (stderr,":-( unable to open(\"%s\"): ",dev), perror (NULL),
312 exit(1);
313
314 cmd[0] = 0x12; // INQUIRY
315 cmd[4] = 36;
316 cmd[5] = 0;
317 if ((err=cmd.transport(READ,inq,36)))
318 sperror ("INQUIRY",err), exit (1);
319
320 if ((inq[0]&0x1F) != 5)
321 fprintf (stderr,":-( not an MMC unit!\n"),
322 exit (1);
323
324 cmd[0] = 0x46; // GET CONFIGURATION
325 cmd[8] = 8;
326 cmd[9] = 0;
327 if ((err=cmd.transport(READ,formats,8)))
328 sperror ("GET CONFIGURATION",err), exit (1);
329
330 mmc_profile = formats[6]<<8|formats[7];
331
332 blu_ray = ((mmc_profile&0xF0)==0x40);
333
334 if (mmc_profile!=0x1A && mmc_profile!=0x2A
335 && mmc_profile!=0x14 && mmc_profile!=0x13
336 && mmc_profile!=0x12
337 && !blu_ray)
338 fprintf (stderr,":-( mounted media doesn't appear to be "
339 "DVD%sRW, DVD-RAM or Blu-ray\n",plusminus_locale()),
340 exit (1);
341
342 /*
343 * First figure out how long the actual list is. Problem here is
344 * that (at least Linux) USB units absolutely insist on accurate
345 * cgc.buflen and you can't just set buflen to arbitrary value
346 * larger than actual transfer length.
347 */
348 int once=1;
349 do
350 { cmd[0] = 0x23; // READ FORMAT CAPACITIES
351 cmd[8] = 4;
352 cmd[9] = 0;
353 if ((err=cmd.transport(READ,formats,4)))
354 { if (err==0x62800 && once) // "MEDIUM MAY HAVE CHANGED"
355 { cmd[0] = 0; // TEST UNIT READY
356 cmd[5] = 0;
357 cmd.transport(); // just swallow it...
358 continue;
359 }
360 sperror ("READ FORMAT CAPACITIES",err), exit (1);
361 }
362 } while (once--);
363
364 len = formats[3];
365 if (len&7 || len<8)
366 fprintf (stderr,":-( allocation length isn't sane\n"),
367 exit(1);
368
369 cmd[0] = 0x23; // READ FORMAT CAPACITIES
370 cmd[7] = (4+len)>>8; // now with real length...
371 cmd[8] = (4+len)&0xFF;
372 cmd[9] = 0;
373 if ((err=cmd.transport(READ,formats,4+len)))
374 sperror ("READ FORMAT CAPACITIES",err), exit (1);
375
376 if (len != formats[3])
377 fprintf (stderr,":-( parameter length inconsistency\n"),
378 exit(1);
379
380 if (mmc_profile==0x1A || mmc_profile==0x2A) // DVD+RW
381 { for (i=8;i<len;i+=8) // look for "DVD+RW Full" descriptor
382 if ((formats [4+i+4]>>2) == 0x26) break;
383 }
384 else if (mmc_profile==0x12) // DVD-RAM
385 { unsigned int v,ref;
386 unsigned char *f,descr=0x01;
387 int j;
388
389 switch (ssa)
390 { case -1: // no ssa
391 for (ref=0,i=len,j=8;j<len;j+=8)
392 { f = formats+4+j;
393 if ((f[4]>>2) == 0x00)
394 { v=f[0]<<24|f[1]<<16|f[2]<<8|f[3];
395 if (v>ref) ref=v,i=j;
396 }
397 }
398 break;
399 case 1: // first ssa
400 for (i=8;i<len;i+=8)
401 if ((formats[4+i+4]>>2) == 0x01) break;
402 break;
403 case 2: // default ssa
404 descr=0x00;
405 case 3: // max ssa
406 for (ref=0xFFFFFFFF,i=len,j=8;j<len;j+=8)
407 { f = formats+4+j;
408 if ((f[4]>>2) == descr)
409 { v=f[0]<<24|f[1]<<16|f[2]<<8|f[3];
410 if (v<ref) ref=v,i=j;
411 }
412 }
413 break;
414 default:
415 i=8; // just grab the first descriptor?
416 break;
417 }
418 }
419 else if (mmc_profile==0x41) // BD-R
420 { unsigned int max,min,cap;
421 unsigned char *f;
422 int j;
423
424 switch (ssa)
425 { case -1: // no spare -> nothing to do
426 case 0:
427 exit (0);
428 break;
429 case 1: // min spare <- max capacity
430 i=len;
431 for (max=0,j=8;j<len;j+=8)
432 { f = formats+4+j;
433 if ((f[4]>>2) == 0x32)
434 { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
435 if (max < cap) max=cap,i=j;
436 }
437 }
438 break;
439 case 2: // default ssa
440 i=8; // just grab first descriptor
441 break;
442 case 3: // max, ~10GB, is too big to trust user
443 fprintf (stderr,"- -ssa=max is not supported for BD-R, "
444 "specify explicit size with -ssa=XXXG\n");
445 exit (1);
446 default:
447 i=len;
448 for (max=0,min=0xffffffff,j=8;j<len;j+=8)
449 { f = formats+4+j;
450 if ((f[4]>>2) == 0x32)
451 { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
452 if (max < cap) max=cap;
453 if (min > cap) min=cap;
454 }
455 }
456 if (max==0) break;
457
458 // for simplicity adjust spare size according to DL(!) rules
459 ssa += 8192, ssa &= ~16383; // i.e. in 32MB increments
460
461 f = formats+4;
462 capacity = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
463
464 cap = capacity - ssa;
465 // place it within given boundaries
466 if (cap < min) cap = min;
467 else if (cap > max) cap = max;
468
469 i = 8;
470 f = formats+4+i;
471 f[0] = cap>>24;
472 f[1] = cap>>16;
473 f[2] = cap>>8;
474 f[3] = cap;
475 f[4] = 0x32<<2 | not_pow;
476 f[5] = 0;
477 f[6] = 0;
478 f[7] = 0;
479 break;
480 }
481
482 if (i<len)
483 { f = formats+4+i;
484 f[4] &= ~3; // it's either SRM+POW ...
485 f[4] |= not_pow; // ... or SRM-POW
486 }
487 }
488 else if (mmc_profile==0x43) // BD-RE
489 { unsigned int max,min,cap;
490 unsigned char *f;
491 int j;
492
493 switch (ssa)
494 { case -1: // no spare
495 for (i=8;i<len;i+=8) // look for descriptor 0x31
496 if ((formats [4+i+4]>>2) == 0x31) break;
497 break;
498 case 0:
499 i = 8;
500 if ((formats[4+4]&3)==2)// same capacity for already formatted
501 { f = formats+4+i;
502 memcpy (f,formats+4,4);
503 f[4] = 0x30<<2;
504 f[5] = 0;
505 f[6] = 0;
506 f[7] = 0;
507 }
508 break;
509 case 1: // min spare <- max capacity
510 i=len;
511 for (max=0,j=8;j<len;j+=8)
512 { f = formats+4+j;
513 if ((f[4]>>2) == 0x30)
514 { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
515 if (max < cap) max=cap,i=j;
516 }
517 }
518 break;
519 case 2: // default ssa
520 i=8; // just grab first descriptor
521 break;
522 case 3: // max spare <- min capacity
523 i=len;
524 for (min=0xffffffff,j=8;j<len;j+=8)
525 { f = formats+4+j;
526 if ((f[4]>>2) == 0x30)
527 { cap=f[0]<<24|f[1]<<16|f[2]<<8|f[3];
528 if (min > cap) min=cap,i=j;
529 }
530 }
531 break;
532 default:
533 i=len;
534 capacity=0;
535 for (max=0,min=0xffffffff,j=8;j<len;j+=8)
536 { f = formats+4+j;
537 if ((f[4]>>2) == 0x30)
538 { cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
539 if (max < cap) max=cap;
540 if (min > cap) min=cap;
541 }
542 else if ((f[4]>>2) == 0x31)
543 capacity = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
544 }
545 if (max==0 || capacity==0) break;
546
547 // for simplicity adjust spare size according to DL(!) rules
548 ssa += 8192, ssa &= ~16383; // i.e. in 32MB increments
549
550 cap = capacity - ssa;
551 // place it within given boundaries
552 if (cap < min) cap = min;
553 else if (cap > max) cap = max;
554
555 i = 8;
556 f = formats+4+i;
557 f[0] = cap>>24;
558 f[1] = cap>>16;
559 f[2] = cap>>8;
560 f[3] = cap;
561 f[4] = 0x30<<2;
562 f[5] = 0;
563 f[6] = 0;
564 f[7] = 0;
565 break;
566 }
567
568 if (i<len)
569 { f = formats+4+i;
570 f[4] &= ~3;
571 if ((f[4]>>2)==0x30)
572 f[4] |= full?2:3; // "Full" or "Quick Certification"
573 }
574 }
575 else // DVD-RW
576 { int descr=full?0x10:0x15;
577
578 for (i=8;i<len;i+=8) // look for "DVD-RW Quick" descriptor
579 if ((formats [4+i+4]>>2) == descr) break;
580 if (descr==0x15 && i==len)
581 { fprintf (stderr,":-( failed to locate \"Quick Format\" descriptor.\n");
582 for (i=8;i<len;i+=8)// ... alternatively for "DVD-RW Full"
583 if ((formats [4+i+4]>>2) == 0x10) break;
584 }
585 }
586
587 if (i==len)
588 { fprintf (stderr,":-( can't locate appropriate format descriptor\n");
589 if (blank) i=0;
590 else exit(1);
591 }
592
593 capacity = 0;
594 if (blu_ray)
595 { capacity |= formats[4+0], capacity <<= 8;
596 capacity |= formats[4+1], capacity <<= 8;
597 capacity |= formats[4+2], capacity <<= 8;
598 capacity |= formats[4+3];
599 }
600 else
601 { capacity |= formats[4+i+0], capacity <<= 8;
602 capacity |= formats[4+i+1], capacity <<= 8;
603 capacity |= formats[4+i+2], capacity <<= 8;
604 capacity |= formats[4+i+3];
605 }
606
607 if (mmc_profile==0x1A || mmc_profile==0x2A) // DVD+RW
608 fprintf (stderr,"* %.1fGB DVD+RW media detected.\n",
609 2048.0*capacity/1e9);
610 else if (mmc_profile==0x12) // DVD-RAM
611 fprintf (stderr,"* %.1fGB DVD-RAM media detected.\n",
612 2048.0*capacity/1e9);
613 else if (blu_ray) // BD
614 fprintf (stderr,"* %.1fGB BD media detected.\n",
615 2048.0*capacity/1e9);
616 else // DVD-RW
617 fprintf (stderr,"* %.1fGB DVD-RW media in %s mode detected.\n",
618 2048.0*capacity/1e9,
619 mmc_profile==0x13?"Restricted Overwrite":"Sequential");
620
621 lead_out = 0;
622 lead_out |= formats[4+0], lead_out <<= 8;
623 lead_out |= formats[4+1], lead_out <<= 8;
624 lead_out |= formats[4+2], lead_out <<= 8;
625 lead_out |= formats[4+3];
626
627 cmd[0] = 0x51; // READ DISC INFORMATION
628 cmd[8] = sizeof(dinfo);
629 cmd[9] = 0;
630 if ((err=cmd.transport(READ,dinfo,sizeof(dinfo))))
631 { sperror ("READ DISC INFORMATION",err);
632 if (!force) exit(1);
633 memset (dinfo,0xff,sizeof(dinfo));
634 cmd[0] = 0x35;
635 cmd[9] = 0;
636 cmd.transport();
637 }
638
639 do_opc = ((dinfo[0]<<8|dinfo[1])<=0x20);
640
641 if (dinfo[2]&3) // non-blank media
642 { if (!force)
643 { if (mmc_profile==0x1A || mmc_profile==0x2A || mmc_profile==0x13 || mmc_profile==0x12)
644 fprintf (stderr,"- media is already formatted, lead-out is currently at\n"
645 " %d KiB which is %.1f%% of total capacity.\n",
646 lead_out*2,(100.0*lead_out)/capacity);
647 else
648 fprintf (stderr,"- media is not blank\n");
649 offer_options:
650 if (mmc_profile == 0x1A || mmc_profile == 0x2A)
651 fprintf (stderr,"- you have the option to re-run %s with:\n"
652 " -lead-out to elicit lead-out relocation for better\n"
653 " DVD-ROM compatibility, data is not affected;\n"
654 " -force to enforce new format (not recommended)\n"
655 " and wipe the data.\n",
656 argv[0]);
657 else if (mmc_profile == 0x12)
658 fprintf (stderr,"- you have the option to re-run %s with:\n"
659 " -format=full to perform full (lengthy) reformat;\n"
660 " -ssa[=none|default|max]\n"
661 " to grow, eliminate, reset to default or\n"
662 " maximize Supplementary Spare Area.\n",
663 argv[0]);
664 else if (mmc_profile == 0x43)
665 fprintf (stderr,"- you have the option to re-run %s with:\n"
666 " -format=full to perform (lengthy) Full Certification;\n"
667 " -ssa[=none|default|max|XXX[GM]]\n"
668 " to eliminate or adjust Spare Area.\n",
669 argv[0]);
670 else if (blu_ray) // BD-R
671 fprintf (stderr,"- BD-R can be pre-formatted only once\n");
672 else
673 { fprintf (stderr,"- you have the option to re-run %s with:\n",
674 argv[0]);
675 if (i) fprintf (stderr,
676 " -force[=full] to enforce new format or mode transition\n"
677 " and wipe the data;\n");
678 fprintf (stderr," -blank[=full] to change to Sequential mode.\n");
679 }
680 exit (0);
681 }
682 else if (cmd.umount())
683 perror (errno==EBUSY ? ":-( unable to proceed with format" :
684 ":-( unable to umount"),
685 exit (1);
686 }
687 else
688 { if (mmc_profile==0x14 && blank==0 && !force)
689 { fprintf (stderr,"- media is blank\n");
690 fprintf (stderr,"- given the time to apply full blanking procedure I've chosen\n"
691 " to insist on -force option upon mode transition.\n");
692 exit (0);
693 }
694 else if (mmc_profile==041 && !force)
695 { fprintf (stderr,"- media is blank\n");
696 fprintf (stderr,"- as BD-R can be pre-formance only once, I've chosen\n"
697 " to insist on -force option.\n");
698 }
699 force = 0;
700 }
701
702 if (((mmc_profile == 0x1A || mmc_profile == 0x2A) && blank)
703 || (mmc_profile != 0x1A && compat)
704 || (mmc_profile != 0x12 && mmc_profile != 0x43 && ssa) )
705 { fprintf (stderr,"- illegal command-line option for this media.\n");
706 goto offer_options;
707 }
708 else if ((mmc_profile == 0x1A || mmc_profile == 0x2A) && full)
709 { fprintf (stderr,"- unimplemented command-line option for this media.\n");
710 goto offer_options;
711 }
712
713 #if defined(__unix) || defined(__unix__)
714 /*
715 * You can suspend, terminate, etc. the parent. We will keep on
716 * working in background...
717 */
718 setsid();
719 signal(SIGHUP,SIG_IGN);
720 signal(SIGINT,SIG_IGN);
721 signal(SIGTERM,SIG_IGN);
722 #endif
723
724 if (compat && force) str="relocating lead-out";
725 else if (blank) str="blanking";
726 else str="formatting";
727 if (gui) gui_action=str;
728 else fprintf (stderr,"* %s .",str);
729
730 *progress = 1;
731
732 // formats[i] becomes "Format Unit Parameter List"
733 formats[i+0] = 0; // "Reserved"
734 formats[i+1] = 2; // "IMMED" flag
735 formats[i+2] = 0; // "Descriptor Length" (MSB)
736 formats[i+3] = 8; // "Descriptor Length" (LSB)
737
738 handle_events(cmd);
739
740 if (mmc_profile==0x1A || mmc_profile==0x2A) // DVD+RW
741 { if (compat && force && (dinfo[2]&3))
742 formats[i+4+0]=formats[i+4+1]=formats[i+4+2]=formats[i+4+3]=0,
743 formats[i+4+7] = 1; // "Restart format"
744
745 cmd[0] = 0x04; // FORMAT UNIT
746 cmd[1] = 0x11; // "FmtData" and "Format Code"
747 cmd[5] = 0;
748 if ((err=cmd.transport(WRITE,formats+i,12)))
749 sperror ("FORMAT UNIT",err), exit(1);
750
751 if (wait_for_unit (cmd,progress)) exit (1);
752
753 if (!compat)
754 { cmd[0] = 0x5B; // CLOSE TRACK/SESSION
755 cmd[1] = 1; // "IMMED" flag on
756 cmd[2] = 0; // "Stop De-Icing"
757 cmd[9] = 0;
758 if ((err=cmd.transport()))
759 sperror ("STOP DE-ICING",err), exit(1);
760
761 if (wait_for_unit (cmd,progress)) exit (1);
762 }
763
764 cmd[0] = 0x5B; // CLOSE TRACK/SESSION
765 cmd[1] = 1; // "IMMED" flag on
766 cmd[2] = 2; // "Close Session"
767 cmd[9] = 0;
768 if ((err=cmd.transport()))
769 sperror ("CLOSE SESSION",err), exit(1);
770
771 if (wait_for_unit (cmd,progress)) exit (1);
772 }
773 else if (mmc_profile==0x12) // DVD-RAM
774 { cmd[0] = 0x04; // FORMAT UNIT
775 cmd[1] = 0x11; // "FmtData"|"Format Code"
776 cmd[5] = 0;
777 formats[i+1] = 0x82; // "FOV"|"IMMED"
778 if ((formats[i+4+4]>>2) != 0x01 && !full)
779 formats[i+1] |= 0x20,// |"DCRT"
780 cmd[1] |= 0x08; // |"CmpLst"
781 if ((err=cmd.transport(WRITE,formats+i,12)))
782 sperror ("FORMAT UNIT",err), exit(1);
783
784 if (wait_for_unit (cmd,progress)) exit(1);
785 }
786 else if (mmc_profile==0x43) // BD-RE
787 { cmd[0] = 0x04; // FORMAT UNIT
788 cmd[1] = 0x11; // "FmtData"|"Format Code"
789 cmd[5] = 0;
790 formats[i+1] = 0x82; // "FOV"|"IMMED"
791 if (full && (formats[i+4+4]>>2)!=0x31)
792 formats[i+4+4] |= 2;// "Full Certificaton"
793 else if ((formats[i+4+4]>>2)==0x30)
794 formats[i+4+4] |= 3;// "Quick Certification"
795 if ((err=cmd.transport(WRITE,formats+i,12)))
796 sperror ("FORMAT UNIT",err), exit(1);
797
798 if (wait_for_unit (cmd,progress)) exit(1);
799 }
800 else if (mmc_profile==0x41) // BD-R
801 { cmd[0] = 0x04; // FORMAT UNIT
802 cmd[1] = 0x11; // "FmtData"|"Format Code"
803 cmd[5] = 0;
804 formats[i+1] = 0x2; // IMMED"
805 if ((err=cmd.transport(WRITE,formats+i,12)))
806 sperror ("FORMAT UNIT",err), exit(1);
807
808 if (wait_for_unit (cmd,progress)) exit(1);
809 }
810 else // DVD-RW
811 { page05_setup (cmd,mmc_profile);
812
813 if (do_opc)
814 { cmd[0] = 0x54; // SEND OPC INFORMATION
815 cmd[1] = 1; // "Perform OPC"
816 cmd[9] = 0;
817 cmd.timeout(120); // NEC units can be slooo...w
818 if ((err=cmd.transport()))
819 { if (err==0x17301) // "POWER CALIBRATION AREA ALMOST FULL"
820 fprintf (stderr,":-! WARNING: Power Calibration Area "
821 "is almost full\n");
822 else
823 { sperror ("PERFORM OPC",err);
824 if ((err&0x0FF00)==0x07300 && (err&0xF0000)!=0x10000)
825 exit (1);
826 /* The rest of errors are ignored, see groisofs_mmc.cpp
827 * for further details... */
828 }
829 }
830 }
831
832 if (blank) // DVD-RW blanking procedure
833 { cmd[0] = 0xA1; // BLANK
834 cmd[1] = blank;
835 cmd[11] = 0;
836 if ((err=cmd.transport()))
837 sperror ("BLANK",err), exit(1);
838
839 if (wait_for_unit (cmd,progress)) exit (1);
840 }
841 else // DVD-RW format
842 { if ((formats[i+4+4]>>2)==0x15) // make it really quick
843 formats[i+4+0]=formats[i+4+1]=formats[i+4+2]=formats[i+4+3]=0;
844
845 cmd[0] = 0x04; // FORMAT UNIT
846 cmd[1] = 0x11; // "FmtData" and "Format Code"
847 cmd[5] = 0;
848 if ((err=cmd.transport(WRITE,formats+i,12)))
849 sperror ("FORMAT UNIT",err), exit(1);
850
851 if (wait_for_unit (cmd,progress)) exit (1);
852
853 cmd[0] = 0x35; // FLUSH CACHE
854 cmd[9] = 0;
855 cmd.transport ();
856 }
857 }
858
859 pioneer_stop (cmd,progress);
860
861 #if 0
862 cmd[0] = 0x1E; // ALLOW MEDIA REMOVAL
863 cmd[5] = 0;
864 if (cmd.transport ()) return 1;
865
866 cmd[0] = 0x1B; // START/STOP UNIT
867 cmd[4] = 0x2; // "Eject"
868 cmd[5] = 0;
869 if (cmd.transport()) return 1;
870
871 cmd[0] = 0x1B; // START/STOP UNIT
872 cmd[1] = 0x1; // "IMMED"
873 cmd[4] = 0x3; // "Load"
874 cmd[5] = 0;
875 cmd.transport ();
876 #endif
877
878 return 0;
879 }
880