2 /* writeisofs - simple ISO9660-format-image writing utility */
4 #if HAVE_NBTOOL_CONFIG_H
5 #include "nbtool_config.h"
18 #include <partition.h>
23 #define Writefield(fd, f) Write(fd, &(f), sizeof(f))
29 #define min(a,b) ((a) < (b) ? (a) : (b))
34 #include <sys/types.h>
38 #define ISONAMELEN 12 /* XXX could easily be 31 */
39 #define PLATFORM_80X86 0
41 #define ISO_SECTOR 2048
42 #define VIRTUAL_SECTOR 512
43 #define ROUNDUP(v, n) (((v)+(n)-1)/(n))
45 #define CURRENTDIR "."
46 #define PARENTDIR ".."
48 /* *** CD (disk) data structures ********************* */
50 /* primary volume descriptor */
63 u_int16_t sectorsize
[2];
64 u_int32_t pathtablesize
[2];
65 u_int32_t first_little_pathtable_start
;
66 u_int32_t second_little_pathtable_start
;
67 u_int32_t first_big_pathtable_start
;
68 u_int32_t second_big_pathtable_start
;
69 u_int8_t rootrecord
[34];
70 u_int8_t volumeset
[128];
71 u_int8_t publisher
[128];
72 u_int8_t preparer
[128];
73 u_int8_t application
[128];
74 u_int8_t copyrightfile
[37];
75 u_int8_t abstractfile
[37];
76 u_int8_t bibliofile
[37];
78 u_int8_t modified
[17];
80 u_int8_t effective
[17];
83 u_int8_t zeroes3
[512];
84 u_int8_t zeroes4
[653];
87 /* boot record volume descriptor */
90 u_int8_t indicator
; /* 0 */
91 char set
[5]; /* "CD001" */
92 u_int8_t version
; /* 1 */
93 char ident
[32]; /* "EL TORITO SPECIFICATION" */
94 u_int8_t zero
[32]; /* unused, must be 0 */
95 u_int32_t bootcatalog
; /* starting sector of boot catalog */
96 u_int8_t zero2
[1973]; /* unused, must be 0 */
99 /* boot catalog validation entry */
101 struct bc_validation
{
102 u_int8_t headerid
; /* 1 */
103 u_int8_t platform
; /* 0: 80x86; 1: powerpc; 2: mac */
104 u_int8_t zero
[2]; /* unused, must be 0 */
105 char idstring
[24]; /* id string */
107 u_int8_t keys
[2]; /* 0x55AA */
110 /* boot catalog initial/default entry */
112 #define INDICATE_BOOTABLE 0x88
114 #define BOOTMEDIA_UNSPECIFIED -1
115 #define BOOTMEDIA_NONE 0
116 #define BOOTMEDIA_1200K 1
117 #define BOOTMEDIA_1440K 2
118 #define BOOTMEDIA_2880K 3
119 #define BOOTMEDIA_HARDDISK 4
122 u_int8_t indicator
; /* INDICATE_BOOTABLE */
123 u_int8_t media
; /* BOOTMEDIA_* */
124 u_int16_t seg
; /* load segment or 0 for default */
125 u_int8_t type
; /* system type (from part. table) */
128 u_int32_t startsector
;
132 /* directory entry */
137 u_int32_t datasector
[2];
138 u_int32_t filesize
[2];
147 u_int8_t interleaved
;
148 u_int8_t interleavegap
;
149 u_int16_t sequence
[2];
154 /* *** program (memory) data structures ********************* */
161 struct node
*firstchild
, *nextchild
;
163 /* filled out at i/o time */
164 u_int32_t startsector
, bytesize
;
167 int n_reserved_pathtableentries
= 0, n_used_pathtableentries
= 0;
168 int bootmedia
= BOOTMEDIA_UNSPECIFIED
;
169 unsigned long bootseg
= 0;
172 int get_system_type(int fd
);
175 Write(int fd
, void *buf
, ssize_t len
)
178 if((r
=write(fd
, buf
, len
)) != len
) {
179 if(r
< 0) { perror("write"); }
180 fprintf(stderr
, "failed or short write - aborting.\n");
187 Lseek(int fd
, off_t pos
, int rel
)
191 if((r
=lseek(fd
, pos
, rel
)) < 0) {
193 fprintf(stderr
, "lseek failed - aborting.\n");
201 writesector(int fd
, char *block
, int *currentsector
)
203 Write(fd
, block
, ISO_SECTOR
);
209 seeksector(int fd
, int sector
, int *currentsector
)
211 Lseek(fd
, sector
*ISO_SECTOR
, SEEK_SET
);
212 *currentsector
= sector
;
216 seekwritesector(int fd
, int sector
, char *block
, int *currentsector
)
218 seeksector(fd
, sector
, currentsector
);
219 writesector(fd
, block
, currentsector
);
223 Read(int fd
, void *buf
, ssize_t len
)
226 if((r
=read(fd
, buf
, len
)) != len
) {
227 if(r
< 0) { perror("read"); }
228 fprintf(stderr
, "failed or short read.\n");
235 void both16(unsigned char *both
, unsigned short i16
)
237 unsigned char *little
, *big
;
242 little
[0] = big
[1] = i16
& 0xFF;
243 little
[1] = big
[0] = (i16
>> 8) & 0xFF;
246 void both32(unsigned char *both
, unsigned long i32
)
248 unsigned char *little
, *big
;
253 little
[0] = big
[3] = i32
& 0xFF;
254 little
[1] = big
[2] = (i32
>> 8) & 0xFF;
255 little
[2] = big
[1] = (i32
>> 16) & 0xFF;
256 little
[3] = big
[0] = (i32
>> 24) & 0xFF;
264 static int cmpf(const void *v1
, const void *v2
)
266 struct node
*n1
, *n2
;
268 char f1
[NAMELEN
], f2
[NAMELEN
];
270 n1
= (struct node
*) v1
;
271 n2
= (struct node
*) v2
;
272 strcpy(f1
, n1
->name
);
273 strcpy(f2
, n2
->name
);
274 for(i
= 0; i
< strlen(f1
); i
++) f1
[i
] = toupper(f1
[i
]);
275 for(i
= 0; i
< strlen(f2
); i
++) f2
[i
] = toupper(f2
[i
]);
278 return -strcmp(f1
, f2
);
282 maketree(struct node
*thisdir
, char *name
, int level
)
286 struct node
*dirnodes
= NULL
;
287 int reserved_dirnodes
= 0, used_dirnodes
= 0;
290 thisdir
->firstchild
= NULL
;
292 thisdir
->startsector
= 0xdeadbeef;
294 if(level
>= MAXLEVEL
) {
295 fprintf(stderr
, "ignoring entries in %s (too deep for iso9660)\n",
300 if(!(dir
= opendir(CURRENTDIR
))) {
305 /* how many entries do we need to allocate? */
306 while(readdir(dir
)) reserved_dirnodes
++;
307 if(!reserved_dirnodes
) {
312 if(!(dirnodes
= malloc(sizeof(*dirnodes
)*reserved_dirnodes
))) {
313 fprintf(stderr
, "couldn't allocate dirnodes (%zu bytes)\n",
314 sizeof(*dirnodes
)*reserved_dirnodes
);
319 /* remember all entries in this dir */
323 while((e
=readdir(dir
))) {
326 if(!strcmp(e
->d_name
, CURRENTDIR
) || !strcmp(e
->d_name
, PARENTDIR
))
328 if(stat(e
->d_name
, &st
) < 0) {
330 fprintf(stderr
, "failed to stat file/dir\n");
334 type
= st
.st_mode
& S_IFMT
;
337 printf("%s type: %x dir: %x file: %x\n",
338 e->d_name, type, S_IFDIR, S_IFREG);
340 if(type
!= S_IFDIR
&& type
!= S_IFREG
)
344 if(used_dirnodes
> reserved_dirnodes
) {
345 fprintf(stderr
, "huh, directory entries appeared "
346 "(not enough pre-allocated nodes; this can't happen) ?\n");
350 if(type
== S_IFDIR
) {
354 child
->firstchild
= NULL
;
356 strlcpy(child
->name
, e
->d_name
, sizeof(child
->name
));
357 child
->timestamp
= st
.st_mtime
;
367 if(!(dirnodes
=realloc(dirnodes
, used_dirnodes
*sizeof(*dirnodes
)))) {
368 fprintf(stderr
, "realloc() of dirnodes failed - aborting\n");
372 qsort(dirnodes
, used_dirnodes
, sizeof(*dirnodes
), cmpf
);
376 while(used_dirnodes
--) {
377 child
->nextchild
= thisdir
->firstchild
;
378 thisdir
->firstchild
= child
;
380 if(chdir(child
->name
) < 0) {
383 maketree(child
, child
->name
, level
+1);
384 if(chdir(PARENTDIR
) < 0) {
385 perror("chdir() failed");
386 fprintf(stderr
, "couldn't chdir() to parent, aborting\n");
398 little32(unsigned char *dest
, u_int32_t src
)
400 dest
[0] = ((src
>> 0) & 0xFF);
401 dest
[1] = ((src
>> 8) & 0xFF);
402 dest
[2] = ((src
>> 16) & 0xFF);
403 dest
[3] = ((src
>> 24) & 0xFF);
409 little16(unsigned char *dest
, u_int16_t src
)
411 dest
[0] = ((src
>> 0) & 0xFF);
412 dest
[1] = ((src
>> 8) & 0xFF);
418 big32(unsigned char *dest
, u_int32_t src
)
420 dest
[3] = ((src
>> 0) & 0xFF);
421 dest
[2] = ((src
>> 8) & 0xFF);
422 dest
[1] = ((src
>> 16) & 0xFF);
423 dest
[0] = ((src
>> 24) & 0xFF);
428 big16(unsigned char *dest
, u_int16_t src
)
430 dest
[1] = ((src
>> 0) & 0xFF);
431 dest
[0] = ((src
>> 8) & 0xFF);
437 traversetree(struct node
*root
, int level
, int littleendian
,
438 int maxlevel
, int *bytes
, int fd
, int parentrecord
, int *recordno
)
444 u_int32_t startsector
;
448 if(level
== maxlevel
) {
450 char newname
[NAMELEN
];
458 root
->name
[0] = root
->name
[1] = '\0';
460 pte
.len
= strlen(root
->name
);
461 pte
.parent
= parentrecord
;
463 pte
.startsector
= root
->startsector
;
464 root
->pathtablerecord
= (*recordno
)++;
467 little32((unsigned char *) &pte
.startsector
, pte
.startsector
);
468 little16((unsigned char *) &pte
.parent
, pte
.parent
);
470 big32((unsigned char *) &pte
.startsector
, pte
.startsector
);
471 big16((unsigned char *) &pte
.parent
, pte
.parent
);
474 *bytes
+= Write(fd
, &pte
.len
, sizeof(pte
.len
));
475 *bytes
+= Write(fd
, &pte
.zero
, sizeof(pte
.zero
));
476 *bytes
+= Write(fd
, &pte
.startsector
, sizeof(pte
.startsector
));
477 *bytes
+= Write(fd
, &pte
.parent
, sizeof(pte
.parent
));
479 root
->name
[pte
.len
++] = '\0';
480 for(i
= 0; i
< pte
.len
; i
++)
481 newname
[i
] = toupper(root
->name
[i
]);
482 *bytes
+= Write(fd
, newname
, pte
.len
);
486 for(child
= root
->firstchild
; child
; child
= child
->nextchild
)
488 traversetree(child
, level
+1, littleendian
,
489 maxlevel
, bytes
, fd
, root
->pathtablerecord
,
496 makepathtables(struct node
*root
, int littleendian
, int *bytes
, int fd
)
499 static char block
[ISO_SECTOR
];
506 for(level
= 1; level
<= MAXLEVEL
; level
++)
507 traversetree(root
, 1, littleendian
, level
, bytes
, fd
, 1, &recordno
);
509 if(*bytes
% ISO_SECTOR
) {
511 x
= ISO_SECTOR
-(*bytes
% ISO_SECTOR
);
516 return *bytes
/ISO_SECTOR
;
520 write_direntry(struct node
* n
, char *origname
, int fd
)
522 int namelen
, total
= 0;
524 char copyname
[NAMELEN
];
527 memset(&entry
, 0, sizeof(entry
));
529 if(!strcmp(origname
, CURRENTDIR
)) {
530 entry
.name
[0] = '\000';
532 } else if(!strcmp(origname
, PARENTDIR
)) {
533 entry
.name
[0] = '\001';
537 strlcpy(copyname
, origname
, sizeof(copyname
));
538 namelen
= strlen(copyname
);
540 /* XXX No check for 8+3 ? (DOS compatibility) */
541 assert(ISONAMELEN
<= NAMELEN
-2);
542 if(namelen
> ISONAMELEN
) {
543 fprintf(stderr
, "%s: truncated, too long for iso9660\n", copyname
);
544 namelen
= ISONAMELEN
;
545 copyname
[namelen
] = '\0';
548 strlcpy(entry
.name
, copyname
, namelen
+1);
549 for(i
= 0; i
< namelen
; i
++)
550 entry
.name
[i
] = toupper(entry
.name
[i
]);
552 /* padding byte + system field */
553 entry
.name
[namelen
] = '\0';
554 entry
.name
[namelen
+1] = '\0';
555 entry
.name
[namelen
+2] = '\0';
557 entry
.namelen
= namelen
; /* original length */
558 if(!(namelen
%2)) namelen
++; /* length with padding byte */
561 /* XXX 2 extra bytes for 'system use'.. */
562 entry
.recordsize
= 33 + namelen
;
563 both32((unsigned char *) entry
.datasector
, n
->startsector
);
564 both32((unsigned char *) entry
.filesize
, n
->bytesize
);
566 if(n
->isdir
) entry
.flags
= FLAG_DIR
;
568 memcpy(&tm
, gmtime(&n
->timestamp
), sizeof(tm
));
569 entry
.year
= (unsigned)tm
.tm_year
> 255 ? 255 : tm
.tm_year
;
570 entry
.month
= tm
.tm_mon
+ 1;
571 entry
.day
= tm
.tm_mday
;
572 entry
.hour
= tm
.tm_hour
;
573 entry
.minute
= tm
.tm_min
;
574 entry
.second
= tm
.tm_sec
;
575 entry
.offset
= 0; /* Posix uses UTC timestamps! */
577 both16((unsigned char *) entry
.sequence
, 1);
579 total
= Write(fd
, &entry
.recordsize
, sizeof(entry
.recordsize
));
580 total
+= Write(fd
, &entry
.extended
, sizeof(entry
.extended
));
581 total
+= Write(fd
, entry
.datasector
, sizeof(entry
.datasector
));
582 total
+= Write(fd
, entry
.filesize
, sizeof(entry
.filesize
));
583 total
+= Write(fd
, &entry
.year
, sizeof(entry
.year
));
584 total
+= Write(fd
, &entry
.month
, sizeof(entry
.month
));
585 total
+= Write(fd
, &entry
.day
, sizeof(entry
.day
));
586 total
+= Write(fd
, &entry
.hour
, sizeof(entry
.hour
));
587 total
+= Write(fd
, &entry
.minute
, sizeof(entry
.minute
));
588 total
+= Write(fd
, &entry
.second
, sizeof(entry
.second
));
589 total
+= Write(fd
, &entry
.offset
, sizeof(entry
.offset
));
590 total
+= Write(fd
, &entry
.flags
, sizeof(entry
.flags
));
591 total
+= Write(fd
, &entry
.interleaved
, sizeof(entry
.interleaved
));
592 total
+= Write(fd
, &entry
.interleavegap
, sizeof(entry
.interleavegap
));
593 total
+= Write(fd
, entry
.sequence
, sizeof(entry
.sequence
));
594 total
+= Write(fd
, &entry
.namelen
, sizeof(entry
.namelen
));
595 total
+= Write(fd
, entry
.name
, namelen
);
597 if(total
!= entry
.recordsize
|| (total
% 2) != 0) {
598 printf("%2d, %2d! ", total
, entry
.recordsize
);
599 printf("%3d = %3zu - %2zu + %2d\n",
600 entry
.recordsize
, sizeof(entry
), sizeof(entry
.name
), namelen
);
603 return entry
.recordsize
;
607 writedata(struct node
*parent
, struct node
*root
,
608 int fd
, int *currentsector
, int dirs
, struct dir
*rootentry
,
609 int rootsize
, int remove_after
)
611 static char buf
[1024*1024];
613 ssize_t written
= 0, rest
;
615 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
616 if(c
->isdir
&& chdir(c
->name
) < 0) {
618 fprintf(stderr
, "couldn't chdir to %s - aborting\n",
622 writedata(root
, c
, fd
, currentsector
, dirs
, rootentry
, rootsize
, remove_after
);
623 if(c
->isdir
&& chdir(PARENTDIR
) < 0) {
624 perror("chdir to ..");
625 fprintf(stderr
, "couldn't chdir to parent - "
631 /* write nodes depth-first, down-top */
633 if(root
->isdir
&& dirs
) {
636 root
->startsector
= *currentsector
;
637 written
+= write_direntry(root
, CURRENTDIR
, fd
);
639 written
+= write_direntry(parent
, PARENTDIR
, fd
);
641 written
+= write_direntry(root
, PARENTDIR
, fd
);
643 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
645 ssize_t written_before
;
646 cur1
= Lseek(fd
, 0, SEEK_CUR
);
647 written_before
= written
;
648 written
+= write_direntry(c
, c
->name
, fd
);
649 cur2
= Lseek(fd
, 0, SEEK_CUR
);
650 if(cur1
/ISO_SECTOR
!= (cur2
-1)/ISO_SECTOR
) {
651 /* passed a sector boundary, argh! */
652 Lseek(fd
, cur1
, SEEK_SET
);
653 written
= written_before
;
654 rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
));
655 memset(buf
, 0, rest
);
656 Write(fd
, buf
, rest
);
658 written
+= write_direntry(c
, c
->name
, fd
);
661 root
->bytesize
= written
;
662 } else if(!root
->isdir
&& !dirs
) {
668 if(stat(root
->name
, &st
) < 0) {
670 fprintf(stderr
, "couldn't stat %s - aborting\n", root
->name
);
674 if((filefd
= open(root
->name
, O_RDONLY
)) < 0) {
676 fprintf(stderr
, "couldn't open %s - aborting\n", root
->name
);
682 root
->startsector
= *currentsector
;
686 chunk
= min(sizeof(buf
), rem
);
687 Read(filefd
, buf
, chunk
);
688 Write(fd
, buf
, chunk
);
694 root
->bytesize
= written
= st
.st_size
;
695 if(remove_after
&& unlink(root
->name
) < 0) {
697 fprintf(stderr
, "couldn't remove %s\n", root
->name
);
700 /* nothing to be done */
704 /* fill out sector with zero bytes */
706 if((rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
)))) {
707 memset(buf
, 0, rest
);
708 Write(fd
, buf
, rest
);
712 /* update dir size with padded size */
714 if(root
->isdir
) { root
->bytesize
= written
; }
716 *currentsector
+= written
/ISO_SECTOR
;
720 writebootcatalog(int fd
, int *currentsector
, int imagesector
, int imagesectors
)
722 static char buf
[ISO_SECTOR
];
723 struct bc_validation validate
;
724 struct bc_initial initial
;
726 ssize_t written
, rest
;
727 u_int16_t
*v
, sum
= 0;
730 /* write validation entry */
732 memset(&validate
, 0, sizeof(validate
));
733 validate
.headerid
= 1;
734 validate
.platform
= PLATFORM_80X86
;
735 strcpy(validate
.idstring
, "");
736 validate
.keys
[0] = 0x55;
737 validate
.keys
[1] = 0xaa;
739 v
= (u_int16_t
*) &validate
;
740 for(i
= 0; i
< sizeof(validate
)/2; i
++)
742 validate
.checksum
= 65535 - sum
+ 1; /* sum must be 0 */
744 written
= Write(fd
, &validate
, sizeof(validate
));
746 /* write initial/default entry */
748 memset(&initial
, 0, sizeof(initial
));
750 initial
.indicator
= INDICATE_BOOTABLE
;
751 initial
.media
= bootmedia
;
752 initial
.seg
= (u_int16_t
) (bootseg
& 0xFFFF);
754 if (bootmedia
== BOOTMEDIA_HARDDISK
)
756 initial
.type
= system_type
;
758 if (bootmedia
== BOOTMEDIA_NONE
)
760 initial
.sectors
= imagesectors
;
762 initial
.startsector
= imagesector
;
764 written
+= Write(fd
, &initial
, sizeof(initial
));
766 /* fill out the rest of the sector with 0's */
768 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
769 memset(buf
, 0, sizeof(buf
));
770 written
+= Write(fd
, buf
, rest
);
773 (*currentsector
) += written
/ ISO_SECTOR
;
779 writebootimage(char *bootimage
, int bootfd
, int fd
, int *currentsector
,
780 char *appendsectorinfo
, struct node
*root
)
782 static unsigned char buf
[1024*64], *addr
;
783 ssize_t written
= 0, rest
;
791 bap
[0].length
= bap
[0].sector
= 0;
792 bap
[1].length
= bap
[1].sector
= 0;
794 if (fstat(bootfd
, &sb
) < 0) {
795 perror("stat boot image");
803 want
= rem
< sizeof(buf
) ? rem
: sizeof(buf
);
804 Read(bootfd
, buf
, want
);
806 /* check some properties at beginning. */
807 if (buf
[0] == 1 && buf
[1] == 3) {
808 fprintf(stderr
, "boot image %s is an a.out executable\n",
812 if (rem
>= VIRTUAL_SECTOR
813 && (buf
[510] != 0x55 || buf
[511] != 0xaa) ) {
814 fprintf(stderr
, "invalid boot sector (bad magic.)\n");
818 written
+= Write(fd
, buf
, want
);
822 if(appendsectorinfo
) {
824 for(n
= root
->firstchild
; n
; n
= n
->nextchild
) {
825 if(!strcasecmp(appendsectorinfo
, n
->name
)) {
826 bap
[0].sector
= n
->startsector
;
827 bap
[0].length
= ROUNDUP(n
->bytesize
, ISO_SECTOR
);
832 fprintf(stderr
, "%s not found in root.\n",
838 " * appended sector info: 0x%"PRIx64
" len 0x%x\n",
839 bap
[0].sector
, bap
[0].length
);
842 addr
[0] = bap
[0].length
;
844 addr
[1] = (bap
[0].sector
>> 0) & 0xFF;
845 addr
[2] = (bap
[0].sector
>> 8) & 0xFF;
846 addr
[3] = (bap
[0].sector
>> 16) & 0xFF;
850 written
+= Write(fd
, addr
, 6);
853 virtuals
= ROUNDUP(written
, VIRTUAL_SECTOR
);
854 assert(virtuals
* VIRTUAL_SECTOR
>= written
);
856 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
857 memset(buf
, 0, sizeof(buf
));
858 written
+= Write(fd
, buf
, rest
);
861 (*currentsector
) += written
/ISO_SECTOR
;
867 writebootrecord(int fd
, int *currentsector
, int bootcatalogsector
)
870 static struct bootrecord bootrecord
;
872 /* boot record volume descriptor */
874 memset(&bootrecord
, 0, sizeof(bootrecord
));
875 bootrecord
.set
[0] = 'C';
876 bootrecord
.set
[1] = 'D';
877 bootrecord
.set
[2] = '0';
878 bootrecord
.set
[3] = '0';
879 bootrecord
.set
[4] = '1';
880 bootrecord
.version
= 1;
881 bootrecord
.bootcatalog
= bootcatalogsector
;
882 strcpy(bootrecord
.ident
, "EL TORITO SPECIFICATION");
883 for(i
= strlen(bootrecord
.ident
);
884 i
< sizeof(bootrecord
.ident
); i
++)
885 bootrecord
.ident
[i
] = '\0';
887 w
= Writefield(fd
, bootrecord
.indicator
);
888 w
+= Writefield(fd
, bootrecord
.set
);
889 w
+= Writefield(fd
, bootrecord
.version
);
890 w
+= Writefield(fd
, bootrecord
.ident
);
891 w
+= Writefield(fd
, bootrecord
.zero
);
892 w
+= Writefield(fd
, bootrecord
.bootcatalog
);
893 w
+= Writefield(fd
, bootrecord
.zero2
);
895 if(w
!= ISO_SECTOR
) {
896 fprintf(stderr
, "WARNING: something went wrong - "
897 "boot record (%zd) isn't a sector size (%d)\n",
905 main(int argc
, char *argv
[])
907 int currentsector
= 0;
908 int imagesector
, imagesectors
;
909 int bootfd
, fd
, i
, ch
, nsectors
;
910 int remove_after
= 0;
911 static char block
[ISO_SECTOR
];
912 static struct pvd pvd
;
913 char *label
= "ISO9660";
916 char timestr
[20], *prog
;
917 char *bootimage
= NULL
;
920 int bigpath
, littlepath
, pathbytes
= 0, dirsector
, filesector
, enddir
;
921 int bootvolumesector
, bootcatalogsector
;
922 char *appendsectorinfo
= NULL
;
926 /* This check is to prevent compiler padding screwing up
930 if(sizeof(struct pvd
) != ISO_SECTOR
) {
931 fprintf(stderr
, "Something confusing happened at\n"
932 "compile-time; pvd should be a sector size. "
933 "%zd != %d\n", sizeof(struct pvd
), ISO_SECTOR
);
937 while ((ch
= getopt(argc
, argv
, "a:b:B:s:Rb:hl:nfF")) != -1) {
940 if(optarg
[0] != '0' || optarg
[1] != 'x') {
941 fprintf(stderr
, "%s: -s<hex>\n",
945 bootseg
= strtoul(optarg
+2, NULL
, 16);
948 bootmedia
= BOOTMEDIA_HARDDISK
;
951 bootmedia
= BOOTMEDIA_NONE
;
954 bootmedia
= BOOTMEDIA_1440K
;
957 bootmedia
= BOOTMEDIA_2880K
;
960 if(!(appendsectorinfo
= strdup(optarg
)))
971 if((bootfd
= open(bootimage
, O_RDONLY
)) < 0) {
985 fprintf(stderr
, "usage: %s [-l <label>] [-(b|B) <bootimage> [-n|-f|-F|-h] [-s <bootsegment>] [ -a <appendfile> ] <dir> <isofile>\n",
990 if((bootimage
&& bootmedia
== BOOTMEDIA_UNSPECIFIED
) ||
991 (!bootimage
&& bootmedia
!= BOOTMEDIA_UNSPECIFIED
)) {
992 fprintf(stderr
, "%s: provide both boot image and boot type or neither.\n",
997 if(!bootimage
&& bootseg
) {
998 fprintf(stderr
, "%s: boot seg provided but no boot image\n",
1003 if(appendsectorinfo
) {
1004 if(!bootimage
|| bootmedia
!= BOOTMEDIA_NONE
) {
1005 fprintf(stderr
, "%s: append sector info where?\n",
1011 /* create .iso file */
1013 if((fd
=open(argv
[1], O_WRONLY
| O_TRUNC
| O_CREAT
, 0600)) < 0) {
1018 /* go to where the iso has to be made from */
1020 if(chdir(argv
[0]) < 0) {
1025 /* collect dirs and files */
1027 fprintf(stderr
, " * traversing input tree\n");
1029 maketree(&root
, "", 1);
1031 fprintf(stderr
, " * writing initial zeroes and pvd\n");
1033 /* first sixteen sectors are zero */
1035 memset(block
, 0, sizeof(block
));
1037 for(i
= 0; i
< 16; i
++)
1038 writesector(fd
, block
, ¤tsector
);
1040 /* Primary Volume Descriptor */
1041 memset(&pvd
, 0, sizeof(pvd
));
1051 strncpy(pvd
.volume
, label
, sizeof(pvd
.volume
)-1);
1052 for(i
= strlen(pvd
.volume
); i
< sizeof(pvd
.volume
); i
++)
1053 pvd
.volume
[i
] = ' ';
1054 for(i
= 0; i
< sizeof(pvd
.system
); i
++)
1055 pvd
.system
[i
] = ' ';
1057 both16((unsigned char *) pvd
.setsize
, 1);
1058 both16((unsigned char *) pvd
.seq
, 1);
1059 both16((unsigned char *) pvd
.sectorsize
, ISO_SECTOR
);
1061 /* fill time fields */
1063 now
= gmtime(&nowtime
);
1064 strftime(timestr
, sizeof(timestr
), "%Y%m%d%H%M%S000", now
);
1065 memcpy(pvd
.create
, timestr
, strlen(timestr
));
1066 memcpy(pvd
.modified
, timestr
, strlen(timestr
));
1067 memcpy(pvd
.effective
, timestr
, strlen(timestr
));
1068 strcpy(pvd
.expiry
, "0000000000000000"); /* not specified */
1070 pvdsector
= currentsector
;
1072 writesector(fd
, (char *) &pvd
, ¤tsector
);
1075 fprintf(stderr
, " * writing boot record volume descriptor\n");
1076 bootvolumesector
= currentsector
;
1077 writebootrecord(fd
, ¤tsector
, 0);
1080 /* volume descriptor set terminator */
1081 memset(block
, 0, sizeof(block
));
1090 writesector(fd
, block
, ¤tsector
);
1093 /* write the boot catalog */
1094 fprintf(stderr
, " * writing the boot catalog\n");
1095 bootcatalogsector
= currentsector
;
1096 if (bootmedia
== BOOTMEDIA_HARDDISK
)
1097 system_type
= get_system_type(bootfd
);
1098 writebootcatalog(fd
, ¤tsector
, 0, 0);
1100 /* write boot image */
1101 fprintf(stderr
, " * writing the boot image\n");
1102 imagesector
= currentsector
;
1103 imagesectors
= writebootimage(bootimage
, bootfd
,
1104 fd
, ¤tsector
, NULL
, &root
);
1105 fprintf(stderr
, " * image: %d %d-byte sectors @ cd sector 0x%x\n",
1106 imagesectors
, VIRTUAL_SECTOR
, imagesector
);
1109 /* write out all the file data */
1111 filesector
= currentsector
;
1112 fprintf(stderr
, " * writing file data\n");
1113 writedata(NULL
, &root
, fd
, ¤tsector
, 0,
1114 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1117 /* write out all the dir data */
1119 dirsector
= currentsector
;
1120 fprintf(stderr
, " * writing dir data\n");
1121 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1122 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1124 enddir
= currentsector
;
1125 seeksector(fd
, dirsector
, ¤tsector
);
1126 fprintf(stderr
, " * rewriting dir data\n");
1128 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1129 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1131 if(currentsector
!= enddir
) {
1132 fprintf(stderr
, "warning: inconsistent directories - "
1133 "I have a bug! iso may be broken.\n");
1136 /* now write the path table in both formats */
1138 fprintf(stderr
, " * writing big-endian path table\n");
1139 bigpath
= currentsector
;
1140 currentsector
+= makepathtables(&root
, 0, &pathbytes
, fd
);
1142 fprintf(stderr
, " * writing little-endian path table\n");
1143 littlepath
= currentsector
;
1144 currentsector
+= makepathtables(&root
, 1, &pathbytes
, fd
);
1146 both32((unsigned char *) pvd
.pathtablesize
, pathbytes
);
1147 little32((unsigned char *) &pvd
.first_little_pathtable_start
, littlepath
);
1148 big32((unsigned char *) &pvd
.first_big_pathtable_start
, bigpath
);
1150 /* this is the size of the iso filesystem for use in the pvd later */
1152 nsectors
= currentsector
;
1153 both32((unsigned char *) pvd
.sectors
, nsectors
);
1155 /* *********** Filesystem writing done ************************* */
1157 /* finish and rewrite the pvd. */
1158 fprintf(stderr
, " * rewriting pvd\n");
1159 seekwritesector(fd
, pvdsector
, (char *) &pvd
, ¤tsector
);
1161 /* write root dir entry in pvd */
1162 seeksector(fd
, pvdsector
, ¤tsector
);
1163 Lseek(fd
, (int)((char *) &pvd
.rootrecord
- (char *) &pvd
), SEEK_CUR
);
1164 if(write_direntry(&root
, CURRENTDIR
, fd
) > sizeof(pvd
.rootrecord
)) {
1165 fprintf(stderr
, "warning: unexpectedly large root record\n");
1169 fprintf(stderr
, " * rewriting boot catalog\n");
1170 seeksector(fd
, bootcatalogsector
, ¤tsector
);
1171 writebootcatalog(fd
, ¤tsector
, imagesector
, imagesectors
);
1173 /* finish and rewrite the boot record volume descriptor */
1174 fprintf(stderr
, " * rewriting the boot rvd\n");
1175 seeksector(fd
, bootvolumesector
, ¤tsector
);
1176 writebootrecord(fd
, ¤tsector
, bootcatalogsector
);
1178 if(appendsectorinfo
) {
1179 Lseek(bootfd
, 0, SEEK_SET
);
1180 fprintf(stderr
, " * rewriting boot image\n");
1181 seeksector(fd
, imagesector
, ¤tsector
);
1182 writebootimage(bootimage
, bootfd
,
1183 fd
, ¤tsector
, appendsectorinfo
, &root
);
1189 fprintf(stderr
, " * all ok\n");
1194 int get_system_type(int fd
)
1200 struct part_entry
*partp
;
1201 unsigned char bootsector
[512];
1204 old_pos
= lseek(fd
, 0, SEEK_SET
);
1205 if (old_pos
== -1 && errno
!= 0)
1207 fprintf(stderr
, "bootimage file is not seekable: %s\n",
1211 size
= sizeof(bootsector
);
1212 r
= read(fd
, bootsector
, size
);
1215 fprintf(stderr
, "error reading bootimage file: %s\n",
1216 r
< 0 ? strerror(errno
) : "unexpected EOF");
1219 if (bootsector
[size
-2] != 0x55 && bootsector
[size
-1] != 0xAA)
1221 fprintf(stderr
, "bad magic in bootimage file\n");
1225 partp
= (struct part_entry
*)&bootsector
[PART_TABLE_OFF
];
1226 type
= partp
->sysind
;
1227 if (type
== NO_PART
)
1229 fprintf(stderr
, "first partition table entry is unused\n");
1232 if (!(partp
->bootind
& ACTIVE_FLAG
))
1234 fprintf(stderr
, "first partition table entry is not active\n");
1238 lseek(fd
, old_pos
, SEEK_SET
);