/* minit Minix INITializer . Freely distributable Minix filesys creator. * Copyright S N Henson 1991,1992,1993. * Use entirely at your own risk ! If it trashes your hard-drive then * it isn't my fault ! */ /* Version 0.27 */ #include #include #include #include #include #include #include #include "minixfs/hdio.h" #include "minixfs/xhdi.h" #include "minixfs/pun.h" #define MNAME_MAX 14 int shift,drive=-1,no_phys; long numblocks,numinodes,incr=1; /* various flags */ char protect,sonly,v2,lrecno,tst,no_size; /* tosfs restore flags */ char restore_tosfs; struct hdinfo hdinf,hdinf2; unsigned char block_buf[1024]; /* Structures we will need */ typedef struct { unsigned short s_ninodes; /* # usable inodes on the minor device */ unsigned short s_nzones; /* total device size, including bit maps etc */ unsigned short s_imap_blks; /* # of blocks used by inode bit map */ unsigned short s_zmap_blks; /* # of blocks used by zone bit map */ unsigned short s_firstdatazn; /* number of first data zone */ short int s_log_zsize; /* log2 of blocks/zone */ unsigned long s_max_size; /* maximum file size on this device */ short s_magic; /* magic number to recognize super-blocks */ short pad; /* padding */ long s_zones; /* equivalent to 's_nzones' for V2 */ } super_block; super_block *sblk=(super_block *)block_buf; /* This structure is used to restore the original TOS filesystem */ struct tfsav { unsigned char bstart[64]; /* Start of bootsector */ #define SAV_MAGIC 0xcaba1372l unsigned sav_datrec; /* First data record */ unsigned long sav_magic; /* Contains SAV_MAGIC if info valid */ } *sav_tosfs=(struct tfsav *)(block_buf+256),sav_tmp; typedef struct { /* directory entry */ unsigned short d_inum; /* inode number */ char d_name[MNAME_MAX]; /* character string */ } dir_struct; typedef struct { /* disk inode. */ unsigned short i_mode; /* file type, protection, etc. */ unsigned short i_uid; /* user id of the file's owner */ unsigned long i_size; /* current file size in bytes */ unsigned long i_mtime; /* when was file data last changed */ unsigned char i_gid; /* group number */ unsigned char i_nlinks; /* how many links to this file */ unsigned short i_zone[9]; /* block nums for direct, ind, and dbl ind */ } d_inode; typedef struct { unsigned short i_mode; unsigned short i_nlinks; unsigned short i_uid; unsigned short i_gid; unsigned long i_size; unsigned long i_atime; unsigned long i_mtime; unsigned long i_ctime; long i_zone[10]; } d_inode2; _BPB *bpb; /* prototypes */ #ifdef __STDC__ # define P(s) s #else # define P(s) () #endif /* Useful macro: DIV, divide a by b rounded up to nearest integer */ #define DIV(a,b) ((a+b-1)/b) void main P((int argc , char **argv )); int nrwabs P((int rw , void *buf , unsigned count , long recno , int drive )); void get_block P((long num )); void put_block P((long num )); void check_lrecno P((void )); void warn P((void )); void make_tosfs P((void )); #undef P void main(argc,argv) int argc; char **argv; { extern int optind,opterr; extern char *optarg; extern int __mint; long hderr; int c ; static char err=0; int i,j; unsigned short ioff,zone1; super_block csblk; d_inode *rip=(d_inode *)block_buf; d_inode2 *ripn=(d_inode2 *)block_buf; dir_struct *dir=(dir_struct *)block_buf; unsigned short *srt=(unsigned short *)block_buf; long icount, zcount; struct { long start; long finish; char shadow; char scsiz; } pp; if(__mint==0) { fprintf(stderr,"Error: MiNT not active.\n"); exit(1); } /* Parse command-line options */ opterr=0; while((c=getopt(argc,argv,"b:B:i:I:n:pPSZztVeRr"))!=EOF) { switch(c){ case 'B': case 'b': numblocks=atol(optarg); break; case 'n': incr=atol(optarg); break; case 'i': case 'I': numinodes=atol(optarg); break; case 'P': protect=1; break; case 'p': protect=2; break; case 'S': sonly=1; break; case 'Z': protect=1; break; case 'z': protect=2; break; case 'V': v2=1; break; case 't': tst=1; break; case 'e': no_size=1; break; case 'R': case 'r': restore_tosfs=1; break; case '?': err=1; break; } } if(argc-optind!=1 || err) { fprintf(stderr,"Minix-compatible filesystem initializer\n"); fprintf(stderr,"Copyright S N Henson 1991,1992,1993,1994\n"); fprintf(stderr,"Version 0.27\n"); fprintf(stderr,"Usage\t(auto)\t: minit drive\n"); fprintf(stderr,"\t(manual): minit -b blocks -i inodes drive\n"); fprintf(stderr,"Also :\t-S only write out super-block\n"); fprintf(stderr,"\t-P/-Z protect filesystem with null disk\n"); fprintf(stderr,"\t-p/-z make null disk of existing filestystem\n"); fprintf(stderr,"\t-V make a V2 filesystem\n"); fprintf(stderr,"\t-n dirincrement\n"); fprintf(stderr,"\t-t test mode (no writing)\n"); fprintf(stderr,"\t-e find size by reading past partition end\n"); fprintf(stderr,"\t-r restore a tos filesystem to partition\n"); exit(1); } drive=(argv[optind][0] & ~32)-'A' ; bpb=Getbpb(drive); if(restore_tosfs) make_tosfs(); if(tst) { if(bpb) { printf("Sector size %d\n",bpb->recsiz); printf("Cluster size in sectors: %d\n",bpb->clsiz); printf("Cluster size in bytes: %d\n",bpb->clsizb); printf("Root dir length %d\n",bpb->rdlen); printf("Fat size %d\n",bpb->fsiz); printf("Second Fat start %d\n",bpb->fatrec); printf("First data record %d\n",bpb->datrec); printf("Flags %d\n",bpb->bflags); printf("Total Clusters %d\n",bpb->numcl); } else printf("Invalid BPB\n"); } /* Sanity checking time */ if((incr < 1) || (incr > 16) || ( (incr) & (incr-1) ) ) { fprintf(stderr,"Dirincrement must be a power of two between\n"); fprintf(stderr,"1 and 16 (inclusive)\n"); exit(1); } if( (numinodes < 0) || (numinodes > 65535) ) { fprintf(stderr,"Need at least 1 and no more than 65535 inodes\n"); exit(1); } if(protect==2 && bpb->recsiz!=512) { fprintf(stderr,"Sorry can't add protection to this filesytem.\n"); fprintf(stderr,"Sector size not 512 bytes.\n"); exit(1); } /* Test for physical partition */ if(!Dcntl(0x109,argv[optind],&pp) && pp.start!=-1) { long tstack; hdinf.start=pp.start; hdinf.size=pp.finish-hdinf.start+1; hdinf.scsiz=pp.scsiz; hdinf.major = pp.shadow; hdinf.drive = drive; tstack=Super(0l); if(init_icd()==2) { Super(tstack); fprintf(stderr,"Can't kludge ICD bug\n"); exit(1); } Super(tstack); hdinf.rwmode = RW_PHYS; if(hdinf.start > 0xfffe) { if(no_plrecno(hdinf.major)) fprintf(stderr,"Cannot access Drive %c:\n",drive+'A'); hdinf.rwmode |= RW_LRECNO; } } else { pp.start=-1; if( (hderr=get_hddinf(drive,&hdinf,0)) ) { fprintf(stderr,"Cannot access Drive %c: %s\n",drive+'A', hdd_err[hderr]); exit(1); } } if(tst) { unsigned int llrecno,xhret; no_phys=0; if(pp.start==-1) { llrecno=no_lrecno(drive); if(llrecno && llrecno!=3) fprintf(stderr,"Logical lrecno error\n"); else fprintf(stderr,"Logical lrecno OK\n"); } else { fprintf(stderr,"Physical Partition\n"); hdinf2=hdinf; } if( (no_phys=get_hddinf(drive,&hdinf2,1) ) ) fprintf(stderr,"Can't get physical drive info: %s\n",hdd_err[no_phys]); else if( (hdinf2.rwmode & RW_MODE) != RW_XHDI ) { llrecno=no_plrecno(hdinf2.major); if(llrecno && llrecno!=3) fprintf(stderr,"Physical lrecno error\n"); else fprintf(stderr,"Physical lrecno OK\n"); } if( (xhret=XHGetVersion()) ) fprintf(stderr,"XHDI supported" " version %x.%02x\n", xhret>>8,xhret & 0xff); else fprintf(stderr,"XHDI not supported\n"); if(!no_phys) { fprintf(stderr,"Partition start: %ld\n",hdinf2.start); if(hdinf2.size) fprintf(stderr,"Partition size: %ld\n",hdinf2.size); if( (hdinf2.rwmode & RW_MODE) == RW_PHYS) { unsigned ddev; char *sbus; ddev=hdinf2.minor; fprintf(stderr,"Unit number %d\n",ddev); if( ddev & PUN_IDE) sbus="IDE"; else { if( ddev & PUN_SCSI) sbus="SCSI"; else sbus="ACSI"; } fprintf(stderr,"%s bus: device %d.(",sbus, ddev & PUN_UNIT); if(ddev & PUN_REMOVABLE) fprintf(stderr,"Removable)\n"); else fprintf(stderr,"Non-removable)\n"); } else fprintf(stderr,"Major number %d Minor number %d\n", hdinf2.major,hdinf2.minor); } } if(!numblocks) numblocks=hdinf.size>>hdinf.scsiz; else if(hdinf.size && (numblocks > hdinf.size>>hdinf.scsiz)) { fprintf(stderr,"Partition has only %ld blocks\n", hdinf.size>>hdinf.scsiz); exit(1); } if(!numblocks && no_size) { if( ( hderr=get_size(drive,&numblocks) ) ) fprintf(stderr,"get_size Warning: %s\n",size_err[hderr]); } /* read in boot sector */ get_block(0); /* Fill in TOS save info */ bcopy(block_buf,sav_tmp.bstart,64l); sav_tmp.sav_magic=SAV_MAGIC; if(bpb) sav_tmp.sav_datrec=bpb->datrec; else sav_tmp.sav_datrec=0; /* If size of partition not known try BPB/boot sector */ if(!numblocks) { if(!bpb || (bpb->recsiz & 511)) { fprintf(stderr,"Can't figure out partition size: " "try the -b option\n"); exit(1); } numblocks=( (block_buf[19]+( ((long)block_buf[20])<<8))* bpb->recsiz)>>10; if(numblocks < 40 ) { fprintf(stderr,"%ld blocks ? Is that bootsector OK ?\n",numblocks); exit(1); } } if(!v2 && (numblocks > 65535) ) { fprintf(stderr,"V1 filesystems can be at most 65535 blocks\n"); exit(1); } if( (hderr=set_lrecno(&hdinf,numblocks)) ) { fprintf(stderr,"Can't access partition: %s\n",hdd_err[hderr]); exit(1); } if(tst) { fprintf(stderr,"\nHard disk access information:\nAccess mode: "); switch(hdinf.rwmode & RW_MODE) { case RW_NORMAL: fprintf(stderr,"Normal mode\n"); break; case RW_XHDI: fprintf(stderr,"XHDI mode\n"); break; case RW_PHYS: fprintf(stderr,"Physical mode\n"); break; } if(hdinf.rwmode & RW_LRECNO) fprintf(stderr,"Lrecno access\n\n"); else fprintf(stderr,"Non lrecno access\n\n"); } /* Special test to check PHYS mode is OK: * read in block 0 with Rwabs and our routines. If they are * different then signal error and halt. */ if( ( ( (hdinf.rwmode & RW_MODE) == RW_PHYS ) || ( tst && !no_phys ) ) && bpb ) { char *tmp1,*tmp2; tmp1=malloc(1024); tmp2=malloc(bpb->recsiz); if(!tmp1 || !tmp2) { fprintf(stderr,"Memory allocation error\n"); exit(1); } if( Rwabs(2,tmp2,1,0,hdinf.drive) ) { fprintf(stderr,"Rwabs failure\n"); exit(1); } if(tst) block_rwabs(2,tmp1,1,0,&hdinf2); else block_rwabs(2,tmp1,1,0,&hdinf); if( bcmp(tmp1,tmp2,512) ) { fprintf(stderr,"Physical Comparison error!\n"); if(!tst) exit(1); } else if(tst) fprintf(stderr,"Physical Comparison OK\n"); free(tmp1); free(tmp2); } if(numinodes==0) { numinodes = numblocks/3; /* Round up inode number to nearest block */ if(v2) numinodes = (numinodes + 15) & ~15; else numinodes=(numinodes + 31 ) & ~31; } if(numinodes > 65535) numinodes = 65535; if(protect==2) { get_block(1); if( sblk->s_magic!=0x137f && sblk->s_magic!=0x2468 && sblk->s_magic!=0x138f) { fprintf(stderr,"Fatal: bad magic number\n"); exit(1); } } if(!tst) warn(); /* OK lets work out some stuff */ if(protect==2) get_block(1); else { bzero(block_buf,1024l); /* Super block */ sblk->s_ninodes=numinodes; if(v2) sblk->s_zones=numblocks; else sblk->s_nzones=numblocks; sblk->s_imap_blks=(numinodes+8192)/8192; sblk->s_zmap_blks=(numblocks+8191)/8192; sblk->s_firstdatazn=2+sblk->s_imap_blks+sblk->s_zmap_blks + ( v2 ? ((numinodes+15)/16) : ((numinodes+31)/32)) ; sblk->s_log_zsize=0; sblk->s_max_size= v2 ? 0x4041c00l : 0x10081c00l; if(v2) sblk->s_magic=0x2468; else { if(incr==2) sblk->s_magic=0x138f; else sblk->s_magic=0x137f; } } /* If we have a valid sav_tosfs structure in the superblock leave * it there. Otherwise copy our structure across. */ if(sav_tosfs->sav_magic!=SAV_MAGIC) *sav_tosfs=sav_tmp; /* If sector size 512 bytes handle protection now */ if(protect) { unsigned pseudo_root,root_entries; /* 512 bytes pseudo root after super block */ if(bpb->recsiz==512) { bzero(&block_buf[512],512); for(i=512;i<1024;i+=32) { strncpy(block_buf+i,"MINIXFS ",11); block_buf[i+11]=0x08; } put_block(1); csblk=*sblk; pseudo_root=3; } else /* Not 512 bytes: insert pseudo root after inodes but * before first data zone. */ { unsigned secblocks; /* blocks per log. sector */ secblocks = bpb->recsiz/1024; /* Round up first data zone to sector boundary + 1 */ sblk->s_firstdatazn += 2*secblocks - 1; sblk->s_firstdatazn /= secblocks; sblk->s_firstdatazn *= secblocks; put_block(1); pseudo_root = sblk->s_firstdatazn / secblocks - 1; csblk=*sblk; /* Pseudo root directory : whole block */ for(i=0;i<1024;i+=32) { strncpy((char *)(block_buf+i),"MINIXFS ",11); block_buf[i+11]=0x8; } /* Write them all out */ for(i = - secblocks ; i < 0 ;i++) put_block(csblk.s_firstdatazn+i); } /* Set up boot sector to point to pseudo root */ get_block(0); strcpy((char *)(block_buf+2),"MINIX"); block_buf[16] = 2; /* 2 FAT's */ root_entries = bpb->recsiz/32; /* Root directory: 1 sector */ block_buf[17] = root_entries & 0xff; block_buf[18] = root_entries >> 8; block_buf[22] = 1; /* FAT = 1 sector */ block_buf[23] = 0; pseudo_root-=2; block_buf[14] = pseudo_root & 0xff; block_buf[15] = pseudo_root >> 8; put_block(0); } else { put_block(1); csblk=*sblk; } if( sonly || protect==2 ) exit(0); ioff=2+csblk.s_imap_blks+csblk.s_zmap_blks; zone1=csblk.s_firstdatazn; bzero(block_buf,1024l); /* Inode bitmaps */ icount = numinodes + 1; for(i=2;i<2+csblk.s_imap_blks;i++) { if(i==2) { srt[0]=3; } if(icount < 8192) /* Need to mark dead inodes as used */ { if(icount & 15) { srt[icount/16] = 0xffff << (icount & 15); icount+= 16 - (icount & 15); } for(j=icount/16;j<512;j++)srt[j]=0xffff; } put_block(i); if(i==2)srt[0]=0; icount-=8192; } bzero(block_buf,1024l); /* Zone bitmaps */ zcount = numblocks + 1 - csblk.s_firstdatazn; for(i=2+csblk.s_imap_blks;ii_mode=040777; /* Directory */ ripn->i_size=32*incr; ripn->i_mtime=time((time_t *)0); ripn->i_ctime=ripn->i_mtime; ripn->i_atime=ripn->i_mtime; ripn->i_nlinks=2; ripn->i_zone[0]=zone1; } else { rip->i_mode=040777; /* Directory */ rip->i_size=32*incr; rip->i_mtime=time((time_t *)0); rip->i_nlinks=2; rip->i_zone[0]=zone1; } } put_block(i); if(i==ioff)bzero(block_buf,1024l); } bzero(block_buf,1024l); /* And finally the root directory */ dir[0].d_inum=1; strcpy(dir[0].d_name,"."); dir[incr].d_inum=1; strcpy(dir[incr].d_name,".."); put_block(zone1); if(!tst) fprintf(stderr,"Initialised OK.\n"); fprintf(stderr,"%ld Blocks, %ld Inodes.\n",numblocks,numinodes); /* Force media change on specified drive */ if(Dlock(1,drive)) fprintf(stderr,"Can't Lock Drive, Reboot to be sure\n"); exit(0); } void get_block(num) long num; { long r; if( (r = block_rwabs(2,block_buf,1,num,&hdinf)) ) { fprintf(stderr,"Fatal Read Error %ld block %ld\n",r,num); exit(2); } } void put_block(num) long num; { long r; if(tst) return; if( (r = block_rwabs(3,block_buf,1,num,&hdinf)) ) { fprintf(stderr,"Fatal Write Error %ld block %ld\n",r,num); exit(2); } } void warn() { int ch; fprintf(stderr,"WARNING ! THIS %s TOTALLY DESTROY ANY DATA ON ", (sonly || protect==2 ) ? "MAY":"WILL"); fprintf(stderr,"DRIVE %c !\n",drive+'A'); fprintf(stderr,"Are you ABSOLUTELY SURE you want to do this (y/n)?\n"); ch=Crawcin() & 0xff ; if((ch & ~32) !='Y') { fprintf(stderr,"Aborted\n"); exit(0); } } /* Restore a tosfs filesystem. Using the tfsav structure. */ void make_tosfs() { int hderr,i; long clear_blk; /* Number of blocks to clear */ char ch; if( (hderr=get_hddinf(drive,&hdinf,0)) ) { fprintf(stderr,"Cannot access Drive %c: %s\n",drive+'A', hdd_err[hderr]); exit(1); } get_block(1); if(sblk->s_magic!=0x2468 && sblk->s_magic!=0x137f && sblk->s_magic!=0x138f ) { fprintf(stderr,"Can't restore: not a Minixfs filesystem\n"); exit(1); } if( sav_tosfs->sav_magic!=SAV_MAGIC ) { fprintf(stderr,"Can't recreate filesystem: perhaps you made the\ \nfilesystem with an older version of minit?\n"); exit(1); } fprintf(stderr,"WARNING: You are about to Restore a TOS filesystem\n"); fprintf(stderr,"on a Minixfs Filesystem. This will TOTALLY DESTROY\n"); fprintf(stderr,"the Minixfs files!\n"); fprintf(stderr,"ARE YOU ABSOLUTELY SURE YOU WANT TO DO THIS ? (y/n)\n"); ch=Crawcin() & 0xff; if((ch & ~32) != 'Y') exit(0); sav_tmp=*sav_tosfs; get_block(0); bcopy(sav_tmp.bstart,block_buf,64l); if(sav_tmp.sav_datrec) clear_blk = (sav_tmp.sav_datrec*block_buf[12])/2; else /* Work out datrec from other parameters */ { int nphys; /* 512 byte sectors per logical sector */ long dirent; /* root dir logical sectors */ nphys = block_buf[12]/2; clear_blk = nphys; /* Boot sector */ /* Add the FATs */ clear_blk += nphys*block_buf[16]* (block_buf[22]+(block_buf[23]<<8)); /* Root dir 512 byte sectors (16 entries per sector) */ dirent = DIV(block_buf[17]+(block_buf[18]<<8),16); /* Now round up to nearest physical sector */ dirent = DIV(dirent,nphys); clear_blk += nphys*dirent; } /* convert clear_blk to blocks */ clear_blk = DIV(clear_blk,2); bzero(block_buf+512,512); put_block(0); /* Now we zero 2 FATs and root directory */ bzero(block_buf,512); for(i=1;i < 1+clear_blk; i++) put_block(i); /* Force disk change */ (void)Dlock(1,drive); fprintf(stderr,"TOS filesystem recreated: Reboot to be sure\n"); exit(0); }