1 /* #includes */ /*{{{C}}}*//*{{{*/
2 #include "config.h"
3
4 #include <ctype.h>
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <time.h>
10
11 #include "getopt_.h"
12 #include "cpmfs.h"
13 /*}}}*/
14 /* #defines */ /*{{{*/
15 #ifndef O_BINARY
16 #define O_BINARY 0
17 #endif
18 /*}}}*/
19
20 /* mkfs -- make file system */ /*{{{*/
mkfs(struct cpmSuperBlock * drive,const char * name,const char * format,const char * label,char * bootTracks,int timeStamps,int uppercase)21 static int mkfs(struct cpmSuperBlock *drive, const char *name, const char *format, const char *label, char *bootTracks, int timeStamps, int uppercase)
22 {
23 /* variables */ /*{{{*/
24 unsigned int i;
25 char buf[128];
26 char firstbuf[128];
27 int fd;
28 unsigned int bytes;
29 unsigned int trkbytes;
30 /*}}}*/
31
32 /* open image file */ /*{{{*/
33 if ((fd = open(name, O_BINARY|O_CREAT|O_WRONLY, 0666)) < 0)
34 {
35 boo=strerror(errno);
36 return -1;
37 }
38 /*}}}*/
39 /* write system tracks */ /*{{{*/
40 /* this initialises only whole tracks, so it skew is not an issue */
41 trkbytes=drive->secLength*drive->sectrk;
42 for (i=0; i<trkbytes*drive->boottrk; i+=drive->secLength) if (write(fd, bootTracks+i, drive->secLength)!=(ssize_t)drive->secLength)
43 {
44 boo=strerror(errno);
45 close(fd);
46 return -1;
47 }
48 /*}}}*/
49 /* write directory */ /*{{{*/
50 memset(buf,0xe5,128);
51 bytes=drive->maxdir*32;
52 if (bytes%trkbytes) bytes=((bytes+trkbytes)/trkbytes)*trkbytes;
53 if (timeStamps && (drive->type==CPMFS_P2DOS || drive->type==CPMFS_DR3)) buf[3*32]=0x21;
54 memcpy(firstbuf,buf,128);
55 if (drive->type==CPMFS_DR3)
56 {
57 time_t now;
58 struct tm *t;
59 int min,hour,days;
60
61 firstbuf[0]=0x20;
62 for (i=0; i<11 && *label; ++i,++label) firstbuf[1+i]=toupper(*label&0x7f);
63 while (i<11) firstbuf[1+i++]=' ';
64 firstbuf[12]=timeStamps ? 0x11 : 0x01; /* label set and first time stamp is creation date */
65 memset(&firstbuf[13],0,1+2+8);
66 if (timeStamps)
67 {
68 int year;
69
70 /* Stamp label. */
71 time(&now);
72 t=localtime(&now);
73 min=((t->tm_min/10)<<4)|(t->tm_min%10);
74 hour=((t->tm_hour/10)<<4)|(t->tm_hour%10);
75 for (year=1978,days=0; year<1900+t->tm_year; ++year)
76 {
77 days+=365;
78 if (year%4==0 && (year%100!=0 || year%400==0)) ++days;
79 }
80 days += t->tm_yday + 1;
81 firstbuf[24]=firstbuf[28]=days&0xff; firstbuf[25]=firstbuf[29]=days>>8;
82 firstbuf[26]=firstbuf[30]=hour;
83 firstbuf[27]=firstbuf[31]=min;
84 }
85 }
86 for (i=0; i<bytes; i+=128) if (write(fd, i==0 ? firstbuf : buf, 128)!=128)
87 {
88 boo=strerror(errno);
89 close(fd);
90 return -1;
91 }
92 /*}}}*/
93 /* close image file */ /*{{{*/
94 if (close(fd)==-1)
95 {
96 boo=strerror(errno);
97 return -1;
98 }
99 /*}}}*/
100 if (timeStamps && !(drive->type==CPMFS_P2DOS || drive->type==CPMFS_DR3)) /*{{{*/
101 {
102 int offset,j;
103 struct cpmInode ino, root;
104 static const char sig[] = "!!!TIME";
105 unsigned int records;
106 struct dsDate *ds;
107 struct cpmSuperBlock super;
108 const char *err;
109
110 if ((err=Device_open(&super.dev,name,O_RDWR,NULL)))
111 {
112 fprintf(stderr,"%s: can not open %s (%s)\n",cmd,name,err);
113 exit(1);
114 }
115 cpmReadSuper(&super,&root,format,uppercase);
116
117 records=root.sb->maxdir/8;
118 if (!(ds=malloc(records*128)))
119 {
120 cpmUmount(&super);
121 return -1;
122 }
123 memset(ds,0,records*128);
124 offset=15;
125 for (i=0; i<records; i++)
126 {
127 for (j=0; j<7; j++,offset+=16)
128 {
129 *((char*)ds+offset) = sig[j];
130 }
131 /* skip checksum byte */
132 offset+=16;
133 }
134
135 /* Set things up so cpmSync will generate checksums and write the
136 * file.
137 */
138 if (cpmCreat(&root,"00!!!TIME&.DAT",&ino,0)==-1)
139 {
140 fprintf(stderr,"%s: Unable to create DateStamper file: %s\n",cmd,boo);
141 return -1;
142 }
143 root.sb->ds=ds;
144 root.sb->dirtyDs=1;
145 cpmUmount(&super);
146 }
147 /*}}}*/
148
149 return 0;
150 }
151 /*}}}*/
152
153 const char cmd[]="mkfs.cpm";
154
main(int argc,char * argv[])155 int main(int argc, char *argv[]) /*{{{*/
156 {
157 char *image;
158 const char *format;
159 int uppercase=0;
160 int c,usage=0;
161 struct cpmSuperBlock drive;
162 struct cpmInode root;
163 const char *label="unlabeled";
164 int timeStamps=0;
165 size_t bootTrackSize,used;
166 char *bootTracks;
167 const char *boot[4]={(const char*)0,(const char*)0,(const char*)0,(const char*)0};
168
169 if (!(format=getenv("CPMTOOLSFMT"))) format=FORMAT;
170 while ((c=getopt(argc,argv,"b:f:L:tuh?"))!=EOF) switch(c)
171 {
172 case 'b':
173 {
174 if (boot[0]==(const char*)0) boot[0]=optarg;
175 else if (boot[1]==(const char*)0) boot[1]=optarg;
176 else if (boot[2]==(const char*)0) boot[2]=optarg;
177 else if (boot[3]==(const char*)0) boot[3]=optarg;
178 else usage=1;
179 break;
180 }
181 case 'f': format=optarg; break;
182 case 'L': label=optarg; break;
183 case 't': timeStamps=1; break;
184 case 'u': uppercase=1; break;
185 case 'h':
186 case '?': usage=1; break;
187 }
188
189 if (optind!=(argc-1)) usage=1;
190 else image=argv[optind++];
191
192 if (usage)
193 {
194 fprintf(stderr,"Usage: %s [-f format] [-b boot] [-L label] [-t] [-u] image\n",cmd);
195 exit(1);
196 }
197 drive.dev.opened=0;
198 cpmReadSuper(&drive,&root,format,uppercase);
199 bootTrackSize=drive.boottrk*drive.secLength*drive.sectrk;
200 if ((bootTracks=malloc(bootTrackSize))==(void*)0)
201 {
202 fprintf(stderr,"%s: can not allocate boot track buffer: %s\n",cmd,strerror(errno));
203 exit(1);
204 }
205 memset(bootTracks,0xe5,bootTrackSize);
206 used=0;
207 for (c=0; c<4 && boot[c]; ++c)
208 {
209 int fd;
210 size_t size;
211
212 if ((fd=open(boot[c],O_BINARY|O_RDONLY))==-1)
213 {
214 fprintf(stderr,"%s: can not open %s: %s\n",cmd,boot[c],strerror(errno));
215 exit(1);
216 }
217 size=read(fd,bootTracks+used,bootTrackSize-used);
218 #if 0
219 fprintf(stderr,"%d %04x %s\n",c,used+0x800,boot[c]);
220 #endif
221 if (size%drive.secLength) size=(size|(drive.secLength-1))+1;
222 used+=size;
223 close(fd);
224 }
225 if (mkfs(&drive,image,format,label,bootTracks,timeStamps,uppercase)==-1)
226 {
227 fprintf(stderr,"%s: can not make new file system: %s\n",cmd,boo);
228 exit(1);
229 }
230 else exit(0);
231 }
232 /*}}}*/
233