root / libburn / trunk / test / libburner.c

Revision 3358, 28.7 kB (checked in by scdbackup, 2 weeks ago)

Clarified the meaning of 0x0 and 0x30 signal handlers

Line 
1
2/* test/libburner.c , API illustration of burning data or audio tracks to CD */
3/* Copyright (C) 2005 - 2010 Thomas Schmitt <scdbackup@gmx.net> */
4/* Provided under GPL, see also "License and copyright aspects" at file end */
5
6
7/**                               Overview
8 
9  libburner is a minimal demo application for the library libburn as provided
10  on  http://libburnia-project.org . It can list the available devices, can
11  blank a CD-RW or DVD-RW, can format DVD-RW and BD, can burn to CD-R,
12  CD-RW, DVD-R, DVD+R, DVD+R/DL, DVD+RW, DVD-RW, DVD-RAM, BD-R, BD-RE.
13  Not supported yet: DVD-R/DL.
14
15  It's main purpose, nevertheless, is to show you how to use libburn and also
16  to serve the libburnia team as reference application. libburner.c does indeed
17  define the standard way how above three gestures can be implemented and
18  stay upward compatible for a good while.
19 
20  Before you can do anything, you have to initialize libburn by
21     burn_initialize()
22  and provide some signal and abort handling, e.g. by the builtin handler, by
23     burn_set_signal_handling("libburner : ", NULL, 0x0)
24  as it is done in main() at the end of this file.
25  Then you aquire a drive in an appropriate way conforming to the API. The twoi
26  main approaches are shown here in application functions:
27     libburner_aquire_by_adr()     demonstrates usage as of cdrecord traditions
28     libburner_aquire_by_driveno()      demonstrates a scan-and-choose approach
29
30  With that aquired drive you can blank a CD-RW or DVD-RW as shown in
31     libburner_blank_disc()
32  or you can format a DVD-RW to profile "Restricted Overwrite" (needed once)
33  or an unused BD to default size with spare blocks
34     libburner_format()
35  With the aquired drive you can burn to CD, DVD, BD. See
36     libburner_payload()
37
38  These three functions switch temporarily to a non-fatal signal handler
39  while they are waiting for the drive to become idle again:
40     burn_set_signal_handling("libburner : ", NULL, 0x30)
41  After the waiting loop ended, they check for eventual abort events by
42     burn_is_aborting(0)
43  The 0x30 handler will eventually execute
44     burn_abort()
45  but not wait for the drive to become idle and not call exit().
46  This is needed because the worker threads might block as long as the signal
47  handler has not returned. The 0x0 handler would wait for them to finish.
48  Take this into respect when implementing own signal handlers.
49
50  When everything is done, main() releases the drive and shuts down libburn:
51     burn_drive_release();
52     burn_finish()
53
54  Applications must use 64 bit off_t. E.g. by defining
55    #define _LARGEFILE_SOURCE
56    #define _FILE_OFFSET_BITS 64
57  or take special precautions to interface with the library by 64 bit integers
58  where libburn/libburn.h prescribes off_t.
59  This program gets fed with appropriate settings externally by libburn's
60  autotools generated build system.
61*/
62
63
64/** See this for the decisive API specs . libburn.h is The Original */
65/*  For using the installed header file :  #include <libburn/libburn.h> */
66/*  This program insists in the own headerfile. */
67#include "../libburn/libburn.h"
68
69/* libburn works on Linux systems with kernel 2.4 or 2.6, FreeBSD, Solaris */
70#include <stdio.h>
71#include <ctype.h>
72#include <sys/types.h>
73#include <unistd.h>
74#include <string.h>
75#include <stdlib.h>
76#include <time.h>
77#include <errno.h>
78#include <sys/stat.h>
79#include <fcntl.h>
80
81
82/** For simplicity i use global variables to represent the drives.
83    Drives are systemwide global, so we do not give away much of good style.
84*/
85
86/** This list will hold the drives known to libburn. This might be all CD
87    drives of the system and thus might impose severe impact on the system.
88*/
89static struct burn_drive_info *drive_list;
90
91/** If you start a long lasting operation with drive_count > 1 then you are
92    not friendly to the users of other drives on those systems. Beware. */
93static unsigned int drive_count;
94
95/** This variable indicates wether the drive is grabbed and must be
96    finally released */
97static int drive_is_grabbed = 0;
98
99/** A number and a text describing the type of media in aquired drive */
100static int current_profile= -1;
101static char current_profile_name[80]= {""};
102
103
104/* Some in-advance definitions to allow a more comprehensive ordering
105   of the functions and their explanations in here */
106int libburner_aquire_by_adr(char *drive_adr);
107int libburner_aquire_by_driveno(int *drive_no);
108
109
110/* ------------------------------- API gestures ---------------------------- */
111
112/** You need to aquire a drive before burning. The API offers this as one
113    compact call and alternatively as application controllable gestures of
114    whitelisting, scanning for drives and finally grabbing one of them.
115
116    If you have a persistent address of the drive, then the compact call is
117    to prefer because it only touches one drive. On modern Linux kernels,
118    there should be no fatal disturbance of ongoing burns of other libburn
119    instances with any of our approaches. We use open(O_EXCL) by default.
120    On /dev/hdX it should cooperate with growisofs and some cdrecord variants.
121    On /dev/sgN versus /dev/scdM expect it not to respect other programs.
122*/
123int libburner_aquire_drive(char *drive_adr, int *driveno)
124{
125        int ret;
126
127        if(drive_adr != NULL && drive_adr[0] != 0)
128                ret = libburner_aquire_by_adr(drive_adr);
129        else
130                ret = libburner_aquire_by_driveno(driveno);
131        if (ret <= 0 || *driveno <= 0)
132                return ret;
133        burn_disc_get_profile(drive_list[0].drive, &current_profile,
134                                 current_profile_name);
135        if (current_profile_name[0])
136                printf("Detected media type: %s\n", current_profile_name);
137        return 1;
138}
139
140
141/** If the persistent drive address is known, then this approach is much
142    more un-obtrusive to the systemwide livestock of drives. Only the
143    given drive device will be opened during this procedure.
144*/
145int libburner_aquire_by_adr(char *drive_adr)
146{
147        int ret;
148        char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
149
150        /* Some not-so-harmless drive addresses get blocked in this demo */
151        if (strncmp(drive_adr, "stdio:/dev/fd/", 14) == 0 ||
152                strcmp(drive_adr, "stdio:-") == 0) {
153                fprintf(stderr, "Will not work with pseudo-drive '%s'\n",
154                        drive_adr);
155                return 0;
156        }
157
158        /* This tries to resolve links or alternative device files */
159        ret = burn_drive_convert_fs_adr(drive_adr, libburn_drive_adr); 
160        if (ret<=0) {
161                fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
162                                 drive_adr);
163                return 0;
164        }
165        fprintf(stderr,"Aquiring drive '%s' ...\n", libburn_drive_adr);
166        ret = burn_drive_scan_and_grab(&drive_list, libburn_drive_adr, 1);
167        if (ret <= 0) {
168                fprintf(stderr,"FAILURE with persistent drive address  '%s'\n",
169                        libburn_drive_adr);
170        } else {
171                fprintf(stderr,"Done\n");
172                drive_is_grabbed = 1;
173        }
174        return ret;
175}
176
177
178/** This method demonstrates how to use libburn without knowing a persistent
179    drive address in advance. It has to make sure that after assessing the list
180    of available drives, all unwanted drives get closed again. As long as they
181    are open, no other libburn instance can see them. This is an intended
182    locking feature. The application is responsible for giving up the locks
183    by either burn_drive_release() (only after burn_drive_grab() !),
184    burn_drive_info_forget(), burn_drive_info_free(), or burn_finish().
185    @param driveno the index number in libburn's drive list. This will get
186                   set to 0 on success and will then be the drive index to
187                   use in the further dourse of processing.
188    @return 1 success , <= 0 failure
189*/
190int libburner_aquire_by_driveno(int *driveno)
191{
192        char adr[BURN_DRIVE_ADR_LEN];
193        int ret, i;
194
195        printf("Beginning to scan for devices ...\n");
196        while (!burn_drive_scan(&drive_list, &drive_count))
197                usleep(100002);
198        if (drive_count <= 0 && *driveno >= 0) {
199                printf("FAILED (no drives found)\n");
200                return 0;
201        }
202        printf("Done\n");
203
204        /*
205        Interactive programs may choose the drive number at this moment.
206
207        drive[0] to drive[drive_count-1] are struct burn_drive_info
208        as defined in  libburn/libburn.h  . This structure is part of API
209        and thus will strive for future compatibility on source level.
210        Have a look at the info offered.
211        Caution: do not take .location for drive address. Always use
212                burn_drive_get_adr() or you might become incompatible
213                in future.
214        Note: bugs with struct burn_drive_info - if any - will not be
215                easy to fix. Please report them but also strive for
216                workarounds on application level.
217        */
218        printf("\nOverview of accessible drives (%d found) :\n",
219                drive_count);
220        printf("-----------------------------------------------------------------------------\n");
221        for (i = 0; i < drive_count; i++) {
222                if (burn_drive_get_adr(&(drive_list[i]), adr) <=0)
223                        strcpy(adr, "-get_adr_failed-");
224                printf("%d  --drive '%s'  :  '%s'  '%s'\n",
225                        i,adr,drive_list[i].vendor,drive_list[i].product);
226        }
227        printf("-----------------------------------------------------------------------------\n\n");
228
229        /*
230        On multi-drive systems save yourself from sysadmins' revenge.
231
232        Be aware that you hold reserved all available drives at this point.
233        So either make your choice quick enough not to annoy other system
234        users, or set free the drives for a while.
235
236        The tested way of setting free all drives is to shutdown the library
237        and to restart when the choice has been made. The list of selectable
238        drives should also hold persistent drive addresses as obtained
239        above by burn_drive_get_adr(). By such an address one may use
240        burn_drive_scan_and_grab() to finally aquire exactly one drive.
241
242        A not yet tested shortcut should be to call burn_drive_info_free()
243        and to call either burn_drive_scan() or burn_drive_scan_and_grab()
244        before accessing any drives again.
245
246        In both cases you have to be aware that the desired drive might get
247        aquired in the meantime by another user resp. libburn process.
248        */
249
250        /* We already made our choice via command line. (default is 0)
251           So we just have to keep our desired drive and drop all others.
252           No other libburn instance will have a chance to steal our drive.
253         */
254        if (*driveno < 0) {
255                printf("Pseudo-drive \"-\" given : bus scanning done.\n");
256                return 2; /* the program will end after this */
257        }
258        if (drive_count <= *driveno) {
259                fprintf(stderr,
260                        "Found only %d drives. Number %d not available.\n",
261                        drive_count, *driveno);
262                return 0; /* the program will end after this */
263        }
264
265        /* Drop all drives which we do not want to use */
266        for (i = 0; i < drive_count; i++) {
267                if (i == *driveno) /* the one drive we want to keep */
268        continue;
269                ret = burn_drive_info_forget(&(drive_list[i]),0);
270                if (ret != 1)
271                        fprintf(stderr, "Cannot drop drive %d. Please report \"ret=%d\" to libburn-hackers@pykix.org\n",
272                                i, ret);
273                else
274                        printf("Dropped unwanted drive %d\n",i);
275        }
276        /* Make the one we want ready for blanking or burning */
277        ret= burn_drive_grab(drive_list[*driveno].drive, 1);
278        if (ret != 1)
279                return 0;
280        drive_is_grabbed = 1;
281        return 1;
282}
283
284
285/** Makes a previously used CD-RW or unformatted DVD-RW ready for thorough
286    re-usal.
287
288    To our knowledge it is hardly possible to abort an ongoing blank operation
289    because after start it is entirely handled by the drive.
290    So expect signal handling to wait the normal blanking timespan until it
291    can allow the process to end. External kill -9 will not help the drive.
292*/
293int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
294{
295        enum burn_disc_status disc_state;
296        struct burn_progress p;
297        double percent = 1.0;
298
299        disc_state = burn_disc_get_status(drive);
300        printf(
301            "Drive media status:  %d  (see  libburn/libburn.h  BURN_DISC_*)\n",
302            disc_state);
303        if (current_profile == 0x13) {
304                ; /* formatted DVD-RW will get blanked to sequential state */
305        } else if (disc_state == BURN_DISC_BLANK) {
306                fprintf(stderr,
307                  "IDLE: Blank media detected. Will leave it untouched\n");
308                return 2;
309        } else if (disc_state == BURN_DISC_FULL ||
310                   disc_state == BURN_DISC_APPENDABLE) {
311                ; /* this is what libburner is willing to blank */
312        } else if (disc_state == BURN_DISC_EMPTY) {
313                fprintf(stderr,"FATAL: No media detected in drive\n");
314                return 0;
315        } else {
316                fprintf(stderr,
317                        "FATAL: Unsuitable drive and media state\n");
318                return 0;
319        }
320        if(!burn_disc_erasable(drive)) {
321                fprintf(stderr,
322                        "FATAL : Media is not of erasable type\n");
323                return 0;
324        }
325        /* Switch to asynchronous signal handling for the time of waiting */
326        burn_set_signal_handling("libburner : ", NULL, 0x30);
327
328        printf("Beginning to %s-blank media.\n", (blank_fast?"fast":"full"));
329        burn_disc_erase(drive, blank_fast);
330
331        sleep(1);
332        while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
333                if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
334                        percent = 1.0 + ((double) p.sector+1.0)
335                                         / ((double) p.sectors) * 98.0;
336                printf("Blanking  ( %.1f%% done )\n", percent);
337                sleep(1);
338        }
339        if (burn_is_aborting(0) > 0)
340                return -1;
341        /* Back to synchronous handling */
342        burn_set_signal_handling("libburner : ", NULL, 0x0);
343        printf("Done\n");
344        return 1;
345}
346
347
348/** Formats unformatted DVD-RW to profile 0013h "Restricted Overwrite"
349    which needs no blanking for re-use but is not capable of multi-session.
350    Expect a behavior similar to blanking with unusual noises from the drive.
351
352    Formats unformatted BD-RE to default size. This will allocate some
353    reserve space, test for bad blocks and make the media ready for writing.
354    Expect a very long run time.
355
356    Formats unformatted blank BD-R to hold a default amount of spare blocks
357    for eventual mishaps during writing. If BD-R get written without being
358    formatted, then they get no such reserve and will burn at full speed.
359*/
360int libburner_format(struct burn_drive *drive)
361{
362        struct burn_progress p;
363        double percent = 1.0;
364        int ret, status, num_formats, format_flag= 0;
365        off_t size = 0;
366        unsigned dummy;
367        enum burn_disc_status disc_state;
368
369        if (current_profile == 0x13) {
370                fprintf(stderr, "IDLE: DVD-RW media is already formatted\n");
371                return 2;
372        } else if (current_profile == 0x41 || current_profile == 0x43) {
373                disc_state = burn_disc_get_status(drive);
374                if (disc_state != BURN_DISC_BLANK && current_profile == 0x41) {
375                        fprintf(stderr,
376                                "FATAL: BD-R is not blank. Cannot format.\n");
377                        return 0;
378                }
379                ret = burn_disc_get_formats(drive, &status, &size, &dummy,
380                                                                &num_formats);
381                if (ret > 0 && status != BURN_FORMAT_IS_UNFORMATTED) {
382                        fprintf(stderr,
383                                "IDLE: BD media is already formatted\n");
384                        return 2;
385                }
386                size = 0;           /* does not really matter */
387                format_flag = 3<<1; /* format to default size, no quick */
388        } else if (current_profile == 0x14) { /* sequential DVD-RW */
389                size = 128 * 1024 * 1024;
390                format_flag = 1; /* write initial 128 MiB */
391        } else {
392                fprintf(stderr, "FATAL: Can only format DVD-RW or BD\n");
393                return 0;
394        }
395        burn_set_signal_handling("libburner : ", NULL, 0x30);
396
397        printf("Beginning to format media.\n");
398        burn_disc_format(drive, size, format_flag);
399
400        sleep(1);
401        while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
402                if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
403                        percent = 1.0 + ((double) p.sector+1.0)
404                                         / ((double) p.sectors) * 98.0;
405                printf("Formatting  ( %.1f%% done )\n", percent);
406                sleep(1);
407        }
408        if (burn_is_aborting(0) > 0)
409                return -1;
410        burn_set_signal_handling("libburner : ", NULL, 0x0);
411        burn_disc_get_profile(drive_list[0].drive, &current_profile,
412                                 current_profile_name);
413        if (current_profile == 0x14 || current_profile == 0x13)
414                printf("Media type now: %4.4xh  \"%s\"\n",
415                                 current_profile, current_profile_name);
416        if (current_profile == 0x14) {
417                fprintf(stderr,
418                  "FATAL: Failed to change media profile to desired value\n");
419                return 0;
420        }
421        return 1;
422}
423
424
425/** Brings preformatted track images (ISO 9660, audio, ...) onto media.
426    To make sure a data image is fully readable on any Linux machine, this
427    function adds 300 kiB of padding to the (usualy single) track.
428    Audio tracks get padded to complete their last sector.
429    A fifo of 4 MB is installed between each track and its data source.
430    Each of the 4 MB buffers gets allocated automatically as soon as a track
431    begins to be processed and it gets freed as soon as the track is done.
432    The fifos do not wait for buffer fill but writing starts immediately.
433
434    In case of external signals expect abort handling of an ongoing burn to
435    last up to a minute. Wait the normal burning timespan before any kill -9.
436
437    For simplicity, this function allows memory leaks in case of failure.
438    In apps which do not abort immediately, one should clean up better.
439*/
440int libburner_payload(struct burn_drive *drive,
441                      char source_adr[][4096], int source_adr_count,
442                      int multi, int simulate_burn, int all_tracks_type)
443{
444        struct burn_source *data_src, *fifo_src[99];
445        struct burn_disc *target_disc;
446        struct burn_session *session;
447        struct burn_write_opts *burn_options;
448        enum burn_disc_status disc_state;
449        struct burn_track *track, *tracklist[99];
450        struct burn_progress progress;
451        time_t start_time;
452        int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
453        int fifo_chunksize = 2352, fifo_chunks = 1783; /* ~ 4 MB fifo */
454        off_t fixed_size;
455        char *adr, reasons[BURN_REASONS_LEN];
456        struct stat stbuf;
457
458        if (all_tracks_type != BURN_AUDIO) {
459                all_tracks_type = BURN_MODE1;
460                /* a padding of 300 kiB helps to avoid the read-ahead bug */
461                padding = 300*1024;
462                fifo_chunksize = 2048;
463                fifo_chunks = 2048; /* 4 MB fifo */
464        }
465
466        target_disc = burn_disc_create();
467        session = burn_session_create();
468        burn_disc_add_session(target_disc, session, BURN_POS_END);
469
470        for (trackno = 0 ; trackno < source_adr_count; trackno++) {
471          tracklist[trackno] = track = burn_track_create();
472          burn_track_define_data(track, 0, padding, 1, all_tracks_type);
473
474          /* Open file descriptor to source of track data */
475          adr = source_adr[trackno];
476          fixed_size = 0;
477          if (adr[0] == '-' && adr[1] == 0) {
478                fd = 0;
479          } else {
480                fd = open(adr, O_RDONLY);
481                if (fd>=0)
482                        if (fstat(fd,&stbuf)!=-1)
483                                if((stbuf.st_mode&S_IFMT)==S_IFREG)
484                                        fixed_size = stbuf.st_size;
485          }
486          if (fixed_size==0)
487                unpredicted_size = 1;
488
489          /* Convert this filedescriptor into a burn_source object */
490          data_src = NULL;
491          if (fd>=0)
492                data_src = burn_fd_source_new(fd, -1, fixed_size);
493          if (data_src == NULL) {
494                fprintf(stderr,
495                       "FATAL: Could not open data source '%s'.\n",adr);
496                if(errno!=0)
497                        fprintf(stderr,"(Most recent system error: %s )\n",
498                                strerror(errno));
499                return 0;
500          }
501          /* Install a fifo object on top of that data source object */
502          fifo_src[trackno] = burn_fifo_source_new(data_src,
503                                        fifo_chunksize, fifo_chunks, 0);
504          if (fifo_src[trackno] == NULL) {
505                fprintf(stderr,
506                        "FATAL: Could not create fifo object of 4 MB\n");
507                return 0;
508          }
509
510          /* Use the fifo object as data source for the track */
511          if (burn_track_set_source(track, fifo_src[trackno])
512                                                         != BURN_SOURCE_OK) {
513                fprintf(stderr,
514                       "FATAL: Cannot attach source object to track object\n");
515                return 0;
516          }
517
518          burn_session_add_track(session, track, BURN_POS_END);
519          printf("Track %d : source is '%s'\n", trackno+1, adr);
520
521          /* Give up local reference to the data burn_source object */
522          burn_source_free(data_src);
523         
524        } /* trackno loop end */
525
526        /* Evaluate drive and media */
527        disc_state = burn_disc_get_status(drive);
528        if (disc_state != BURN_DISC_BLANK &&
529            disc_state != BURN_DISC_APPENDABLE) {
530                if (disc_state == BURN_DISC_FULL) {
531                        fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
532                        if (burn_disc_erasable(drive))
533                                fprintf(stderr, "HINT: Try --blank_fast\n\n");
534                } else if (disc_state == BURN_DISC_EMPTY)
535                        fprintf(stderr,"FATAL: No media detected in drive\n");
536                else
537                        fprintf(stderr,
538                         "FATAL: Cannot recognize state of drive and media\n");
539                return 0;
540        }
541
542        burn_options = burn_write_opts_new(drive);
543        burn_write_opts_set_perform_opc(burn_options, 0);
544        burn_write_opts_set_multi(burn_options, !!multi);
545        if(simulate_burn)
546                printf("\n*** Will TRY to SIMULATE burning ***\n\n");
547        burn_write_opts_set_simulate(burn_options, simulate_burn);
548        burn_drive_set_speed(drive, 0, 0);
549        burn_write_opts_set_underrun_proof(burn_options, 1);
550        if (burn_write_opts_auto_write_type(burn_options, target_disc,
551                                        reasons, 0) == BURN_WRITE_NONE) {
552                fprintf(stderr, "FATAL: Failed to find a suitable write mode with this media.\n");
553                fprintf(stderr, "Reasons given:\n%s\n", reasons);
554                return 0;
555        }
556        burn_set_signal_handling("libburner : ", NULL, 0x30);
557
558        printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
559        start_time = time(0);
560        burn_disc_write(burn_options, target_disc);
561
562        burn_write_opts_free(burn_options);
563        while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
564                usleep(100002);
565        while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
566                if (progress.sectors <= 0 ||
567                    (progress.sector >= progress.sectors - 1 &&
568                     !unpredicted_size) ||
569                    (unpredicted_size && progress.sector == last_sector))
570                        printf(
571                             "Thank you for being patient since %d seconds.",
572                             (int) (time(0) - start_time));
573                else if(unpredicted_size)
574                        printf("Track %d : sector %d", progress.track+1,
575                                progress.sector);
576                else
577                        printf("Track %d : sector %d of %d",progress.track+1,
578                                progress.sector, progress.sectors);
579                last_sector = progress.sector;
580                if (progress.track >= 0 && progress.track < source_adr_count) {
581                        int size, free_bytes, ret;
582                        char *status_text;
583       
584                        ret = burn_fifo_inquire_status(
585                                fifo_src[progress.track], &size, &free_bytes,
586                                &status_text);
587                        if (ret >= 0 )
588                                printf("  [fifo %s, %2d%% fill]", status_text,
589                                        (int) (100.0 - 100.0 *
590                                                ((double) free_bytes) /
591                                                (double) size));
592                }
593                printf("\n");
594                sleep(1);
595        }
596        printf("\n");
597
598        for (trackno = 0 ; trackno < source_adr_count; trackno++) {
599                burn_source_free(fifo_src[trackno]);
600                burn_track_free(tracklist[trackno]);
601        }
602        burn_session_free(session);
603        burn_disc_free(target_disc);
604        if (burn_is_aborting(0) > 0)
605                return -1;
606        if (multi && current_profile != 0x1a && current_profile != 0x13 &&
607                current_profile != 0x12 && current_profile != 0x43)
608                        /* not with DVD+RW, formatted DVD-RW, DVD-RAM, BD-RE */
609                printf("NOTE: Media left appendable.\n");
610        if (simulate_burn)
611                printf("\n*** Did TRY to SIMULATE burning ***\n\n");
612        return 1;
613}
614
615
616/** The setup parameters of libburner */
617static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
618static int driveno = 0;
619static int do_blank = 0;
620static char source_adr[99][4096];
621static int source_adr_count = 0;
622static int do_multi = 0;
623static int simulate_burn = 0;
624static int all_tracks_type = BURN_MODE1;
625
626
627/** Converts command line arguments into above setup parameters.
628*/
629int libburner_setup(int argc, char **argv)
630{
631    int i, insuffient_parameters = 0, print_help = 0;
632
633    for (i = 1; i < argc; ++i) {
634        if (!strcmp(argv[i], "--audio")) {
635            all_tracks_type = BURN_AUDIO;
636
637        } else if (!strcmp(argv[i], "--blank_fast")) {
638            do_blank = 1;
639
640        } else if (!strcmp(argv[i], "--blank_full")) {
641            do_blank = 2;
642
643        } else if (!strcmp(argv[i], "--burn_for_real")) {
644            simulate_burn = 0;
645
646        } else if (!strcmp(argv[i], "--drive")) {
647            ++i;
648            if (i >= argc) {
649                fprintf(stderr,"--drive requires an argument\n");
650                return 1;
651            } else if (strcmp(argv[i], "-") == 0) {
652                drive_adr[0] = 0;
653                driveno = -1;
654            } else if (isdigit(argv[i][0])) {
655                drive_adr[0] = 0;
656                driveno = atoi(argv[i]);
657            } else {
658                if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
659                    fprintf(stderr,"--drive address too long (max. %d)\n",
660                            BURN_DRIVE_ADR_LEN-1);
661                    return 2;
662                }
663                strcpy(drive_adr, argv[i]);
664            }
665        } else if ((!strcmp(argv[i], "--format_overwrite")) ||
666                   (!strcmp(argv[i], "--format"))) {
667            do_blank = 101;
668
669        } else if (!strcmp(argv[i], "--multi")) {
670            do_multi = 1;
671
672        } else if (!strcmp(argv[i], "--stdin_size")) { /* obsoleted */
673            i++;
674
675        } else if (!strcmp(argv[i], "--try_to_simulate")) {
676            simulate_burn = 1;
677
678        } else if (!strcmp(argv[i], "--help")) {
679            print_help = 1;
680
681        } else if (!strncmp(argv[i], "--",2)) {
682            fprintf(stderr, "Unidentified option: %s\n", argv[i]);
683            return 7;
684        } else {
685            if(strlen(argv[i]) >= 4096) {
686                fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
687                return 5;
688            }
689            if(source_adr_count >= 99) {
690                fprintf(stderr, "Too many tracks (max. 99)\n");
691                return 6;
692            }
693            strcpy(source_adr[source_adr_count], argv[i]);
694            source_adr_count++;
695        }
696    }
697    insuffient_parameters = 1;
698    if (driveno < 0)
699        insuffient_parameters = 0;
700    if (source_adr_count > 0)
701        insuffient_parameters = 0;
702    if (do_blank)
703        insuffient_parameters = 0;
704    if (print_help || insuffient_parameters ) {
705        printf("Usage: %s\n", argv[0]);
706        printf("       [--drive <address>|<driveno>|\"-\"]  [--audio]\n");
707        printf("       [--blank_fast|--blank_full|--format]  [--try_to_simulate]\n");
708        printf("       [--multi]  [<one or more imagefiles>|\"-\"]\n");
709        printf("Examples\n");
710        printf("A bus scan (needs rw-permissions to see a drive):\n");
711        printf("  %s --drive -\n",argv[0]);
712        printf("Burn a file to drive chosen by number, leave appendable:\n");
713        printf("  %s --drive 0 --multi my_image_file\n", argv[0]);
714        printf("Burn a file to drive chosen by persistent address, close:\n");
715        printf("  %s --drive /dev/hdc my_image_file\n", argv[0]);
716        printf("Blank a used CD-RW (is combinable with burning in one run):\n");
717        printf("  %s --drive /dev/hdc --blank_fast\n",argv[0]);
718        printf("Blank a used DVD-RW (is combinable with burning in one run):\n");
719        printf("  %s --drive /dev/hdc --blank_full\n",argv[0]);
720        printf("Format a DVD-RW, BD-RE or BD-R:\n");
721        printf("  %s --drive /dev/hdc --format\n", argv[0]);
722        printf("Burn two audio tracks (to CD only):\n");
723        printf("  lame --decode -t /path/to/track1.mp3 track1.cd\n");
724        printf("  test/dewav /path/to/track2.wav -o track2.cd\n");
725        printf("  %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
726        printf("Burn a compressed afio archive on-the-fly:\n");
727        printf("  ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
728        printf("  %s --drive /dev/hdc -\n", argv[0]);
729        printf("To be read from *not mounted* media via: afio -tvZ /dev/hdc\n");
730        if (insuffient_parameters)
731            return 6;
732    }
733    return 0;
734}
735
736
737int main(int argc, char **argv)
738{
739        int ret;
740
741        /* A warning to programmers who start their own projekt from here. */
742        if (sizeof(off_t) != 8) {
743                 fprintf(stderr,
744           "\nFATAL: Compile time misconfiguration. off_t is not 64 bit.\n\n");
745                 exit(39);
746        }
747
748        ret = libburner_setup(argc, argv);
749        if (ret)
750                exit(ret);
751
752        printf("Initializing libburnia-project.org ...\n");
753        if (burn_initialize())
754                printf("Done\n");
755        else {
756                printf("FAILED\n");
757                fprintf(stderr,"\nFATAL: Failed to initialize.\n");
758                exit(33);
759        }
760
761        /* Print messages of severity SORRY or more directly to stderr */
762        burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
763
764        /* Activate the synchronous signal handler which eventually will try to
765           properly shutdown drive and library on aborting events. */
766        burn_set_signal_handling("libburner : ", NULL, 0x0);
767
768        /** Note: driveno might change its value in this call */
769        ret = libburner_aquire_drive(drive_adr, &driveno);
770        if (ret<=0) {
771                fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
772                { ret = 34; goto finish_libburn; }
773        }
774        if (ret == 2)
775                { ret = 0; goto release_drive; }
776        if (do_blank) {
777                if (do_blank > 100)
778                        ret = libburner_format(drive_list[driveno].drive);
779                else
780                        ret = libburner_blank_disc(drive_list[driveno].drive,
781                                                        do_blank == 1);
782                if (ret<=0)
783                        { ret = 36; goto release_drive; }
784        }
785        if (source_adr_count > 0) {
786                ret = libburner_payload(drive_list[driveno].drive,
787                                source_adr, source_adr_count,
788                                do_multi, simulate_burn, all_tracks_type);
789                if (ret<=0)
790                        { ret = 38; goto release_drive; }
791        }
792        ret = 0;
793release_drive:;
794        if (drive_is_grabbed)
795                burn_drive_release(drive_list[driveno].drive, 0);
796
797finish_libburn:;
798        if (burn_is_aborting(0) > 0) {
799                burn_abort(4400, burn_abort_pacifier, "libburner : ");
800                fprintf(stderr,"\nlibburner run aborted\n");
801                exit(1);
802        }
803        /* This app does not bother to know about exact scan state.
804           Better to accept a memory leak here. We are done anyway. */
805        /* burn_drive_info_free(drive_list); */
806        burn_finish();
807        exit(ret);
808}
809
810
811/*  License and copyright aspects:
812
813This all is provided under GPL.
814Read. Try. Think. Play. Write yourself some code. Be free of my copyright.
815
816Be also invited to study the code of cdrskin/cdrskin.c et al.
817
818History:
819libburner is a compilation of my own contributions to test/burniso.c and
820fresh code which replaced the remaining parts under copyright of
821Derek Foreman.
822My respect and my thanks to Derek for providing me a start back in 2005.
823
824*/
Note: See TracBrowser for help on using the browser.