2 /* writeisofs - simple ISO9660-format-image writing utility */
4 #if HAVE_NBTOOL_CONFIG_H
5 #include "nbtool_config.h"
18 #include <partition.h>
22 #define Writefield(fd, f) Write(fd, &(f), sizeof(f))
28 #define min(a,b) ((a) < (b) ? (a) : (b))
33 #include <sys/types.h>
37 #define ISONAMELEN 12 /* XXX could easily be 31 */
38 #define PLATFORM_80X86 0
40 #define ISO_SECTOR 2048
41 #define VIRTUAL_SECTOR 512
42 #define ROUNDUP(v, n) (((v)+(n)-1)/(n))
44 #define CURRENTDIR "."
45 #define PARENTDIR ".."
47 /* *** CD (disk) data structures ********************* */
49 /* primary volume descriptor */
62 u_int16_t sectorsize
[2];
63 u_int32_t pathtablesize
[2];
64 u_int32_t first_little_pathtable_start
;
65 u_int32_t second_little_pathtable_start
;
66 u_int32_t first_big_pathtable_start
;
67 u_int32_t second_big_pathtable_start
;
68 u_int8_t rootrecord
[34];
69 u_int8_t volumeset
[128];
70 u_int8_t publisher
[128];
71 u_int8_t preparer
[128];
72 u_int8_t application
[128];
73 u_int8_t copyrightfile
[37];
74 u_int8_t abstractfile
[37];
75 u_int8_t bibliofile
[37];
77 u_int8_t modified
[17];
79 u_int8_t effective
[17];
82 u_int8_t zeroes3
[512];
83 u_int8_t zeroes4
[653];
86 /* boot record volume descriptor */
89 u_int8_t indicator
; /* 0 */
90 char set
[5]; /* "CD001" */
91 u_int8_t version
; /* 1 */
92 char ident
[32]; /* "EL TORITO SPECIFICATION" */
93 u_int8_t zero
[32]; /* unused, must be 0 */
94 u_int32_t bootcatalog
; /* starting sector of boot catalog */
95 u_int8_t zero2
[1973]; /* unused, must be 0 */
98 /* boot catalog validation entry */
100 struct bc_validation
{
101 u_int8_t headerid
; /* 1 */
102 u_int8_t platform
; /* 0: 80x86; 1: powerpc; 2: mac */
103 u_int8_t zero
[2]; /* unused, must be 0 */
104 char idstring
[24]; /* id string */
106 u_int8_t keys
[2]; /* 0x55AA */
109 /* boot catalog initial/default entry */
111 #define INDICATE_BOOTABLE 0x88
113 #define BOOTMEDIA_UNSPECIFIED -1
114 #define BOOTMEDIA_NONE 0
115 #define BOOTMEDIA_1200K 1
116 #define BOOTMEDIA_1440K 2
117 #define BOOTMEDIA_2880K 3
118 #define BOOTMEDIA_HARDDISK 4
121 u_int8_t indicator
; /* INDICATE_BOOTABLE */
122 u_int8_t media
; /* BOOTMEDIA_* */
123 u_int16_t seg
; /* load segment or 0 for default */
124 u_int8_t type
; /* system type (from part. table) */
127 u_int32_t startsector
;
131 /* directory entry */
136 u_int32_t datasector
[2];
137 u_int32_t filesize
[2];
146 u_int8_t interleaved
;
147 u_int8_t interleavegap
;
148 u_int16_t sequence
[2];
153 /* *** program (memory) data structures ********************* */
160 struct node
*firstchild
, *nextchild
;
162 /* filled out at i/o time */
163 u_int32_t startsector
, bytesize
;
166 int n_reserved_pathtableentries
= 0, n_used_pathtableentries
= 0;
167 int bootmedia
= BOOTMEDIA_UNSPECIFIED
;
168 unsigned long bootseg
= 0;
171 int get_system_type(int fd
);
174 Write(int fd
, void *buf
, ssize_t len
)
177 if((r
=write(fd
, buf
, len
)) != len
) {
178 if(r
< 0) { perror("write"); }
179 fprintf(stderr
, "failed or short write - aborting.\n");
186 Lseek(int fd
, off_t pos
, int rel
)
190 if((r
=lseek(fd
, pos
, rel
)) < 0) {
192 fprintf(stderr
, "lseek failed - aborting.\n");
200 writesector(int fd
, char *block
, int *currentsector
)
202 Write(fd
, block
, ISO_SECTOR
);
208 seeksector(int fd
, int sector
, int *currentsector
)
210 Lseek(fd
, sector
*ISO_SECTOR
, SEEK_SET
);
211 *currentsector
= sector
;
215 seekwritesector(int fd
, int sector
, char *block
, int *currentsector
)
217 seeksector(fd
, sector
, currentsector
);
218 writesector(fd
, block
, currentsector
);
222 Read(int fd
, void *buf
, ssize_t len
)
225 if((r
=read(fd
, buf
, len
)) != len
) {
226 if(r
< 0) { perror("read"); }
227 fprintf(stderr
, "failed or short read.\n");
234 void both16(unsigned char *both
, unsigned short i16
)
236 unsigned char *little
, *big
;
241 little
[0] = big
[1] = i16
& 0xFF;
242 little
[1] = big
[0] = (i16
>> 8) & 0xFF;
245 void both32(unsigned char *both
, unsigned long i32
)
247 unsigned char *little
, *big
;
252 little
[0] = big
[3] = i32
& 0xFF;
253 little
[1] = big
[2] = (i32
>> 8) & 0xFF;
254 little
[2] = big
[1] = (i32
>> 16) & 0xFF;
255 little
[3] = big
[0] = (i32
>> 24) & 0xFF;
263 static int cmpf(const void *v1
, const void *v2
)
265 struct node
*n1
, *n2
;
267 char f1
[NAMELEN
], f2
[NAMELEN
];
269 n1
= (struct node
*) v1
;
270 n2
= (struct node
*) v2
;
271 strcpy(f1
, n1
->name
);
272 strcpy(f2
, n2
->name
);
273 for(i
= 0; i
< strlen(f1
); i
++) f1
[i
] = toupper(f1
[i
]);
274 for(i
= 0; i
< strlen(f2
); i
++) f2
[i
] = toupper(f2
[i
]);
277 return -strcmp(f1
, f2
);
281 maketree(struct node
*thisdir
, char *name
, int level
)
285 struct node
*dirnodes
= NULL
;
286 int reserved_dirnodes
= 0, used_dirnodes
= 0;
289 thisdir
->firstchild
= NULL
;
291 thisdir
->startsector
= 0xdeadbeef;
293 if(level
>= MAXLEVEL
) {
294 fprintf(stderr
, "ignoring entries in %s (too deep for iso9660)\n",
299 if(!(dir
= opendir(CURRENTDIR
))) {
304 /* how many entries do we need to allocate? */
305 while(readdir(dir
)) reserved_dirnodes
++;
306 if(!reserved_dirnodes
) {
311 if(!(dirnodes
= malloc(sizeof(*dirnodes
)*reserved_dirnodes
))) {
312 fprintf(stderr
, "couldn't allocate dirnodes (%d bytes)\n",
313 sizeof(*dirnodes
)*reserved_dirnodes
);
318 /* remember all entries in this dir */
322 while((e
=readdir(dir
))) {
325 if(!strcmp(e
->d_name
, CURRENTDIR
) || !strcmp(e
->d_name
, PARENTDIR
))
327 if(stat(e
->d_name
, &st
) < 0) {
329 fprintf(stderr
, "failed to stat file/dir\n");
333 type
= st
.st_mode
& S_IFMT
;
336 printf("%s type: %x dir: %x file: %x\n",
337 e->d_name, type, S_IFDIR, S_IFREG);
339 if(type
!= S_IFDIR
&& type
!= S_IFREG
)
343 if(used_dirnodes
> reserved_dirnodes
) {
344 fprintf(stderr
, "huh, directory entries appeared "
345 "(not enough pre-allocated nodes; this can't happen) ?\n");
349 if(type
== S_IFDIR
) {
353 child
->firstchild
= NULL
;
355 strlcpy(child
->name
, e
->d_name
, sizeof(child
->name
));
356 child
->timestamp
= st
.st_mtime
;
366 if(!(dirnodes
=realloc(dirnodes
, used_dirnodes
*sizeof(*dirnodes
)))) {
367 fprintf(stderr
, "realloc() of dirnodes failed - aborting\n");
371 qsort(dirnodes
, used_dirnodes
, sizeof(*dirnodes
), cmpf
);
375 while(used_dirnodes
--) {
376 child
->nextchild
= thisdir
->firstchild
;
377 thisdir
->firstchild
= child
;
379 if(chdir(child
->name
) < 0) {
382 maketree(child
, child
->name
, level
+1);
383 if(chdir(PARENTDIR
) < 0) {
384 perror("chdir() failed");
385 fprintf(stderr
, "couldn't chdir() to parent, aborting\n");
397 little32(unsigned char *dest
, u_int32_t src
)
399 dest
[0] = ((src
>> 0) & 0xFF);
400 dest
[1] = ((src
>> 8) & 0xFF);
401 dest
[2] = ((src
>> 16) & 0xFF);
402 dest
[3] = ((src
>> 24) & 0xFF);
408 little16(unsigned char *dest
, u_int16_t src
)
410 dest
[0] = ((src
>> 0) & 0xFF);
411 dest
[1] = ((src
>> 8) & 0xFF);
417 big32(unsigned char *dest
, u_int32_t src
)
419 dest
[3] = ((src
>> 0) & 0xFF);
420 dest
[2] = ((src
>> 8) & 0xFF);
421 dest
[1] = ((src
>> 16) & 0xFF);
422 dest
[0] = ((src
>> 24) & 0xFF);
427 big16(unsigned char *dest
, u_int16_t src
)
429 dest
[1] = ((src
>> 0) & 0xFF);
430 dest
[0] = ((src
>> 8) & 0xFF);
436 traversetree(struct node
*root
, int level
, int littleendian
,
437 int maxlevel
, int *bytes
, int fd
, int parentrecord
, int *recordno
)
443 u_int32_t startsector
;
447 if(level
== maxlevel
) {
449 char newname
[NAMELEN
];
457 root
->name
[0] = root
->name
[1] = '\0';
459 pte
.len
= strlen(root
->name
);
460 pte
.parent
= parentrecord
;
462 pte
.startsector
= root
->startsector
;
463 root
->pathtablerecord
= (*recordno
)++;
466 little32((unsigned char *) &pte
.startsector
, pte
.startsector
);
467 little16((unsigned char *) &pte
.parent
, pte
.parent
);
469 big32((unsigned char *) &pte
.startsector
, pte
.startsector
);
470 big16((unsigned char *) &pte
.parent
, pte
.parent
);
473 *bytes
+= Write(fd
, &pte
.len
, sizeof(pte
.len
));
474 *bytes
+= Write(fd
, &pte
.zero
, sizeof(pte
.zero
));
475 *bytes
+= Write(fd
, &pte
.startsector
, sizeof(pte
.startsector
));
476 *bytes
+= Write(fd
, &pte
.parent
, sizeof(pte
.parent
));
478 root
->name
[pte
.len
++] = '\0';
479 for(i
= 0; i
< pte
.len
; i
++)
480 newname
[i
] = toupper(root
->name
[i
]);
481 *bytes
+= Write(fd
, newname
, pte
.len
);
485 for(child
= root
->firstchild
; child
; child
= child
->nextchild
)
487 traversetree(child
, level
+1, littleendian
,
488 maxlevel
, bytes
, fd
, root
->pathtablerecord
,
495 makepathtables(struct node
*root
, int littleendian
, int *bytes
, int fd
)
498 static char block
[ISO_SECTOR
];
505 for(level
= 1; level
<= MAXLEVEL
; level
++)
506 traversetree(root
, 1, littleendian
, level
, bytes
, fd
, 1, &recordno
);
508 if(*bytes
% ISO_SECTOR
) {
510 x
= ISO_SECTOR
-(*bytes
% ISO_SECTOR
);
515 return *bytes
/ISO_SECTOR
;
519 write_direntry(struct node
* n
, char *origname
, int fd
)
521 int namelen
, total
= 0;
523 char copyname
[NAMELEN
];
526 memset(&entry
, 0, sizeof(entry
));
528 if(!strcmp(origname
, CURRENTDIR
)) {
529 entry
.name
[0] = '\000';
531 } else if(!strcmp(origname
, PARENTDIR
)) {
532 entry
.name
[0] = '\001';
536 strlcpy(copyname
, origname
, sizeof(copyname
));
537 namelen
= strlen(copyname
);
539 /* XXX No check for 8+3 ? (DOS compatibility) */
540 assert(ISONAMELEN
<= NAMELEN
-2);
541 if(namelen
> ISONAMELEN
) {
542 fprintf(stderr
, "%s: truncated, too long for iso9660\n", copyname
);
543 namelen
= ISONAMELEN
;
544 copyname
[namelen
] = '\0';
547 strlcpy(entry
.name
, copyname
, namelen
+1);
548 for(i
= 0; i
< namelen
; i
++)
549 entry
.name
[i
] = toupper(entry
.name
[i
]);
551 /* padding byte + system field */
552 entry
.name
[namelen
] = '\0';
553 entry
.name
[namelen
+1] = '\0';
554 entry
.name
[namelen
+2] = '\0';
556 entry
.namelen
= namelen
; /* original length */
557 if(!(namelen
%2)) namelen
++; /* length with padding byte */
560 /* XXX 2 extra bytes for 'system use'.. */
561 entry
.recordsize
= 33 + namelen
;
562 both32((unsigned char *) entry
.datasector
, n
->startsector
);
563 both32((unsigned char *) entry
.filesize
, n
->bytesize
);
565 if(n
->isdir
) entry
.flags
= FLAG_DIR
;
567 memcpy(&tm
, gmtime(&n
->timestamp
), sizeof(tm
));
568 entry
.year
= (unsigned)tm
.tm_year
> 255 ? 255 : tm
.tm_year
;
569 entry
.month
= tm
.tm_mon
+ 1;
570 entry
.day
= tm
.tm_mday
;
571 entry
.hour
= tm
.tm_hour
;
572 entry
.minute
= tm
.tm_min
;
573 entry
.second
= tm
.tm_sec
;
574 entry
.offset
= 0; /* Posix uses UTC timestamps! */
576 both16((unsigned char *) entry
.sequence
, 1);
578 total
= Write(fd
, &entry
.recordsize
, sizeof(entry
.recordsize
));
579 total
+= Write(fd
, &entry
.extended
, sizeof(entry
.extended
));
580 total
+= Write(fd
, entry
.datasector
, sizeof(entry
.datasector
));
581 total
+= Write(fd
, entry
.filesize
, sizeof(entry
.filesize
));
582 total
+= Write(fd
, &entry
.year
, sizeof(entry
.year
));
583 total
+= Write(fd
, &entry
.month
, sizeof(entry
.month
));
584 total
+= Write(fd
, &entry
.day
, sizeof(entry
.day
));
585 total
+= Write(fd
, &entry
.hour
, sizeof(entry
.hour
));
586 total
+= Write(fd
, &entry
.minute
, sizeof(entry
.minute
));
587 total
+= Write(fd
, &entry
.second
, sizeof(entry
.second
));
588 total
+= Write(fd
, &entry
.offset
, sizeof(entry
.offset
));
589 total
+= Write(fd
, &entry
.flags
, sizeof(entry
.flags
));
590 total
+= Write(fd
, &entry
.interleaved
, sizeof(entry
.interleaved
));
591 total
+= Write(fd
, &entry
.interleavegap
, sizeof(entry
.interleavegap
));
592 total
+= Write(fd
, entry
.sequence
, sizeof(entry
.sequence
));
593 total
+= Write(fd
, &entry
.namelen
, sizeof(entry
.namelen
));
594 total
+= Write(fd
, entry
.name
, namelen
);
596 if(total
!= entry
.recordsize
|| (total
% 2) != 0) {
597 printf("%2d, %2d! ", total
, entry
.recordsize
);
598 printf("%3d = %3d - %2d + %2d\n",
599 entry
.recordsize
, sizeof(entry
), sizeof(entry
.name
), namelen
);
602 return entry
.recordsize
;
606 writedata(struct node
*parent
, struct node
*root
,
607 int fd
, int *currentsector
, int dirs
, struct dir
*rootentry
,
608 int rootsize
, int remove_after
)
610 static char buf
[1024*1024];
612 ssize_t written
= 0, rest
;
614 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
615 if(c
->isdir
&& chdir(c
->name
) < 0) {
617 fprintf(stderr
, "couldn't chdir to %s - aborting\n",
621 writedata(root
, c
, fd
, currentsector
, dirs
, rootentry
, rootsize
, remove_after
);
622 if(c
->isdir
&& chdir(PARENTDIR
) < 0) {
623 perror("chdir to ..");
624 fprintf(stderr
, "couldn't chdir to parent - "
630 /* write nodes depth-first, down-top */
632 if(root
->isdir
&& dirs
) {
635 root
->startsector
= *currentsector
;
636 written
+= write_direntry(root
, CURRENTDIR
, fd
);
638 written
+= write_direntry(parent
, PARENTDIR
, fd
);
640 written
+= write_direntry(root
, PARENTDIR
, fd
);
642 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
644 ssize_t written_before
;
645 cur1
= Lseek(fd
, 0, SEEK_CUR
);
646 written_before
= written
;
647 written
+= write_direntry(c
, c
->name
, fd
);
648 cur2
= Lseek(fd
, 0, SEEK_CUR
);
649 if(cur1
/ISO_SECTOR
!= (cur2
-1)/ISO_SECTOR
) {
650 /* passed a sector boundary, argh! */
651 Lseek(fd
, cur1
, SEEK_SET
);
652 written
= written_before
;
653 rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
));
654 memset(buf
, 0, rest
);
655 Write(fd
, buf
, rest
);
657 written
+= write_direntry(c
, c
->name
, fd
);
660 root
->bytesize
= written
;
661 } else if(!root
->isdir
&& !dirs
) {
667 if(stat(root
->name
, &st
) < 0) {
669 fprintf(stderr
, "couldn't stat %s - aborting\n", root
->name
);
673 if((filefd
= open(root
->name
, O_RDONLY
)) < 0) {
675 fprintf(stderr
, "couldn't open %s - aborting\n", root
->name
);
681 root
->startsector
= *currentsector
;
685 chunk
= min(sizeof(buf
), rem
);
686 Read(filefd
, buf
, chunk
);
687 Write(fd
, buf
, chunk
);
693 root
->bytesize
= written
= st
.st_size
;
694 if(remove_after
&& unlink(root
->name
) < 0) {
696 fprintf(stderr
, "couldn't remove %s\n", root
->name
);
699 /* nothing to be done */
703 /* fill out sector with zero bytes */
705 if((rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
)))) {
706 memset(buf
, 0, rest
);
707 Write(fd
, buf
, rest
);
711 /* update dir size with padded size */
713 if(root
->isdir
) { root
->bytesize
= written
; }
715 *currentsector
+= written
/ISO_SECTOR
;
719 writebootcatalog(int fd
, int *currentsector
, int imagesector
, int imagesectors
)
721 static char buf
[ISO_SECTOR
];
722 struct bc_validation validate
;
723 struct bc_initial initial
;
725 ssize_t written
, rest
;
726 u_int16_t
*v
, sum
= 0;
729 /* write validation entry */
731 memset(&validate
, 0, sizeof(validate
));
732 validate
.headerid
= 1;
733 validate
.platform
= PLATFORM_80X86
;
734 strcpy(validate
.idstring
, "");
735 validate
.keys
[0] = 0x55;
736 validate
.keys
[1] = 0xaa;
738 v
= (u_int16_t
*) &validate
;
739 for(i
= 0; i
< sizeof(validate
)/2; i
++)
741 validate
.checksum
= 65535 - sum
+ 1; /* sum must be 0 */
743 written
= Write(fd
, &validate
, sizeof(validate
));
745 /* write initial/default entry */
747 memset(&initial
, 0, sizeof(initial
));
749 initial
.indicator
= INDICATE_BOOTABLE
;
750 initial
.media
= bootmedia
;
751 initial
.seg
= (u_int16_t
) (bootseg
& 0xFFFF);
753 if (bootmedia
== BOOTMEDIA_HARDDISK
)
755 initial
.type
= system_type
;
757 if (bootmedia
== BOOTMEDIA_NONE
)
759 initial
.sectors
= imagesectors
;
761 initial
.startsector
= imagesector
;
763 written
+= Write(fd
, &initial
, sizeof(initial
));
765 /* fill out the rest of the sector with 0's */
767 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
768 memset(buf
, 0, sizeof(buf
));
769 written
+= Write(fd
, buf
, rest
);
772 (*currentsector
) += written
/ ISO_SECTOR
;
778 writebootimage(char *bootimage
, int bootfd
, int fd
, int *currentsector
,
779 char *appendsectorinfo
, struct node
*root
)
781 static unsigned char buf
[1024*64], *addr
;
782 ssize_t written
= 0, rest
;
790 bap
[0].length
= bap
[0].sector
= 0;
791 bap
[1].length
= bap
[1].sector
= 0;
793 if (fstat(bootfd
, &sb
) < 0) {
794 perror("stat boot image");
802 want
= rem
< sizeof(buf
) ? rem
: sizeof(buf
);
803 Read(bootfd
, buf
, want
);
805 /* check some properties at beginning. */
806 if (buf
[0] == 1 && buf
[1] == 3) {
807 fprintf(stderr
, "boot image %s is an a.out executable\n",
811 if (rem
>= VIRTUAL_SECTOR
812 && (buf
[510] != 0x55 || buf
[511] != 0xaa) ) {
813 fprintf(stderr
, "invalid boot sector (bad magic.)\n");
817 written
+= Write(fd
, buf
, want
);
821 if(appendsectorinfo
) {
823 for(n
= root
->firstchild
; n
; n
= n
->nextchild
) {
824 if(!strcasecmp(appendsectorinfo
, n
->name
)) {
825 bap
[0].sector
= n
->startsector
;
826 bap
[0].length
= ROUNDUP(n
->bytesize
, ISO_SECTOR
);
831 fprintf(stderr
, "%s not found in root.\n",
836 fprintf(stderr
, " * appended sector info: 0x%x len 0x%x\n",
837 bap
[0].sector
, bap
[0].length
);
840 addr
[0] = bap
[0].length
;
842 addr
[1] = (bap
[0].sector
>> 0) & 0xFF;
843 addr
[2] = (bap
[0].sector
>> 8) & 0xFF;
844 addr
[3] = (bap
[0].sector
>> 16) & 0xFF;
848 written
+= Write(fd
, addr
, 6);
851 virtuals
= ROUNDUP(written
, VIRTUAL_SECTOR
);
852 assert(virtuals
* VIRTUAL_SECTOR
>= written
);
854 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
855 memset(buf
, 0, sizeof(buf
));
856 written
+= Write(fd
, buf
, rest
);
859 (*currentsector
) += written
/ISO_SECTOR
;
865 writebootrecord(int fd
, int *currentsector
, int bootcatalogsector
)
868 static struct bootrecord bootrecord
;
870 /* boot record volume descriptor */
872 memset(&bootrecord
, 0, sizeof(bootrecord
));
873 bootrecord
.set
[0] = 'C';
874 bootrecord
.set
[1] = 'D';
875 bootrecord
.set
[2] = '0';
876 bootrecord
.set
[3] = '0';
877 bootrecord
.set
[4] = '1';
878 bootrecord
.version
= 1;
879 bootrecord
.bootcatalog
= bootcatalogsector
;
880 strcpy(bootrecord
.ident
, "EL TORITO SPECIFICATION");
881 for(i
= strlen(bootrecord
.ident
);
882 i
< sizeof(bootrecord
.ident
); i
++)
883 bootrecord
.ident
[i
] = '\0';
885 w
= Writefield(fd
, bootrecord
.indicator
);
886 w
+= Writefield(fd
, bootrecord
.set
);
887 w
+= Writefield(fd
, bootrecord
.version
);
888 w
+= Writefield(fd
, bootrecord
.ident
);
889 w
+= Writefield(fd
, bootrecord
.zero
);
890 w
+= Writefield(fd
, bootrecord
.bootcatalog
);
891 w
+= Writefield(fd
, bootrecord
.zero2
);
893 if(w
!= ISO_SECTOR
) {
894 fprintf(stderr
, "WARNING: something went wrong - boot record (%d) isn't a sector size (%d)\n",
902 main(int argc
, char *argv
[])
904 int currentsector
= 0;
905 int imagesector
, imagesectors
;
906 int bootfd
, fd
, i
, ch
, nsectors
;
907 int remove_after
= 0;
908 static char block
[ISO_SECTOR
];
909 static struct pvd pvd
;
910 char *label
= "ISO9660";
913 char timestr
[20], *prog
;
914 char *bootimage
= NULL
;
917 int bigpath
, littlepath
, pathbytes
= 0, dirsector
, filesector
, enddir
;
918 int bootvolumesector
, bootcatalogsector
;
919 char *appendsectorinfo
= NULL
;
923 /* This check is to prevent compiler padding screwing up
927 if(sizeof(struct pvd
) != ISO_SECTOR
) {
928 fprintf(stderr
, "Something confusing happened at\n"
929 "compile-time; pvd should be a sector size. %d != %d\n",
930 sizeof(struct pvd
), ISO_SECTOR
);
934 while ((ch
= getopt(argc
, argv
, "a:b:B:s:Rb:hl:nfF")) != -1) {
937 if(optarg
[0] != '0' || optarg
[1] != 'x') {
938 fprintf(stderr
, "%s: -s<hex>\n",
942 bootseg
= strtoul(optarg
+2, NULL
, 16);
945 bootmedia
= BOOTMEDIA_HARDDISK
;
948 bootmedia
= BOOTMEDIA_NONE
;
951 bootmedia
= BOOTMEDIA_1440K
;
954 bootmedia
= BOOTMEDIA_2880K
;
957 if(!(appendsectorinfo
= strdup(optarg
)))
968 if((bootfd
= open(bootimage
, O_RDONLY
)) < 0) {
982 fprintf(stderr
, "usage: %s [-l <label>] [-(b|B) <bootimage> [-n|-f|-F|-h] [-s <bootsegment>] [ -a <appendfile> ] <dir> <isofile>\n",
987 if((bootimage
&& bootmedia
== BOOTMEDIA_UNSPECIFIED
) ||
988 (!bootimage
&& bootmedia
!= BOOTMEDIA_UNSPECIFIED
)) {
989 fprintf(stderr
, "%s: provide both boot image and boot type or neither.\n",
994 if(!bootimage
&& bootseg
) {
995 fprintf(stderr
, "%s: boot seg provided but no boot image\n",
1000 if(appendsectorinfo
) {
1001 if(!bootimage
|| bootmedia
!= BOOTMEDIA_NONE
) {
1002 fprintf(stderr
, "%s: append sector info where?\n",
1008 /* create .iso file */
1010 if((fd
=open(argv
[1], O_WRONLY
| O_TRUNC
| O_CREAT
, 0600)) < 0) {
1015 /* go to where the iso has to be made from */
1017 if(chdir(argv
[0]) < 0) {
1022 /* collect dirs and files */
1024 fprintf(stderr
, " * traversing input tree\n");
1026 maketree(&root
, "", 1);
1028 fprintf(stderr
, " * writing initial zeroes and pvd\n");
1030 /* first sixteen sectors are zero */
1032 memset(block
, 0, sizeof(block
));
1034 for(i
= 0; i
< 16; i
++)
1035 writesector(fd
, block
, ¤tsector
);
1037 /* Primary Volume Descriptor */
1038 memset(&pvd
, 0, sizeof(pvd
));
1048 strncpy(pvd
.volume
, label
, sizeof(pvd
.volume
)-1);
1049 for(i
= strlen(pvd
.volume
); i
< sizeof(pvd
.volume
); i
++)
1050 pvd
.volume
[i
] = ' ';
1051 for(i
= 0; i
< sizeof(pvd
.system
); i
++)
1052 pvd
.system
[i
] = ' ';
1054 both16((unsigned char *) pvd
.setsize
, 1);
1055 both16((unsigned char *) pvd
.seq
, 1);
1056 both16((unsigned char *) pvd
.sectorsize
, ISO_SECTOR
);
1058 /* fill time fields */
1060 now
= gmtime(&nowtime
);
1061 strftime(timestr
, sizeof(timestr
), "%Y%m%d%H%M%S000", now
);
1062 memcpy(pvd
.create
, timestr
, strlen(timestr
));
1063 memcpy(pvd
.modified
, timestr
, strlen(timestr
));
1064 memcpy(pvd
.effective
, timestr
, strlen(timestr
));
1065 strcpy(pvd
.expiry
, "0000000000000000"); /* not specified */
1066 pvdsector
= currentsector
;
1068 writesector(fd
, (char *) &pvd
, ¤tsector
);
1071 fprintf(stderr
, " * writing boot record volume descriptor\n");
1072 bootvolumesector
= currentsector
;
1073 writebootrecord(fd
, ¤tsector
, 0);
1076 /* volume descriptor set terminator */
1077 memset(block
, 0, sizeof(block
));
1086 writesector(fd
, block
, ¤tsector
);
1089 /* write the boot catalog */
1090 fprintf(stderr
, " * writing the boot catalog\n");
1091 bootcatalogsector
= currentsector
;
1092 if (bootmedia
== BOOTMEDIA_HARDDISK
)
1093 system_type
= get_system_type(bootfd
);
1094 writebootcatalog(fd
, ¤tsector
, 0, 0);
1096 /* write boot image */
1097 fprintf(stderr
, " * writing the boot image\n");
1098 imagesector
= currentsector
;
1099 imagesectors
= writebootimage(bootimage
, bootfd
,
1100 fd
, ¤tsector
, NULL
, &root
);
1101 fprintf(stderr
, " * image: %d %d-byte sectors @ cd sector 0x%x\n",
1102 imagesectors
, VIRTUAL_SECTOR
, imagesector
);
1105 /* write out all the file data */
1107 filesector
= currentsector
;
1108 fprintf(stderr
, " * writing file data\n");
1109 writedata(NULL
, &root
, fd
, ¤tsector
, 0,
1110 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1113 /* write out all the dir data */
1115 dirsector
= currentsector
;
1116 fprintf(stderr
, " * writing dir data\n");
1117 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1118 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1120 enddir
= currentsector
;
1121 seeksector(fd
, dirsector
, ¤tsector
);
1122 fprintf(stderr
, " * rewriting dir data\n");
1124 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1125 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1127 if(currentsector
!= enddir
) {
1128 fprintf(stderr
, "warning: inconsistent directories - "
1129 "I have a bug! iso may be broken.\n");
1132 /* now write the path table in both formats */
1134 fprintf(stderr
, " * writing big-endian path table\n");
1135 bigpath
= currentsector
;
1136 currentsector
+= makepathtables(&root
, 0, &pathbytes
, fd
);
1138 fprintf(stderr
, " * writing little-endian path table\n");
1139 littlepath
= currentsector
;
1140 currentsector
+= makepathtables(&root
, 1, &pathbytes
, fd
);
1142 both32((unsigned char *) pvd
.pathtablesize
, pathbytes
);
1143 little32((unsigned char *) &pvd
.first_little_pathtable_start
, littlepath
);
1144 big32((unsigned char *) &pvd
.first_big_pathtable_start
, bigpath
);
1146 /* this is the size of the iso filesystem for use in the pvd later */
1148 nsectors
= currentsector
;
1149 both32((unsigned char *) pvd
.sectors
, nsectors
);
1151 /* *********** Filesystem writing done ************************* */
1153 /* finish and rewrite the pvd. */
1154 fprintf(stderr
, " * rewriting pvd\n");
1155 seekwritesector(fd
, pvdsector
, (char *) &pvd
, ¤tsector
);
1157 /* write root dir entry in pvd */
1158 seeksector(fd
, pvdsector
, ¤tsector
);
1159 Lseek(fd
, (int)((char *) &pvd
.rootrecord
- (char *) &pvd
), SEEK_CUR
);
1160 if(write_direntry(&root
, CURRENTDIR
, fd
) > sizeof(pvd
.rootrecord
)) {
1161 fprintf(stderr
, "warning: unexpectedly large root record\n");
1165 fprintf(stderr
, " * rewriting boot catalog\n");
1166 seeksector(fd
, bootcatalogsector
, ¤tsector
);
1167 writebootcatalog(fd
, ¤tsector
, imagesector
, imagesectors
);
1169 /* finish and rewrite the boot record volume descriptor */
1170 fprintf(stderr
, " * rewriting the boot rvd\n");
1171 seeksector(fd
, bootvolumesector
, ¤tsector
);
1172 writebootrecord(fd
, ¤tsector
, bootcatalogsector
);
1174 if(appendsectorinfo
) {
1175 Lseek(bootfd
, 0, SEEK_SET
);
1176 fprintf(stderr
, " * rewriting boot image\n");
1177 seeksector(fd
, imagesector
, ¤tsector
);
1178 writebootimage(bootimage
, bootfd
,
1179 fd
, ¤tsector
, appendsectorinfo
, &root
);
1185 fprintf(stderr
, " * all ok\n");
1190 int get_system_type(int fd
)
1196 struct part_entry
*partp
;
1197 unsigned char bootsector
[512];
1200 old_pos
= lseek(fd
, 0, SEEK_SET
);
1201 if (old_pos
== -1 && errno
!= 0)
1203 fprintf(stderr
, "bootimage file is not seekable: %s\n",
1207 size
= sizeof(bootsector
);
1208 r
= read(fd
, bootsector
, size
);
1211 fprintf(stderr
, "error reading bootimage file: %s\n",
1212 r
< 0 ? strerror(errno
) : "unexpected EOF");
1215 if (bootsector
[size
-2] != 0x55 && bootsector
[size
-1] != 0xAA)
1217 fprintf(stderr
, "bad magic in bootimage file\n");
1221 partp
= (struct part_entry
*)&bootsector
[PART_TABLE_OFF
];
1222 type
= partp
->sysind
;
1223 if (type
== NO_PART
)
1225 fprintf(stderr
, "first partition table entry is unused\n");
1228 if (!(partp
->bootind
& ACTIVE_FLAG
))
1230 fprintf(stderr
, "first partition table entry is not active\n");
1234 lseek(fd
, old_pos
, SEEK_SET
);