root / libburn / trunk / test / telltoc.c

Revision 3036, 28.6 kB (checked in by scdbackup, 8 months ago)

Lifted ban to derive GPLv3, extended copyright range to 2010

Line 
1
2/*  test/telltoc.c , API illustration of obtaining media status info */
3/*  Copyright (C) 2006 - 2010 Thomas Schmitt <scdbackup@gmx.net>
4    Provided under GPL */
5
6/**                               Overview
7 
8  telltoc is a minimal demo application for the library libburn as provided
9  on  http://libburnia-project.org . It can list the available devices, can
10  display some drive properties, the type of media, eventual table of content
11  and multisession info for mkisofs option -C .
12  It's main purpose, nevertheless, is to show you how to use libburn and also
13  to serve the libburn team as reference application. telltoc.c does indeed
14  define the standard way how above gestures can be implemented and stay upward
15  compatible for a good while.
16 
17  Before you can do anything, you have to initialize libburn by
18     burn_initialize()
19  as it is done in main() at the end of this file. Then you aquire a
20  drive in an appropriate way conforming to the API. The two main
21  approaches are shown here in application functions:
22     telltoc_aquire_by_adr()       demonstrates usage as of cdrecord traditions
23     telltoc_aquire_by_driveno()   demonstrates a scan-and-choose approach
24  With that aquired drive you can call
25     telltoc_media()   prints some information about the media in a drive
26     telltoc_toc()     prints a table of content (if there is content)
27     telltoc_msinfo()  prints parameters for mkisofs option -C
28     telltoc_read_and_print()  reads from data CD or from DVD and prints 7-bit
29                       to stdout (encodings 0,2) or 8-bit to file (encoding 1)
30  When everything is done, main() releases the drive and shuts down libburn:
31     burn_drive_release();
32     burn_finish()
33 
34*/
35
36/** See this for the decisive API specs . libburn.h is The Original */
37/*  For using the installed header file :  #include <libburn/libburn.h> */
38/*  This program insists in the own headerfile. */
39#include "../libburn/libburn.h"
40
41/* libburn is intended for Linux systems with kernel 2.4 or 2.6 for now */
42#include <stdio.h>
43#include <ctype.h>
44#include <sys/types.h>
45#include <unistd.h>
46#include <string.h>
47#include <stdlib.h>
48#include <time.h>
49#include <errno.h>
50#include <sys/stat.h>
51#include <fcntl.h>
52
53
54/** For simplicity i use global variables to represent the drives.
55    Drives are systemwide global, so we do not give away much of good style.
56*/
57
58/** This list will hold the drives known to libburn. This might be all CD
59    drives of the system and thus might impose severe impact on the system.
60*/
61static struct burn_drive_info *drive_list;
62
63/** If you start a long lasting operation with drive_count > 1 then you are
64    not friendly to the users of other drives on those systems. Beware. */
65static unsigned int drive_count;
66
67/** This variable indicates wether the drive is grabbed and must be
68    finally released */
69static int drive_is_grabbed = 0;
70
71
72/* Some in-advance definitions to allow a more comprehensive ordering
73   of the functions and their explanations in here */
74int telltoc_aquire_by_adr(char *drive_adr);
75int telltoc_aquire_by_driveno(int *drive_no, int silent);
76
77
78/* A message from --toc to --read_and_print (CD tracksize is a bit tricky) */
79static int last_track_start = 0, last_track_size = -1;
80static int media_is_cd_profile = 0;
81
82
83/* ------------------------------- API gestures ---------------------------- */
84
85/** You need to aquire a drive before burning. The API offers this as one
86    compact call and alternatively as application controllable gestures of
87    whitelisting, scanning for drives and finally grabbing one of them.
88
89    If you have a persistent address of the drive, then the compact call is
90    to prefer because it only touches one drive. On modern Linux kernels,
91    there should be no fatal disturbance of ongoing burns of other libburn
92    instances with any of our approaches. We use open(O_EXCL) by default.
93    On /dev/hdX it should cooperate with growisofs and some cdrecord variants.
94    On /dev/sgN versus /dev/scdM expect it not to respect other programs.
95*/
96int telltoc_aquire_drive(char *drive_adr, int *driveno, int silent_drive)
97{
98        int ret;
99
100        if(drive_adr != NULL && drive_adr[0] != 0)
101                ret = telltoc_aquire_by_adr(drive_adr);
102        else
103                ret = telltoc_aquire_by_driveno(driveno, silent_drive);
104        return ret;
105}
106
107
108/** If the persistent drive address is known, then this approach is much
109    more un-obtrusive to the systemwide livestock of drives. Only the
110    given drive device will be opened during this procedure.
111    Special drive addresses stdio:<path> direct output to a hard disk file
112    which will behave much like a DVD-RAM.
113*/
114int telltoc_aquire_by_adr(char *drive_adr)
115{
116        int ret;
117        char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
118
119        /* <<< ts A70907 FOR TESTING ONLY !
120        struct burn_drive_info *test_drive_list;
121        */
122
123        /* This tries to resolve links or alternative device files */
124        ret = burn_drive_convert_fs_adr(drive_adr, libburn_drive_adr); 
125        if (ret<=0) {
126                fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
127                        drive_adr);
128                return 0;
129        }
130
131        /* <<< ts A70907 FOR TESTING ONLY !
132        ret = burn_drive_scan_and_grab(&test_drive_list, "/dev/sg2", 1);
133        */
134
135        fprintf(stderr,"Aquiring drive '%s' ...\n", libburn_drive_adr);
136        ret = burn_drive_scan_and_grab(&drive_list, libburn_drive_adr, 1);
137
138        if (ret <= 0) {
139                fprintf(stderr,"FAILURE with persistent drive address  '%s'\n",
140                        libburn_drive_adr);
141        } else {
142                fprintf(stderr,"Done\n");
143                drive_is_grabbed = 1;
144        }
145
146        /* <<< ts A70907 FOR TESTING ONLY !
147        burn_drive_info_free(test_drive_list);
148        */
149
150        return ret;
151}
152
153
154/** This method demonstrates how to use libburn without knowing a persistent
155    drive address in advance. It has to make sure that after assessing the list
156    of available drives, all unwanted drives get closed again. As long as they
157    are open, no other libburn instance can see them. This is an intended
158    locking feature. The application is responsible for giving up the locks
159    by either burn_drive_release() (only after burn_drive_grab() !),
160    burn_drive_info_forget(), burn_drive_info_free(), or burn_finish().
161    @param driveno the index number in libburn's drive list. This will get
162                   set to 0 on success and will then be the drive index to
163                   use in the further dourse of processing.
164    @param silent_drive 1=do not print "Drive found  :" line with *driveno >= 0
165    @return 1 success , <= 0 failure
166*/
167int telltoc_aquire_by_driveno(int *driveno, int silent_drive)
168{
169        char adr[BURN_DRIVE_ADR_LEN];
170        int ret, i;
171
172        fprintf(stderr, "Beginning to scan for devices ...\n");
173        while (!burn_drive_scan(&drive_list, &drive_count))
174                usleep(100002);
175        if (drive_count <= 0 && *driveno >= 0) {
176                fprintf(stderr, "FAILED (no drives found)\n");
177                return 0;
178        }
179        fprintf(stderr, "Done\n");
180
181        for (i = 0; i < drive_count; i++) {
182                if (*driveno >= 0 && (silent_drive || *driveno != i))
183        continue;
184                if (burn_drive_get_adr(&(drive_list[i]), adr) <=0)
185                        strcpy(adr, "-get_adr_failed-");
186                printf("Drive found  : %d  --drive '%s'  : ", i,adr);
187                printf("%-8s  %-16s  (%4s)\n",
188                        drive_list[i].vendor,drive_list[i].product,
189                        drive_list[i].revision);
190        }
191        if (*driveno < 0) {
192                fprintf(stderr,
193                        "Pseudo-drive \"-\" given : bus scanning done.\n");
194                return 2; /* the program will end after this */
195        }
196
197        /* We already made our choice via command line. (default is 0)
198           So we just have to keep our desired drive and drop all others.
199         */
200        if (drive_count <= *driveno) {
201                fprintf(stderr,
202                        "Found only %d drives. Number %d not available.\n",
203                        drive_count, *driveno);
204                return 0; /* the program will end after this */
205        }
206
207        /* Drop all drives which we do not want to use */
208        for (i = 0; i < drive_count; i++) {
209                if (i == *driveno) /* the one drive we want to keep */
210        continue;
211                ret = burn_drive_info_forget(&(drive_list[i]),0);
212                if (ret != 1)
213                        fprintf(stderr, "Cannot drop drive %d. Please report \"ret=%d\" to libburn-hackers@pykix.org\n",
214                                i, ret);
215                else
216                        fprintf(stderr, "Dropped unwanted drive %d\n",i);
217        }
218        /* Make the one we want ready for inquiry */
219        ret= burn_drive_grab(drive_list[*driveno].drive, 1);
220        if (ret != 1)
221                return 0;
222        drive_is_grabbed = 1;
223        return 1;
224}
225
226
227/** This gesture is necessary to get my NEC DVD_RW ND-4570A out of a state
228    of noisy overexcitement after its tray was loaded and it then was inquired
229    for Next Writeable Address.
230    The noise then still lasts 20 seconds. Same with cdrecord -toc, btw.
231    This opens a small gap for losing the drive to another libburn instance.
232    Not a problem in telltoc. This is done as very last drive operation.
233    Eventually the other libburn instance will have the same sanitizing effect.
234*/
235int telltoc_regrab(struct burn_drive *drive) {
236        int ret;
237
238        if (drive_is_grabbed)
239                burn_drive_release(drive, 0);
240        drive_is_grabbed = 0;
241        ret = burn_drive_grab(drive, 0);
242        if (ret != 0) {
243                drive_is_grabbed = 1;
244        }
245        return !!ret;
246}
247
248
249int telltoc_media(struct burn_drive *drive)
250{
251        int ret, media_found = 0, profile_no = -1;
252        double max_speed = 0.0, min_speed = 0.0, speed_conv;
253        off_t available = 0;
254        enum burn_disc_status s;
255        char profile_name[80], speed_unit[40];
256        struct burn_multi_caps *caps;
257        struct burn_write_opts *o = NULL;
258
259        printf("Media current: ");
260        ret = burn_disc_get_profile(drive, &profile_no, profile_name);
261        if (profile_no > 0 && ret > 0) {
262                if (profile_name[0])
263                        printf("%s\n", profile_name);
264                else
265                        printf("%4.4Xh\n", profile_no);
266        } else
267                printf("is not recognizable\n");
268
269        speed_conv = 176.4;
270        strcpy(speed_unit,"176.4 kB/s  (CD, data speed 150 KiB/s)");
271        if (strstr(profile_name, "DVD") == profile_name) {
272                speed_conv = 1385.0;
273                strcpy(speed_unit,"1385.0 kB/s  (DVD)");
274        }
275
276        /* >>> libburn does not obtain full profile list yet */
277
278        printf("Media status : ");
279        s = burn_disc_get_status(drive);
280        if (s == BURN_DISC_FULL) {
281                printf("is written , is closed\n");
282                media_found = 1;
283        } else if (s == BURN_DISC_APPENDABLE) {
284                printf("is written , is appendable\n");
285                media_found = 1;
286        } else if (s == BURN_DISC_BLANK) {
287                printf("is blank\n");
288                media_found = 1;
289        } else if (s == BURN_DISC_EMPTY)
290                printf("is not present\n");
291        else
292                printf("is not recognizable\n");
293
294        printf("Media reuse  : ");
295        if (media_found) {
296                if (burn_disc_erasable(drive))
297                        printf("is erasable\n");
298                else
299                        printf("is not erasable\n");   
300        } else
301                printf("is not recognizable\n");
302
303        ret = burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
304        if (ret > 0) {
305                /* Media appears writeable */
306                printf("Write multi  : ");
307                printf("%s multi-session , ",
308                         caps->multi_session == 1 ? "allows" : "prohibits");
309                if (caps->multi_track)
310                        printf("allows multiple tracks\n");
311                else
312                        printf("enforces single track\n");
313                printf("Write start  : ");
314                if (caps->start_adr == 1)
315                        printf(
316                        "allows addresses [%.f , %.f]s , alignment=%.fs\n",
317                                (double) caps->start_range_low / 2048 ,
318                                (double) caps->start_range_high / 2048 ,
319                                (double) caps->start_alignment / 2048 );
320                else
321                        printf("prohibits write start addressing\n");
322                printf("Write modes  : ");
323                if (caps->might_do_tao)
324                        printf("TAO%s",
325                                caps->advised_write_mode == BURN_WRITE_TAO ?
326                                " (advised)" : "");
327                if (caps->might_do_sao)
328                        printf("%sSAO%s",
329                                caps->might_do_tao ? " , " : "",
330                                caps->advised_write_mode == BURN_WRITE_SAO ?
331                                " (advised)" : "");
332                if (caps->might_do_raw)
333                        printf("%sRAW%s",
334                                caps->might_do_tao | caps->might_do_sao ?
335                                " , " : "",
336                                caps->advised_write_mode == BURN_WRITE_RAW ?
337                                " (advised)" : "");
338                printf("\n");
339                printf("Write dummy  : ");
340                if (caps->might_simulate)
341                        printf("supposed to work with non-RAW modes\n");
342                else
343                        printf("will not work\n");
344                o= burn_write_opts_new(drive);
345                if (o != NULL) {
346                        burn_write_opts_set_perform_opc(o, 0);
347                        if(caps->advised_write_mode == BURN_WRITE_TAO)
348                                burn_write_opts_set_write_type(o,
349                                        BURN_WRITE_TAO, BURN_BLOCK_MODE1);
350                        else if (caps->advised_write_mode == BURN_WRITE_SAO)
351                                burn_write_opts_set_write_type(o,
352                                        BURN_WRITE_SAO, BURN_BLOCK_SAO);
353                        else {
354                                burn_write_opts_free(o);
355                                o = NULL;
356                        }
357                }
358                available = burn_disc_available_space(drive, o);
359                printf("Write space  : %.1f MiB  (%.fs)\n",
360                        ((double) available) / 1024.0 / 1024.0,
361                        ((double) available) / 2048.0);
362                burn_disc_free_multi_caps(&caps);
363                if (o != NULL)
364                        burn_write_opts_free(o);
365        }
366
367        ret = burn_drive_get_write_speed(drive);
368        max_speed = ((double ) ret) / speed_conv;
369        ret = burn_drive_get_min_write_speed(drive);
370        min_speed = ((double ) ret) / speed_conv;
371        if (!media_found)
372                printf("Drive speed  : max=%.1f  , min=%.1f\n",
373                         max_speed, min_speed);
374        else
375                printf("Avail. speed : max=%.1f  , min=%.1f\n",
376                         max_speed, min_speed);
377
378        ret = 0;
379        if (media_found)
380                ret = burn_disc_read_atip(drive);
381        if(ret>0) {
382                ret = burn_drive_get_min_write_speed(drive);
383                min_speed = ((double ) ret) / speed_conv;
384                ret = burn_drive_get_write_speed(drive);
385                max_speed = ((double ) ret) / speed_conv;
386                printf("Media speed  : max=%.1f  , min=%.1f\n",
387                        max_speed, min_speed);
388        }
389        printf("Speed unit 1x: %s\n", speed_unit);
390
391        return 1;
392}
393
394
395int telltoc_speedlist(struct burn_drive *drive)
396{
397        int ret, has_modern_entries = 0;
398        struct burn_speed_descriptor *speed_list, *sd;
399
400        ret = burn_drive_get_speedlist(drive, &speed_list);
401        if (ret <= 0) {
402                fprintf(stderr, "SORRY: Cannot obtain speed list info\n");
403                return 2;
404        }
405        for (sd = speed_list; sd != NULL; sd = sd->next)
406                if (sd->source == 2)
407                        has_modern_entries = 1;
408        for (sd = speed_list; sd != NULL; sd = sd->next) {
409                if (has_modern_entries && sd->source < 2)
410        continue;
411                if (sd->write_speed <= 0)
412        continue;
413                printf("Speed descr. : %d kB/s", sd->write_speed);
414                if (sd->end_lba >= 0)
415                        printf(", %.1f MiB", ((double) sd->end_lba) / 512.0);
416                if (sd->profile_name[0])
417                        printf(", %s", sd->profile_name);
418                printf("\n");
419        }
420        burn_drive_free_speedlist(&speed_list);
421        return 1;
422}
423
424
425int telltoc_formatlist(struct burn_drive *drive)
426{
427        int ret, i, status, num_formats, profile_no, type;
428        off_t size;
429        unsigned dummy;
430        char status_text[80], profile_name[90];
431
432        ret = burn_disc_get_formats(drive, &status, &size, &dummy,
433                                 &num_formats);
434        if (ret <= 0) {
435                fprintf(stderr, "SORRY: Cannot obtain format list info\n");
436                return 2;
437        }
438        if (status == BURN_FORMAT_IS_UNFORMATTED)
439                sprintf(status_text, "unformatted, up to %.1f MiB",
440                        ((double) size) / 1024.0 / 1024.0);
441        else if(status == BURN_FORMAT_IS_FORMATTED)
442                sprintf(status_text, "formatted, with %.1f MiB",
443                        ((double) size) / 1024.0 / 1024.0);
444        else if(status == BURN_FORMAT_IS_UNKNOWN) {
445                burn_disc_get_profile(drive, &profile_no, profile_name);
446                if (profile_no > 0)
447                        sprintf(status_text, "intermediate or unknown");
448                else
449                        sprintf(status_text, "no media or unknown media");
450        } else
451                sprintf(status_text, "illegal status according to MMC-5");
452        printf("Format status: %s\n", status_text);
453
454        for (i = 0; i < num_formats; i++) {
455                ret = burn_disc_get_format_descr(drive, i,
456                                                 &type, &size, &dummy);
457                if (ret <= 0)
458        continue;
459                printf("Format descr.: %2.2Xh  , %.1f MiB  (%.fs)\n",
460                        type, ((double) size) / 1024.0 / 1024.0,
461                        ((double) size) / 2048.0);
462        }
463        return 1;
464}
465
466
467int telltoc_toc(struct burn_drive *drive)
468{
469        int num_sessions = 0 , num_tracks = 0 , lba = 0, pmin, psec, pframe;
470        int track_count = 0, pno;
471        int session_no, track_no;
472        char profile_name[80];
473        struct burn_disc *disc= NULL;
474        struct burn_session **sessions;
475        struct burn_track **tracks;
476        struct burn_toc_entry toc_entry;
477
478        disc = burn_drive_get_disc(drive);
479        if (disc==NULL) {
480                fprintf(stderr, "SORRY: Cannot obtain Table Of Content\n");
481                return 2;
482        }
483        sessions = burn_disc_get_sessions(disc, &num_sessions);
484        for (session_no = 0; session_no<num_sessions; session_no++) {
485                tracks = burn_session_get_tracks(sessions[session_no],
486                                                &num_tracks);
487                if (tracks==NULL)
488        continue;
489                for(track_no= 0; track_no<num_tracks; track_no++) {
490                        track_count++;
491                        burn_track_get_entry(tracks[track_no], &toc_entry);
492                        if (toc_entry.extensions_valid & 1) {
493                                /* DVD extension valid */
494                                lba = toc_entry.start_lba;
495                                burn_lba_to_msf(lba, &pmin, &psec, &pframe);
496                        } else {
497                                pmin = toc_entry.pmin;
498                                psec = toc_entry.psec;
499                                pframe = toc_entry.pframe;
500                                lba= burn_msf_to_lba(pmin, psec, pframe);
501                        }
502                        printf("Media content: session %2d  ", session_no+1);
503                        printf("track    %2d %s  lba: %9d  %4.2d:%2.2d:%2.2d\n",
504                                track_count,
505                                ((toc_entry.control&7)<4?"audio":"data "),
506                                lba, pmin, psec, pframe);
507                        last_track_start = lba;
508                }
509                burn_session_get_leadout_entry(sessions[session_no],
510                                                &toc_entry);
511                if (toc_entry.extensions_valid & 1) {
512                        lba = toc_entry.start_lba;
513                        burn_lba_to_msf(lba, &pmin, &psec, &pframe);
514                } else {
515                        pmin = toc_entry.pmin;
516                        psec = toc_entry.psec;
517                        pframe = toc_entry.pframe;
518                        lba= burn_msf_to_lba(pmin, psec, pframe);
519                }
520                printf("Media content: session %2d  ", session_no+1);
521                printf("leadout            lba: %9d  %4.2d:%2.2d:%2.2d\n",
522                        lba, pmin, psec, pframe);
523                last_track_size = lba - last_track_start;
524                if (burn_disc_get_profile(drive, &pno, profile_name) > 0)
525                        if (pno == 0x09 || pno == 0x0a)
526                                media_is_cd_profile = 1;
527                       
528        }
529        if (disc!=NULL)
530                burn_disc_free(disc);
531        return 1;
532}
533
534
535int telltoc_msinfo(struct burn_drive *drive,
536                        int msinfo_explicit, int msinfo_alone)
537{
538        int ret, lba, nwa = -123456789, aux_lba;
539        enum burn_disc_status s;
540        struct burn_write_opts *o= NULL;
541
542        s = burn_disc_get_status(drive);
543        if (s!=BURN_DISC_APPENDABLE) {
544                if (!msinfo_explicit)
545                        return 2;
546                fprintf(stderr,
547                   "SORRY: --msinfo can only operate on appendable media.\n");
548                return 0;
549        }
550
551        /* man mkisofs , option -C :
552           The first number is the sector number of the first sector in
553           the last session of the disk that should be appended to.
554        */
555        ret = burn_disc_get_msc1(drive, &lba);
556        if (ret <= 0) {
557                fprintf(stderr,
558                        "SORRY: Cannot obtain start address of last session\n");
559                { ret = 0; goto ex; }
560        }
561
562        /* man mkisofs , option -C :
563           The second  number is the starting sector number of the new session.
564        */
565        /* Set some roughly suitable write opts to be sent to drive. */
566        o= burn_write_opts_new(drive);
567        if(o!=NULL) {
568                burn_write_opts_set_perform_opc(o, 0);
569                burn_write_opts_set_write_type(o,
570                                        BURN_WRITE_TAO, BURN_BLOCK_MODE1);
571        }
572        /* Now try to inquire nwa from drive */
573        ret= burn_disc_track_lba_nwa(drive,o,0,&aux_lba,&nwa);
574        telltoc_regrab(drive); /* necessary to calm down my NEC drive */
575        if(ret<=0) {
576                fprintf(stderr,
577                        "SORRY: Cannot obtain next writeable address\n");
578                { ret = 0; goto ex; }
579        }
580
581        if (!msinfo_alone)
582                printf("Media msinfo : mkisofs ... -C ");
583        printf("%d,%d\n",lba,nwa);
584        ret = 1;
585ex:;
586        if (o != NULL)
587                burn_write_opts_free(o);
588        return ret;
589}
590
591
592/**
593  @param encoding determins how to format output on stdout:
594                  0 = default , 1 = raw 8 bit (dangerous for tty) , 2 = hex
595*/
596int telltoc_read_and_print(struct burn_drive *drive,
597        int start_sector, int sector_count, char *raw_file, int encoding)
598{
599        int j, i, request = 16, done, lbas = 0, final_cd_try = -1, todo;
600        int ret = 0;
601        char buf[16 * 2048], line[81];
602        off_t data_count, total_count= 0, last_reported_count= 0;
603        struct stat stbuf;
604        FILE *raw_fp = NULL;
605
606        if (start_sector == -1)
607                start_sector = last_track_start;
608        if (sector_count == -1) {
609                sector_count = last_track_start + last_track_size
610                                - start_sector;
611                if (media_is_cd_profile)  /* In case it is a TAO track */
612                        final_cd_try = 0; /* allow it (-1 is denial) */
613        }
614        if (start_sector < 0)
615                start_sector = 0;
616        if (sector_count <= 0)
617                sector_count = 2147483632;
618
619        if (sector_count <= 0)
620                return -1;
621        if (encoding == 1) {
622                if (stat(raw_file,&stbuf) != -1) {
623                        if (!(S_ISCHR(stbuf.st_mode) || S_ISFIFO(stbuf.st_mode)
624                                 || (stbuf.st_mode & S_IFMT) == S_IFSOCK )) {
625                                fprintf(stderr,
626                                  "SORRY: target file '%s' already existing\n",
627                                  raw_file);
628                                return 1;
629                        }
630                }
631                raw_fp = fopen(raw_file,"w");
632                if (raw_fp == NULL) {
633                    fprintf(stderr,"SORRY: cannot open target file '%s' (%s)\n", raw_file, strerror(errno));
634                    return 1;
635                }
636                printf(
637        "Data         : start=%ds , count=%ds , read=0s , encoding=%d:'%s'\n",
638                start_sector, sector_count, encoding, raw_file);
639        } else 
640                printf(
641                "Data         : start=%ds , count=%ds , read=0 , encoding=%d\n",
642                start_sector, sector_count, encoding);
643        todo = sector_count - 2*(final_cd_try > -1);
644        for (done = 0; done < todo && final_cd_try != 1; done += request) {
645                if (todo - done > 16)
646                        request = 16;
647                else
648                        request = todo - done;
649                ret = burn_read_data(drive,
650                        ((off_t) start_sector + done) * (off_t) 2048,
651                        buf, (off_t) (request * 2048), &data_count, 1);
652                       
653print_result:;
654                total_count += data_count;
655                if (encoding == 1) {
656                        if (data_count > 0)
657                                fwrite(buf, data_count, 1, raw_fp);
658                } else for (i = 0; i < data_count; i += 16) {
659                        if (encoding == 0) {
660                                sprintf(line, "%8ds + %4d : ",
661                                        start_sector + done + i / 2048,
662                                        i % 2048);
663                                lbas = strlen(line);
664                        }
665                        for (j = 0; j < 16 && i + j < data_count; j++) {
666                                if (buf[i + j] >= ' ' && buf[i + j] <= 126 &&
667                                        encoding != 2)
668                                        sprintf(line + lbas + 3 * j, " %c ",
669                                                (int) buf[i + j]);
670                                else
671                                        sprintf(line + lbas + 3 * j, "%2.2X ",
672                                                (unsigned char) buf[i + j]);
673                        }
674                        line[lbas + 3 * (j - 1) + 2] = 0;
675                        printf("%s\n",line);
676                }
677                if (encoding == 1 &&
678                    total_count - last_reported_count >= 1000 * 2048) {
679                        fprintf(stderr,
680                         "\rReading data : start=%ds , count=%ds , read=%ds  ",
681                         start_sector, sector_count,
682                          (int) (total_count / (off_t) 2048));
683                        last_reported_count = total_count;
684                }
685                if (ret <= 0) {
686                        fprintf(stderr, "SORRY : Reading failed.\n");
687        break;
688                }
689        }
690        if (ret > 0 && media_is_cd_profile && final_cd_try == 0) {
691                /* In a SAO track the last 2 frames should be data too */
692                final_cd_try = 1;
693                burn_read_data(drive,
694                        ((off_t) start_sector + todo) * (off_t) 2048,
695                        buf, (off_t) (2 * 2048), &data_count, 2);
696                if (data_count < 2 * 2048)
697                        fprintf(stderr, "\rNOTE : Last two frames of CD track unreadable. This is normal if TAO track.\n");
698                if (data_count > 0)
699                        goto print_result;     
700        }
701        if (last_reported_count > 0)
702                fprintf(stderr,
703"\r                                                                       \r");
704        printf("End Of Data  : start=%ds , count=%ds , read=%ds\n",
705                start_sector, sector_count,(int) (total_count / (off_t) 2048));
706
707        return ret;
708}
709
710
711/** The setup parameters of telltoc */
712static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
713static int driveno = 0;
714static int do_media = 0;
715static int do_toc = 0;
716static int do_msinfo = 0;
717static int print_help = 0;
718static int do_capacities = 0;
719static int read_start = -2, read_count = -2, print_encoding = 0;
720static char print_raw_file[4096] = {""};
721
722
723/** Converts command line arguments into above setup parameters.
724    drive_adr[] must provide at least BURN_DRIVE_ADR_LEN bytes.
725    source_adr[] must provide at least 4096 bytes.
726*/
727int telltoc_setup(int argc, char **argv)
728{
729    int i;
730
731    for (i = 1; i < argc; ++i) {
732        if (!strcmp(argv[i], "--drive")) {
733            ++i;
734            if (i >= argc) {
735                fprintf(stderr,"--drive requires an argument\n");
736                return 1;
737            } else if (strcmp(argv[i], "-") == 0) {
738                drive_adr[0] = 0;
739                driveno = -1;
740            } else if (isdigit(argv[i][0])) {
741                drive_adr[0] = 0;
742                driveno = atoi(argv[i]);
743            } else {
744                if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
745                    fprintf(stderr,"--drive address too long (max. %d)\n",
746                            BURN_DRIVE_ADR_LEN-1);
747                    return 2;
748                }
749                strcpy(drive_adr, argv[i]);
750            }
751        } else if (strcmp(argv[i],"--media")==0) {
752            do_media = 1;
753
754        } else if (!strcmp(argv[i], "--msinfo")) {
755            do_msinfo = 1;
756
757        } else if (!strcmp(argv[i], "--capacities")) {
758            do_capacities = 1;
759
760        } else if (!strcmp(argv[i], "--toc")) {
761            do_toc = 1;
762
763        } else if (!strcmp(argv[i], "--read_and_print")) {
764            i+= 3;
765            if (i >= argc) {
766                fprintf(stderr,"--read_and_print requires three arguments: start count encoding(try 0, not 1)\n");
767                return 1;
768            }
769            sscanf(argv[i-2], "%d", &read_start);
770            sscanf(argv[i-1], "%d", &read_count);
771            print_encoding = 0;
772            if(strncmp(argv[i], "raw:", 4) == 0 || strcmp(argv[i],"1:") == 0) {
773                print_encoding = 1;
774                strcpy(print_raw_file, strchr(argv[i], ':') + 1);
775                if (strcmp(print_raw_file, "-") == 0) {
776                        fprintf(stderr,
777                "--read_and_print does not write to \"-\" as stdout.\n");
778                        return 1;
779                }
780            } else if(strcmp(argv[i], "hex") == 0 || strcmp(argv[i], "2") == 0)
781               print_encoding = 2;
782           
783        } else if (!strcmp(argv[i], "--help")) {
784            print_help = 1;
785
786        } else  {
787            fprintf(stderr, "Unidentified option: %s\n", argv[i]);
788            return 7;
789        }
790    }
791    if (argc==1)
792        print_help = 1;
793    if (print_help) {
794        printf("Usage: %s\n", argv[0]);
795        printf("       [--drive <address>|<driveno>|\"-\"]\n");
796        printf("       [--media]  [--capacities]  [--toc]  [--msinfo]\n");
797        printf("       [--read_and_print <start> <count> \"0\"|\"hex\"|\"raw\":<path>]\n");
798        printf("Examples\n");
799        printf("A bus scan (needs rw-permissions to see a drive):\n");
800        printf("  %s --drive -\n",argv[0]);
801        printf("Obtain info about the type of loaded media:\n");
802        printf("  %s --drive /dev/hdc --media\n",argv[0]);
803        printf("Obtain table of content:\n");
804        printf("  %s --drive /dev/hdc --toc\n",argv[0]);
805        printf("Obtain parameters for option -C of program mkisofs:\n");
806        printf("  msinfo=$(%s --drive /dev/hdc --msinfo 2>/dev/null)\n",
807                argv[0]);
808        printf("  mkisofs ... -C \"$msinfo\" ...\n");
809        printf("Obtain what is available about drive 0 and its media\n");
810        printf("  %s --drive 0\n",argv[0]);
811        printf("View blocks 16 to 19 of data CD or DVD in human readable form\n");
812        printf("  %s --drive /dev/sr1 --read_and_print 16 4 0 | less\n",
813                argv[0]);
814        printf("Copy last data track from CD to file /tmp/data\n");
815        printf("  %s --drive /dev/sr1 --toc --read_and_print -1 -1 raw:/tmp/data\n",
816                argv[0]);
817    }
818    return 0;
819}
820
821
822int main(int argc, char **argv)
823{
824        int ret, toc_failed = 0, msinfo_alone = 0, msinfo_explicit = 0;
825        int full_default = 0;
826
827        ret = telltoc_setup(argc, argv);
828        if (ret)
829                exit(ret);
830
831        /* Behavior shall be different if --msinfo is only option */
832        if (do_msinfo) {
833                msinfo_explicit = 1;
834                if (!(do_media || do_toc))
835                        msinfo_alone = 1;
836        }
837        /* Default option is to do everything if possible */
838        if (do_media==0 && do_msinfo==0 && do_capacities==0 && do_toc==0 &&
839                (read_start < 0 || read_count <= 0) && driveno!=-1) {
840                if(print_help)
841                        exit(0);
842                full_default = do_media = do_msinfo = do_capacities= do_toc= 1;
843        }
844
845        fprintf(stderr, "Initializing libburnia-project.org ...\n");
846        if (burn_initialize())
847                fprintf(stderr, "Done\n");
848        else {
849                fprintf(stderr,"\nFATAL: Failed to initialize.\n");
850                exit(33);
851        }
852
853        /* Print messages of severity WARNING or more directly to stderr */
854        burn_msgs_set_severities("NEVER", "WARNING", "telltoc : ");
855
856        /* Activate the default signal handler */
857        burn_set_signal_handling("telltoc : ", NULL, 0);
858
859        /** Note: driveno might change its value in this call */
860        ret = telltoc_aquire_drive(drive_adr, &driveno, !full_default);
861        if (ret<=0) {
862                fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
863                { ret = 34; goto finish_libburn; }
864        }
865        if (ret == 2)
866                { ret = 0; goto release_drive; }
867
868        if (do_media) {
869                ret = telltoc_media(drive_list[driveno].drive);
870                if (ret<=0)
871                        {ret = 36; goto release_drive; }
872        }
873        if (do_capacities) {
874                ret = telltoc_speedlist(drive_list[driveno].drive);
875                if (ret<=0)
876                        {ret = 39; goto release_drive; }
877                ret = telltoc_formatlist(drive_list[driveno].drive);
878                if (ret<=0)
879                        {ret = 39; goto release_drive; }
880        }
881        if (do_toc) {
882                ret = telltoc_toc(drive_list[driveno].drive);
883                if (ret<=0)
884                        {ret = 37; goto release_drive; }
885                if (ret==2)
886                        toc_failed = 1;
887        }
888        if (do_msinfo) {
889                ret = telltoc_msinfo(drive_list[driveno].drive,
890                                        msinfo_explicit, msinfo_alone);
891                if (ret<=0)
892                        {ret = 38; goto release_drive; }
893        }
894        if (read_start >= -1 && (read_count > 0 || read_count == -1)) {
895                ret = telltoc_read_and_print(drive_list[driveno].drive,
896                                read_start, read_count, print_raw_file,
897                                print_encoding);
898                if (ret<=0)
899                        {ret = 40; goto release_drive; }
900        }
901
902        ret = 0;
903        if (toc_failed)
904                ret = 37;
905release_drive:;
906        if (drive_is_grabbed)
907                burn_drive_release(drive_list[driveno].drive, 0);
908
909finish_libburn:;
910        /* This app does not bother to know about exact scan state.
911           Better to accept a memory leak here. We are done anyway. */
912        /* burn_drive_info_free(drive_list); */
913
914        burn_finish();
915        exit(ret);
916}
917
918/*  License and copyright aspects:
919    See libburner.c
920*/
Note: See TracBrowser for help on using the browser.