2 /* writeisofs - simple ISO9660-format-image writing utility */
15 #include <machine/partition.h>
19 #define Writefield(fd, f) Write(fd, &(f), sizeof(f))
25 typedef unsigned char u_int8_t
;
26 typedef unsigned short int u_int16_t
;
27 typedef unsigned long int u_int32_t
;
31 #define min(a,b) ((a) < (b) ? (a) : (b))
36 #include <sys/types.h>
39 #define NAMELEN (NAME_MAX+5)
40 #define ISONAMELEN 12 /* XXX could easily be 31 */
41 #define PLATFORM_80X86 0
43 #define ISO_SECTOR 2048
44 #define VIRTUAL_SECTOR 512
45 #define ROUNDUP(v, n) (((v)+(n)-1)/(n))
47 #define CURRENTDIR "."
48 #define PARENTDIR ".."
50 /* *** CD (disk) data structures ********************* */
52 /* primary volume descriptor */
65 u_int16_t sectorsize
[2];
66 u_int32_t pathtablesize
[2];
67 u_int32_t first_little_pathtable_start
;
68 u_int32_t second_little_pathtable_start
;
69 u_int32_t first_big_pathtable_start
;
70 u_int32_t second_big_pathtable_start
;
71 u_int8_t rootrecord
[34];
72 u_int8_t volumeset
[128];
73 u_int8_t publisher
[128];
74 u_int8_t preparer
[128];
75 u_int8_t application
[128];
76 u_int8_t copyrightfile
[37];
77 u_int8_t abstractfile
[37];
78 u_int8_t bibliofile
[37];
80 u_int8_t modified
[17];
82 u_int8_t effective
[17];
85 u_int8_t zeroes3
[512];
86 u_int8_t zeroes4
[653];
89 /* boot record volume descriptor */
92 u_int8_t indicator
; /* 0 */
93 char set
[5]; /* "CD001" */
94 u_int8_t version
; /* 1 */
95 char ident
[32]; /* "EL TORITO SPECIFICATION" */
96 u_int8_t zero
[32]; /* unused, must be 0 */
97 u_int32_t bootcatalog
; /* starting sector of boot catalog */
98 u_int8_t zero2
[1973]; /* unused, must be 0 */
101 /* boot catalog validation entry */
103 struct bc_validation
{
104 u_int8_t headerid
; /* 1 */
105 u_int8_t platform
; /* 0: 80x86; 1: powerpc; 2: mac */
106 u_int8_t zero
[2]; /* unused, must be 0 */
107 char idstring
[24]; /* id string */
109 u_int8_t keys
[2]; /* 0x55AA */
112 /* boot catalog initial/default entry */
114 #define INDICATE_BOOTABLE 0x88
116 #define BOOTMEDIA_UNSPECIFIED -1
117 #define BOOTMEDIA_NONE 0
118 #define BOOTMEDIA_1200K 1
119 #define BOOTMEDIA_1440K 2
120 #define BOOTMEDIA_2880K 3
121 #define BOOTMEDIA_HARDDISK 4
124 u_int8_t indicator
; /* INDICATE_BOOTABLE */
125 u_int8_t media
; /* BOOTMEDIA_* */
126 u_int16_t seg
; /* load segment or 0 for default */
127 u_int8_t type
; /* system type (from part. table) */
130 u_int32_t startsector
;
134 /* directory entry */
139 u_int32_t datasector
[2];
140 u_int32_t filesize
[2];
149 u_int8_t interleaved
;
150 u_int8_t interleavegap
;
151 u_int16_t sequence
[2];
156 /* *** program (memory) data structures ********************* */
163 struct node
*firstchild
, *nextchild
;
165 /* filled out at i/o time */
166 u_int32_t startsector
, bytesize
;
169 int n_reserved_pathtableentries
= 0, n_used_pathtableentries
= 0;
170 int bootmedia
= BOOTMEDIA_UNSPECIFIED
;
171 unsigned long bootseg
= 0;
173 int bootimage_is_aout
= 0;
175 int get_system_type(int fd
);
178 Write(int fd
, void *buf
, ssize_t len
)
181 if((r
=write(fd
, buf
, len
)) != len
) {
182 if(r
< 0) { perror("write"); }
183 fprintf(stderr
, "failed or short write - aborting.\n");
190 Lseek(int fd
, off_t pos
, int rel
)
194 if((r
=lseek(fd
, pos
, rel
)) < 0) {
196 fprintf(stderr
, "lseek failed - aborting.\n");
204 writesector(int fd
, char *block
, int *currentsector
)
206 Write(fd
, block
, ISO_SECTOR
);
212 seeksector(int fd
, int sector
, int *currentsector
)
214 Lseek(fd
, sector
*ISO_SECTOR
, SEEK_SET
);
215 *currentsector
= sector
;
219 seekwritesector(int fd
, int sector
, char *block
, int *currentsector
)
221 seeksector(fd
, sector
, currentsector
);
222 writesector(fd
, block
, currentsector
);
226 Read(int fd
, void *buf
, ssize_t len
)
229 if((r
=read(fd
, buf
, len
)) != len
) {
230 if(r
< 0) { perror("read"); }
231 fprintf(stderr
, "failed or short read.\n");
238 void both16(unsigned char *both
, unsigned short i16
)
240 unsigned char *little
, *big
;
245 little
[0] = big
[1] = i16
& 0xFF;
246 little
[1] = big
[0] = (i16
>> 8) & 0xFF;
249 void both32(unsigned char *both
, unsigned long i32
)
251 unsigned char *little
, *big
;
256 little
[0] = big
[3] = i32
& 0xFF;
257 little
[1] = big
[2] = (i32
>> 8) & 0xFF;
258 little
[2] = big
[1] = (i32
>> 16) & 0xFF;
259 little
[3] = big
[0] = (i32
>> 24) & 0xFF;
267 static int cmpf(const void *v1
, const void *v2
)
269 struct node
*n1
, *n2
;
271 char f1
[NAMELEN
], f2
[NAMELEN
];
273 n1
= (struct node
*) v1
;
274 n2
= (struct node
*) v2
;
275 strcpy(f1
, n1
->name
);
276 strcpy(f2
, n2
->name
);
277 for(i
= 0; i
< strlen(f1
); i
++) f1
[i
] = toupper(f1
[i
]);
278 for(i
= 0; i
< strlen(f2
); i
++) f2
[i
] = toupper(f2
[i
]);
281 return -strcmp(f1
, f2
);
285 maketree(struct node
*thisdir
, char *name
, int level
)
289 struct node
*dirnodes
= NULL
;
290 int reserved_dirnodes
= 0, used_dirnodes
= 0;
293 thisdir
->firstchild
= NULL
;
295 thisdir
->startsector
= 0xdeadbeef;
297 if(level
>= MAXLEVEL
) {
298 fprintf(stderr
, "ignoring entries in %s (too deep for iso9660)\n",
303 if(!(dir
= opendir(CURRENTDIR
))) {
308 /* how many entries do we need to allocate? */
309 while(readdir(dir
)) reserved_dirnodes
++;
310 if(!reserved_dirnodes
) {
315 if(!(dirnodes
= malloc(sizeof(*dirnodes
)*reserved_dirnodes
))) {
316 fprintf(stderr
, "couldn't allocate dirnodes (%d bytes)\n",
317 sizeof(*dirnodes
)*reserved_dirnodes
);
322 /* remember all entries in this dir */
326 while((e
=readdir(dir
))) {
329 if(!strcmp(e
->d_name
, CURRENTDIR
) || !strcmp(e
->d_name
, PARENTDIR
))
331 if(stat(e
->d_name
, &st
) < 0) {
333 fprintf(stderr
, "failed to stat file/dir\n");
337 type
= st
.st_mode
& S_IFMT
;
340 printf("%s type: %x dir: %x file: %x\n",
341 e->d_name, type, S_IFDIR, S_IFREG);
343 if(type
!= S_IFDIR
&& type
!= S_IFREG
)
347 if(used_dirnodes
> reserved_dirnodes
) {
348 fprintf(stderr
, "huh, directory entries appeared "
349 "(not enough pre-allocated nodes; this can't happen) ?\n");
353 if(type
== S_IFDIR
) {
357 child
->firstchild
= NULL
;
359 strlcpy(child
->name
, e
->d_name
, sizeof(child
->name
));
360 child
->timestamp
= st
.st_mtime
;
370 if(!(dirnodes
=realloc(dirnodes
, used_dirnodes
*sizeof(*dirnodes
)))) {
371 fprintf(stderr
, "realloc() of dirnodes failed - aborting\n");
375 qsort(dirnodes
, used_dirnodes
, sizeof(*dirnodes
), cmpf
);
379 while(used_dirnodes
--) {
380 child
->nextchild
= thisdir
->firstchild
;
381 thisdir
->firstchild
= child
;
383 if(chdir(child
->name
) < 0) {
386 maketree(child
, child
->name
, level
+1);
387 if(chdir(PARENTDIR
) < 0) {
388 perror("chdir() failed");
389 fprintf(stderr
, "couldn't chdir() to parent, aborting\n");
401 little32(unsigned char *dest
, u_int32_t src
)
403 dest
[0] = ((src
>> 0) & 0xFF);
404 dest
[1] = ((src
>> 8) & 0xFF);
405 dest
[2] = ((src
>> 16) & 0xFF);
406 dest
[3] = ((src
>> 24) & 0xFF);
412 little16(unsigned char *dest
, u_int16_t src
)
414 dest
[0] = ((src
>> 0) & 0xFF);
415 dest
[1] = ((src
>> 8) & 0xFF);
421 big32(unsigned char *dest
, u_int32_t src
)
423 dest
[3] = ((src
>> 0) & 0xFF);
424 dest
[2] = ((src
>> 8) & 0xFF);
425 dest
[1] = ((src
>> 16) & 0xFF);
426 dest
[0] = ((src
>> 24) & 0xFF);
431 big16(unsigned char *dest
, u_int16_t src
)
433 dest
[1] = ((src
>> 0) & 0xFF);
434 dest
[0] = ((src
>> 8) & 0xFF);
440 traversetree(struct node
*root
, int level
, int littleendian
,
441 int maxlevel
, int *bytes
, int fd
, int parentrecord
, int *recordno
)
447 u_int32_t startsector
;
451 if(level
== maxlevel
) {
453 char newname
[NAMELEN
];
461 root
->name
[0] = root
->name
[1] = '\0';
463 pte
.len
= strlen(root
->name
);
464 pte
.parent
= parentrecord
;
466 pte
.startsector
= root
->startsector
;
467 root
->pathtablerecord
= (*recordno
)++;
470 little32((unsigned char *) &pte
.startsector
, pte
.startsector
);
471 little16((unsigned char *) &pte
.parent
, pte
.parent
);
473 big32((unsigned char *) &pte
.startsector
, pte
.startsector
);
474 big16((unsigned char *) &pte
.parent
, pte
.parent
);
477 *bytes
+= Write(fd
, &pte
.len
, sizeof(pte
.len
));
478 *bytes
+= Write(fd
, &pte
.zero
, sizeof(pte
.zero
));
479 *bytes
+= Write(fd
, &pte
.startsector
, sizeof(pte
.startsector
));
480 *bytes
+= Write(fd
, &pte
.parent
, sizeof(pte
.parent
));
482 root
->name
[pte
.len
++] = '\0';
483 for(i
= 0; i
< pte
.len
; i
++)
484 newname
[i
] = toupper(root
->name
[i
]);
485 *bytes
+= Write(fd
, newname
, pte
.len
);
489 for(child
= root
->firstchild
; child
; child
= child
->nextchild
)
491 traversetree(child
, level
+1, littleendian
,
492 maxlevel
, bytes
, fd
, root
->pathtablerecord
,
499 makepathtables(struct node
*root
, int littleendian
, int *bytes
, int fd
)
502 static char block
[ISO_SECTOR
];
509 for(level
= 1; level
<= MAXLEVEL
; level
++)
510 traversetree(root
, 1, littleendian
, level
, bytes
, fd
, 1, &recordno
);
512 if(*bytes
% ISO_SECTOR
) {
514 x
= ISO_SECTOR
-(*bytes
% ISO_SECTOR
);
519 return *bytes
/ISO_SECTOR
;
523 write_direntry(struct node
* n
, char *origname
, int fd
)
525 int namelen
, total
= 0;
527 char copyname
[NAMELEN
];
530 memset(&entry
, 0, sizeof(entry
));
532 if(!strcmp(origname
, CURRENTDIR
)) {
533 entry
.name
[0] = '\000';
535 } else if(!strcmp(origname
, PARENTDIR
)) {
536 entry
.name
[0] = '\001';
540 strlcpy(copyname
, origname
, sizeof(copyname
));
541 namelen
= strlen(copyname
);
543 /* XXX No check for 8+3 ? (DOS compatibility) */
544 assert(ISONAMELEN
<= NAMELEN
-2);
545 if(namelen
> ISONAMELEN
) {
546 fprintf(stderr
, "%s: truncated, too long for iso9660\n", copyname
);
547 namelen
= ISONAMELEN
;
548 copyname
[namelen
] = '\0';
551 strlcpy(entry
.name
, copyname
, namelen
+1);
552 for(i
= 0; i
< namelen
; i
++)
553 entry
.name
[i
] = toupper(entry
.name
[i
]);
555 /* padding byte + system field */
556 entry
.name
[namelen
] = '\0';
557 entry
.name
[namelen
+1] = '\0';
558 entry
.name
[namelen
+2] = '\0';
560 entry
.namelen
= namelen
; /* original length */
561 if(!(namelen
%2)) namelen
++; /* length with padding byte */
564 /* XXX 2 extra bytes for 'system use'.. */
565 entry
.recordsize
= 33 + namelen
;
566 both32((unsigned char *) entry
.datasector
, n
->startsector
);
567 both32((unsigned char *) entry
.filesize
, n
->bytesize
);
569 if(n
->isdir
) entry
.flags
= FLAG_DIR
;
571 memcpy(&tm
, gmtime(&n
->timestamp
), sizeof(tm
));
572 entry
.year
= (unsigned)tm
.tm_year
> 255 ? 255 : tm
.tm_year
;
573 entry
.month
= tm
.tm_mon
+ 1;
574 entry
.day
= tm
.tm_mday
;
575 entry
.hour
= tm
.tm_hour
;
576 entry
.minute
= tm
.tm_min
;
577 entry
.second
= tm
.tm_sec
;
578 entry
.offset
= 0; /* Posix uses UTC timestamps! */
580 both16((unsigned char *) entry
.sequence
, 1);
582 total
= Write(fd
, &entry
.recordsize
, sizeof(entry
.recordsize
));
583 total
+= Write(fd
, &entry
.extended
, sizeof(entry
.extended
));
584 total
+= Write(fd
, entry
.datasector
, sizeof(entry
.datasector
));
585 total
+= Write(fd
, entry
.filesize
, sizeof(entry
.filesize
));
586 total
+= Write(fd
, &entry
.year
, sizeof(entry
.year
));
587 total
+= Write(fd
, &entry
.month
, sizeof(entry
.month
));
588 total
+= Write(fd
, &entry
.day
, sizeof(entry
.day
));
589 total
+= Write(fd
, &entry
.hour
, sizeof(entry
.hour
));
590 total
+= Write(fd
, &entry
.minute
, sizeof(entry
.minute
));
591 total
+= Write(fd
, &entry
.second
, sizeof(entry
.second
));
592 total
+= Write(fd
, &entry
.offset
, sizeof(entry
.offset
));
593 total
+= Write(fd
, &entry
.flags
, sizeof(entry
.flags
));
594 total
+= Write(fd
, &entry
.interleaved
, sizeof(entry
.interleaved
));
595 total
+= Write(fd
, &entry
.interleavegap
, sizeof(entry
.interleavegap
));
596 total
+= Write(fd
, entry
.sequence
, sizeof(entry
.sequence
));
597 total
+= Write(fd
, &entry
.namelen
, sizeof(entry
.namelen
));
598 total
+= Write(fd
, entry
.name
, namelen
);
600 if(total
!= entry
.recordsize
|| (total
% 2) != 0) {
601 printf("%2d, %2d! ", total
, entry
.recordsize
);
602 printf("%3d = %3d - %2d + %2d\n",
603 entry
.recordsize
, sizeof(entry
), sizeof(entry
.name
), namelen
);
606 return entry
.recordsize
;
610 writedata(struct node
*parent
, struct node
*root
,
611 int fd
, int *currentsector
, int dirs
, struct dir
*rootentry
,
612 int rootsize
, int remove_after
)
614 static char buf
[1024*1024];
616 ssize_t written
= 0, rest
;
618 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
619 if(c
->isdir
&& chdir(c
->name
) < 0) {
621 fprintf(stderr
, "couldn't chdir to %s - aborting\n",
625 writedata(root
, c
, fd
, currentsector
, dirs
, rootentry
, rootsize
, remove_after
);
626 if(c
->isdir
&& chdir(PARENTDIR
) < 0) {
627 perror("chdir to ..");
628 fprintf(stderr
, "couldn't chdir to parent - "
634 /* write nodes depth-first, down-top */
636 if(root
->isdir
&& dirs
) {
639 root
->startsector
= *currentsector
;
640 written
+= write_direntry(root
, CURRENTDIR
, fd
);
642 written
+= write_direntry(parent
, PARENTDIR
, fd
);
644 written
+= write_direntry(root
, PARENTDIR
, fd
);
646 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
648 ssize_t written_before
;
649 cur1
= Lseek(fd
, 0, SEEK_CUR
);
650 written_before
= written
;
651 written
+= write_direntry(c
, c
->name
, fd
);
652 cur2
= Lseek(fd
, 0, SEEK_CUR
);
653 if(cur1
/ISO_SECTOR
!= (cur2
-1)/ISO_SECTOR
) {
654 /* passed a sector boundary, argh! */
655 Lseek(fd
, cur1
, SEEK_SET
);
656 written
= written_before
;
657 rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
));
658 memset(buf
, 0, rest
);
659 Write(fd
, buf
, rest
);
661 written
+= write_direntry(c
, c
->name
, fd
);
664 root
->bytesize
= written
;
665 } else if(!root
->isdir
&& !dirs
) {
671 if(stat(root
->name
, &st
) < 0) {
673 fprintf(stderr
, "couldn't stat %s - aborting\n", root
->name
);
677 if((filefd
= open(root
->name
, O_RDONLY
)) < 0) {
679 fprintf(stderr
, "couldn't open %s - aborting\n", root
->name
);
685 root
->startsector
= *currentsector
;
689 chunk
= min(sizeof(buf
), rem
);
690 Read(filefd
, buf
, chunk
);
691 Write(fd
, buf
, chunk
);
697 root
->bytesize
= written
= st
.st_size
;
698 if(remove_after
&& unlink(root
->name
) < 0) {
700 fprintf(stderr
, "couldn't remove %s\n", root
->name
);
703 /* nothing to be done */
707 /* fill out sector with zero bytes */
709 if((rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
)))) {
710 memset(buf
, 0, rest
);
711 Write(fd
, buf
, rest
);
715 /* update dir size with padded size */
717 if(root
->isdir
) { root
->bytesize
= written
; }
719 *currentsector
+= written
/ISO_SECTOR
;
723 writebootcatalog(int fd
, int *currentsector
, int imagesector
, int imagesectors
)
725 static char buf
[ISO_SECTOR
];
726 struct bc_validation validate
;
727 struct bc_initial initial
;
729 ssize_t written
, rest
;
730 u_int16_t
*v
, sum
= 0;
733 /* write validation entry */
735 memset(&validate
, 0, sizeof(validate
));
736 validate
.headerid
= 1;
737 validate
.platform
= PLATFORM_80X86
;
738 strcpy(validate
.idstring
, "");
739 validate
.keys
[0] = 0x55;
740 validate
.keys
[1] = 0xaa;
742 v
= (u_int16_t
*) &validate
;
743 for(i
= 0; i
< sizeof(validate
)/2; i
++)
745 validate
.checksum
= 65535 - sum
+ 1; /* sum must be 0 */
747 written
= Write(fd
, &validate
, sizeof(validate
));
749 /* write initial/default entry */
751 memset(&initial
, 0, sizeof(initial
));
753 initial
.indicator
= INDICATE_BOOTABLE
;
754 initial
.media
= bootmedia
;
755 initial
.seg
= (u_int16_t
) (bootseg
& 0xFFFF);
757 if (bootmedia
== BOOTMEDIA_HARDDISK
)
759 initial
.type
= system_type
;
761 if (bootmedia
== BOOTMEDIA_NONE
)
763 initial
.sectors
= imagesectors
;
765 initial
.startsector
= imagesector
;
767 written
+= Write(fd
, &initial
, sizeof(initial
));
769 /* fill out the rest of the sector with 0's */
771 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
772 memset(buf
, 0, sizeof(buf
));
773 written
+= Write(fd
, buf
, rest
);
776 (*currentsector
) += written
/ ISO_SECTOR
;
782 writebootimage(char *bootimage
, int bootfd
, int fd
, int *currentsector
,
783 char *appendsectorinfo
, struct node
*root
)
785 static unsigned char buf
[1024*64], *addr
;
786 ssize_t written
= 0, rest
;
795 bap
[0].length
= bap
[0].sector
= 0;
796 bap
[1].length
= bap
[1].sector
= 0;
798 if (fstat(bootfd
, &sb
) < 0) {
799 perror("stat boot image");
803 if (bootimage_is_aout
) {
804 Read(bootfd
, &hdr
, A_MINHDR
);
806 if(hdr
.a_magic
[0] != A_MAGIC0
) {
807 fprintf(stderr
, "bad magic in a.out of boot image.\n");
811 if(hdr
.a_hdrlen
> sizeof(hdr
)) {
812 fprintf(stderr
, "surprisingly large header in boot image.\n");
816 /* read rest of a.out header. */
817 Read(bootfd
, (char *) &hdr
+ A_MINHDR
, hdr
.a_hdrlen
- A_MINHDR
);
820 rem
= hdr
.a_text
+ hdr
.a_data
;
826 want
= rem
< sizeof(buf
) ? rem
: sizeof(buf
);
827 Read(bootfd
, buf
, want
);
829 /* check some properties at beginning. */
830 if (!bootimage_is_aout
&& buf
[0] == 1 && buf
[1] == 3) {
831 fprintf(stderr
, "boot image %s is an a.out executable\n",
835 if (rem
>= VIRTUAL_SECTOR
836 && (buf
[510] != 0x55 || buf
[511] != 0xaa) ) {
837 fprintf(stderr
, "invalid boot sector (bad magic.)\n");
841 written
+= Write(fd
, buf
, want
);
845 if(appendsectorinfo
) {
847 for(n
= root
->firstchild
; n
; n
= n
->nextchild
) {
848 if(!strcasecmp(appendsectorinfo
, n
->name
)) {
849 bap
[0].sector
= n
->startsector
;
850 bap
[0].length
= ROUNDUP(n
->bytesize
, ISO_SECTOR
);
855 fprintf(stderr
, "%s not found in root.\n",
860 fprintf(stderr
, " * appended sector info: 0x%lx len 0x%x\n",
861 bap
[0].sector
, bap
[0].length
);
864 addr
[0] = bap
[0].length
;
866 addr
[1] = (bap
[0].sector
>> 0) & 0xFF;
867 addr
[2] = (bap
[0].sector
>> 8) & 0xFF;
868 addr
[3] = (bap
[0].sector
>> 16) & 0xFF;
872 written
+= Write(fd
, addr
, 6);
875 virtuals
= ROUNDUP(written
, VIRTUAL_SECTOR
);
876 assert(virtuals
* VIRTUAL_SECTOR
>= written
);
878 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
879 memset(buf
, 0, sizeof(buf
));
880 written
+= Write(fd
, buf
, rest
);
883 (*currentsector
) += written
/ISO_SECTOR
;
889 writebootrecord(int fd
, int *currentsector
, int bootcatalogsector
)
892 static struct bootrecord bootrecord
;
894 /* boot record volume descriptor */
896 memset(&bootrecord
, 0, sizeof(bootrecord
));
897 bootrecord
.set
[0] = 'C';
898 bootrecord
.set
[1] = 'D';
899 bootrecord
.set
[2] = '0';
900 bootrecord
.set
[3] = '0';
901 bootrecord
.set
[4] = '1';
902 bootrecord
.version
= 1;
903 bootrecord
.bootcatalog
= bootcatalogsector
;
904 strcpy(bootrecord
.ident
, "EL TORITO SPECIFICATION");
905 for(i
= strlen(bootrecord
.ident
);
906 i
< sizeof(bootrecord
.ident
); i
++)
907 bootrecord
.ident
[i
] = '\0';
909 w
= Writefield(fd
, bootrecord
.indicator
);
910 w
+= Writefield(fd
, bootrecord
.set
);
911 w
+= Writefield(fd
, bootrecord
.version
);
912 w
+= Writefield(fd
, bootrecord
.ident
);
913 w
+= Writefield(fd
, bootrecord
.zero
);
914 w
+= Writefield(fd
, bootrecord
.bootcatalog
);
915 w
+= Writefield(fd
, bootrecord
.zero2
);
917 if(w
!= ISO_SECTOR
) {
918 fprintf(stderr
, "WARNING: something went wrong - boot record (%d) isn't a sector size (%d)\n",
926 main(int argc
, char *argv
[])
928 int currentsector
= 0;
929 int imagesector
, imagesectors
;
930 int bootfd
, fd
, i
, ch
, nsectors
;
931 int remove_after
= 0;
932 static char block
[ISO_SECTOR
];
933 static struct pvd pvd
;
934 char *label
= "ISO9660";
937 char timestr
[20], *prog
;
938 char *bootimage
= NULL
;
941 int bigpath
, littlepath
, pathbytes
= 0, dirsector
, filesector
, enddir
;
942 int bootvolumesector
, bootcatalogsector
;
943 char *appendsectorinfo
= NULL
;
947 /* This check is to prevent compiler padding screwing up
951 if(sizeof(struct pvd
) != ISO_SECTOR
) {
952 fprintf(stderr
, "Something confusing happened at\n"
953 "compile-time; pvd should be a sector size. %d != %d\n",
954 sizeof(struct pvd
), ISO_SECTOR
);
958 while ((ch
= getopt(argc
, argv
, "a:b:B:s:Rb:hl:nfF")) != -1) {
961 if(optarg
[0] != '0' || optarg
[1] != 'x') {
962 fprintf(stderr
, "%s: -s<hex>\n",
966 bootseg
= strtoul(optarg
+2, NULL
, 16);
969 bootmedia
= BOOTMEDIA_HARDDISK
;
972 bootmedia
= BOOTMEDIA_NONE
;
975 bootmedia
= BOOTMEDIA_1440K
;
978 bootmedia
= BOOTMEDIA_2880K
;
981 if(!(appendsectorinfo
= strdup(optarg
)))
991 bootimage_is_aout
= 1;
995 if((bootfd
= open(bootimage
, O_RDONLY
)) < 0) {
1009 fprintf(stderr
, "usage: %s [-l <label>] [-(b|B) <bootimage> [-n|-f|-F|-h] [-s <bootsegment>] [ -a <appendfile> ] <dir> <isofile>\n",
1014 if((bootimage
&& bootmedia
== BOOTMEDIA_UNSPECIFIED
) ||
1015 (!bootimage
&& bootmedia
!= BOOTMEDIA_UNSPECIFIED
)) {
1016 fprintf(stderr
, "%s: provide both boot image and boot type or neither.\n",
1021 if(!bootimage
&& bootseg
) {
1022 fprintf(stderr
, "%s: boot seg provided but no boot image\n",
1027 if(appendsectorinfo
) {
1028 if(!bootimage
|| bootmedia
!= BOOTMEDIA_NONE
) {
1029 fprintf(stderr
, "%s: append sector info where?\n",
1035 /* create .iso file */
1037 if((fd
=open(argv
[1], O_WRONLY
| O_TRUNC
| O_CREAT
, 0600)) < 0) {
1042 /* go to where the iso has to be made from */
1044 if(chdir(argv
[0]) < 0) {
1049 /* collect dirs and files */
1051 fprintf(stderr
, " * traversing input tree\n");
1053 maketree(&root
, "", 1);
1055 fprintf(stderr
, " * writing initial zeroes and pvd\n");
1057 /* first sixteen sectors are zero */
1059 memset(block
, 0, sizeof(block
));
1061 for(i
= 0; i
< 16; i
++)
1062 writesector(fd
, block
, ¤tsector
);
1064 /* Primary Volume Descriptor */
1065 memset(&pvd
, 0, sizeof(pvd
));
1075 strncpy(pvd
.volume
, label
, sizeof(pvd
.volume
)-1);
1076 for(i
= strlen(pvd
.volume
); i
< sizeof(pvd
.volume
); i
++)
1077 pvd
.volume
[i
] = ' ';
1078 for(i
= 0; i
< sizeof(pvd
.system
); i
++)
1079 pvd
.system
[i
] = ' ';
1081 both16((unsigned char *) pvd
.setsize
, 1);
1082 both16((unsigned char *) pvd
.seq
, 1);
1083 both16((unsigned char *) pvd
.sectorsize
, ISO_SECTOR
);
1085 /* fill time fields */
1087 now
= gmtime(&nowtime
);
1088 strftime(timestr
, sizeof(timestr
), "%Y%m%d%H%M%S000", now
);
1089 memcpy(pvd
.create
, timestr
, strlen(timestr
));
1090 memcpy(pvd
.modified
, timestr
, strlen(timestr
));
1091 memcpy(pvd
.effective
, timestr
, strlen(timestr
));
1092 strcpy(pvd
.expiry
, "0000000000000000"); /* not specified */
1093 pvdsector
= currentsector
;
1095 writesector(fd
, (char *) &pvd
, ¤tsector
);
1098 fprintf(stderr
, " * writing boot record volume descriptor\n");
1099 bootvolumesector
= currentsector
;
1100 writebootrecord(fd
, ¤tsector
, 0);
1103 /* volume descriptor set terminator */
1104 memset(block
, 0, sizeof(block
));
1113 writesector(fd
, block
, ¤tsector
);
1116 /* write the boot catalog */
1117 fprintf(stderr
, " * writing the boot catalog\n");
1118 bootcatalogsector
= currentsector
;
1119 if (bootmedia
== BOOTMEDIA_HARDDISK
)
1120 system_type
= get_system_type(bootfd
);
1121 writebootcatalog(fd
, ¤tsector
, 0, 0);
1123 /* write boot image */
1124 fprintf(stderr
, " * writing the boot image\n");
1125 imagesector
= currentsector
;
1126 imagesectors
= writebootimage(bootimage
, bootfd
,
1127 fd
, ¤tsector
, NULL
, &root
);
1128 fprintf(stderr
, " * image: %d %d-byte sectors @ cd sector 0x%x\n",
1129 imagesectors
, VIRTUAL_SECTOR
, imagesector
);
1132 /* write out all the file data */
1134 filesector
= currentsector
;
1135 fprintf(stderr
, " * writing file data\n");
1136 writedata(NULL
, &root
, fd
, ¤tsector
, 0,
1137 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1140 /* write out all the dir data */
1142 dirsector
= currentsector
;
1143 fprintf(stderr
, " * writing dir data\n");
1144 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1145 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1147 enddir
= currentsector
;
1148 seeksector(fd
, dirsector
, ¤tsector
);
1149 fprintf(stderr
, " * rewriting dir data\n");
1151 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1152 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1154 if(currentsector
!= enddir
) {
1155 fprintf(stderr
, "warning: inconsistent directories - "
1156 "I have a bug! iso may be broken.\n");
1159 /* now write the path table in both formats */
1161 fprintf(stderr
, " * writing big-endian path table\n");
1162 bigpath
= currentsector
;
1163 currentsector
+= makepathtables(&root
, 0, &pathbytes
, fd
);
1165 fprintf(stderr
, " * writing little-endian path table\n");
1166 littlepath
= currentsector
;
1167 currentsector
+= makepathtables(&root
, 1, &pathbytes
, fd
);
1169 both32((unsigned char *) pvd
.pathtablesize
, pathbytes
);
1170 little32((unsigned char *) &pvd
.first_little_pathtable_start
, littlepath
);
1171 big32((unsigned char *) &pvd
.first_big_pathtable_start
, bigpath
);
1173 /* this is the size of the iso filesystem for use in the pvd later */
1175 nsectors
= currentsector
;
1176 both32((unsigned char *) pvd
.sectors
, nsectors
);
1178 /* *********** Filesystem writing done ************************* */
1180 /* finish and rewrite the pvd. */
1181 fprintf(stderr
, " * rewriting pvd\n");
1182 seekwritesector(fd
, pvdsector
, (char *) &pvd
, ¤tsector
);
1184 /* write root dir entry in pvd */
1185 seeksector(fd
, pvdsector
, ¤tsector
);
1186 Lseek(fd
, (int)((char *) &pvd
.rootrecord
- (char *) &pvd
), SEEK_CUR
);
1187 if(write_direntry(&root
, CURRENTDIR
, fd
) > sizeof(pvd
.rootrecord
)) {
1188 fprintf(stderr
, "warning: unexpectedly large root record\n");
1192 fprintf(stderr
, " * rewriting boot catalog\n");
1193 seeksector(fd
, bootcatalogsector
, ¤tsector
);
1194 writebootcatalog(fd
, ¤tsector
, imagesector
, imagesectors
);
1196 /* finish and rewrite the boot record volume descriptor */
1197 fprintf(stderr
, " * rewriting the boot rvd\n");
1198 seeksector(fd
, bootvolumesector
, ¤tsector
);
1199 writebootrecord(fd
, ¤tsector
, bootcatalogsector
);
1201 if(appendsectorinfo
) {
1202 Lseek(bootfd
, 0, SEEK_SET
);
1203 fprintf(stderr
, " * rewriting boot image\n");
1204 seeksector(fd
, imagesector
, ¤tsector
);
1205 writebootimage(bootimage
, bootfd
,
1206 fd
, ¤tsector
, appendsectorinfo
, &root
);
1212 fprintf(stderr
, " * all ok\n");
1217 int get_system_type(int fd
)
1223 struct part_entry
*partp
;
1224 unsigned char bootsector
[512];
1227 old_pos
= lseek(fd
, 0, SEEK_SET
);
1228 if (old_pos
== -1 && errno
!= 0)
1230 fprintf(stderr
, "bootimage file is not seekable: %s\n",
1234 size
= sizeof(bootsector
);
1235 r
= read(fd
, bootsector
, size
);
1238 fprintf(stderr
, "error reading bootimage file: %s\n",
1239 r
< 0 ? strerror(errno
) : "unexpected EOF");
1242 if (bootsector
[size
-2] != 0x55 && bootsector
[size
-1] != 0xAA)
1244 fprintf(stderr
, "bad magic in bootimage file\n");
1248 partp
= (struct part_entry
*)&bootsector
[PART_TABLE_OFF
];
1249 type
= partp
->sysind
;
1250 if (type
== NO_PART
)
1252 fprintf(stderr
, "first partition table entry is unused\n");
1255 if (!(partp
->bootind
& ACTIVE_FLAG
))
1257 fprintf(stderr
, "first partition table entry is not active\n");
1261 lseek(fd
, old_pos
, SEEK_SET
);