2 /* writeisofs - simple ISO9660-format-image writing utility */
15 #include <machine/partition.h>
19 #define Writefield(fd, f) Write(fd, &(f), sizeof(f))
24 typedef unsigned char u_int8_t
;
25 typedef unsigned short int u_int16_t
;
26 typedef unsigned long int u_int32_t
;
29 #define min(a,b) ((a) < (b) ? (a) : (b))
34 #include <sys/types.h>
37 #define NAMELEN (DIRSIZ+5)
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 pathtable
[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_120M 1
117 #define BOOTMEDIA_144M 2
118 #define BOOTMEDIA_288M 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 ********************* */
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 strncpy(child
->name
, e
->d_name
, sizeof(child
->name
));
365 if(!(dirnodes
=realloc(dirnodes
, used_dirnodes
*sizeof(*dirnodes
)))) {
366 fprintf(stderr
, "realloc() of dirnodes failed - aborting\n");
370 qsort(dirnodes
, used_dirnodes
, sizeof(*dirnodes
), cmpf
);
374 while(used_dirnodes
--) {
375 child
->nextchild
= thisdir
->firstchild
;
376 thisdir
->firstchild
= child
;
378 if(chdir(child
->name
) < 0) {
381 maketree(child
, child
->name
, level
+1);
382 if(chdir(PARENTDIR
) < 0) {
383 perror("chdir() failed");
384 fprintf(stderr
, "couldn't chdir() to parent, aborting\n");
396 little32(unsigned char *dest
, u_int32_t src
)
398 dest
[0] = ((src
>> 0) & 0xFF);
399 dest
[1] = ((src
>> 8) & 0xFF);
400 dest
[2] = ((src
>> 16) & 0xFF);
401 dest
[3] = ((src
>> 24) & 0xFF);
407 little16(unsigned char *dest
, u_int16_t src
)
409 dest
[0] = ((src
>> 0) & 0xFF);
410 dest
[1] = ((src
>> 8) & 0xFF);
416 big32(unsigned char *dest
, u_int32_t src
)
418 dest
[3] = ((src
>> 0) & 0xFF);
419 dest
[2] = ((src
>> 8) & 0xFF);
420 dest
[1] = ((src
>> 16) & 0xFF);
421 dest
[0] = ((src
>> 24) & 0xFF);
426 big16(unsigned char *dest
, u_int16_t src
)
428 dest
[1] = ((src
>> 0) & 0xFF);
429 dest
[0] = ((src
>> 8) & 0xFF);
435 traversetree(struct node
*root
, int level
, int littleendian
,
436 int maxlevel
, int *bytes
, int fd
, int parentrecord
, int *recordno
)
442 u_int32_t startsector
;
446 if(level
== maxlevel
) {
448 char newname
[NAMELEN
];
456 root
->name
[0] = root
->name
[1] = '\0';
458 pte
.len
= strlen(root
->name
);
459 pte
.parent
= parentrecord
;
461 pte
.startsector
= root
->startsector
;
462 root
->pathtablerecord
= (*recordno
)++;
465 little32((unsigned char *) &pte
.startsector
, pte
.startsector
);
466 little16((unsigned char *) &pte
.parent
, pte
.parent
);
468 big32((unsigned char *) &pte
.startsector
, pte
.startsector
);
469 big16((unsigned char *) &pte
.parent
, pte
.parent
);
472 *bytes
+= Write(fd
, &pte
.len
, sizeof(pte
.len
));
473 *bytes
+= Write(fd
, &pte
.zero
, sizeof(pte
.zero
));
474 *bytes
+= Write(fd
, &pte
.startsector
, sizeof(pte
.startsector
));
475 *bytes
+= Write(fd
, &pte
.parent
, sizeof(pte
.parent
));
477 root
->name
[pte
.len
++] = '\0';
478 for(i
= 0; i
< pte
.len
; i
++)
479 newname
[i
] = toupper(root
->name
[i
]);
480 *bytes
+= Write(fd
, newname
, pte
.len
);
484 for(child
= root
->firstchild
; child
; child
= child
->nextchild
)
486 traversetree(child
, level
+1, littleendian
,
487 maxlevel
, bytes
, fd
, root
->pathtablerecord
,
494 makepathtables(struct node
*root
, int littleendian
, int *bytes
, int fd
)
497 static char block
[ISO_SECTOR
];
504 for(level
= 1; level
<= MAXLEVEL
; level
++)
505 traversetree(root
, 1, littleendian
, level
, bytes
, fd
, 1, &recordno
);
507 if(*bytes
% ISO_SECTOR
) {
509 x
= ISO_SECTOR
-(*bytes
% ISO_SECTOR
);
514 return *bytes
/ISO_SECTOR
;
518 write_direntry(char *origname
, u_int32_t sector
, u_int32_t size
, int isdir
,
521 int namelen
, total
= 0;
523 char copyname
[NAMELEN
];
525 memset(&entry
, 0, sizeof(entry
));
527 if(!strcmp(origname
, CURRENTDIR
)) {
529 } else if(!strcmp(origname
, PARENTDIR
)) {
530 entry
.name
[0] = '\001';
534 strcpy(copyname
, origname
);
535 namelen
= strlen(copyname
);
537 if(namelen
> ISONAMELEN
) {
538 fprintf(stderr
, "%s: truncated, too long for iso9660\n", copyname
);
539 namelen
= ISONAMELEN
;
540 copyname
[namelen
] = '\0';
543 strcpy(entry
.name
, copyname
);
544 for(i
= 0; i
< namelen
; i
++)
545 entry
.name
[i
] = toupper(entry
.name
[i
]);
547 /* padding byte + system field */
548 entry
.name
[namelen
] = '\0';
549 entry
.name
[namelen
+1] = '\0';
550 entry
.name
[namelen
+2] = '\0';
552 entry
.namelen
= namelen
; /* original length */
553 if(!(namelen
%2)) namelen
++; /* length with padding byte */
556 /* XXX 2 extra bytes for 'system use'.. */
557 entry
.recordsize
= 33 + namelen
;
558 both32((unsigned char *) entry
.datasector
, sector
);
559 both32((unsigned char *) entry
.filesize
, size
);
561 if(isdir
) entry
.flags
= FLAG_DIR
;
565 both16((unsigned char *) entry
.sequence
, 1);
567 total
= Write(fd
, &entry
.recordsize
, sizeof(entry
.recordsize
));
568 total
+= Write(fd
, &entry
.extended
, sizeof(entry
.extended
));
569 total
+= Write(fd
, entry
.datasector
, sizeof(entry
.datasector
));
570 total
+= Write(fd
, entry
.filesize
, sizeof(entry
.filesize
));
571 total
+= Write(fd
, &entry
.year
, sizeof(entry
.year
));
572 total
+= Write(fd
, &entry
.month
, sizeof(entry
.month
));
573 total
+= Write(fd
, &entry
.day
, sizeof(entry
.day
));
574 total
+= Write(fd
, &entry
.hour
, sizeof(entry
.hour
));
575 total
+= Write(fd
, &entry
.minute
, sizeof(entry
.minute
));
576 total
+= Write(fd
, &entry
.second
, sizeof(entry
.second
));
577 total
+= Write(fd
, &entry
.offset
, sizeof(entry
.offset
));
578 total
+= Write(fd
, &entry
.flags
, sizeof(entry
.flags
));
579 total
+= Write(fd
, &entry
.interleaved
, sizeof(entry
.interleaved
));
580 total
+= Write(fd
, &entry
.interleavegap
, sizeof(entry
.interleavegap
));
581 total
+= Write(fd
, entry
.sequence
, sizeof(entry
.sequence
));
582 total
+= Write(fd
, &entry
.namelen
, sizeof(entry
.namelen
));
583 total
+= Write(fd
, entry
.name
, namelen
);
585 if(total
!= entry
.recordsize
|| (total
% 2) != 0) {
586 printf("%2d, %2d! ", total
, entry
.recordsize
);
587 printf("%3d = %3d - %2d + %2d\n",
588 entry
.recordsize
, sizeof(entry
), sizeof(entry
.name
), namelen
);
591 return entry
.recordsize
;
595 writedata(struct node
*parent
, struct node
*root
,
596 int fd
, int *currentsector
, int dirs
, struct dir
*rootentry
,
597 int rootsize
, int remove_after
)
599 static char buf
[1024*1024];
601 ssize_t written
= 0, rest
;
603 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
604 if(c
->isdir
&& chdir(c
->name
) < 0) {
606 fprintf(stderr
, "couldn't chdir to %s - aborting\n",
610 writedata(root
, c
, fd
, currentsector
, dirs
, rootentry
, rootsize
, remove_after
);
611 if(c
->isdir
&& chdir(PARENTDIR
) < 0) {
612 perror("chdir to ..");
613 fprintf(stderr
, "couldn't chdir to parent - "
619 /* write nodes depth-first, down-top */
621 if(root
->isdir
&& dirs
) {
624 root
->startsector
= *currentsector
;
625 written
+= write_direntry(CURRENTDIR
, root
->startsector
,
626 root
->bytesize
, root
->isdir
, fd
);
628 written
+= write_direntry(PARENTDIR
, parent
->startsector
,
629 root
->bytesize
, root
->isdir
, fd
);
631 written
+= write_direntry(PARENTDIR
, root
->startsector
,
632 root
->bytesize
, root
->isdir
, fd
);
634 for(c
= root
->firstchild
; c
; c
= c
->nextchild
) {
636 ssize_t written_before
;
637 cur1
= Lseek(fd
, 0, SEEK_CUR
);
638 written_before
= written
;
639 written
+= write_direntry(c
->name
,
640 c
->startsector
, c
->bytesize
, c
->isdir
, fd
);
641 cur2
= Lseek(fd
, 0, SEEK_CUR
);
642 if(cur1
/ISO_SECTOR
!= (cur2
-1)/ISO_SECTOR
) {
643 /* passed a sector boundary, argh! */
644 Lseek(fd
, cur1
, SEEK_SET
);
645 written
= written_before
;
646 rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
));
647 memset(buf
, 0, rest
);
648 Write(fd
, buf
, rest
);
650 written
+= write_direntry(c
->name
,
651 c
->startsector
, c
->bytesize
, c
->isdir
, fd
);
654 root
->bytesize
= written
;
655 } else if(!root
->isdir
&& !dirs
) {
661 if(stat(root
->name
, &st
) < 0) {
663 fprintf(stderr
, "couldn't stat %s - aborting\n", root
->name
);
667 if((filefd
= open(root
->name
, O_RDONLY
)) < 0) {
669 fprintf(stderr
, "couldn't open %s - aborting\n", root
->name
);
675 root
->startsector
= *currentsector
;
679 chunk
= min(sizeof(buf
), rem
);
680 Read(filefd
, buf
, chunk
);
681 Write(fd
, buf
, chunk
);
687 root
->bytesize
= written
= st
.st_size
;
688 if(remove_after
&& unlink(root
->name
) < 0) {
690 fprintf(stderr
, "couldn't remove %s\n", root
->name
);
693 /* nothing to be done */
697 /* fill out sector with zero bytes */
699 if((rest
=(ISO_SECTOR
-(written
% ISO_SECTOR
)))) {
700 memset(buf
, 0, rest
);
701 Write(fd
, buf
, rest
);
705 /* update dir size with padded size */
707 if(root
->isdir
) { root
->bytesize
= written
; }
709 *currentsector
+= written
/ISO_SECTOR
;
713 writebootcatalog(int fd
, int *currentsector
, int imagesector
, int imagesectors
)
715 static char buf
[ISO_SECTOR
];
716 struct bc_validation validate
;
717 struct bc_initial initial
;
719 ssize_t written
, rest
;
720 u_int16_t
*v
, sum
= 0;
723 /* write validation entry */
725 memset(&validate
, 0, sizeof(validate
));
726 validate
.headerid
= 1;
727 validate
.platform
= PLATFORM_80X86
;
728 strcpy(validate
.idstring
, "");
729 validate
.keys
[0] = 0x55;
730 validate
.keys
[1] = 0xaa;
732 v
= (u_int16_t
*) &validate
;
733 for(i
= 0; i
< sizeof(validate
)/2; i
++)
735 validate
.checksum
= 65535 - sum
+ 1; /* sum must be 0 */
737 written
= Write(fd
, &validate
, sizeof(validate
));
739 /* write initial/default entry */
741 memset(&initial
, 0, sizeof(initial
));
743 initial
.indicator
= INDICATE_BOOTABLE
;
744 initial
.media
= bootmedia
;
745 initial
.seg
= (u_int16_t
) (bootseg
& 0xFFFF);
747 if (bootmedia
== BOOTMEDIA_HARDDISK
)
749 initial
.type
= system_type
;
751 if (bootmedia
== BOOTMEDIA_NONE
)
753 initial
.sectors
= imagesectors
;
755 initial
.startsector
= imagesector
;
757 written
+= Write(fd
, &initial
, sizeof(initial
));
759 /* fill out the rest of the sector with 0's */
761 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
762 memset(buf
, 0, sizeof(buf
));
763 written
+= Write(fd
, buf
, rest
);
766 (*currentsector
) += written
/ ISO_SECTOR
;
772 writebootimage(char *bootimage
, int bootfd
, int fd
, int *currentsector
,
773 char *appendsectorinfo
, struct node
*root
)
775 static unsigned char buf
[1024*64], *addr
;
776 ssize_t written
= 0, rest
;
784 bap
[1].length
= bap
[1].sector
= 0;
786 Read(bootfd
, &hdr
, A_MINHDR
);
788 if(hdr
.a_magic
[0] != A_MAGIC0
) {
789 fprintf(stderr
, "bad magic in a.out of boot image.\n");
793 if(hdr
.a_hdrlen
> sizeof(hdr
)) {
794 fprintf(stderr
, "surprisingly large header in boot image.\n");
798 /* read rest of a.out header. */
799 Read(bootfd
, (char *) &hdr
+ A_MINHDR
, hdr
.a_hdrlen
- A_MINHDR
);
802 rem
= hdr
.a_text
+ hdr
.a_data
;
806 want
= rem
< sizeof(buf
) ? rem
: sizeof(buf
);
807 Read(bootfd
, buf
, want
);
808 written
+= Write(fd
, buf
, want
);
812 if(appendsectorinfo
) {
814 for(n
= root
->firstchild
; n
; n
= n
->nextchild
) {
815 if(!strcasecmp(appendsectorinfo
, n
->name
)) {
816 bap
[0].sector
= n
->startsector
;
817 bap
[0].length
= ROUNDUP(n
->bytesize
, ISO_SECTOR
);
822 fprintf(stderr
, "%s not found in root.\n",
827 fprintf(stderr
, " * appended sector info: 0x%lx len 0x%lx\n",
828 bap
[0].sector
, bap
[0].length
);
832 addr
[0] = bap
[0].length
; assert(addr
[0] > 0);
833 addr
[1] = (bap
[0].sector
>> 0) & 0xFF;
834 addr
[2] = (bap
[0].sector
>> 8) & 0xFF;
835 addr
[3] = (bap
[0].sector
>> 16) & 0xFF;
839 /* Always save space for sector info after the boot image. */
840 written
+= Write(fd
, addr
, 6);
842 virtuals
= ROUNDUP(written
, VIRTUAL_SECTOR
);
843 assert(virtuals
* VIRTUAL_SECTOR
>= written
);
845 if((rest
= ISO_SECTOR
- (written
% ISO_SECTOR
))) {
846 memset(buf
, 0, sizeof(buf
));
847 written
+= Write(fd
, buf
, rest
);
850 (*currentsector
) += written
/ISO_SECTOR
;
856 writebootrecord(int fd
, int *currentsector
, int bootcatalogsector
)
859 static struct bootrecord bootrecord
;
861 /* boot record volume descriptor */
863 memset(&bootrecord
, 0, sizeof(bootrecord
));
864 bootrecord
.set
[0] = 'C';
865 bootrecord
.set
[1] = 'D';
866 bootrecord
.set
[2] = '0';
867 bootrecord
.set
[3] = '0';
868 bootrecord
.set
[4] = '1';
869 bootrecord
.version
= 1;
870 bootrecord
.bootcatalog
= bootcatalogsector
;
871 strcpy(bootrecord
.ident
, "EL TORITO SPECIFICATION");
872 for(i
= strlen(bootrecord
.ident
);
873 i
< sizeof(bootrecord
.ident
); i
++)
874 bootrecord
.ident
[i
] = '\0';
876 w
= Writefield(fd
, bootrecord
.indicator
);
877 w
+= Writefield(fd
, bootrecord
.set
);
878 w
+= Writefield(fd
, bootrecord
.version
);
879 w
+= Writefield(fd
, bootrecord
.ident
);
880 w
+= Writefield(fd
, bootrecord
.zero
);
881 w
+= Writefield(fd
, bootrecord
.bootcatalog
);
882 w
+= Writefield(fd
, bootrecord
.zero2
);
884 if(w
!= ISO_SECTOR
) {
885 fprintf(stderr
, "WARNING: something went wrong - boot record (%d) isn't a sector size (%d)\n",
893 main(int argc
, char *argv
[])
895 int currentsector
= 0;
896 int imagesector
, imagesectors
;
897 int bootfd
, fd
, i
, ch
, nsectors
;
898 int remove_after
= 0;
899 static char block
[ISO_SECTOR
];
900 static struct pvd pvd
;
901 char *label
= "ISO9660";
904 char timestr
[20], *prog
;
905 char *bootimage
= NULL
;
908 int bigpath
, littlepath
, pathbytes
= 0, dirsector
, filesector
, enddir
;
909 int bootvolumesector
, bootcatalogsector
;
910 char *appendsectorinfo
= NULL
;
914 /* This check is to prevent compiler padding screwing up
918 if(sizeof(struct pvd
) != ISO_SECTOR
) {
919 fprintf(stderr
, "Something confusing happened at\n"
920 "compile-time; pvd should be a sector size. %d != %d\n",
921 sizeof(struct pvd
), ISO_SECTOR
);
925 while ((ch
= getopt(argc
, argv
, "a:b:s:Rb:hl:nf")) != -1) {
928 if(optarg
[0] != '0' || optarg
[1] != 'x') {
929 fprintf(stderr
, "%s: -s<hex>\n",
933 bootseg
= strtoul(optarg
+2, NULL
, 16);
936 bootmedia
= BOOTMEDIA_HARDDISK
;
939 bootmedia
= BOOTMEDIA_NONE
;
942 bootmedia
= BOOTMEDIA_144M
;
945 if(!(appendsectorinfo
= strdup(optarg
)))
956 if((bootfd
= open(bootimage
, O_RDONLY
)) < 0) {
970 fprintf(stderr
, "usage: %s [-l <label>] [-b <bootimage> [-n] [-f] [-h] [-s <bootsegment>] [ -a <appendfile> ] <dir> <isofile>\n",
975 if((bootimage
&& bootmedia
== BOOTMEDIA_UNSPECIFIED
) ||
976 (!bootimage
&& bootmedia
!= BOOTMEDIA_UNSPECIFIED
)) {
977 fprintf(stderr
, "%s: provide both boot image and boot type or neither.\n",
982 if(!bootimage
&& bootseg
) {
983 fprintf(stderr
, "%s: boot seg provided but no boot image\n",
988 if(appendsectorinfo
) {
989 if(!bootimage
|| bootmedia
!= BOOTMEDIA_NONE
) {
990 fprintf(stderr
, "%s: append sector info where?\n",
996 /* create .iso file */
998 if((fd
=open(argv
[1], O_WRONLY
| O_TRUNC
| O_CREAT
, 0600)) < 0) {
1003 /* go to where the iso has to be made from */
1005 if(chdir(argv
[0]) < 0) {
1010 /* collect dirs and files */
1012 fprintf(stderr
, " * traversing input tree\n");
1014 maketree(&root
, "", 1);
1016 fprintf(stderr
, " * writing initial zeroes and pvd\n");
1018 /* first sixteen sectors are zero */
1020 memset(block
, 0, sizeof(block
));
1022 for(i
= 0; i
< 16; i
++)
1023 writesector(fd
, block
, ¤tsector
);
1025 /* Primary Volume Descriptor */
1026 memset(&pvd
, 0, sizeof(pvd
));
1036 strncpy(pvd
.volume
, label
, sizeof(pvd
.volume
)-1);
1037 for(i
= strlen(pvd
.volume
); i
< sizeof(pvd
.volume
); i
++)
1038 pvd
.volume
[i
] = ' ';
1039 for(i
= 0; i
< sizeof(pvd
.system
); i
++)
1040 pvd
.system
[i
] = ' ';
1042 both16((unsigned char *) pvd
.setsize
, 1);
1043 both16((unsigned char *) pvd
.seq
, 1);
1044 both16((unsigned char *) pvd
.sectorsize
, ISO_SECTOR
);
1046 /* fill time fields */
1048 now
= gmtime(&nowtime
);
1049 strftime(timestr
, sizeof(timestr
), "%Y%m%d%H%M%S000", now
);
1050 memcpy(pvd
.create
, timestr
, strlen(timestr
));
1051 memcpy(pvd
.modified
, timestr
, strlen(timestr
));
1052 memcpy(pvd
.effective
, timestr
, strlen(timestr
));
1053 strcpy(pvd
.expiry
, "0000000000000000"); /* not specified */
1054 pvdsector
= currentsector
;
1056 writesector(fd
, (char *) &pvd
, ¤tsector
);
1059 fprintf(stderr
, " * writing boot record volume descriptor\n");
1060 bootvolumesector
= currentsector
;
1061 writebootrecord(fd
, ¤tsector
, 0);
1064 /* volume descriptor set terminator */
1065 memset(block
, 0, sizeof(block
));
1074 writesector(fd
, block
, ¤tsector
);
1077 /* write the boot catalog */
1078 fprintf(stderr
, " * writing the boot catalog\n");
1079 bootcatalogsector
= currentsector
;
1080 if (bootmedia
== BOOTMEDIA_HARDDISK
)
1081 system_type
= get_system_type(bootfd
);
1082 writebootcatalog(fd
, ¤tsector
, 0, 0);
1084 /* write boot image */
1085 fprintf(stderr
, " * writing the boot image\n");
1086 imagesector
= currentsector
;
1087 imagesectors
= writebootimage(bootimage
, bootfd
,
1088 fd
, ¤tsector
, NULL
, &root
);
1089 fprintf(stderr
, " * image: %d %d-byte sectors @ cd sector 0x%x\n",
1090 imagesectors
, VIRTUAL_SECTOR
, imagesector
);
1093 /* write out all the file data */
1095 filesector
= currentsector
;
1096 fprintf(stderr
, " * writing file data\n");
1097 writedata(NULL
, &root
, fd
, ¤tsector
, 0,
1098 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1101 /* write out all the dir data */
1103 dirsector
= currentsector
;
1104 fprintf(stderr
, " * writing dir data\n");
1105 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1106 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1108 enddir
= currentsector
;
1109 seeksector(fd
, dirsector
, ¤tsector
);
1110 fprintf(stderr
, " * rewriting dir data\n");
1112 writedata(NULL
, &root
, fd
, ¤tsector
, 1,
1113 (struct dir
*) &pvd
.rootrecord
, sizeof(pvd
.rootrecord
),
1115 if(currentsector
!= enddir
) {
1116 fprintf(stderr
, "warning: inconsistent directories - "
1117 "I have a bug! iso may be broken.\n");
1120 /* now write the path table in both formats */
1122 fprintf(stderr
, " * writing big-endian path table\n");
1123 bigpath
= currentsector
;
1124 currentsector
+= makepathtables(&root
, 0, &pathbytes
, fd
);
1126 fprintf(stderr
, " * writing little-endian path table\n");
1127 littlepath
= currentsector
;
1128 currentsector
+= makepathtables(&root
, 1, &pathbytes
, fd
);
1130 /* this is the size of the iso filesystem for use in the pvd later */
1132 nsectors
= currentsector
;
1133 both32((unsigned char *) pvd
.sectors
, nsectors
);
1135 /* *********** Filesystem writing done ************************* */
1137 /* finish and rewrite the pvd. */
1138 fprintf(stderr
, " * rewriting pvd\n");
1139 seekwritesector(fd
, pvdsector
, (char *) &pvd
, ¤tsector
);
1141 both32((unsigned char *) pvd
.pathtable
, pathbytes
);
1142 little32((unsigned char *) &pvd
.first_little_pathtable_start
, littlepath
);
1143 little32((unsigned char *) &pvd
.first_big_pathtable_start
, bigpath
);
1145 /* write root dir entry in pvd */
1146 seeksector(fd
, pvdsector
, ¤tsector
);
1147 Lseek(fd
, (int)((char *) &pvd
.rootrecord
- (char *) &pvd
), SEEK_CUR
);
1148 if(write_direntry(CURRENTDIR
, root
.startsector
, root
.bytesize
,
1149 root
.isdir
, fd
) > sizeof(pvd
.rootrecord
)) {
1150 fprintf(stderr
, "warning: unexpectedly large root record\n");
1154 fprintf(stderr
, " * rewriting boot catalog\n");
1155 seeksector(fd
, bootcatalogsector
, ¤tsector
);
1156 writebootcatalog(fd
, ¤tsector
, imagesector
, imagesectors
);
1158 /* finish and rewrite the boot record volume descriptor */
1159 fprintf(stderr
, " * rewriting the boot rvd\n");
1160 seeksector(fd
, bootvolumesector
, ¤tsector
);
1161 writebootrecord(fd
, ¤tsector
, bootcatalogsector
);
1163 if(appendsectorinfo
) {
1164 Lseek(bootfd
, 0, SEEK_SET
);
1165 fprintf(stderr
, " * rewriting boot image\n");
1166 seeksector(fd
, imagesector
, ¤tsector
);
1167 writebootimage(bootimage
, bootfd
,
1168 fd
, ¤tsector
, appendsectorinfo
, &root
);
1174 fprintf(stderr
, " * all ok\n");
1179 int get_system_type(int fd
)
1185 struct part_entry
*partp
;
1186 unsigned char bootsector
[512];
1189 old_pos
= lseek(fd
, 0, SEEK_SET
);
1190 if (old_pos
== -1 && errno
!= 0)
1192 fprintf(stderr
, "bootimage file is not seekable: %s\n",
1196 size
= sizeof(bootsector
);
1197 r
= read(fd
, bootsector
, size
);
1200 fprintf(stderr
, "error reading bootimage file: %s\n",
1201 r
< 0 ? strerror(errno
) : "unexpected EOF");
1204 if (bootsector
[size
-2] != 0x55 && bootsector
[size
-1] != 0xAA)
1206 fprintf(stderr
, "bad magic in bootimage file\n");
1210 partp
= (struct part_entry
*)&bootsector
[PART_TABLE_OFF
];
1211 type
= partp
->sysind
;
1212 if (type
== NO_PART
)
1214 fprintf(stderr
, "first partition table entry is unused\n");
1217 if (!(partp
->bootind
& ACTIVE_FLAG
))
1219 fprintf(stderr
, "first partition table entry is not active\n");
1223 lseek(fd
, old_pos
, SEEK_SET
);