1 
2 /* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
3 
4    Copyright 2007-2015 Thomas Schmitt, <scdbackup@gmx.net>
5 
6    Provided under GPL version 2 or later.
7 
8    This file contains the implementation of classes SpotlistiteM, SectorbitmaP,
9    CheckmediajoB which perform verifying runs on media resp. images.
10 */
11 
12 #ifdef HAVE_CONFIG_H
13 #include "../config.h"
14 #endif
15 
16 #include <ctype.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/time.h>
24 #include <time.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 
28 /* O_BINARY is needed for Cygwin but undefined elsewhere */
29 #ifndef O_BINARY
30 #define O_BINARY 0
31 #endif
32 
33 #include "xorriso.h"
34 #include "xorriso_private.h"
35 #include "xorrisoburn.h"
36 
37 
38 /* ------------------------------ SpotlisT -------------------------------- */
39 
40 
41 struct SpotlistiteM {
42  int start_lba;
43  int blocks;
44  int quality;
45  struct SpotlistiteM *next;
46 };
47 
48 
Spotlistitem_new(struct SpotlistiteM ** o,int start_lba,int blocks,int quality,int flag)49 int Spotlistitem_new(struct SpotlistiteM **o, int start_lba, int blocks,
50                      int quality, int flag)
51 {
52  struct SpotlistiteM *m;
53 
54  m= TSOB_FELD(struct SpotlistiteM,1);
55  if(m==NULL)
56    return(-1);
57  *o= m;
58  m->start_lba= start_lba;
59  m->blocks= blocks;
60  m->quality= quality;
61  m->next= NULL;
62  return(1);
63 }
64 
65 
Spotlistitem_destroy(struct SpotlistiteM ** o,int flag)66 int Spotlistitem_destroy(struct SpotlistiteM **o, int flag)
67 {
68  if((*o) == NULL)
69    return(0);
70  free((char *) *o);
71  *o= NULL;
72  return(1);
73 }
74 
75 
76 struct SpotlisT {
77  struct SpotlistiteM *list_start;
78  struct SpotlistiteM *list_end;
79  int list_count;
80  struct SpotlistiteM *current_item;
81  int current_idx;
82 };
83 
84 
Spotlist_new(struct SpotlisT ** o,int flag)85 int Spotlist_new(struct SpotlisT **o, int flag)
86 {
87  struct SpotlisT *m;
88 
89  m= TSOB_FELD(struct SpotlisT,1);
90  if(m==NULL)
91    return(-1);
92  *o= m;
93  m->list_start= NULL;
94  m->list_end= NULL;
95  m->list_count= 0;
96  m->current_item= NULL;
97  m->current_idx= -1;
98  return(1);
99 }
100 
101 
Spotlist_destroy(struct SpotlisT ** o,int flag)102 int Spotlist_destroy(struct SpotlisT **o, int flag)
103 {
104  struct SpotlisT *m;
105  struct SpotlistiteM *li, *next_li;
106 
107  if((*o) == NULL)
108    return(0);
109  m= *o;
110  for(li= m->list_start; li != NULL; li= next_li) {
111    next_li= li->next;
112    Spotlistitem_destroy(&li, 0);
113  }
114  free((char *) *o);
115  *o= NULL;
116  return(1);
117 }
118 
119 
Spotlist_add_item(struct SpotlisT * o,int start_lba,int blocks,int quality,int flag)120 int Spotlist_add_item(struct SpotlisT *o, int start_lba, int blocks,
121                       int quality, int flag)
122 {
123  int ret;
124  struct SpotlistiteM *li;
125  static int debug_verbous= 0;
126 
127  ret= Spotlistitem_new(&li, start_lba, blocks, quality, 0);
128  if(ret <= 0)
129    return(ret);
130  if(o->list_end != NULL)
131    o->list_end->next= li;
132  o->list_end= li;
133  if(o->list_start == NULL)
134    o->list_start= li;
135  (o->list_count)++;
136 
137  if(debug_verbous) {char quality_name[80];
138    fprintf(stderr, "debug: lba %10d , size %10d , quality '%s'\n",
139           start_lba, blocks, Spotlist__quality_name(quality, quality_name,
140                                          Xorriso_read_quality_invaliD, 0) + 2);
141  }
142 
143  return(1);
144 }
145 
146 
Spotlist_count(struct SpotlisT * o,int flag)147 int Spotlist_count(struct SpotlisT *o, int flag)
148 {
149  return o->list_count;
150 }
151 
152 
Spotlist_block_count(struct SpotlisT * o,int flag)153 int Spotlist_block_count(struct SpotlisT *o, int flag)
154 {
155  int list_blocks= 0;
156  struct SpotlistiteM *li;
157 
158  for(li= o->list_start; li != NULL; li= li->next) {
159    if(li->start_lba + li->blocks > list_blocks)
160      list_blocks= li->start_lba + li->blocks;
161  }
162  return(list_blocks);
163 }
164 
165 
Spotlist_sector_size(struct SpotlisT * o,int read_chunk,int flag)166 int Spotlist_sector_size(struct SpotlisT *o, int read_chunk, int flag)
167 {
168  int sector_size;
169  struct SpotlistiteM *li;
170 
171  sector_size= read_chunk * 2048;
172  for(li= o->list_start; li != NULL; li= li->next) {
173    if((li->start_lba % read_chunk) || (li->blocks % read_chunk)) {
174      sector_size= 2048;
175  break;
176    }
177  }
178  return(sector_size);
179 }
180 
181 
Spotlist_get_item(struct SpotlisT * o,int idx,int * start_lba,int * blocks,int * quality,int flag)182 int Spotlist_get_item(struct SpotlisT *o, int idx,
183                       int *start_lba, int *blocks, int *quality, int flag)
184 {
185  int i;
186  struct SpotlistiteM *li;
187 
188  if(idx < 0 || idx > o->list_count)
189    return(0);
190  if(idx == o->current_idx && o->current_item != NULL)
191    li= o->current_item;
192  else if(idx == o->current_idx + 1 && o->current_item != NULL) {
193    li= o->current_item->next;
194  } else {
195    li= o->list_start;
196    for(i= 0; i < idx; i++)
197      li= li->next;
198  }
199  o->current_item= li;
200  o->current_idx= idx;
201  *start_lba= li->start_lba;
202  *blocks= li->blocks;
203  *quality= li->quality;
204  return(1);
205 }
206 
207 
Spotlist__quality_name(int quality,char name[80],int bad_limit,int flag)208 char *Spotlist__quality_name(int quality, char name[80], int bad_limit,
209                              int flag)
210 {
211  if(quality == Xorriso_read_quality_untesteD ||
212    quality == Xorriso_read_quality_tao_enD ||
213    quality == Xorriso_read_quality_off_tracK)
214    strcpy(name, "0 ");
215  else if(quality <= bad_limit)
216    strcpy(name, "- ");
217  else
218    strcpy(name, "+ ");
219  if(quality == Xorriso_read_quality_gooD)
220    strcat(name, "good");
221  else if(quality == Xorriso_read_quality_md5_matcH)
222    strcat(name, "md5_match");
223  else if(quality == Xorriso_read_quality_sloW)
224    strcat(name, "slow");
225  else if(quality == Xorriso_read_quality_partiaL)
226    strcat(name, "partial");
227  else if(quality == Xorriso_read_quality_valiD)
228    strcat(name, "valid");
229  else if(quality == Xorriso_read_quality_untesteD)
230    strcat(name, "untested");
231  else if(quality == Xorriso_read_quality_md5_mismatcH)
232    strcat(name, "md5_mismatch");
233  else if(quality == Xorriso_read_quality_invaliD)
234    strcat(name, "invalid");
235  else if(quality == Xorriso_read_quality_tao_enD)
236    strcat(name, "tao_end");
237  else if(quality == Xorriso_read_quality_off_tracK)
238    strcat(name, "off_track");
239  else if(quality == Xorriso_read_quality_unreadablE)
240    strcat(name, "unreadable");
241  else
242    sprintf(name, "0 0x%8.8X", (unsigned int) quality);
243  return(name);
244 }
245 
246 
247 /* ---------------------------- End SpotlisT ------------------------------ */
248 
249 /* ---------------------------- SectorbitmaP ------------------------------ */
250 
Sectorbitmap_new(struct SectorbitmaP ** o,int sectors,int sector_size,int flag)251 int Sectorbitmap_new(struct SectorbitmaP **o, int sectors, int sector_size,
252                      int flag)
253 {
254  struct SectorbitmaP *m;
255 
256  m= TSOB_FELD(struct SectorbitmaP,1);
257  if(m==NULL)
258    return(-1);
259  *o= m;
260  m->sectors= sectors;
261  m->sector_size= sector_size;
262  m->map= NULL;
263  m->map_size= sectors / 8 + 1;
264 
265  m->map= calloc(m->map_size, 1);
266  if(m->map == NULL)
267    goto failure;
268  return(1);
269 failure:;
270  Sectorbitmap_destroy(o, 0);
271  return(-1);
272 }
273 
274 
Sectorbitmap_destroy(struct SectorbitmaP ** o,int flag)275 int Sectorbitmap_destroy(struct SectorbitmaP **o, int flag)
276 {
277  if((*o) == NULL)
278    return(0);
279  if((*o)->map != NULL)
280    free((char *) (*o)->map);
281  free((char *) *o);
282  *o= NULL;
283  return(1);
284 }
285 
286 
Sectorbitmap_from_file(struct SectorbitmaP ** o,char * path,char * msg,int * os_errno,int flag)287 int Sectorbitmap_from_file(struct SectorbitmaP **o, char *path, char *msg,
288                            int *os_errno, int flag)
289 {
290  int ret, fd= -1, sectors, sector_size, i, todo, map_size, skip, bufsize= 1024;
291  unsigned char *map;
292  unsigned char *buf;
293 
294  buf= TSOB_FELD(unsigned char, bufsize);
295  if(buf == NULL)
296    return(-1);
297 
298  *os_errno= 0;
299  if(msg != NULL)
300    msg[0]= 0;
301  fd= open(path, O_RDONLY | O_BINARY);
302  if(fd == -1) {
303    *os_errno= errno;
304    if(msg != NULL) {
305      strcpy(msg, "Cannot open path ");
306      Text_shellsafe(path, msg+strlen(msg), 0);
307    }
308    {ret= 0; goto ex;}
309  }
310  ret= read(fd, buf, 32);
311  if(ret < 32) {
312 wrong_filetype:;
313    if(ret == -1)
314      *os_errno= errno;
315    if(msg != NULL) {
316      strcpy(msg, "Not a sector bitmap file: ");
317      Text_shellsafe(path, msg+strlen(msg), 0);
318    }
319    ret= 0; goto ex;
320  }
321  if(strncmp((char *) buf, "xorriso sector bitmap v1        ", 32) == 0)
322    /* ok */;
323  else if(strncmp((char *) buf, "xorriso sector bitmap v2 ", 25) == 0) {
324    skip= -1;
325    sscanf(((char *) buf) + 25, "%d", &skip);
326    if(skip < 0)
327      {ret= 0; goto wrong_filetype;}
328    for(i= 0; i < skip; i+= bufsize) {
329      todo= bufsize;
330      if(i + todo > skip)
331        todo= skip - i;
332      ret= read(fd, buf, todo);
333      if(ret < todo)
334        goto wrong_filetype;
335    }
336  } else
337    {ret= 0; goto wrong_filetype;}
338  ret= read(fd, buf, 8);
339  if(ret < 4)
340    goto wrong_filetype;
341  sectors= (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
342  sector_size= (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
343  if(sectors <= 0 || sector_size <= 0)
344    goto wrong_filetype;
345  ret= Sectorbitmap_new(o, sectors, sector_size, 0);
346  if(ret <= 0) {
347    if(msg != NULL)
348      sprintf(msg, "Cannot allocate bitmap memory for %d sectors", sectors);
349    ret= -1; goto ex;
350  }
351  map= (*o)->map;
352  map_size= (*o)->map_size;
353  for(i= 0; i < map_size; i+= bufsize) {
354    todo= bufsize;
355    if(i + todo > map_size)
356      todo= map_size - i;
357    ret= read(fd, buf, todo);
358    if(ret != todo)
359      goto wrong_filetype;
360    memcpy(map + i, buf, todo);
361  }
362  ret= 1;
363 ex:;
364  if(fd != -1)
365    close(fd);
366  if(buf != NULL)
367    free(buf);
368  if(ret <= 0)
369    Sectorbitmap_destroy(o, 0);
370  return(ret);
371 }
372 
373 
Sectorbitmap_to_file(struct SectorbitmaP * o,char * path,char * info,char * msg,int * os_errno,int flag)374 int Sectorbitmap_to_file(struct SectorbitmaP *o, char *path, char *info,
375                          char *msg, int *os_errno, int flag)
376 {
377  int ret, fd= -1, j, l;
378  unsigned char buf[40];
379 
380  *os_errno= 0;
381  fd= open(path, O_WRONLY | O_CREAT | O_BINARY,  S_IRUSR | S_IWUSR);
382  if(fd == -1) {
383    *os_errno= errno;
384    if(msg != NULL) {
385      strcpy(msg, "Cannot open path ");
386      Text_shellsafe(path, msg+strlen(msg), 0);
387    }
388    ret= 0; goto ex;
389  }
390 
391  l= 0;
392  if(info != NULL)
393    l= strlen(info);
394  if(l > 999999) {
395    strcpy(msg, "Info string is longer than 999999 bytes");
396    ret= 0; goto ex;
397  }
398  sprintf((char *) buf, "xorriso sector bitmap v2 %-6d\n", l);
399 
400  ret= write(fd, buf, 32);
401  if(ret != 32) {
402 cannot_write:;
403    *os_errno= errno;
404    if(msg != NULL) {
405      strcpy(msg, "Cannot write to ");
406      Text_shellsafe(path, msg+strlen(msg), 0);
407    }
408    ret= 0; goto ex;
409  }
410  if(l > 0) {
411    ret= write(fd, info, l);
412    if(ret != l)
413      goto cannot_write;
414  }
415 
416  for(j= 0; j < 4; j++) {
417    buf[j]= o->sectors >> (24 - j * 8);
418    buf[j+4]= o->sector_size >> (24 - j * 8);
419  }
420  ret= write(fd, buf, 8);
421  if(ret != 8)
422    goto cannot_write;
423  ret= write(fd, o->map, o->map_size);
424  if(ret != o->map_size)
425    goto cannot_write;
426 
427  ret= 1;
428 ex:;
429  if(fd != -1)
430    close(fd);
431  return(ret);
432 }
433 
434 
435 /* @param flag bit0= sector bit value
436 */
Sectorbitmap_set(struct SectorbitmaP * o,int sector,int flag)437 int Sectorbitmap_set(struct SectorbitmaP *o, int sector, int flag)
438 {
439  if(sector < 0 || sector >= o->sectors)
440    return(0);
441  if(flag & 1)
442    o->map[sector / 8]|= 1 << (sector % 8);
443  else
444    o->map[sector / 8]&= ~(1 << (sector % 8));
445  return(1);
446 }
447 
448 
449 /* @param flag bit0= sector bit value
450 */
Sectorbitmap_set_range(struct SectorbitmaP * o,int start_sector,int sectors,int flag)451 int Sectorbitmap_set_range(struct SectorbitmaP *o,
452                            int start_sector, int sectors, int flag)
453 {
454  int start_i, end_i, i;
455  unsigned char value;
456 
457  if(start_sector < 0 || start_sector + sectors > o->sectors || sectors < 1)
458    return(0);
459  if(flag & 1)
460    value= ~0;
461  else
462    value= 0;
463  start_i= start_sector / 8;
464  end_i= (start_sector + sectors - 1) / 8;
465  for(i= start_sector; i / 8 == start_i && i < start_sector + sectors; i++)
466    Sectorbitmap_set(o, i, flag & 1);
467  for(i= start_i + 1; i < end_i; i++)
468    o->map[i]= value;
469  if(end_i > start_i)
470    for(i= end_i * 8; i < start_sector + sectors; i++)
471      Sectorbitmap_set(o, i, flag & 1);
472  return(1);
473 }
474 
475 
Sectorbitmap_is_set(struct SectorbitmaP * o,int sector,int flag)476 int Sectorbitmap_is_set(struct SectorbitmaP *o, int sector, int flag)
477 {
478  if(sector < 0 || sector >= o->sectors)
479    return(0);
480  return(!! (o->map[sector / 8] & (1 << (sector % 8))));
481 }
482 
483 
Sectorbitmap_bytes_are_set(struct SectorbitmaP * o,off_t start_byte,off_t end_byte,int flag)484 int Sectorbitmap_bytes_are_set(struct SectorbitmaP *o,
485                                off_t start_byte, off_t end_byte, int flag)
486 {
487  int end_sector, i;
488 
489  end_sector= end_byte / o->sector_size;
490  for(i= start_byte / o->sector_size; i <= end_sector; i++)
491    if(!Sectorbitmap_is_set(o, i, 0))
492      return(0);
493  return(1);
494 }
495 
496 
Sectorbitmap_get_layout(struct SectorbitmaP * o,int * sectors,int * sector_size,int flag)497 int Sectorbitmap_get_layout(struct SectorbitmaP *o,
498                            int *sectors, int *sector_size, int flag)
499 {
500  *sectors= o->sectors;
501  *sector_size= o->sector_size;
502  return(1);
503 }
504 
505 
Sectorbitmap_copy(struct SectorbitmaP * from,struct SectorbitmaP * to,int flag)506 int Sectorbitmap_copy(struct SectorbitmaP *from, struct SectorbitmaP *to,
507                       int flag)
508 {
509  int i, run_start, run_value, start_sec, limit_sec, start_aligned;
510  int end_complete;
511 
512  if(((off_t) from->sectors) * ((off_t) from->sector_size) >
513     ((off_t) to->sectors) * ((off_t) to->sector_size))
514    return(-1);
515  if(from->sector_size == to->sector_size) {
516    for(i= 0; i < from->map_size; i++)
517      to->map[i]= from->map[i];
518    return(1);
519  }
520  run_start= 0;
521  run_value= Sectorbitmap_is_set(from, 0, 0);
522  for(i= 1; i <= from->sectors; i++) {
523    if(i < from->sectors)
524      if(Sectorbitmap_is_set(from, i, 0) == run_value)
525  continue;
526    start_sec= run_start * from->sector_size / to->sector_size;
527    start_aligned=
528                 (start_sec * to->sector_size == run_start * from->sector_size);
529    limit_sec= i * from->sector_size / to->sector_size;
530    end_complete= (limit_sec * to->sector_size == i * from->sector_size);
531    if(run_value) {
532      if(!start_aligned)
533        start_sec++;
534    } else {
535      if(!end_complete)
536        limit_sec++;
537    }
538    if(start_sec < limit_sec)
539      Sectorbitmap_set_range(to, start_sec, limit_sec - 1 - start_sec,
540                             !!run_value);
541    run_value= !run_value;
542    run_start= i;
543  }
544  return(1);
545 }
546 
547 
Sectorbitmap_clone(struct SectorbitmaP * from,struct SectorbitmaP ** clone,int flag)548 int Sectorbitmap_clone(struct SectorbitmaP *from, struct SectorbitmaP **clone,
549                       int flag)
550 {
551  int ret;
552 
553  ret= Sectorbitmap_new(clone, from->sectors, from->sector_size, 0);
554  if(ret <= 0)
555    return(ret);
556  ret= Sectorbitmap_copy(from, *clone, 0);
557  if(ret <= 0)
558    Sectorbitmap_destroy(clone, 0);
559  return(ret);
560 }
561 
562 
563 /* -------------------------- End SectorbitmaP ---------------------------- */
564 
565 /* ---------------------------- CheckmediajoB ----------------------------- */
566 
Checkmediajob_new(struct CheckmediajoB ** o,int flag)567 int Checkmediajob_new(struct CheckmediajoB **o, int flag)
568 {
569  struct CheckmediajoB *m;
570 
571  m= TSOB_FELD(struct CheckmediajoB,1);
572  if(m==NULL)
573    return(-1);
574  *o= m;
575  m->use_dev= 0;
576  m->min_lba= -1;
577  m->max_lba= -1;
578  m->min_block_size= 0;
579  m->async_chunks= 0;
580  m->mode= 0;
581  m->start_time= time(NULL);
582  m->time_limit= 28800;
583  m->item_limit= 100000;
584  strcpy(m->abort_file_path, "/var/opt/xorriso/do_abort_check_media");
585  m->data_to_path[0]= 0;
586  m->data_to_fd= -1;
587  m->data_to_offset= 0;
588  m->data_to_limit= -1;
589  m->patch_lba0= 0;
590  m->patch_lba0_msc1= -1;
591  m->sector_map_path[0]= 0;
592  m->sector_map= NULL;
593  m->map_with_volid= 0;
594  m->retry= 0;
595  m->report_mode= 0;
596  strcpy(m->event_severity, "ALL");
597  m->slow_threshold_seq= 1.0;
598  return(1);
599 }
600 
601 
Checkmediajob_destroy(struct CheckmediajoB ** o,int flag)602 int Checkmediajob_destroy(struct CheckmediajoB **o, int flag)
603 {
604  if((*o) == NULL)
605    return(0);
606  if((*o)->data_to_fd != -1)
607    close((*o)->data_to_fd);
608  Sectorbitmap_destroy(&((*o)->sector_map), 0);
609  free((char *) *o);
610  *o= NULL;
611  return(1);
612 }
613 
614 
Checkmediajob_copy(struct CheckmediajoB * from,struct CheckmediajoB * to,int flag)615 int Checkmediajob_copy(struct CheckmediajoB *from, struct CheckmediajoB *to,
616                        int flag)
617 {
618  to->use_dev= from->use_dev;
619  to->min_lba= from->min_lba;
620  to->max_lba= from->max_lba;
621  to->min_block_size= from->min_block_size;
622  to->mode= from->mode;
623  to->time_limit= from->time_limit;
624  to->item_limit= from->item_limit;
625  strcpy(to->abort_file_path, from->abort_file_path);
626  strcpy(to->data_to_path, from->data_to_path);
627  /* not copied: data_to_fd */
628  to->data_to_offset= from->data_to_offset;
629  to->data_to_limit= from->data_to_limit;
630  to->patch_lba0= from->patch_lba0;
631  to->patch_lba0_msc1= from->patch_lba0_msc1;
632  strcpy(to->sector_map_path, from->sector_map_path);
633  /* not copied: sector_map */
634  to->map_with_volid= from->map_with_volid;
635  to->retry= from->retry;
636  to->report_mode= from->report_mode;
637  strcpy(to->event_severity, from->event_severity);
638  to->slow_threshold_seq= from->slow_threshold_seq;
639  return(1);
640 }
641 
642 
643 /* -------------------------- End CheckmediajoB --------------------------- */
644 
645 
Xorriso_check_media_setup_job(struct XorrisO * xorriso,struct CheckmediajoB * job,char ** argv,int old_idx,int end_idx,int flag)646 int Xorriso_check_media_setup_job(struct XorrisO *xorriso,
647                                struct CheckmediajoB *job,
648                                char **argv, int old_idx, int end_idx, int flag)
649 {
650  int ret, i, sev;
651  double num;
652  struct CheckmediajoB *default_job;
653  char sev_text[20];
654 
655  if(xorriso->check_media_default != NULL)
656    Checkmediajob_copy(xorriso->check_media_default, job, 0);
657  for(i= old_idx; i < end_idx; i++) {
658    if(strncmp(argv[i], "abort_file=", 11) == 0) {
659      ret= Sfile_str(job->abort_file_path, argv[i] + 11, 0);
660      if(ret <= 0)
661        goto ex;
662    } else if(strncmp(argv[i], "async_chunks=", 13) == 0) {
663      num= Scanf_io_size(argv[i] + 13, 1);
664      if(num >= 0 && num <= 1024)
665        job->async_chunks= num;
666      else
667        goto bad_value;
668    } else if(strncmp(argv[i], "bad_limit=", 10) == 0) {
669      if(strcmp(argv[i] + 10, "good") == 0)
670        xorriso->check_media_bad_limit= Xorriso_read_quality_gooD;
671      else if(strcmp(argv[i] + 10, "md5_match") == 0)
672        xorriso->check_media_bad_limit= Xorriso_read_quality_md5_matcH;
673      else if(strcmp(argv[i] + 10, "slow") == 0)
674        xorriso->check_media_bad_limit= Xorriso_read_quality_sloW;
675      else if(strcmp(argv[i] + 10, "partial") == 0)
676        xorriso->check_media_bad_limit= Xorriso_read_quality_partiaL;
677      else if(strcmp(argv[i] + 10, "valid") == 0)
678        xorriso->check_media_bad_limit= Xorriso_read_quality_valiD;
679      else if(strcmp(argv[i] + 10, "untested") == 0)
680        xorriso->check_media_bad_limit= Xorriso_read_quality_untesteD;
681      else if(strcmp(argv[i] + 10, "md5_mismatch") == 0)
682        xorriso->check_media_bad_limit= Xorriso_read_quality_md5_mismatcH;
683      else if(strcmp(argv[i] + 10, "invalid") == 0)
684        xorriso->check_media_bad_limit= Xorriso_read_quality_invaliD;
685      else if(strcmp(argv[i] + 10, "tao_end") == 0)
686        xorriso->check_media_bad_limit= Xorriso_read_quality_tao_enD;
687      else if(strcmp(argv[i] + 10, "off_track") == 0)
688        xorriso->check_media_bad_limit= Xorriso_read_quality_off_tracK;
689      else if(strcmp(argv[i] + 10, "unreadable") == 0)
690        xorriso->check_media_bad_limit= Xorriso_read_quality_unreadablE;
691      else
692        goto unknown_value;
693    } else if(strncmp(argv[i], "data_to=", 8) == 0) {
694      ret= Sfile_str(job->data_to_path, argv[i] + 8, 0);
695      if(ret <= 0)
696        goto ex;
697    } else if(strncmp(argv[i], "chunk_size=", 11) == 0) {
698      num= Scanf_io_size(argv[i] + 11, 1);
699      if(num >= 2048 || num == 0)
700        job->min_block_size= num / 2048;
701      else
702        goto bad_value;
703    } else if(strncmp(argv[i], "event=", 6) == 0) {
704      strncpy(sev_text, argv[i] + 6, 19);
705      sev_text[19]= 0;
706      ret= Xorriso__text_to_sev(sev_text, &sev, 0);
707      if(ret <= 0) {
708        strcpy(xorriso->info_text, "-check_media event=");
709        Text_shellsafe(sev_text, xorriso->info_text, 1);
710        strcat(xorriso->info_text, " : Not a known severity name");
711        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
712        goto ex;
713      }
714      strcpy(job->event_severity, sev_text);
715    } else if(strncmp(argv[i], "map_with_volid=", 15) == 0) {
716      if(strcmp(argv[i] + 15, "on") == 0)
717        job->map_with_volid= 1;
718      else if(strcmp(argv[i] + 15, "off") == 0)
719        job->map_with_volid= 0;
720      else
721        goto unknown_value;
722    } else if(strncmp(argv[i], "max_lba=", 8) == 0 ||
723       strncmp(argv[i], "min_lba=", 8) == 0) {
724      num= -1;
725      sscanf(argv[i] + 8, "%lf", &num);
726      if(num > 0x7fffffff || num < 0)
727        num= -1;
728      if(strncmp(argv[i], "max_lba=", 8) == 0)
729        job->max_lba= num;
730      else
731        job->min_lba= num;
732    } else if(strncmp(argv[i], "patch_lba0=", 11) == 0) {
733      job->patch_lba0_msc1= -1;
734      if(strcmp(argv[i] + 11, "on") == 0)
735        job->patch_lba0= 1;
736      else if(strcmp(argv[i] + 11, "off") == 0)
737        job->patch_lba0= 0;
738      else if(strcmp(argv[i] + 11, "force") == 0)
739        job->patch_lba0= 2;
740      else if(argv[i][11] >= '1' && argv[i][11] <= '9') {
741        num= -1;
742        sscanf(argv[i] + 11, "%lf", &num);
743        if(num > 0x7fffffff || num < 0)
744          goto bad_value;
745        job->patch_lba0_msc1= num;
746        job->patch_lba0= (num >= 32) + (strstr(argv[i] + 11, ":force") != NULL);
747      } else
748        goto unknown_value;
749    } else if(strncmp(argv[i], "report=", 7) == 0) {
750      if(strcmp(argv[i] + 7, "blocks") == 0)
751        job->report_mode= 0;
752      else if(strcmp(argv[i] + 7, "files") == 0)
753        job->report_mode= 1;
754      else if(strcmp(argv[i] + 7, "blocks_files") == 0)
755        job->report_mode= 2;
756      else
757        goto unknown_value;
758    } else if(strcmp(argv[i], "reset=now") == 0) {
759      ret= Checkmediajob_new(&default_job, 0);
760      if(ret <= 0) {
761        sprintf(xorriso->info_text,
762                "-check_media: Cannot reset options due to lack of resources");
763        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
764        ret= -1; goto ex;
765      }
766      Checkmediajob_copy(default_job, job, 0);
767      Checkmediajob_destroy(&default_job, 0);
768      xorriso->check_media_bad_limit= Xorriso_read_quality_invaliD;
769    } else if(strncmp(argv[i], "retry=", 6) == 0) {
770      if(strcmp(argv[i] + 6, "on") == 0)
771        job->retry= 1;
772      else if(strcmp(argv[i] + 6, "off") == 0)
773        job->retry= -1;
774      else if(strcmp(argv[i] + 6, "default") == 0)
775        job->retry= 0;
776      else
777        goto unknown_value;
778    } else if(strncmp(argv[i], "sector_map=", 11) == 0) {
779      ret= Sfile_str(job->sector_map_path, argv[i] + 11, 0);
780      if(ret <= 0)
781        goto ex;
782    } else if(strncmp(argv[i], "slow_limit=", 11) == 0) {
783      sscanf(argv[i] + 11, "%lf", &(job->slow_threshold_seq));
784    } else if(strncmp(argv[i], "time_limit=", 11) == 0 ||
785              strncmp(argv[i], "item_limit=", 11) == 0 ) {
786      num= -1;
787      sscanf(argv[i] + 11, "%lf", &num);
788      if(num > 0x7fffffff || num < 0)
789        num= -1;
790      if(strncmp(argv[i], "time_limit=", 11) == 0)
791        job->time_limit= num;
792      else
793        job->item_limit= num;
794    } else if(strncmp(argv[i], "use=", 4) == 0) {
795      if(strcmp(argv[i] + 4, "outdev") == 0)
796        job->use_dev= 1;
797      else if(strcmp(argv[i] + 4, "indev") == 0)
798        job->use_dev= 0;
799      else if(strcmp(argv[i] + 4, "sector_map") == 0)
800        job->use_dev= 2;
801      else
802        goto unknown_value;
803    } else if(strncmp(argv[i], "what=", 5) == 0) {
804      if(strcmp(argv[i]+5, "tracks") == 0)
805        job->mode= 0;
806      else if(strcmp(argv[i]+5, "image")== 0)
807        job->mode= 1;
808      else if(strcmp(argv[i]+5, "disc")== 0)
809        job->mode= 2;
810      else {
811 unknown_value:;
812        sprintf(xorriso->info_text,
813                "-check_media: Unknown value with option %s", argv[i]);
814        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
815        ret= 0; goto ex;
816 bad_value:;
817        sprintf(xorriso->info_text,
818                "-check_media: Unsuitable value with option %s", argv[i]);
819        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
820        ret= 0; goto ex;
821      }
822    } else {
823      sprintf(xorriso->info_text, "-check_media: Unknown option '%s'", argv[i]);
824      Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
825      ret= 0; goto ex;
826    }
827  }
828  ret= 1;
829 ex:;
830  return(ret);
831 }
832 
833 
834 /* @param report Buffer of at least 10*SfileadrL
835    @param flag bit0= only report non-default settings
836    @return <=0 error , 1 ok , 2 with bit0: every option is on default setting
837 */
Xorriso_check_media_list_job(struct XorrisO * xorriso,struct CheckmediajoB * job,char * report,int flag)838 int Xorriso_check_media_list_job(struct XorrisO *xorriso,
839                                  struct CheckmediajoB *job,
840                                  char *report, int flag)
841 {
842  int all, ret;
843  char *default_report= NULL, quality_name[80];
844  struct CheckmediajoB *dflt= NULL;
845 
846  Xorriso_alloc_meM(default_report, char, 161);
847 
848  all= !(flag&1);
849  report[0]= 0;
850  ret= Checkmediajob_new(&dflt, 0);
851  if(ret <= 0)
852    {ret= -1; goto ex;}
853  sprintf(report, "-check_media_defaults");
854  if(!all)
855    strcat(report, " reset=now");
856  if(all || job->use_dev != dflt->use_dev)
857    sprintf(report + strlen(report), " use=%s",
858            job->use_dev == 1 ? "outdev" :
859            job->use_dev == 2 ? "sector_map" : "indev");
860  if(all || job->mode != dflt->mode)
861    sprintf(report + strlen(report), " what=%s",
862            job->mode == 1 ? "disc" : "tracks");
863  if(all || job->min_lba != dflt->min_lba)
864    sprintf(report + strlen(report), " min_lba=%d", job->min_lba);
865  if(all || job->max_lba != dflt->max_lba)
866    sprintf(report + strlen(report), " max_lba=%d", job->max_lba);
867  if(all || job->retry != dflt->retry)
868    sprintf(report + strlen(report), " retry=%s",
869            job->retry == 1 ? "on" : job->retry == -1 ? "off" : "default");
870  if(all || job->time_limit != dflt->time_limit)
871    sprintf(report + strlen(report), " time_limit=%d", job->time_limit);
872  if(all || job->item_limit != dflt->item_limit)
873    sprintf(report + strlen(report), " item_limit=%d", job->item_limit);
874  if(all || strcmp(job->abort_file_path, dflt->abort_file_path)) {
875    strcat(report, " abort_file=");
876    Text_shellsafe(job->abort_file_path, report + strlen(report), 0);
877  }
878  if(strlen(report) > 4 * SfileadrL)
879    {ret= 0; goto ex;}
880  if(all || strcmp(job->data_to_path, dflt->data_to_path)) {
881    strcat(report, " data_to=");
882    Text_shellsafe(job->data_to_path, report + strlen(report), 0);
883  }
884  if(strlen(report) > 4 * SfileadrL)
885    {ret= 0; goto ex;}
886  if(all || strcmp(job->sector_map_path, dflt->sector_map_path)) {
887    strcat(report, " sector_map=");
888    Text_shellsafe(job->sector_map_path, report + strlen(report), 0);
889  }
890  if(all || job->map_with_volid != dflt->map_with_volid)
891    sprintf(report + strlen(report), " map_with_volid=%s",
892            job->map_with_volid == 1 ? "on" : "off");
893  if(all || job->patch_lba0 != dflt->patch_lba0) {
894    sprintf(report + strlen(report), " patch_lba0=");
895    if(job->patch_lba0 == 0)
896      sprintf(report + strlen(report), "off");
897    else if(job->patch_lba0_msc1 >= 0)
898      sprintf(report + strlen(report), "%d%s",
899              job->patch_lba0_msc1, job->patch_lba0 == 2 ? ":force" : "");
900    else
901      sprintf(report + strlen(report), "%s",
902              job->patch_lba0 == 2 ? "force" : "on");
903  }
904  if(all || job->report_mode != dflt->report_mode)
905    sprintf(report + strlen(report), " report=%s",
906            job->report_mode == 0 ? "blocks" :
907            job->report_mode == 1 ? "files" : "blocks_files");
908  if(all || job->slow_threshold_seq != dflt->slow_threshold_seq)
909    sprintf(report + strlen(report), " slow_limit=%f", job->slow_threshold_seq);
910  if(all || xorriso->check_media_bad_limit != Xorriso_read_quality_invaliD)
911    sprintf(report + strlen(report), " bad_limit=%s",
912            Spotlist__quality_name(xorriso->check_media_bad_limit, quality_name,
913                                   Xorriso_read_quality_invaliD, 0) + 2);
914  if(all || job->min_block_size != dflt->min_block_size)
915    sprintf(report + strlen(report), " chunk_size=%ds", job->min_block_size);
916  if(all || strcmp(job->event_severity, "ALL") != 0)
917    sprintf(report + strlen(report), " event=%s", job->event_severity);
918  if(strlen(report) > 4 * SfileadrL)
919    {ret= 0; goto ex;}
920  ret= 1;
921 ex:;
922  strcat(report, " ");
923  strcat(report, xorriso->list_delimiter);
924  Checkmediajob_destroy(&dflt, 0);
925  if(default_report != NULL) {
926    sprintf(default_report, "-check_media_defaults reset=now %s",
927            xorriso->list_delimiter);
928    if(ret > 0 && strcmp(report, default_report) == 0)
929      ret= 2;
930  }
931  Xorriso_free_meM(default_report);
932  return(ret);
933 }
934 
935 
Xorriso_sectormap_to_spotlist(struct XorrisO * xorriso,struct CheckmediajoB * job,struct SpotlisT ** spotlist,int flag)936 int Xorriso_sectormap_to_spotlist(struct XorrisO *xorriso,
937                                   struct CheckmediajoB *job,
938                                   struct SpotlisT **spotlist,
939                                   int flag)
940 {
941  struct SectorbitmaP *map;
942  int ret, i, sectors, sector_size, value, old_value= -1, old_start= -1;
943 
944  map= job->sector_map;
945  if(map == NULL)
946    return(-1);
947  ret= Spotlist_new(spotlist, 0);
948  if(ret <= 0)
949    {ret= -1; goto ex;}
950  Sectorbitmap_get_layout(map, &sectors, &sector_size, 0);
951  sector_size/= 2048;
952  if(job->max_lba >= 0)
953    sectors= (job->max_lba + 1) / sector_size;
954  i= 0;
955  if(job->min_lba >= 0)
956    i= job->min_lba / sector_size;
957  for(; i < sectors; i++) {
958    value= Sectorbitmap_is_set(map, i, 0);
959    if(value == old_value)
960  continue;
961    if(old_value >= 0) {
962      ret= Spotlist_add_item(*spotlist, old_start, i * sector_size - old_start,
963                             (old_value ? Xorriso_read_quality_valiD :
964                                          Xorriso_read_quality_invaliD), 0);
965      if(ret <= 0)
966        goto ex;
967      if(job->item_limit > 0 &&
968         Spotlist_count(*spotlist, 0) + 1 >= job->item_limit) {
969        sprintf(xorriso->info_text, "-check_media: Reached item_limit=%d",
970                job->item_limit);
971        Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
972        if(sectors - i > 1) {
973          ret= Spotlist_add_item(*spotlist, i * sector_size,
974                                 (sectors - i - 1) * sector_size,
975                                 Xorriso_read_quality_untesteD, 0);
976          if(ret <= 0)
977            goto ex;
978        }
979        ret= 2; goto ex;
980      }
981    }
982    old_value= value;
983    old_start= i * sector_size;
984  }
985  if(old_value >= 0) {
986    ret= Spotlist_add_item(*spotlist, old_start, i * sector_size - old_start,
987                           (old_value ? Xorriso_read_quality_valiD :
988                                        Xorriso_read_quality_invaliD), 0);
989    if(ret <= 0)
990      goto ex;
991  }
992  ret= 1;
993 ex:;
994  if(ret <= 0)
995    Spotlist_destroy(spotlist, 0);
996  return(ret);
997 }
998 
999 
1000 /* @param flag bit0= mark untested areas as valid
1001                bit1= leave untested areas as they are
1002 */
Xorriso_spotlist_to_sectormap(struct XorrisO * xorriso,struct SpotlisT * spotlist,int read_chunk,struct SectorbitmaP ** map,int flag)1003 int Xorriso_spotlist_to_sectormap(struct XorrisO *xorriso,
1004                                   struct SpotlisT *spotlist,
1005                                   int read_chunk,
1006                                   struct SectorbitmaP **map,
1007                                   int flag)
1008 {
1009  struct SectorbitmaP *m;
1010  int map_sectors= -1, map_sector_size= -1, valid;
1011  int list_sectors, list_blocks, sector_size, sector_blocks;
1012  int replace_map= 0, count, i, lba, blocks, quality, ret, pass;
1013 
1014  sector_size= Spotlist_sector_size(spotlist, read_chunk, 0);
1015  sector_blocks= sector_size / 2048;
1016  if(*map != NULL)
1017    Sectorbitmap_get_layout(*map, &map_sectors, &map_sector_size, 0);
1018 
1019  count= Spotlist_count(spotlist, 0);
1020  list_blocks= Spotlist_block_count(spotlist, 0);
1021 
1022  /* >>> ??? insist in list_blocks % sector_blocks == 0 */
1023 
1024  list_sectors= list_blocks / sector_blocks;
1025  if(list_sectors * sector_blocks < list_blocks)
1026    list_sectors++;
1027  if(*map != NULL && map_sectors * (map_sector_size / 2048) >= list_blocks &&
1028     map_sector_size == sector_size)
1029    m= *map;
1030  else {
1031    if(*map != NULL) {
1032      if(((off_t) (*map)->sectors) * ((off_t) (*map)->sector_size) >
1033         ((off_t) list_sectors)    * ((off_t) sector_size))
1034        list_sectors= (((off_t) (*map)->sectors) *
1035                       ((off_t) (*map)->sector_size)) / ((off_t) sector_size)
1036                      + 1;
1037    }
1038    ret= Sectorbitmap_new(&m, list_sectors, sector_size, 0);
1039    if(ret <= 0)
1040      return(-1);
1041    replace_map= 1;
1042    if(*map != NULL) {
1043      ret= Sectorbitmap_copy(*map, m, 0);
1044      if(ret <= 0) {
1045        Sectorbitmap_destroy(&m, 0);
1046        return(0);
1047      }
1048    }
1049  }
1050 
1051  count= Spotlist_count(spotlist, 0);
1052  /* first set good bits, then eventually override by bad bits */
1053  for(pass= 0; pass < 2; pass++) {
1054    for(i= 0; i < count; i++) {
1055      ret= Spotlist_get_item(spotlist, i, &lba, &blocks, &quality, 0);
1056      if(ret <= 0)
1057    continue;
1058      valid= quality > xorriso->check_media_bad_limit;
1059      if(quality == Xorriso_read_quality_untesteD && (flag & 1))
1060        valid= 1;
1061      if(quality == Xorriso_read_quality_untesteD && (flag & 2))
1062    continue;
1063      if(pass == 0 && !valid)
1064    continue;
1065      else if(pass == 1 && valid)
1066    continue;
1067      Sectorbitmap_set_range(m, lba / sector_blocks, blocks / sector_blocks,
1068                             valid);
1069    }
1070  }
1071  if(replace_map) {
1072    Sectorbitmap_destroy(map, 0);
1073    *map= m;
1074  }
1075  return(1);
1076 }
1077 
1078 
Xorriso_open_job_data_to(struct XorrisO * xorriso,struct CheckmediajoB * job,int flag)1079 int Xorriso_open_job_data_to(struct XorrisO *xorriso,
1080                              struct CheckmediajoB *job, int flag)
1081 {
1082  if(job->data_to_path[0] == 0)
1083    return(2);
1084  job->data_to_fd= open(job->data_to_path, O_RDWR | O_CREAT | O_BINARY,
1085                        S_IRUSR | S_IWUSR);
1086  if(job->data_to_fd == -1) {
1087    sprintf(xorriso->info_text, "Cannot open path ");
1088    Text_shellsafe(job->data_to_path, xorriso->info_text, 1);
1089    Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
1090    return(0);
1091  }
1092  return(1);
1093 }
1094 
1095 
Xorriso_update_in_sector_map(struct XorrisO * xorriso,struct SpotlisT * spotlist,int read_chunk,struct CheckmediajoB * job,int flag)1096 int Xorriso_update_in_sector_map(struct XorrisO *xorriso,
1097                                  struct SpotlisT *spotlist, int read_chunk,
1098                                  struct CheckmediajoB *job, int flag)
1099 {
1100  int sectors, sector_size, sector_blocks, ret;
1101  struct SectorbitmaP *map;
1102 
1103  Sectorbitmap_destroy(&(xorriso->in_sector_map), 0);
1104  if(job->use_dev == 1)
1105    return(1);
1106  map= job->sector_map;
1107  sectors= Spotlist_block_count(spotlist, 0);
1108  if(sectors <= 0)
1109    return(0);
1110  sector_size= Spotlist_sector_size(spotlist, read_chunk, 0);
1111  sector_blocks= sector_size / 2048;
1112  if(sector_blocks > 1)
1113    sectors= sectors / sector_blocks + !!(sectors % sector_blocks);
1114  ret= Sectorbitmap_new(&(xorriso->in_sector_map), sectors, sector_size, 0);
1115  if(ret <= 0)
1116    return(ret);
1117  if(map != NULL)
1118    Sectorbitmap_copy(map, xorriso->in_sector_map, 0);
1119  ret= Xorriso_spotlist_to_sectormap(xorriso, spotlist, read_chunk,
1120                                     &(xorriso->in_sector_map), 1);
1121  return(ret);
1122 }
1123 
1124