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

Generated for libburn by  doxygen 1.8.14