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