1433d6423SLionel Sambuc /* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. */ 2433d6423SLionel Sambuc 3433d6423SLionel Sambuc /* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans */ 4433d6423SLionel Sambuc 5433d6423SLionel Sambuc #if HAVE_NBTOOL_CONFIG_H 6433d6423SLionel Sambuc #include "nbtool_config.h" 7433d6423SLionel Sambuc #endif 8433d6423SLionel Sambuc 9433d6423SLionel Sambuc #include <sys/cdefs.h> 10433d6423SLionel Sambuc #include <sys/types.h> 11433d6423SLionel Sambuc #include <sys/stat.h> 12433d6423SLionel Sambuc 13433d6423SLionel Sambuc #if defined(__minix) 14433d6423SLionel Sambuc #include <minix/minlib.h> 15433d6423SLionel Sambuc #include <minix/partition.h> 16433d6423SLionel Sambuc #include <sys/ioctl.h> 17433d6423SLionel Sambuc #elif defined(__linux__) 18433d6423SLionel Sambuc #include <mntent.h> 19433d6423SLionel Sambuc #endif 20433d6423SLionel Sambuc 21433d6423SLionel Sambuc #include <assert.h> 22433d6423SLionel Sambuc #include <err.h> 23433d6423SLionel Sambuc #include <errno.h> 24433d6423SLionel Sambuc #include <fcntl.h> 25433d6423SLionel Sambuc #include <limits.h> 26433d6423SLionel Sambuc #include <stdarg.h> 27433d6423SLionel Sambuc #include <stdint.h> 28433d6423SLionel Sambuc #include <stdio.h> 29433d6423SLionel Sambuc #include <stdlib.h> 30433d6423SLionel Sambuc #include <string.h> 31433d6423SLionel Sambuc #include <time.h> 32433d6423SLionel Sambuc #include <unistd.h> 33433d6423SLionel Sambuc 34433d6423SLionel Sambuc /* Definition of the file system layout: */ 35433d6423SLionel Sambuc #include "const.h" 36433d6423SLionel Sambuc #include "type.h" 37433d6423SLionel Sambuc #include "mfsdir.h" 38433d6423SLionel Sambuc #include "super.h" 39433d6423SLionel Sambuc 40433d6423SLionel Sambuc #define INODE_MAP START_BLOCK 41433d6423SLionel Sambuc /* inode zone indexes pointing to single and double indirect zones */ 42433d6423SLionel Sambuc #define S_INDIRECT_IDX (NR_DZONES) 43433d6423SLionel Sambuc #define D_INDIRECT_IDX (NR_DZONES+1) 44433d6423SLionel Sambuc 45433d6423SLionel Sambuc 46433d6423SLionel Sambuc #define MAX_TOKENS 10 47433d6423SLionel Sambuc #define LINE_LEN 200 48433d6423SLionel Sambuc /* XXX why do we not use 0 / SU_ID ? */ 49433d6423SLionel Sambuc #define BIN 2 50433d6423SLionel Sambuc #define BINGRP 2 51433d6423SLionel Sambuc 52433d6423SLionel Sambuc /* some Minix specific types that do not conflict with Posix */ 53433d6423SLionel Sambuc #ifndef block_t 54433d6423SLionel Sambuc typedef uint32_t block_t; /* block number */ 55433d6423SLionel Sambuc #endif 56433d6423SLionel Sambuc #ifndef zone_t 57433d6423SLionel Sambuc typedef uint32_t zone_t; /* zone number */ 58433d6423SLionel Sambuc #endif 59433d6423SLionel Sambuc #ifndef bit_t 60433d6423SLionel Sambuc typedef uint32_t bit_t; /* bit number in a bit map */ 61433d6423SLionel Sambuc #endif 62433d6423SLionel Sambuc #ifndef bitchunk_t 63433d6423SLionel Sambuc typedef uint32_t bitchunk_t; /* collection of bits in a bitmap */ 64433d6423SLionel Sambuc #endif 65433d6423SLionel Sambuc 66433d6423SLionel Sambuc struct fs_size { 67433d6423SLionel Sambuc ino_t inocount; /* amount of inodes */ 68433d6423SLionel Sambuc zone_t zonecount; /* amount of zones */ 69433d6423SLionel Sambuc block_t blockcount; /* amount of blocks */ 70433d6423SLionel Sambuc }; 71433d6423SLionel Sambuc 72433d6423SLionel Sambuc extern char *optarg; 73433d6423SLionel Sambuc extern int optind; 74433d6423SLionel Sambuc 75433d6423SLionel Sambuc block_t nrblocks; 76433d6423SLionel Sambuc int zone_per_block, zone_shift = 0; 77433d6423SLionel Sambuc zone_t next_zone, zoff, nr_indirzones; 78433d6423SLionel Sambuc int inodes_per_block, indir_per_block, indir_per_zone; 79433d6423SLionel Sambuc unsigned int zone_size; 80433d6423SLionel Sambuc ino_t nrinodes, inode_offset, next_inode; 81433d6423SLionel Sambuc int lct = 0, fd, print = 0; 82433d6423SLionel Sambuc int simple = 0, dflag = 0, verbose = 0; 83433d6423SLionel Sambuc int donttest; /* skip test if it fits on medium */ 84433d6423SLionel Sambuc char *progname; 85433d6423SLionel Sambuc uint64_t fs_offset_bytes, fs_offset_blocks, written_fs_size = 0; 86433d6423SLionel Sambuc 87433d6423SLionel Sambuc time_t current_time; 88433d6423SLionel Sambuc char *zero; 89433d6423SLionel Sambuc unsigned char *umap_array; /* bit map tells if block read yet */ 90433d6423SLionel Sambuc size_t umap_array_elements; 91433d6423SLionel Sambuc block_t zone_map; /* where is zone map? (depends on # inodes) */ 92433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 93433d6423SLionel Sambuc size_t block_size; 94433d6423SLionel Sambuc #else 95433d6423SLionel Sambuc #define block_size MFS_STATIC_BLOCK_SIZE 96433d6423SLionel Sambuc #endif 97433d6423SLionel Sambuc 98433d6423SLionel Sambuc FILE *proto; 99433d6423SLionel Sambuc 100433d6423SLionel Sambuc int main(int argc, char **argv); 101433d6423SLionel Sambuc void detect_fs_size(struct fs_size * fssize); 102433d6423SLionel Sambuc void sizeup_dir(struct fs_size * fssize); 103433d6423SLionel Sambuc block_t sizeup(char *device); 104433d6423SLionel Sambuc static int bitmapsize(bit_t nr_bits, size_t blk_size); 105433d6423SLionel Sambuc void super(zone_t zones, ino_t inodes); 106433d6423SLionel Sambuc void rootdir(ino_t inode); 107433d6423SLionel Sambuc void enter_symlink(ino_t inode, char *link); 108433d6423SLionel Sambuc int dir_try_enter(zone_t z, ino_t child, char const *name); 109433d6423SLionel Sambuc void eat_dir(ino_t parent); 110433d6423SLionel Sambuc void eat_file(ino_t inode, int f); 111433d6423SLionel Sambuc void enter_dir(ino_t parent, char const *name, ino_t child); 112433d6423SLionel Sambuc void add_zone(ino_t n, zone_t z, size_t bytes, time_t cur_time); 113433d6423SLionel Sambuc void incr_link(ino_t n); 114433d6423SLionel Sambuc void incr_size(ino_t n, size_t count); 115433d6423SLionel Sambuc static ino_t alloc_inode(int mode, int usrid, int grpid); 116433d6423SLionel Sambuc static zone_t alloc_zone(void); 117433d6423SLionel Sambuc void insert_bit(block_t block, bit_t bit); 118433d6423SLionel Sambuc int mode_con(char *p); 119433d6423SLionel Sambuc void get_line(char line[LINE_LEN], char *parse[MAX_TOKENS]); 120433d6423SLionel Sambuc void check_mtab(const char *devname); 121433d6423SLionel Sambuc time_t file_time(int f); 122433d6423SLionel Sambuc __dead void pexit(char const *s, ...) __printflike(1,2); 123433d6423SLionel Sambuc void *alloc_block(void); 124433d6423SLionel Sambuc void print_fs(void); 125433d6423SLionel Sambuc int read_and_set(block_t n); 126433d6423SLionel Sambuc void special(char *string, int insertmode); 127433d6423SLionel Sambuc __dead void usage(void); 128433d6423SLionel Sambuc void get_block(block_t n, void *buf); 129433d6423SLionel Sambuc void get_super_block(void *buf); 130433d6423SLionel Sambuc void put_block(block_t n, void *buf); 131433d6423SLionel Sambuc static uint64_t mkfs_seek(uint64_t pos, int whence); 132433d6423SLionel Sambuc static ssize_t mkfs_write(void * buf, size_t count); 133433d6423SLionel Sambuc 134433d6423SLionel Sambuc /*================================================================ 135433d6423SLionel Sambuc * mkfs - make filesystem 136433d6423SLionel Sambuc *===============================================================*/ 137433d6423SLionel Sambuc int 138433d6423SLionel Sambuc main(int argc, char *argv[]) 139433d6423SLionel Sambuc { 140433d6423SLionel Sambuc int nread, mode, usrid, grpid, ch, extra_space_percent, Tflag = 0; 141433d6423SLionel Sambuc block_t blocks, maxblocks, bblocks; 142433d6423SLionel Sambuc ino_t inodes, root_inum; 143433d6423SLionel Sambuc char *token[MAX_TOKENS], line[LINE_LEN], *sfx; 144433d6423SLionel Sambuc struct fs_size fssize; 145433d6423SLionel Sambuc int insertmode = 0; 146433d6423SLionel Sambuc 147433d6423SLionel Sambuc progname = argv[0]; 148433d6423SLionel Sambuc 149433d6423SLionel Sambuc /* Process switches. */ 150433d6423SLionel Sambuc blocks = 0; 151433d6423SLionel Sambuc inodes = 0; 152433d6423SLionel Sambuc bblocks = 0; 153433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 154433d6423SLionel Sambuc block_size = 0; 155433d6423SLionel Sambuc #endif 156433d6423SLionel Sambuc zone_shift = 0; 157433d6423SLionel Sambuc extra_space_percent = 0; 158433d6423SLionel Sambuc while ((ch = getopt(argc, argv, "B:b:di:ltvx:z:I:T:")) != EOF) 159433d6423SLionel Sambuc switch (ch) { 160433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 161433d6423SLionel Sambuc case 'B': 162433d6423SLionel Sambuc block_size = strtoul(optarg, &sfx, 0); 163433d6423SLionel Sambuc switch(*sfx) { 164433d6423SLionel Sambuc case 'b': case 'B': /* bytes; NetBSD-compatible */ 165433d6423SLionel Sambuc case '\0': break; 166433d6423SLionel Sambuc case 'K': 167433d6423SLionel Sambuc case 'k': block_size*=1024; break; 168433d6423SLionel Sambuc case 's': block_size*=SECTOR_SIZE; break; 169433d6423SLionel Sambuc default: usage(); 170433d6423SLionel Sambuc } 171433d6423SLionel Sambuc break; 172433d6423SLionel Sambuc #else 173433d6423SLionel Sambuc case 'B': 174433d6423SLionel Sambuc if (block_size != strtoul(optarg, (char **) NULL, 0)) 175433d6423SLionel Sambuc errx(4, "block size must be exactly %d bytes", 176433d6423SLionel Sambuc MFS_STATIC_BLOCK_SIZE); 177433d6423SLionel Sambuc break; 178433d6423SLionel Sambuc (void)sfx; /* shut up warnings about unused variable...*/ 179433d6423SLionel Sambuc #endif 180433d6423SLionel Sambuc case 'I': 181433d6423SLionel Sambuc fs_offset_bytes = strtoul(optarg, (char **) NULL, 0); 182433d6423SLionel Sambuc insertmode = 1; 183433d6423SLionel Sambuc break; 184433d6423SLionel Sambuc case 'b': 185433d6423SLionel Sambuc blocks = bblocks = strtoul(optarg, (char **) NULL, 0); 186433d6423SLionel Sambuc break; 187433d6423SLionel Sambuc case 'T': 188433d6423SLionel Sambuc Tflag = 1; 189433d6423SLionel Sambuc current_time = strtoul(optarg, (char **) NULL, 0); 190433d6423SLionel Sambuc break; 191433d6423SLionel Sambuc case 'd': 192433d6423SLionel Sambuc dflag = 1; 193433d6423SLionel Sambuc break; 194433d6423SLionel Sambuc case 'i': 195433d6423SLionel Sambuc inodes = strtoul(optarg, (char **) NULL, 0); 196433d6423SLionel Sambuc break; 197433d6423SLionel Sambuc case 'l': print = 1; break; 198433d6423SLionel Sambuc case 't': donttest = 1; break; 199433d6423SLionel Sambuc case 'v': ++verbose; break; 200433d6423SLionel Sambuc case 'x': extra_space_percent = atoi(optarg); break; 201433d6423SLionel Sambuc case 'z': zone_shift = atoi(optarg); break; 202433d6423SLionel Sambuc default: usage(); 203433d6423SLionel Sambuc } 204433d6423SLionel Sambuc 205433d6423SLionel Sambuc if (argc == optind) usage(); 206433d6423SLionel Sambuc 207433d6423SLionel Sambuc /* Get the current time, set it to the mod time of the binary of 208433d6423SLionel Sambuc * mkfs itself when the -d flag is used. The 'current' time is put into 209433d6423SLionel Sambuc * the i_mtimes of all the files. This -d feature is useful when 210433d6423SLionel Sambuc * producing a set of file systems, and one wants all the times to be 211433d6423SLionel Sambuc * identical. First you set the time of the mkfs binary to what you 212433d6423SLionel Sambuc * want, then go. 213433d6423SLionel Sambuc */ 214433d6423SLionel Sambuc if(Tflag) { 215433d6423SLionel Sambuc if(dflag) 216433d6423SLionel Sambuc errx(1, "-T and -d both specify a time and so are mutually exclusive"); 217433d6423SLionel Sambuc } else if(dflag) { 218433d6423SLionel Sambuc struct stat statbuf; 219433d6423SLionel Sambuc if (stat(progname, &statbuf)) { 220433d6423SLionel Sambuc err(1, "stat of itself"); 221433d6423SLionel Sambuc } 222433d6423SLionel Sambuc current_time = statbuf.st_mtime; 223433d6423SLionel Sambuc } else { 224433d6423SLionel Sambuc current_time = time((time_t *) 0); /* time mkfs is being run */ 225433d6423SLionel Sambuc } 226433d6423SLionel Sambuc 227433d6423SLionel Sambuc /* Percentage of extra size must be nonnegative. 228433d6423SLionel Sambuc * It can legitimately be bigger than 100 but has to make some sort of sense. 229433d6423SLionel Sambuc */ 230433d6423SLionel Sambuc if(extra_space_percent < 0 || extra_space_percent > 2000) usage(); 231433d6423SLionel Sambuc 232433d6423SLionel Sambuc #ifdef DEFAULT_BLOCK_SIZE 233433d6423SLionel Sambuc if(!block_size) block_size = DEFAULT_BLOCK_SIZE; 234433d6423SLionel Sambuc #endif 235433d6423SLionel Sambuc if (block_size % SECTOR_SIZE) 236433d6423SLionel Sambuc errx(4, "block size must be multiple of sector (%d bytes)", SECTOR_SIZE); 237433d6423SLionel Sambuc #ifdef MIN_BLOCK_SIZE 238433d6423SLionel Sambuc if (block_size < MIN_BLOCK_SIZE) 239433d6423SLionel Sambuc errx(4, "block size must be at least %d bytes", MIN_BLOCK_SIZE); 240433d6423SLionel Sambuc #endif 241433d6423SLionel Sambuc #ifdef MAX_BLOCK_SIZE 242433d6423SLionel Sambuc if (block_size > MAX_BLOCK_SIZE) 243433d6423SLionel Sambuc errx(4, "block size must be at most %d bytes", MAX_BLOCK_SIZE); 244433d6423SLionel Sambuc #endif 245433d6423SLionel Sambuc if(block_size%INODE_SIZE) 246433d6423SLionel Sambuc errx(4, "block size must be a multiple of inode size (%d bytes)", INODE_SIZE); 247433d6423SLionel Sambuc 248433d6423SLionel Sambuc if(zone_shift < 0 || zone_shift > 14) 249433d6423SLionel Sambuc errx(4, "zone_shift must be a small non-negative integer"); 250433d6423SLionel Sambuc zone_per_block = 1 << zone_shift; /* nr of blocks per zone */ 251433d6423SLionel Sambuc 252433d6423SLionel Sambuc inodes_per_block = INODES_PER_BLOCK(block_size); 253433d6423SLionel Sambuc indir_per_block = INDIRECTS(block_size); 254433d6423SLionel Sambuc indir_per_zone = INDIRECTS(block_size) << zone_shift; 255433d6423SLionel Sambuc /* number of file zones we can address directly and with a single indirect*/ 256433d6423SLionel Sambuc nr_indirzones = NR_DZONES + indir_per_zone; 257433d6423SLionel Sambuc zone_size = block_size << zone_shift; 258433d6423SLionel Sambuc /* Checks for an overflow: only with very big block size */ 259433d6423SLionel Sambuc if (zone_size <= 0) 260433d6423SLionel Sambuc errx(4, "Zones are too big for this program; smaller -B or -z, please!"); 261433d6423SLionel Sambuc 262433d6423SLionel Sambuc /* now that the block size is known, do buffer allocations where 263433d6423SLionel Sambuc * possible. 264433d6423SLionel Sambuc */ 265433d6423SLionel Sambuc zero = alloc_block(); 266433d6423SLionel Sambuc 267433d6423SLionel Sambuc fs_offset_blocks = roundup(fs_offset_bytes, block_size) / block_size; 268433d6423SLionel Sambuc 269433d6423SLionel Sambuc /* Determine the size of the device if not specified as -b or proto. */ 270433d6423SLionel Sambuc maxblocks = sizeup(argv[optind]); 271433d6423SLionel Sambuc if (bblocks != 0 && bblocks + fs_offset_blocks > maxblocks && !insertmode) { 272433d6423SLionel Sambuc errx(4, "Given size -b %d exeeds device capacity(%d)\n", bblocks, maxblocks); 273433d6423SLionel Sambuc } 274433d6423SLionel Sambuc 275433d6423SLionel Sambuc if (argc - optind == 1 && bblocks == 0) { 276433d6423SLionel Sambuc blocks = maxblocks; 277433d6423SLionel Sambuc /* blocks == 0 is checked later, but leads to a funny way of 278433d6423SLionel Sambuc * reporting a 0-sized device (displays usage). 279433d6423SLionel Sambuc */ 280433d6423SLionel Sambuc if(blocks < 1) { 281433d6423SLionel Sambuc errx(1, "zero size device."); 282433d6423SLionel Sambuc } 283433d6423SLionel Sambuc } 284433d6423SLionel Sambuc 285433d6423SLionel Sambuc /* The remaining args must be 'special proto', or just 'special' if the 286433d6423SLionel Sambuc * no. of blocks has already been specified. 287433d6423SLionel Sambuc */ 288433d6423SLionel Sambuc if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage(); 289433d6423SLionel Sambuc 290433d6423SLionel Sambuc if (maxblocks && blocks > maxblocks && !insertmode) { 291433d6423SLionel Sambuc errx(1, "%s: number of blocks too large for device.", argv[optind]); 292433d6423SLionel Sambuc } 293433d6423SLionel Sambuc 294433d6423SLionel Sambuc /* Check special. */ 295433d6423SLionel Sambuc check_mtab(argv[optind]); 296433d6423SLionel Sambuc 297433d6423SLionel Sambuc /* Check and start processing proto. */ 298433d6423SLionel Sambuc optarg = argv[++optind]; 299433d6423SLionel Sambuc if (optind < argc && (proto = fopen(optarg, "r")) != NULL) { 300433d6423SLionel Sambuc /* Prototype file is readable. */ 301433d6423SLionel Sambuc lct = 1; 302433d6423SLionel Sambuc get_line(line, token); /* skip boot block info */ 303433d6423SLionel Sambuc 304433d6423SLionel Sambuc /* Read the line with the block and inode counts. */ 305433d6423SLionel Sambuc get_line(line, token); 306433d6423SLionel Sambuc if (bblocks == 0){ 307433d6423SLionel Sambuc blocks = strtol(token[0], (char **) NULL, 10); 308433d6423SLionel Sambuc } else { 309433d6423SLionel Sambuc if(bblocks < strtol(token[0], (char **) NULL, 10)) { 310433d6423SLionel Sambuc errx(1, "%s: number of blocks given as parameter(%d)" 311*cd34841dSBen Gras " is too small for given proto file(%ld).", 312433d6423SLionel Sambuc argv[optind], bblocks, 313433d6423SLionel Sambuc strtol(token[0], (char **) NULL, 10)); 314433d6423SLionel Sambuc }; 315433d6423SLionel Sambuc } 316433d6423SLionel Sambuc inodes = strtol(token[1], (char **) NULL, 10); 317433d6423SLionel Sambuc 318433d6423SLionel Sambuc /* Process mode line for root directory. */ 319433d6423SLionel Sambuc get_line(line, token); 320433d6423SLionel Sambuc mode = mode_con(token[0]); 321433d6423SLionel Sambuc usrid = atoi(token[1]); 322433d6423SLionel Sambuc grpid = atoi(token[2]); 323433d6423SLionel Sambuc 324433d6423SLionel Sambuc if(blocks <= 0 && inodes <= 0){ 325433d6423SLionel Sambuc detect_fs_size(&fssize); 326433d6423SLionel Sambuc blocks = fssize.blockcount; 327433d6423SLionel Sambuc inodes = fssize.inocount; 328433d6423SLionel Sambuc blocks += blocks*extra_space_percent/100; 329433d6423SLionel Sambuc inodes += inodes*extra_space_percent/100; 330433d6423SLionel Sambuc /* XXX is it OK to write on stdout? Use warn() instead? Also consider using verbose */ 331433d6423SLionel Sambuc fprintf(stderr, "dynamically sized filesystem: %u blocks, %u inodes\n", 332433d6423SLionel Sambuc (unsigned int) blocks, (unsigned int) inodes); 333433d6423SLionel Sambuc } 334433d6423SLionel Sambuc } else { 335433d6423SLionel Sambuc lct = 0; 336433d6423SLionel Sambuc if (optind < argc) { 337433d6423SLionel Sambuc /* Maybe the prototype file is just a size. Check. */ 338433d6423SLionel Sambuc blocks = strtoul(optarg, (char **) NULL, 0); 339433d6423SLionel Sambuc if (blocks == 0) errx(2, "Can't open prototype file"); 340433d6423SLionel Sambuc } 341433d6423SLionel Sambuc 342433d6423SLionel Sambuc /* Make simple file system of the given size, using defaults. */ 343433d6423SLionel Sambuc mode = 040777; 344433d6423SLionel Sambuc usrid = BIN; 345433d6423SLionel Sambuc grpid = BINGRP; 346433d6423SLionel Sambuc simple = 1; 347433d6423SLionel Sambuc } 348433d6423SLionel Sambuc 349433d6423SLionel Sambuc if (inodes == 0) { 350433d6423SLionel Sambuc long long kb = ((unsigned long long)blocks*block_size) / 1024; 351433d6423SLionel Sambuc 352433d6423SLionel Sambuc inodes = kb / 2; 353433d6423SLionel Sambuc if (kb >= 100000) inodes = kb / 4; 354433d6423SLionel Sambuc if (kb >= 1000000) inodes = kb / 6; 355433d6423SLionel Sambuc if (kb >= 10000000) inodes = kb / 8; 356433d6423SLionel Sambuc if (kb >= 100000000) inodes = kb / 10; 357433d6423SLionel Sambuc if (kb >= 1000000000) inodes = kb / 12; 358433d6423SLionel Sambuc /* XXX check overflow: with very large number of blocks, this results in insanely large number of inodes */ 359433d6423SLionel Sambuc /* XXX check underflow (if/when ino_t is signed), else the message below will look strange */ 360433d6423SLionel Sambuc 361433d6423SLionel Sambuc /* round up to fill inode block */ 362433d6423SLionel Sambuc inodes += inodes_per_block - 1; 363433d6423SLionel Sambuc inodes = inodes / inodes_per_block * inodes_per_block; 364433d6423SLionel Sambuc } 365433d6423SLionel Sambuc 366433d6423SLionel Sambuc if (blocks < 5) errx(1, "Block count too small"); 367433d6423SLionel Sambuc if (inodes < 1) errx(1, "Inode count too small"); 368433d6423SLionel Sambuc 369433d6423SLionel Sambuc nrblocks = blocks; 370433d6423SLionel Sambuc nrinodes = inodes; 371433d6423SLionel Sambuc 372433d6423SLionel Sambuc umap_array_elements = 1 + blocks/8; 373433d6423SLionel Sambuc if(!(umap_array = malloc(umap_array_elements))) 374433d6423SLionel Sambuc err(1, "can't allocate block bitmap (%u bytes).", 375433d6423SLionel Sambuc (unsigned)umap_array_elements); 376433d6423SLionel Sambuc 377433d6423SLionel Sambuc /* Open special. */ 378433d6423SLionel Sambuc special(argv[--optind], insertmode); 379433d6423SLionel Sambuc 380433d6423SLionel Sambuc if (!donttest) { 381433d6423SLionel Sambuc uint16_t *testb; 382433d6423SLionel Sambuc ssize_t w; 383433d6423SLionel Sambuc 384433d6423SLionel Sambuc testb = alloc_block(); 385433d6423SLionel Sambuc 386433d6423SLionel Sambuc /* Try writing the last block of partition or diskette. */ 387433d6423SLionel Sambuc mkfs_seek((uint64_t)(blocks - 1) * block_size, SEEK_SET); 388433d6423SLionel Sambuc testb[0] = 0x3245; 389433d6423SLionel Sambuc testb[1] = 0x11FF; 390433d6423SLionel Sambuc testb[block_size/2-1] = 0x1F2F; 391433d6423SLionel Sambuc w=mkfs_write(testb, block_size); 392433d6423SLionel Sambuc sync(); /* flush write, so if error next read fails */ 393433d6423SLionel Sambuc mkfs_seek((uint64_t)(blocks - 1) * block_size, SEEK_SET); 394433d6423SLionel Sambuc testb[0] = 0; 395433d6423SLionel Sambuc testb[1] = 0; 396433d6423SLionel Sambuc testb[block_size/2-1] = 0; 397433d6423SLionel Sambuc nread = read(fd, testb, block_size); 398433d6423SLionel Sambuc if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF || 399433d6423SLionel Sambuc testb[block_size/2-1] != 0x1F2F) { 400433d6423SLionel Sambuc warn("nread = %d\n", nread); 401433d6423SLionel Sambuc warnx("testb = 0x%x 0x%x 0x%x\n", 402433d6423SLionel Sambuc testb[0], testb[1], testb[block_size-1]); 403433d6423SLionel Sambuc errx(1, "File system is too big for minor device (read)"); 404433d6423SLionel Sambuc } 405433d6423SLionel Sambuc mkfs_seek((uint64_t)(blocks - 1) * block_size, SEEK_SET); 406433d6423SLionel Sambuc testb[0] = 0; 407433d6423SLionel Sambuc testb[1] = 0; 408433d6423SLionel Sambuc testb[block_size/2-1] = 0; 409433d6423SLionel Sambuc mkfs_write(testb, block_size); 410433d6423SLionel Sambuc mkfs_seek(0L, SEEK_SET); 411433d6423SLionel Sambuc free(testb); 412433d6423SLionel Sambuc } 413433d6423SLionel Sambuc 414433d6423SLionel Sambuc /* Make the file-system */ 415433d6423SLionel Sambuc 416433d6423SLionel Sambuc put_block(BOOT_BLOCK, zero); /* Write a null boot block. */ 417433d6423SLionel Sambuc put_block(BOOT_BLOCK+1, zero); /* Write another null block. */ 418433d6423SLionel Sambuc 419433d6423SLionel Sambuc super(nrblocks >> zone_shift, inodes); 420433d6423SLionel Sambuc 421433d6423SLionel Sambuc root_inum = alloc_inode(mode, usrid, grpid); 422433d6423SLionel Sambuc rootdir(root_inum); 423433d6423SLionel Sambuc if (simple == 0) eat_dir(root_inum); 424433d6423SLionel Sambuc 425433d6423SLionel Sambuc if (print) print_fs(); 426433d6423SLionel Sambuc else if (verbose > 1) { 427433d6423SLionel Sambuc if (zone_shift) 428433d6423SLionel Sambuc fprintf(stderr, "%d inodes used. %u zones (%u blocks) used.\n", 429433d6423SLionel Sambuc (int)next_inode-1, next_zone, next_zone*zone_per_block); 430433d6423SLionel Sambuc else 431433d6423SLionel Sambuc fprintf(stderr, "%d inodes used. %u zones used.\n", 432433d6423SLionel Sambuc (int)next_inode-1, next_zone); 433433d6423SLionel Sambuc } 434433d6423SLionel Sambuc 435*cd34841dSBen Gras if(insertmode) printf("%llu\n", written_fs_size); 436433d6423SLionel Sambuc 437433d6423SLionel Sambuc return(0); 438433d6423SLionel Sambuc 439433d6423SLionel Sambuc /* NOTREACHED */ 440433d6423SLionel Sambuc } /* end main */ 441433d6423SLionel Sambuc 442433d6423SLionel Sambuc /*================================================================ 443433d6423SLionel Sambuc * detect_fs_size - determine image size dynamically 444433d6423SLionel Sambuc *===============================================================*/ 445433d6423SLionel Sambuc void 446433d6423SLionel Sambuc detect_fs_size(struct fs_size * fssize) 447433d6423SLionel Sambuc { 448433d6423SLionel Sambuc int prev_lct = lct; 449433d6423SLionel Sambuc off_t point = ftell(proto); 450433d6423SLionel Sambuc block_t initb; 451433d6423SLionel Sambuc zone_t initz; 452433d6423SLionel Sambuc 453433d6423SLionel Sambuc fssize->inocount = 1; /* root directory node */ 454433d6423SLionel Sambuc fssize->zonecount = 0; 455433d6423SLionel Sambuc fssize->blockcount = 0; 456433d6423SLionel Sambuc 457433d6423SLionel Sambuc sizeup_dir(fssize); 458433d6423SLionel Sambuc 459433d6423SLionel Sambuc initb = bitmapsize(1 + fssize->inocount, block_size); 460433d6423SLionel Sambuc initb += bitmapsize(fssize->zonecount, block_size); 461433d6423SLionel Sambuc initb += START_BLOCK; 462433d6423SLionel Sambuc initb += (fssize->inocount + inodes_per_block - 1) / inodes_per_block; 463433d6423SLionel Sambuc initz = (initb + zone_per_block - 1) >> zone_shift; 464433d6423SLionel Sambuc 465433d6423SLionel Sambuc fssize->blockcount = initb+ fssize->zonecount; 466433d6423SLionel Sambuc lct = prev_lct; 467433d6423SLionel Sambuc fseek(proto, point, SEEK_SET); 468433d6423SLionel Sambuc } 469433d6423SLionel Sambuc 470433d6423SLionel Sambuc void 471433d6423SLionel Sambuc sizeup_dir(struct fs_size * fssize) 472433d6423SLionel Sambuc { 473433d6423SLionel Sambuc char *token[MAX_TOKENS], *p; 474433d6423SLionel Sambuc char line[LINE_LEN]; 475433d6423SLionel Sambuc FILE *f; 476433d6423SLionel Sambuc off_t size; 477433d6423SLionel Sambuc int dir_entries = 2; 478433d6423SLionel Sambuc zone_t dir_zones = 0, fzones, indirects; 479433d6423SLionel Sambuc 480433d6423SLionel Sambuc while (1) { 481433d6423SLionel Sambuc get_line(line, token); 482433d6423SLionel Sambuc p = token[0]; 483433d6423SLionel Sambuc if (*p == '$') { 484433d6423SLionel Sambuc dir_zones = (dir_entries / (NR_DIR_ENTRIES(block_size) * zone_per_block)); 485433d6423SLionel Sambuc if(dir_entries % (NR_DIR_ENTRIES(block_size) * zone_per_block)) 486433d6423SLionel Sambuc dir_zones++; 487433d6423SLionel Sambuc if(dir_zones > NR_DZONES) 488433d6423SLionel Sambuc dir_zones++; /* Max single indir */ 489433d6423SLionel Sambuc fssize->zonecount += dir_zones; 490433d6423SLionel Sambuc return; 491433d6423SLionel Sambuc } 492433d6423SLionel Sambuc 493433d6423SLionel Sambuc p = token[1]; 494433d6423SLionel Sambuc fssize->inocount++; 495433d6423SLionel Sambuc dir_entries++; 496433d6423SLionel Sambuc 497433d6423SLionel Sambuc if (*p == 'd') { 498433d6423SLionel Sambuc sizeup_dir(fssize); 499433d6423SLionel Sambuc } else if (*p == 'b' || *p == 'c') { 500433d6423SLionel Sambuc 501433d6423SLionel Sambuc } else if (*p == 's') { 502433d6423SLionel Sambuc fssize->zonecount++; /* Symlink contents is always stored a block */ 503433d6423SLionel Sambuc } else { 504433d6423SLionel Sambuc if ((f = fopen(token[4], "rb")) == NULL) { 505*cd34841dSBen Gras /* on minix natively, allow EACCES and skip the entry. 506*cd34841dSBen Gras * while crossbuilding, always fail on error. 507*cd34841dSBen Gras */ 508*cd34841dSBen Gras #ifdef __minix 509*cd34841dSBen Gras if(errno == EACCES) 510433d6423SLionel Sambuc warn("dynamic sizing: can't open %s", token[4]); 511*cd34841dSBen Gras else 512*cd34841dSBen Gras #endif 513*cd34841dSBen Gras err(1, "dynamic sizing: can't open %s", token[4]); 514433d6423SLionel Sambuc } else if (fseek(f, 0, SEEK_END) < 0) { 515433d6423SLionel Sambuc pexit("dynamic size detection failed: seek to end of %s", 516433d6423SLionel Sambuc token[4]); 517433d6423SLionel Sambuc } else if ( (size = ftell(f)) == (off_t)(-1)) { 518433d6423SLionel Sambuc pexit("dynamic size detection failed: can't tell size of %s", 519433d6423SLionel Sambuc token[4]); 520433d6423SLionel Sambuc } else { 521433d6423SLionel Sambuc fclose(f); 522433d6423SLionel Sambuc fzones = roundup(size, zone_size) / zone_size; 523433d6423SLionel Sambuc indirects = 0; 524433d6423SLionel Sambuc /* XXX overflow? fzones is u32, size is potentially 64-bit */ 525433d6423SLionel Sambuc if (fzones > NR_DZONES) 526433d6423SLionel Sambuc indirects++; /* single indirect needed */ 527433d6423SLionel Sambuc if (fzones > nr_indirzones) { 528433d6423SLionel Sambuc /* Each further group of 'indir_per_zone' 529433d6423SLionel Sambuc * needs one supplementary indirect zone: 530433d6423SLionel Sambuc */ 531433d6423SLionel Sambuc indirects += roundup(fzones - nr_indirzones, 532433d6423SLionel Sambuc indir_per_zone) / indir_per_zone; 533433d6423SLionel Sambuc indirects++; /* + double indirect needed!*/ 534433d6423SLionel Sambuc } 535433d6423SLionel Sambuc fssize->zonecount += fzones + indirects; 536433d6423SLionel Sambuc } 537433d6423SLionel Sambuc } 538433d6423SLionel Sambuc } 539433d6423SLionel Sambuc } 540433d6423SLionel Sambuc 541433d6423SLionel Sambuc /*================================================================ 542433d6423SLionel Sambuc * sizeup - determine device size 543433d6423SLionel Sambuc *===============================================================*/ 544433d6423SLionel Sambuc block_t 545433d6423SLionel Sambuc sizeup(char * device) 546433d6423SLionel Sambuc { 547433d6423SLionel Sambuc block_t d; 548433d6423SLionel Sambuc #if defined(__minix) 549433d6423SLionel Sambuc uint64_t bytes, resize; 550433d6423SLionel Sambuc uint32_t rem; 551433d6423SLionel Sambuc #else 552433d6423SLionel Sambuc off_t size; 553433d6423SLionel Sambuc #endif 554433d6423SLionel Sambuc 555433d6423SLionel Sambuc 556433d6423SLionel Sambuc if ((fd = open(device, O_RDONLY)) == -1) { 557433d6423SLionel Sambuc if (errno != ENOENT) 558433d6423SLionel Sambuc perror("sizeup open"); 559433d6423SLionel Sambuc return 0; 560433d6423SLionel Sambuc } 561433d6423SLionel Sambuc 562433d6423SLionel Sambuc #if defined(__minix) 563433d6423SLionel Sambuc if(minix_sizeup(device, &bytes) < 0) { 564433d6423SLionel Sambuc perror("sizeup"); 565433d6423SLionel Sambuc return 0; 566433d6423SLionel Sambuc } 567433d6423SLionel Sambuc 568433d6423SLionel Sambuc d = (uint32_t)(bytes / block_size); 569433d6423SLionel Sambuc rem = (uint32_t)(bytes % block_size); 570433d6423SLionel Sambuc 571433d6423SLionel Sambuc resize = ((uint64_t)d * block_size) + rem; 572433d6423SLionel Sambuc if(resize != bytes) { 573433d6423SLionel Sambuc /* Assume block_t is unsigned */ 574433d6423SLionel Sambuc d = (block_t)(-1ul); 575433d6423SLionel Sambuc fprintf(stderr, "%s: truncating FS at %lu blocks\n", 576433d6423SLionel Sambuc progname, (unsigned long)d); 577433d6423SLionel Sambuc } 578433d6423SLionel Sambuc #else 579433d6423SLionel Sambuc size = mkfs_seek(0, SEEK_END); 580433d6423SLionel Sambuc /* Assume block_t is unsigned */ 581433d6423SLionel Sambuc if (size / block_size > (block_t)(-1ul)) { 582433d6423SLionel Sambuc d = (block_t)(-1ul); 583433d6423SLionel Sambuc fprintf(stderr, "%s: truncating FS at %lu blocks\n", 584433d6423SLionel Sambuc progname, (unsigned long)d); 585433d6423SLionel Sambuc } else 586433d6423SLionel Sambuc d = size / block_size; 587433d6423SLionel Sambuc #endif 588433d6423SLionel Sambuc 589433d6423SLionel Sambuc return d; 590433d6423SLionel Sambuc } 591433d6423SLionel Sambuc 592433d6423SLionel Sambuc /* 593433d6423SLionel Sambuc * copied from fslib 594433d6423SLionel Sambuc */ 595433d6423SLionel Sambuc static int 596433d6423SLionel Sambuc bitmapsize(bit_t nr_bits, size_t blk_size) 597433d6423SLionel Sambuc { 598433d6423SLionel Sambuc block_t nr_blocks; 599433d6423SLionel Sambuc 600433d6423SLionel Sambuc nr_blocks = nr_bits / FS_BITS_PER_BLOCK(blk_size); 601433d6423SLionel Sambuc if (nr_blocks * FS_BITS_PER_BLOCK(blk_size) < nr_bits) 602433d6423SLionel Sambuc ++nr_blocks; 603433d6423SLionel Sambuc return(nr_blocks); 604433d6423SLionel Sambuc } 605433d6423SLionel Sambuc 606433d6423SLionel Sambuc /*================================================================ 607433d6423SLionel Sambuc * super - construct a superblock 608433d6423SLionel Sambuc *===============================================================*/ 609433d6423SLionel Sambuc 610433d6423SLionel Sambuc void 611433d6423SLionel Sambuc super(zone_t zones, ino_t inodes) 612433d6423SLionel Sambuc { 613433d6423SLionel Sambuc block_t inodeblks, initblks, i; 614433d6423SLionel Sambuc unsigned long nb; 615433d6423SLionel Sambuc long long ind_per_zone, zo; 616433d6423SLionel Sambuc void *buf; 617433d6423SLionel Sambuc struct super_block *sup; 618433d6423SLionel Sambuc 619433d6423SLionel Sambuc sup = buf = alloc_block(); 620433d6423SLionel Sambuc 621433d6423SLionel Sambuc #ifdef MFSFLAG_CLEAN 622433d6423SLionel Sambuc /* The assumption is that mkfs will create a clean FS. */ 623433d6423SLionel Sambuc sup->s_flags = MFSFLAG_CLEAN; 624433d6423SLionel Sambuc #endif 625433d6423SLionel Sambuc 626433d6423SLionel Sambuc sup->s_ninodes = inodes; 627433d6423SLionel Sambuc /* Check for overflow; cannot happen on V3 file systems */ 628433d6423SLionel Sambuc if(inodes != sup->s_ninodes) 629433d6423SLionel Sambuc errx(1, "Too much inodes for that version of Minix FS."); 630433d6423SLionel Sambuc sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */ 631433d6423SLionel Sambuc sup->s_zones = zones; 632433d6423SLionel Sambuc /* Check for overflow; can only happen on V1 file systems */ 633433d6423SLionel Sambuc if(zones != sup->s_zones) 634433d6423SLionel Sambuc errx(1, "Too much zones (blocks) for that version of Minix FS."); 635433d6423SLionel Sambuc 636433d6423SLionel Sambuc #ifndef MFS_STATIC_BLOCK_SIZE 637433d6423SLionel Sambuc #define BIGGERBLOCKS "Please try a larger block size for an FS of this size." 638433d6423SLionel Sambuc #else 639433d6423SLionel Sambuc #define BIGGERBLOCKS "Please use MinixFS V3 for an FS of this size." 640433d6423SLionel Sambuc #endif 641433d6423SLionel Sambuc sup->s_imap_blocks = nb = bitmapsize(1 + inodes, block_size); 642433d6423SLionel Sambuc /* Checks for an overflow: nb is uint32_t while s_imap_blocks is of type 643433d6423SLionel Sambuc * int16_t */ 644433d6423SLionel Sambuc if(sup->s_imap_blocks != nb) { 645433d6423SLionel Sambuc errx(1, "too many inode bitmap blocks.\n" BIGGERBLOCKS); 646433d6423SLionel Sambuc } 647433d6423SLionel Sambuc sup->s_zmap_blocks = nb = bitmapsize(zones, block_size); 648433d6423SLionel Sambuc /* Idem here check for overflow */ 649433d6423SLionel Sambuc if(nb != sup->s_zmap_blocks) { 650433d6423SLionel Sambuc errx(1, "too many block bitmap blocks.\n" BIGGERBLOCKS); 651433d6423SLionel Sambuc } 652433d6423SLionel Sambuc inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks; 653433d6423SLionel Sambuc inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block; 654433d6423SLionel Sambuc initblks = inode_offset + inodeblks; 655433d6423SLionel Sambuc sup->s_firstdatazone_old = nb = 656433d6423SLionel Sambuc (initblks + (1 << zone_shift) - 1) >> zone_shift; 657433d6423SLionel Sambuc if(nb >= zones) errx(1, "bit maps too large"); 658433d6423SLionel Sambuc if(nb != sup->s_firstdatazone_old) { 659433d6423SLionel Sambuc /* The field is too small to store the value. Fortunately, the value 660433d6423SLionel Sambuc * can be computed from other fields. We set the on-disk field to zero 661433d6423SLionel Sambuc * to indicate that it must not be used. Eventually, we can always set 662433d6423SLionel Sambuc * the on-disk field to zero, and stop using it. 663433d6423SLionel Sambuc */ 664433d6423SLionel Sambuc sup->s_firstdatazone_old = 0; 665433d6423SLionel Sambuc } 666433d6423SLionel Sambuc sup->s_firstdatazone = nb; 667433d6423SLionel Sambuc zoff = sup->s_firstdatazone - 1; 668433d6423SLionel Sambuc sup->s_log_zone_size = zone_shift; 669433d6423SLionel Sambuc sup->s_magic = SUPER_MAGIC; 670433d6423SLionel Sambuc #ifdef MFS_SUPER_BLOCK_SIZE 671433d6423SLionel Sambuc sup->s_block_size = block_size; 672433d6423SLionel Sambuc /* Check for overflow */ 673433d6423SLionel Sambuc if(block_size != sup->MFS_SUPER_BLOCK_SIZE) 674433d6423SLionel Sambuc errx(1, "block_size too large."); 675433d6423SLionel Sambuc sup->s_disk_version = 0; 676433d6423SLionel Sambuc #endif 677433d6423SLionel Sambuc 678433d6423SLionel Sambuc ind_per_zone = (long long) indir_per_zone; 679433d6423SLionel Sambuc zo = NR_DZONES + ind_per_zone + ind_per_zone*ind_per_zone; 680433d6423SLionel Sambuc #ifndef MAX_MAX_SIZE 681433d6423SLionel Sambuc #define MAX_MAX_SIZE (INT32_MAX) 682433d6423SLionel Sambuc #endif 683433d6423SLionel Sambuc if(MAX_MAX_SIZE/block_size < zo) { 684433d6423SLionel Sambuc sup->s_max_size = MAX_MAX_SIZE; 685433d6423SLionel Sambuc } 686433d6423SLionel Sambuc else { 687433d6423SLionel Sambuc sup->s_max_size = zo * block_size; 688433d6423SLionel Sambuc } 689433d6423SLionel Sambuc 690433d6423SLionel Sambuc if (verbose>1) { 691433d6423SLionel Sambuc fprintf(stderr, "Super block values:\n" 692433d6423SLionel Sambuc "\tnumber of inodes\t%12d\n" 693433d6423SLionel Sambuc "\tnumber of zones \t%12d\n" 694433d6423SLionel Sambuc "\tinode bit map blocks\t%12d\n" 695433d6423SLionel Sambuc "\tzone bit map blocks\t%12d\n" 696433d6423SLionel Sambuc "\tfirst data zone \t%12d\n" 697433d6423SLionel Sambuc "\tblocks per zone shift\t%12d\n" 698433d6423SLionel Sambuc "\tmaximum file size\t%12d\n" 699433d6423SLionel Sambuc "\tmagic number\t\t%#12X\n", 700433d6423SLionel Sambuc sup->s_ninodes, sup->s_zones, 701433d6423SLionel Sambuc sup->s_imap_blocks, sup->s_zmap_blocks, sup->s_firstdatazone, 702433d6423SLionel Sambuc sup->s_log_zone_size, sup->s_max_size, sup->s_magic); 703433d6423SLionel Sambuc #ifdef MFS_SUPER_BLOCK_SIZE 704433d6423SLionel Sambuc fprintf(stderr, "\tblock size\t\t%12d\n", sup->s_block_size); 705433d6423SLionel Sambuc #endif 706433d6423SLionel Sambuc } 707433d6423SLionel Sambuc 708433d6423SLionel Sambuc mkfs_seek((off_t) SUPER_BLOCK_BYTES, SEEK_SET); 709433d6423SLionel Sambuc mkfs_write(buf, SUPER_BLOCK_BYTES); 710433d6423SLionel Sambuc 711433d6423SLionel Sambuc /* Clear maps and inodes. */ 712433d6423SLionel Sambuc for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero); 713433d6423SLionel Sambuc 714433d6423SLionel Sambuc next_zone = sup->s_firstdatazone; 715433d6423SLionel Sambuc next_inode = 1; 716433d6423SLionel Sambuc 717433d6423SLionel Sambuc zone_map = INODE_MAP + sup->s_imap_blocks; 718433d6423SLionel Sambuc 719433d6423SLionel Sambuc insert_bit(zone_map, 0); /* bit zero must always be allocated */ 720433d6423SLionel Sambuc insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but 721433d6423SLionel Sambuc * must be allocated */ 722433d6423SLionel Sambuc 723433d6423SLionel Sambuc free(buf); 724433d6423SLionel Sambuc } 725433d6423SLionel Sambuc 726433d6423SLionel Sambuc 727433d6423SLionel Sambuc /*================================================================ 728433d6423SLionel Sambuc * rootdir - install the root directory 729433d6423SLionel Sambuc *===============================================================*/ 730433d6423SLionel Sambuc void 731433d6423SLionel Sambuc rootdir(ino_t inode) 732433d6423SLionel Sambuc { 733433d6423SLionel Sambuc zone_t z; 734433d6423SLionel Sambuc 735433d6423SLionel Sambuc z = alloc_zone(); 736433d6423SLionel Sambuc add_zone(inode, z, 2 * sizeof(struct direct), current_time); 737433d6423SLionel Sambuc enter_dir(inode, ".", inode); 738433d6423SLionel Sambuc enter_dir(inode, "..", inode); 739433d6423SLionel Sambuc incr_link(inode); 740433d6423SLionel Sambuc incr_link(inode); 741433d6423SLionel Sambuc } 742433d6423SLionel Sambuc 743433d6423SLionel Sambuc void 744433d6423SLionel Sambuc enter_symlink(ino_t inode, char *lnk) 745433d6423SLionel Sambuc { 746433d6423SLionel Sambuc zone_t z; 747433d6423SLionel Sambuc size_t len; 748433d6423SLionel Sambuc char *buf; 749433d6423SLionel Sambuc 750433d6423SLionel Sambuc buf = alloc_block(); 751433d6423SLionel Sambuc z = alloc_zone(); 752433d6423SLionel Sambuc len = strlen(lnk); 753433d6423SLionel Sambuc if (len >= block_size) 754433d6423SLionel Sambuc pexit("symlink too long, max length is %u", (unsigned)block_size - 1); 755433d6423SLionel Sambuc strcpy(buf, lnk); 756433d6423SLionel Sambuc put_block((z << zone_shift), buf); 757433d6423SLionel Sambuc 758433d6423SLionel Sambuc add_zone(inode, z, len, current_time); 759433d6423SLionel Sambuc 760433d6423SLionel Sambuc free(buf); 761433d6423SLionel Sambuc } 762433d6423SLionel Sambuc 763433d6423SLionel Sambuc 764433d6423SLionel Sambuc /*================================================================ 765433d6423SLionel Sambuc * eat_dir - recursively install directory 766433d6423SLionel Sambuc *===============================================================*/ 767433d6423SLionel Sambuc void 768433d6423SLionel Sambuc eat_dir(ino_t parent) 769433d6423SLionel Sambuc { 770433d6423SLionel Sambuc /* Read prototype lines and set up directory. Recurse if need be. */ 771433d6423SLionel Sambuc char *token[MAX_TOKENS], *p; 772433d6423SLionel Sambuc char line[LINE_LEN]; 773433d6423SLionel Sambuc int mode, usrid, grpid, maj, min, f; 774433d6423SLionel Sambuc ino_t n; 775433d6423SLionel Sambuc zone_t z; 776433d6423SLionel Sambuc size_t size; 777433d6423SLionel Sambuc 778433d6423SLionel Sambuc while (1) { 779433d6423SLionel Sambuc get_line(line, token); 780433d6423SLionel Sambuc p = token[0]; 781433d6423SLionel Sambuc if (*p == '$') return; 782433d6423SLionel Sambuc p = token[1]; 783433d6423SLionel Sambuc mode = mode_con(p); 784433d6423SLionel Sambuc usrid = atoi(token[2]); 785433d6423SLionel Sambuc grpid = atoi(token[3]); 786433d6423SLionel Sambuc n = alloc_inode(mode, usrid, grpid); 787433d6423SLionel Sambuc 788433d6423SLionel Sambuc /* Enter name in directory and update directory's size. */ 789433d6423SLionel Sambuc enter_dir(parent, token[0], n); 790433d6423SLionel Sambuc incr_size(parent, sizeof(struct direct)); 791433d6423SLionel Sambuc 792433d6423SLionel Sambuc /* Check to see if file is directory or special. */ 793433d6423SLionel Sambuc incr_link(n); 794433d6423SLionel Sambuc if (*p == 'd') { 795433d6423SLionel Sambuc /* This is a directory. */ 796433d6423SLionel Sambuc z = alloc_zone(); /* zone for new directory */ 797433d6423SLionel Sambuc add_zone(n, z, 2 * sizeof(struct direct), current_time); 798433d6423SLionel Sambuc enter_dir(n, ".", n); 799433d6423SLionel Sambuc enter_dir(n, "..", parent); 800433d6423SLionel Sambuc incr_link(parent); 801433d6423SLionel Sambuc incr_link(n); 802433d6423SLionel Sambuc eat_dir(n); 803433d6423SLionel Sambuc } else if (*p == 'b' || *p == 'c') { 804433d6423SLionel Sambuc /* Special file. */ 805433d6423SLionel Sambuc maj = atoi(token[4]); 806433d6423SLionel Sambuc min = atoi(token[5]); 807433d6423SLionel Sambuc size = 0; 808433d6423SLionel Sambuc if (token[6]) size = atoi(token[6]); 809433d6423SLionel Sambuc size = block_size * size; 810433d6423SLionel Sambuc add_zone(n, (zone_t) (makedev(maj,min)), size, current_time); 811433d6423SLionel Sambuc } else if (*p == 's') { 812433d6423SLionel Sambuc enter_symlink(n, token[4]); 813433d6423SLionel Sambuc } else { 814433d6423SLionel Sambuc /* Regular file. Go read it. */ 815433d6423SLionel Sambuc if ((f = open(token[4], O_RDONLY)) < 0) { 816*cd34841dSBen Gras /* on minix natively, allow EACCES and skip the entry. 817*cd34841dSBen Gras * while crossbuilding, always fail on error. 818*cd34841dSBen Gras */ 819*cd34841dSBen Gras #ifdef __minix 820*cd34841dSBen Gras if(errno == EACCES) 821*cd34841dSBen Gras warn("Can't open %s", token[4]); 822*cd34841dSBen Gras else 823*cd34841dSBen Gras #endif 824*cd34841dSBen Gras err(1, "Can't open %s", token[4]); 825433d6423SLionel Sambuc } else { 826433d6423SLionel Sambuc eat_file(n, f); 827433d6423SLionel Sambuc } 828433d6423SLionel Sambuc } 829433d6423SLionel Sambuc } 830433d6423SLionel Sambuc 831433d6423SLionel Sambuc } 832433d6423SLionel Sambuc 833433d6423SLionel Sambuc /*================================================================ 834433d6423SLionel Sambuc * eat_file - copy file to MINIX 835433d6423SLionel Sambuc *===============================================================*/ 836433d6423SLionel Sambuc /* Zonesize >= blocksize */ 837433d6423SLionel Sambuc void 838433d6423SLionel Sambuc eat_file(ino_t inode, int f) 839433d6423SLionel Sambuc { 840433d6423SLionel Sambuc int ct = 0, i, j; 841433d6423SLionel Sambuc zone_t z = 0; 842433d6423SLionel Sambuc char *buf; 843433d6423SLionel Sambuc time_t timeval; 844433d6423SLionel Sambuc 845433d6423SLionel Sambuc buf = alloc_block(); 846433d6423SLionel Sambuc 847433d6423SLionel Sambuc do { 848433d6423SLionel Sambuc for (i = 0, j = 0; i < zone_per_block; i++, j += ct) { 849433d6423SLionel Sambuc memset(buf, 0, block_size); 850433d6423SLionel Sambuc if ((ct = read(f, buf, block_size)) > 0) { 851433d6423SLionel Sambuc if (i == 0) z = alloc_zone(); 852433d6423SLionel Sambuc put_block((z << zone_shift) + i, buf); 853433d6423SLionel Sambuc } 854433d6423SLionel Sambuc } 855433d6423SLionel Sambuc timeval = (dflag ? current_time : file_time(f)); 856433d6423SLionel Sambuc if (ct) add_zone(inode, z, (size_t) j, timeval); 857433d6423SLionel Sambuc } while (ct == block_size); 858433d6423SLionel Sambuc close(f); 859433d6423SLionel Sambuc free(buf); 860433d6423SLionel Sambuc } 861433d6423SLionel Sambuc 862433d6423SLionel Sambuc int 863433d6423SLionel Sambuc dir_try_enter(zone_t z, ino_t child, char const *name) 864433d6423SLionel Sambuc { 865433d6423SLionel Sambuc struct direct *dir_entry = alloc_block(); 866433d6423SLionel Sambuc int r = 0; 867433d6423SLionel Sambuc block_t b; 868433d6423SLionel Sambuc int i, l; 869433d6423SLionel Sambuc 870433d6423SLionel Sambuc b = z << zone_shift; 871433d6423SLionel Sambuc for (l = 0; l < zone_per_block; l++, b++) { 872433d6423SLionel Sambuc get_block(b, dir_entry); 873433d6423SLionel Sambuc 874433d6423SLionel Sambuc for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) 875433d6423SLionel Sambuc if (!dir_entry[i].d_ino) 876433d6423SLionel Sambuc break; 877433d6423SLionel Sambuc 878433d6423SLionel Sambuc if(i < NR_DIR_ENTRIES(block_size)) { 879433d6423SLionel Sambuc r = 1; 880433d6423SLionel Sambuc dir_entry[i].d_ino = child; 881433d6423SLionel Sambuc assert(sizeof(dir_entry[i].d_name) == MFS_DIRSIZ); 882433d6423SLionel Sambuc if (verbose && strlen(name) > MFS_DIRSIZ) 883433d6423SLionel Sambuc fprintf(stderr, "File name %s is too long, truncated\n", name); 884433d6423SLionel Sambuc strncpy(dir_entry[i].d_name, name, MFS_DIRSIZ); 885433d6423SLionel Sambuc put_block(b, dir_entry); 886433d6423SLionel Sambuc break; 887433d6423SLionel Sambuc } 888433d6423SLionel Sambuc } 889433d6423SLionel Sambuc 890433d6423SLionel Sambuc free(dir_entry); 891433d6423SLionel Sambuc 892433d6423SLionel Sambuc return r; 893433d6423SLionel Sambuc } 894433d6423SLionel Sambuc 895433d6423SLionel Sambuc /*================================================================ 896433d6423SLionel Sambuc * directory & inode management assist group 897433d6423SLionel Sambuc *===============================================================*/ 898433d6423SLionel Sambuc void 899433d6423SLionel Sambuc enter_dir(ino_t parent, char const *name, ino_t child) 900433d6423SLionel Sambuc { 901433d6423SLionel Sambuc /* Enter child in parent directory */ 902433d6423SLionel Sambuc /* Works for dir > 1 block and zone > block */ 903433d6423SLionel Sambuc unsigned int k; 904433d6423SLionel Sambuc block_t b, indir; 905433d6423SLionel Sambuc zone_t z; 906433d6423SLionel Sambuc int off; 907433d6423SLionel Sambuc struct inode *ino; 908433d6423SLionel Sambuc struct inode *inoblock = alloc_block(); 909433d6423SLionel Sambuc zone_t *indirblock = alloc_block(); 910433d6423SLionel Sambuc 911433d6423SLionel Sambuc assert(!(block_size % sizeof(struct direct))); 912433d6423SLionel Sambuc 913433d6423SLionel Sambuc /* Obtain the inode structure */ 914433d6423SLionel Sambuc b = ((parent - 1) / inodes_per_block) + inode_offset; 915433d6423SLionel Sambuc off = (parent - 1) % inodes_per_block; 916433d6423SLionel Sambuc get_block(b, inoblock); 917433d6423SLionel Sambuc ino = inoblock + off; 918433d6423SLionel Sambuc 919433d6423SLionel Sambuc for (k = 0; k < NR_DZONES; k++) { 920433d6423SLionel Sambuc z = ino->i_zone[k]; 921433d6423SLionel Sambuc if (z == 0) { 922433d6423SLionel Sambuc z = alloc_zone(); 923433d6423SLionel Sambuc ino->i_zone[k] = z; 924433d6423SLionel Sambuc } 925433d6423SLionel Sambuc 926433d6423SLionel Sambuc if(dir_try_enter(z, child, __UNCONST(name))) { 927433d6423SLionel Sambuc put_block(b, inoblock); 928433d6423SLionel Sambuc free(inoblock); 929433d6423SLionel Sambuc free(indirblock); 930433d6423SLionel Sambuc return; 931433d6423SLionel Sambuc } 932433d6423SLionel Sambuc } 933433d6423SLionel Sambuc 934433d6423SLionel Sambuc /* no space in directory using just direct blocks; try indirect */ 935433d6423SLionel Sambuc if (ino->i_zone[S_INDIRECT_IDX] == 0) 936433d6423SLionel Sambuc ino->i_zone[S_INDIRECT_IDX] = alloc_zone(); 937433d6423SLionel Sambuc 938433d6423SLionel Sambuc indir = ino->i_zone[S_INDIRECT_IDX] << zone_shift; 939433d6423SLionel Sambuc --indir; /* Compensate for ++indir below */ 940433d6423SLionel Sambuc for(k = 0; k < (indir_per_zone); k++) { 941433d6423SLionel Sambuc if (k % indir_per_block == 0) 942433d6423SLionel Sambuc get_block(++indir, indirblock); 943433d6423SLionel Sambuc z = indirblock[k % indir_per_block]; 944433d6423SLionel Sambuc if(!z) { 945433d6423SLionel Sambuc z = indirblock[k % indir_per_block] = alloc_zone(); 946433d6423SLionel Sambuc put_block(indir, indirblock); 947433d6423SLionel Sambuc } 948433d6423SLionel Sambuc if(dir_try_enter(z, child, __UNCONST(name))) { 949433d6423SLionel Sambuc put_block(b, inoblock); 950433d6423SLionel Sambuc free(inoblock); 951433d6423SLionel Sambuc free(indirblock); 952433d6423SLionel Sambuc return; 953433d6423SLionel Sambuc } 954433d6423SLionel Sambuc } 955433d6423SLionel Sambuc 956433d6423SLionel Sambuc pexit("Directory-inode %u beyond single indirect blocks. Could not enter %s", 957433d6423SLionel Sambuc (unsigned)parent, name); 958433d6423SLionel Sambuc } 959433d6423SLionel Sambuc 960433d6423SLionel Sambuc 961433d6423SLionel Sambuc void 962433d6423SLionel Sambuc add_zone(ino_t n, zone_t z, size_t bytes, time_t mtime) 963433d6423SLionel Sambuc { 964433d6423SLionel Sambuc /* Add zone z to inode n. The file has grown by 'bytes' bytes. */ 965433d6423SLionel Sambuc 966433d6423SLionel Sambuc int off, i, j; 967433d6423SLionel Sambuc block_t b; 968433d6423SLionel Sambuc zone_t indir, dindir; 969433d6423SLionel Sambuc struct inode *p, *inode; 970433d6423SLionel Sambuc zone_t *blk, *dblk; 971433d6423SLionel Sambuc 972433d6423SLionel Sambuc assert(inodes_per_block*sizeof(*inode) == block_size); 973433d6423SLionel Sambuc if(!(inode = alloc_block())) 974433d6423SLionel Sambuc err(1, "Couldn't allocate block of inodes"); 975433d6423SLionel Sambuc 976433d6423SLionel Sambuc b = ((n - 1) / inodes_per_block) + inode_offset; 977433d6423SLionel Sambuc off = (n - 1) % inodes_per_block; 978433d6423SLionel Sambuc get_block(b, inode); 979433d6423SLionel Sambuc p = &inode[off]; 980433d6423SLionel Sambuc p->i_size += bytes; 981433d6423SLionel Sambuc p->i_mtime = mtime; 982433d6423SLionel Sambuc #ifndef MFS_INODE_ONLY_MTIME /* V1 file systems did not have them... */ 983433d6423SLionel Sambuc p->i_atime = p->i_ctime = current_time; 984433d6423SLionel Sambuc #endif 985433d6423SLionel Sambuc for (i = 0; i < NR_DZONES; i++) 986433d6423SLionel Sambuc if (p->i_zone[i] == 0) { 987433d6423SLionel Sambuc p->i_zone[i] = z; 988433d6423SLionel Sambuc put_block(b, inode); 989433d6423SLionel Sambuc free(inode); 990433d6423SLionel Sambuc return; 991433d6423SLionel Sambuc } 992433d6423SLionel Sambuc 993433d6423SLionel Sambuc assert(indir_per_block*sizeof(*blk) == block_size); 994433d6423SLionel Sambuc if(!(blk = alloc_block())) 995433d6423SLionel Sambuc err(1, "Couldn't allocate indirect block"); 996433d6423SLionel Sambuc 997433d6423SLionel Sambuc /* File has grown beyond a small file. */ 998433d6423SLionel Sambuc if (p->i_zone[S_INDIRECT_IDX] == 0) 999433d6423SLionel Sambuc p->i_zone[S_INDIRECT_IDX] = alloc_zone(); 1000433d6423SLionel Sambuc indir = p->i_zone[S_INDIRECT_IDX] << zone_shift; 1001433d6423SLionel Sambuc put_block(b, inode); 1002433d6423SLionel Sambuc --indir; /* Compensate for ++indir below */ 1003433d6423SLionel Sambuc for (i = 0; i < (indir_per_zone); i++) { 1004433d6423SLionel Sambuc if (i % indir_per_block == 0) 1005433d6423SLionel Sambuc get_block(++indir, blk); 1006433d6423SLionel Sambuc if (blk[i % indir_per_block] == 0) { 1007433d6423SLionel Sambuc blk[i] = z; 1008433d6423SLionel Sambuc put_block(indir, blk); 1009433d6423SLionel Sambuc free(blk); 1010433d6423SLionel Sambuc free(inode); 1011433d6423SLionel Sambuc return; 1012433d6423SLionel Sambuc } 1013433d6423SLionel Sambuc } 1014433d6423SLionel Sambuc 1015433d6423SLionel Sambuc /* File has grown beyond single indirect; we need a double indirect */ 1016433d6423SLionel Sambuc assert(indir_per_block*sizeof(*dblk) == block_size); 1017433d6423SLionel Sambuc if(!(dblk = alloc_block())) 1018433d6423SLionel Sambuc err(1, "Couldn't allocate double indirect block"); 1019433d6423SLionel Sambuc 1020433d6423SLionel Sambuc if (p->i_zone[D_INDIRECT_IDX] == 0) 1021433d6423SLionel Sambuc p->i_zone[D_INDIRECT_IDX] = alloc_zone(); 1022433d6423SLionel Sambuc dindir = p->i_zone[D_INDIRECT_IDX] << zone_shift; 1023433d6423SLionel Sambuc put_block(b, inode); 1024433d6423SLionel Sambuc --dindir; /* Compensate for ++indir below */ 1025433d6423SLionel Sambuc for (j = 0; j < (indir_per_zone); j++) { 1026433d6423SLionel Sambuc if (j % indir_per_block == 0) 1027433d6423SLionel Sambuc get_block(++dindir, dblk); 1028433d6423SLionel Sambuc if (dblk[j % indir_per_block] == 0) 1029433d6423SLionel Sambuc dblk[j % indir_per_block] = alloc_zone(); 1030433d6423SLionel Sambuc indir = dblk[j % indir_per_block] << zone_shift; 1031433d6423SLionel Sambuc --indir; /* Compensate for ++indir below */ 1032433d6423SLionel Sambuc for (i = 0; i < (indir_per_zone); i++) { 1033433d6423SLionel Sambuc if (i % indir_per_block == 0) 1034433d6423SLionel Sambuc get_block(++indir, blk); 1035433d6423SLionel Sambuc if (blk[i % indir_per_block] == 0) { 1036433d6423SLionel Sambuc blk[i] = z; 1037433d6423SLionel Sambuc put_block(dindir, dblk); 1038433d6423SLionel Sambuc put_block(indir, blk); 1039433d6423SLionel Sambuc free(dblk); 1040433d6423SLionel Sambuc free(blk); 1041433d6423SLionel Sambuc free(inode); 1042433d6423SLionel Sambuc return; 1043433d6423SLionel Sambuc } 1044433d6423SLionel Sambuc } 1045433d6423SLionel Sambuc } 1046433d6423SLionel Sambuc 1047433d6423SLionel Sambuc pexit("File has grown beyond double indirect"); 1048433d6423SLionel Sambuc } 1049433d6423SLionel Sambuc 1050433d6423SLionel Sambuc 1051433d6423SLionel Sambuc /* Increment the link count to inode n */ 1052433d6423SLionel Sambuc void 1053433d6423SLionel Sambuc incr_link(ino_t n) 1054433d6423SLionel Sambuc { 1055433d6423SLionel Sambuc int off; 1056433d6423SLionel Sambuc static int enter = 0; 1057433d6423SLionel Sambuc static struct inode *inodes = NULL; 1058433d6423SLionel Sambuc block_t b; 1059433d6423SLionel Sambuc 1060433d6423SLionel Sambuc if (enter++) pexit("internal error: recursive call to incr_link()"); 1061433d6423SLionel Sambuc 1062433d6423SLionel Sambuc b = ((n - 1) / inodes_per_block) + inode_offset; 1063433d6423SLionel Sambuc off = (n - 1) % inodes_per_block; 1064433d6423SLionel Sambuc { 1065433d6423SLionel Sambuc assert(sizeof(*inodes) * inodes_per_block == block_size); 1066433d6423SLionel Sambuc if(!inodes && !(inodes = alloc_block())) 1067433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1068433d6423SLionel Sambuc 1069433d6423SLionel Sambuc get_block(b, inodes); 1070433d6423SLionel Sambuc inodes[off].i_nlinks++; 1071433d6423SLionel Sambuc /* Check overflow (particularly on V1)... */ 1072433d6423SLionel Sambuc if (inodes[off].i_nlinks <= 0) 1073433d6423SLionel Sambuc pexit("Too many links to a directory"); 1074433d6423SLionel Sambuc put_block(b, inodes); 1075433d6423SLionel Sambuc } 1076433d6423SLionel Sambuc enter = 0; 1077433d6423SLionel Sambuc } 1078433d6423SLionel Sambuc 1079433d6423SLionel Sambuc 1080433d6423SLionel Sambuc /* Increment the file-size in inode n */ 1081433d6423SLionel Sambuc void 1082433d6423SLionel Sambuc incr_size(ino_t n, size_t count) 1083433d6423SLionel Sambuc { 1084433d6423SLionel Sambuc block_t b; 1085433d6423SLionel Sambuc int off; 1086433d6423SLionel Sambuc 1087433d6423SLionel Sambuc b = ((n - 1) / inodes_per_block) + inode_offset; 1088433d6423SLionel Sambuc off = (n - 1) % inodes_per_block; 1089433d6423SLionel Sambuc { 1090433d6423SLionel Sambuc struct inode *inodes; 1091433d6423SLionel Sambuc 1092433d6423SLionel Sambuc assert(inodes_per_block * sizeof(*inodes) == block_size); 1093433d6423SLionel Sambuc if(!(inodes = alloc_block())) 1094433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1095433d6423SLionel Sambuc 1096433d6423SLionel Sambuc get_block(b, inodes); 1097433d6423SLionel Sambuc /* Check overflow; avoid compiler spurious warnings */ 1098433d6423SLionel Sambuc if (inodes[off].i_size+(int)count < inodes[off].i_size || 1099433d6423SLionel Sambuc inodes[off].i_size > MAX_MAX_SIZE-(int)count) 1100433d6423SLionel Sambuc pexit("File has become too big to be handled by MFS"); 1101433d6423SLionel Sambuc inodes[off].i_size += count; 1102433d6423SLionel Sambuc put_block(b, inodes); 1103433d6423SLionel Sambuc free(inodes); 1104433d6423SLionel Sambuc } 1105433d6423SLionel Sambuc } 1106433d6423SLionel Sambuc 1107433d6423SLionel Sambuc 1108433d6423SLionel Sambuc /*================================================================ 1109433d6423SLionel Sambuc * allocation assist group 1110433d6423SLionel Sambuc *===============================================================*/ 1111433d6423SLionel Sambuc static ino_t 1112433d6423SLionel Sambuc alloc_inode(int mode, int usrid, int grpid) 1113433d6423SLionel Sambuc { 1114433d6423SLionel Sambuc ino_t num; 1115433d6423SLionel Sambuc int off; 1116433d6423SLionel Sambuc block_t b; 1117433d6423SLionel Sambuc struct inode *inodes; 1118433d6423SLionel Sambuc 1119433d6423SLionel Sambuc num = next_inode++; 1120433d6423SLionel Sambuc if (num > nrinodes) { 1121*cd34841dSBen Gras pexit("File system does not have enough inodes (only %llu)", nrinodes); 1122433d6423SLionel Sambuc } 1123433d6423SLionel Sambuc b = ((num - 1) / inodes_per_block) + inode_offset; 1124433d6423SLionel Sambuc off = (num - 1) % inodes_per_block; 1125433d6423SLionel Sambuc 1126433d6423SLionel Sambuc assert(inodes_per_block * sizeof(*inodes) == block_size); 1127433d6423SLionel Sambuc if(!(inodes = alloc_block())) 1128433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1129433d6423SLionel Sambuc 1130433d6423SLionel Sambuc get_block(b, inodes); 1131433d6423SLionel Sambuc if (inodes[off].i_mode) { 1132*cd34841dSBen Gras pexit("allocation new inode %llu with non-zero mode - this cannot happen", 1133433d6423SLionel Sambuc num); 1134433d6423SLionel Sambuc } 1135433d6423SLionel Sambuc inodes[off].i_mode = mode; 1136433d6423SLionel Sambuc inodes[off].i_uid = usrid; 1137433d6423SLionel Sambuc inodes[off].i_gid = grpid; 1138433d6423SLionel Sambuc if (verbose && (inodes[off].i_uid != usrid || inodes[off].i_gid != grpid)) 1139433d6423SLionel Sambuc fprintf(stderr, "Uid/gid %d.%d do not fit within inode, truncated\n", usrid, grpid); 1140433d6423SLionel Sambuc put_block(b, inodes); 1141433d6423SLionel Sambuc 1142433d6423SLionel Sambuc free(inodes); 1143433d6423SLionel Sambuc 1144433d6423SLionel Sambuc /* Set the bit in the bit map. */ 1145433d6423SLionel Sambuc insert_bit((block_t) INODE_MAP, num); 1146433d6423SLionel Sambuc return(num); 1147433d6423SLionel Sambuc } 1148433d6423SLionel Sambuc 1149433d6423SLionel Sambuc 1150433d6423SLionel Sambuc /* Allocate a new zone */ 1151433d6423SLionel Sambuc static zone_t 1152433d6423SLionel Sambuc alloc_zone(void) 1153433d6423SLionel Sambuc { 1154433d6423SLionel Sambuc /* Works for zone > block */ 1155433d6423SLionel Sambuc block_t b; 1156433d6423SLionel Sambuc int i; 1157433d6423SLionel Sambuc zone_t z; 1158433d6423SLionel Sambuc 1159433d6423SLionel Sambuc z = next_zone++; 1160433d6423SLionel Sambuc b = z << zone_shift; 1161433d6423SLionel Sambuc if (b > nrblocks - zone_per_block) 1162433d6423SLionel Sambuc pexit("File system not big enough for all the files"); 1163433d6423SLionel Sambuc for (i = 0; i < zone_per_block; i++) 1164433d6423SLionel Sambuc put_block(b + i, zero); /* give an empty zone */ 1165433d6423SLionel Sambuc 1166433d6423SLionel Sambuc insert_bit(zone_map, z - zoff); 1167433d6423SLionel Sambuc return z; 1168433d6423SLionel Sambuc } 1169433d6423SLionel Sambuc 1170433d6423SLionel Sambuc 1171433d6423SLionel Sambuc /* Insert one bit into the bitmap */ 1172433d6423SLionel Sambuc void 1173433d6423SLionel Sambuc insert_bit(block_t map, bit_t bit) 1174433d6423SLionel Sambuc { 1175433d6423SLionel Sambuc int boff, w, s; 1176433d6423SLionel Sambuc unsigned int bits_per_block; 1177433d6423SLionel Sambuc block_t map_block; 1178433d6423SLionel Sambuc bitchunk_t *buf; 1179433d6423SLionel Sambuc 1180433d6423SLionel Sambuc buf = alloc_block(); 1181433d6423SLionel Sambuc 1182433d6423SLionel Sambuc bits_per_block = FS_BITS_PER_BLOCK(block_size); 1183433d6423SLionel Sambuc map_block = map + bit / bits_per_block; 1184433d6423SLionel Sambuc if (map_block >= inode_offset) 1185433d6423SLionel Sambuc pexit("insertbit invades inodes area - this cannot happen"); 1186433d6423SLionel Sambuc boff = bit % bits_per_block; 1187433d6423SLionel Sambuc 1188433d6423SLionel Sambuc assert(boff >=0); 1189433d6423SLionel Sambuc assert(boff < FS_BITS_PER_BLOCK(block_size)); 1190433d6423SLionel Sambuc get_block(map_block, buf); 1191433d6423SLionel Sambuc w = boff / FS_BITCHUNK_BITS; 1192433d6423SLionel Sambuc s = boff % FS_BITCHUNK_BITS; 1193433d6423SLionel Sambuc buf[w] |= (1 << s); 1194433d6423SLionel Sambuc put_block(map_block, buf); 1195433d6423SLionel Sambuc 1196433d6423SLionel Sambuc free(buf); 1197433d6423SLionel Sambuc } 1198433d6423SLionel Sambuc 1199433d6423SLionel Sambuc 1200433d6423SLionel Sambuc /*================================================================ 1201433d6423SLionel Sambuc * proto-file processing assist group 1202433d6423SLionel Sambuc *===============================================================*/ 1203433d6423SLionel Sambuc int mode_con(char *p) 1204433d6423SLionel Sambuc { 1205433d6423SLionel Sambuc /* Convert string to mode */ 1206433d6423SLionel Sambuc int o1, o2, o3, mode; 1207433d6423SLionel Sambuc char c1, c2, c3; 1208433d6423SLionel Sambuc 1209433d6423SLionel Sambuc c1 = *p++; 1210433d6423SLionel Sambuc c2 = *p++; 1211433d6423SLionel Sambuc c3 = *p++; 1212433d6423SLionel Sambuc o1 = *p++ - '0'; 1213433d6423SLionel Sambuc o2 = *p++ - '0'; 1214433d6423SLionel Sambuc o3 = *p++ - '0'; 1215433d6423SLionel Sambuc mode = (o1 << 6) | (o2 << 3) | o3; 1216433d6423SLionel Sambuc if (c1 == 'd') mode |= S_IFDIR; 1217433d6423SLionel Sambuc if (c1 == 'b') mode |= S_IFBLK; 1218433d6423SLionel Sambuc if (c1 == 'c') mode |= S_IFCHR; 1219433d6423SLionel Sambuc if (c1 == 's') mode |= S_IFLNK; 1220433d6423SLionel Sambuc if (c1 == 'l') mode |= S_IFLNK; /* just to be somewhat ls-compatible*/ 1221433d6423SLionel Sambuc /* XXX note: some other mkfs programs consider L to create hardlinks */ 1222433d6423SLionel Sambuc if (c1 == '-') mode |= S_IFREG; 1223433d6423SLionel Sambuc if (c2 == 'u') mode |= S_ISUID; 1224433d6423SLionel Sambuc if (c3 == 'g') mode |= S_ISGID; 1225433d6423SLionel Sambuc /* XXX There are no way to encode S_ISVTX */ 1226433d6423SLionel Sambuc return(mode); 1227433d6423SLionel Sambuc } 1228433d6423SLionel Sambuc 1229433d6423SLionel Sambuc void 1230433d6423SLionel Sambuc get_line(char line[LINE_LEN], char *parse[MAX_TOKENS]) 1231433d6423SLionel Sambuc { 1232433d6423SLionel Sambuc /* Read a line and break it up in tokens */ 1233433d6423SLionel Sambuc int k; 1234433d6423SLionel Sambuc char c, *p; 1235433d6423SLionel Sambuc int d; 1236433d6423SLionel Sambuc 1237433d6423SLionel Sambuc for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0; 1238433d6423SLionel Sambuc memset(line, 0, LINE_LEN); 1239433d6423SLionel Sambuc k = 0; 1240433d6423SLionel Sambuc p = line; 1241433d6423SLionel Sambuc while (1) { 1242433d6423SLionel Sambuc if (++k > LINE_LEN) pexit("Line too long"); 1243433d6423SLionel Sambuc d = fgetc(proto); 1244433d6423SLionel Sambuc if (d == EOF) pexit("Unexpected end-of-file"); 1245433d6423SLionel Sambuc *p = d; 1246433d6423SLionel Sambuc if (*p == ' ' || *p == '\t') *p = 0; 1247433d6423SLionel Sambuc if (*p == '\n') { 1248433d6423SLionel Sambuc lct++; 1249433d6423SLionel Sambuc *p++ = 0; 1250433d6423SLionel Sambuc *p = '\n'; 1251433d6423SLionel Sambuc break; 1252433d6423SLionel Sambuc } 1253433d6423SLionel Sambuc p++; 1254433d6423SLionel Sambuc } 1255433d6423SLionel Sambuc 1256433d6423SLionel Sambuc k = 0; 1257433d6423SLionel Sambuc p = line; 1258433d6423SLionel Sambuc while (1) { 1259433d6423SLionel Sambuc c = *p++; 1260433d6423SLionel Sambuc if (c == '\n') return; 1261433d6423SLionel Sambuc if (c == 0) continue; 1262433d6423SLionel Sambuc parse[k++] = p - 1; 1263433d6423SLionel Sambuc do { 1264433d6423SLionel Sambuc c = *p++; 1265433d6423SLionel Sambuc } while (c != 0 && c != '\n'); 1266433d6423SLionel Sambuc } 1267433d6423SLionel Sambuc } 1268433d6423SLionel Sambuc 1269433d6423SLionel Sambuc 1270433d6423SLionel Sambuc /*================================================================ 1271433d6423SLionel Sambuc * other stuff 1272433d6423SLionel Sambuc *===============================================================*/ 1273433d6423SLionel Sambuc 1274433d6423SLionel Sambuc /* 1275433d6423SLionel Sambuc * Check to see if the special file named 'device' is mounted. 1276433d6423SLionel Sambuc */ 1277433d6423SLionel Sambuc void 1278433d6423SLionel Sambuc check_mtab(const char *device) /* /dev/hd1 or whatever */ 1279433d6423SLionel Sambuc { 1280433d6423SLionel Sambuc #if defined(__minix) 1281433d6423SLionel Sambuc int n, r; 1282433d6423SLionel Sambuc struct stat sb; 1283433d6423SLionel Sambuc char dev[PATH_MAX], mount_point[PATH_MAX], 1284433d6423SLionel Sambuc type[MNTNAMELEN], flags[MNTFLAGLEN]; 1285433d6423SLionel Sambuc 1286433d6423SLionel Sambuc r= stat(device, &sb); 1287433d6423SLionel Sambuc if (r == -1) 1288433d6423SLionel Sambuc { 1289433d6423SLionel Sambuc if (errno == ENOENT) 1290433d6423SLionel Sambuc return; /* Does not exist, and therefore not mounted. */ 1291433d6423SLionel Sambuc err(1, "stat %s failed", device); 1292433d6423SLionel Sambuc } 1293433d6423SLionel Sambuc if (!S_ISBLK(sb.st_mode)) 1294433d6423SLionel Sambuc { 1295433d6423SLionel Sambuc /* Not a block device and therefore not mounted. */ 1296433d6423SLionel Sambuc return; 1297433d6423SLionel Sambuc } 1298433d6423SLionel Sambuc 1299433d6423SLionel Sambuc if (load_mtab(__UNCONST("mkfs")) < 0) return; 1300433d6423SLionel Sambuc while (1) { 1301433d6423SLionel Sambuc n = get_mtab_entry(dev, mount_point, type, flags); 1302433d6423SLionel Sambuc if (n < 0) return; 1303433d6423SLionel Sambuc if (strcmp(device, dev) == 0) { 1304433d6423SLionel Sambuc /* Can't mkfs on top of a mounted file system. */ 1305433d6423SLionel Sambuc errx(1, "%s is mounted on %s", device, mount_point); 1306433d6423SLionel Sambuc } 1307433d6423SLionel Sambuc } 1308433d6423SLionel Sambuc #elif defined(__linux__) 1309433d6423SLionel Sambuc /* XXX: this code is copyright Theodore T'so and distributed under the GPLv2. Rewrite. 1310433d6423SLionel Sambuc */ 1311433d6423SLionel Sambuc struct mntent *mnt; 1312433d6423SLionel Sambuc struct stat st_buf; 1313433d6423SLionel Sambuc dev_t file_dev=0, file_rdev=0; 1314433d6423SLionel Sambuc ino_t file_ino=0; 1315433d6423SLionel Sambuc FILE *f; 1316433d6423SLionel Sambuc int fd; 1317433d6423SLionel Sambuc char *mtab_file = "/proc/mounts"; 1318433d6423SLionel Sambuc 1319433d6423SLionel Sambuc if ((f = setmntent (mtab_file, "r")) == NULL) 1320433d6423SLionel Sambuc goto error; 1321433d6423SLionel Sambuc 1322433d6423SLionel Sambuc if (stat(device, &st_buf) == 0) { 1323433d6423SLionel Sambuc if (S_ISBLK(st_buf.st_mode)) { 1324433d6423SLionel Sambuc file_rdev = st_buf.st_rdev; 1325433d6423SLionel Sambuc } else { 1326433d6423SLionel Sambuc file_dev = st_buf.st_dev; 1327433d6423SLionel Sambuc file_ino = st_buf.st_ino; 1328433d6423SLionel Sambuc } 1329433d6423SLionel Sambuc } 1330433d6423SLionel Sambuc 1331433d6423SLionel Sambuc while ((mnt = getmntent (f)) != NULL) { 1332433d6423SLionel Sambuc if (strcmp(device, mnt->mnt_fsname) == 0) 1333433d6423SLionel Sambuc break; 1334433d6423SLionel Sambuc if (stat(mnt->mnt_fsname, &st_buf) == 0) { 1335433d6423SLionel Sambuc if (S_ISBLK(st_buf.st_mode)) { 1336433d6423SLionel Sambuc if (file_rdev && (file_rdev == st_buf.st_rdev)) 1337433d6423SLionel Sambuc break; 1338433d6423SLionel Sambuc } else { 1339433d6423SLionel Sambuc if (file_dev && ((file_dev == st_buf.st_dev) && 1340433d6423SLionel Sambuc (file_ino == st_buf.st_ino))) 1341433d6423SLionel Sambuc break; 1342433d6423SLionel Sambuc } 1343433d6423SLionel Sambuc } 1344433d6423SLionel Sambuc } 1345433d6423SLionel Sambuc 1346433d6423SLionel Sambuc if (mnt == NULL) { 1347433d6423SLionel Sambuc /* 1348433d6423SLionel Sambuc * Do an extra check to see if this is the root device. We 1349433d6423SLionel Sambuc * can't trust /etc/mtab, and /proc/mounts will only list 1350433d6423SLionel Sambuc * /dev/root for the root filesystem. Argh. Instead we 1351433d6423SLionel Sambuc * check if the given device has the same major/minor number 1352433d6423SLionel Sambuc * as the device that the root directory is on. 1353433d6423SLionel Sambuc */ 1354433d6423SLionel Sambuc if (file_rdev && stat("/", &st_buf) == 0) { 1355433d6423SLionel Sambuc if (st_buf.st_dev == file_rdev) { 1356433d6423SLionel Sambuc goto is_root; 1357433d6423SLionel Sambuc } 1358433d6423SLionel Sambuc } 1359433d6423SLionel Sambuc goto test_busy; 1360433d6423SLionel Sambuc } 1361433d6423SLionel Sambuc /* Validate the entry in case /etc/mtab is out of date */ 1362433d6423SLionel Sambuc /* 1363433d6423SLionel Sambuc * We need to be paranoid, because some broken distributions 1364433d6423SLionel Sambuc * (read: Slackware) don't initialize /etc/mtab before checking 1365433d6423SLionel Sambuc * all of the non-root filesystems on the disk. 1366433d6423SLionel Sambuc */ 1367433d6423SLionel Sambuc if (stat(mnt->mnt_dir, &st_buf) < 0) { 1368433d6423SLionel Sambuc if (errno == ENOENT) { 1369433d6423SLionel Sambuc goto test_busy; 1370433d6423SLionel Sambuc } 1371433d6423SLionel Sambuc goto error; 1372433d6423SLionel Sambuc } 1373433d6423SLionel Sambuc if (file_rdev && (st_buf.st_dev != file_rdev)) { 1374433d6423SLionel Sambuc goto error; 1375433d6423SLionel Sambuc } 1376433d6423SLionel Sambuc 1377433d6423SLionel Sambuc fprintf(stderr, "Device %s is mounted, exiting\n", device); 1378433d6423SLionel Sambuc exit(-1); 1379433d6423SLionel Sambuc 1380433d6423SLionel Sambuc /* 1381433d6423SLionel Sambuc * Check to see if we're referring to the root filesystem. 1382433d6423SLionel Sambuc * If so, do a manual check to see if we can open /etc/mtab 1383433d6423SLionel Sambuc * read/write, since if the root is mounted read/only, the 1384433d6423SLionel Sambuc * contents of /etc/mtab may not be accurate. 1385433d6423SLionel Sambuc */ 1386433d6423SLionel Sambuc if (!strcmp(mnt->mnt_dir, "/")) { 1387433d6423SLionel Sambuc is_root: 1388433d6423SLionel Sambuc fprintf(stderr, "Device %s is mounted as root file system!\n", 1389433d6423SLionel Sambuc device); 1390433d6423SLionel Sambuc exit(-1); 1391433d6423SLionel Sambuc } 1392433d6423SLionel Sambuc 1393433d6423SLionel Sambuc test_busy: 1394433d6423SLionel Sambuc 1395433d6423SLionel Sambuc endmntent (f); 1396433d6423SLionel Sambuc if ((stat(device, &st_buf) != 0) || 1397433d6423SLionel Sambuc !S_ISBLK(st_buf.st_mode)) 1398433d6423SLionel Sambuc return; 1399433d6423SLionel Sambuc fd = open(device, O_RDONLY | O_EXCL); 1400433d6423SLionel Sambuc if (fd < 0) { 1401433d6423SLionel Sambuc if (errno == EBUSY) { 1402433d6423SLionel Sambuc fprintf(stderr, "Device %s is used by the system\n", device); 1403433d6423SLionel Sambuc exit(-1); 1404433d6423SLionel Sambuc } 1405433d6423SLionel Sambuc } else 1406433d6423SLionel Sambuc close(fd); 1407433d6423SLionel Sambuc 1408433d6423SLionel Sambuc return; 1409433d6423SLionel Sambuc 1410433d6423SLionel Sambuc error: 1411433d6423SLionel Sambuc endmntent (f); 1412433d6423SLionel Sambuc fprintf(stderr, "Error while checking if device %s is mounted\n", device); 1413433d6423SLionel Sambuc exit(-1); 1414433d6423SLionel Sambuc #else 1415433d6423SLionel Sambuc (void) device; /* shut up warnings about unused variable... */ 1416433d6423SLionel Sambuc #endif 1417433d6423SLionel Sambuc } 1418433d6423SLionel Sambuc 1419433d6423SLionel Sambuc 1420433d6423SLionel Sambuc time_t 1421433d6423SLionel Sambuc file_time(int f) 1422433d6423SLionel Sambuc { 1423433d6423SLionel Sambuc struct stat statbuf; 1424433d6423SLionel Sambuc 1425433d6423SLionel Sambuc if (!fstat(f, &statbuf)) 1426433d6423SLionel Sambuc return current_time; 1427433d6423SLionel Sambuc if (statbuf.st_mtime<0 || statbuf.st_mtime>(uint32_t)(-1)) 1428433d6423SLionel Sambuc return current_time; 1429433d6423SLionel Sambuc return(statbuf.st_mtime); 1430433d6423SLionel Sambuc } 1431433d6423SLionel Sambuc 1432433d6423SLionel Sambuc 1433433d6423SLionel Sambuc __dead void 1434433d6423SLionel Sambuc pexit(char const * s, ...) 1435433d6423SLionel Sambuc { 1436433d6423SLionel Sambuc va_list va; 1437433d6423SLionel Sambuc 1438433d6423SLionel Sambuc va_start(va, s); 1439433d6423SLionel Sambuc vwarn(s, va); 1440433d6423SLionel Sambuc va_end(va); 1441433d6423SLionel Sambuc if (lct != 0) 1442433d6423SLionel Sambuc warnx("Line %d being processed when error detected.\n", lct); 1443433d6423SLionel Sambuc exit(2); 1444433d6423SLionel Sambuc } 1445433d6423SLionel Sambuc 1446433d6423SLionel Sambuc 1447433d6423SLionel Sambuc void * 1448433d6423SLionel Sambuc alloc_block(void) 1449433d6423SLionel Sambuc { 1450433d6423SLionel Sambuc void *buf; 1451433d6423SLionel Sambuc 1452433d6423SLionel Sambuc if(!(buf = malloc(block_size))) { 1453433d6423SLionel Sambuc err(1, "couldn't allocate filesystem buffer"); 1454433d6423SLionel Sambuc } 1455433d6423SLionel Sambuc memset(buf, 0, block_size); 1456433d6423SLionel Sambuc 1457433d6423SLionel Sambuc return buf; 1458433d6423SLionel Sambuc } 1459433d6423SLionel Sambuc 1460433d6423SLionel Sambuc void 1461433d6423SLionel Sambuc print_fs(void) 1462433d6423SLionel Sambuc { 1463433d6423SLionel Sambuc int i, j; 1464433d6423SLionel Sambuc ino_t k; 1465433d6423SLionel Sambuc struct inode *inode2; 1466433d6423SLionel Sambuc unsigned short *usbuf; 1467433d6423SLionel Sambuc block_t b; 1468433d6423SLionel Sambuc struct direct *dir; 1469433d6423SLionel Sambuc 1470433d6423SLionel Sambuc assert(inodes_per_block * sizeof(*inode2) == block_size); 1471433d6423SLionel Sambuc if(!(inode2 = alloc_block())) 1472433d6423SLionel Sambuc err(1, "couldn't allocate a block of inodes"); 1473433d6423SLionel Sambuc 1474433d6423SLionel Sambuc assert(NR_DIR_ENTRIES(block_size)*sizeof(*dir) == block_size); 1475433d6423SLionel Sambuc if(!(dir = alloc_block())) 1476433d6423SLionel Sambuc err(1, "couldn't allocate a block of directory entries"); 1477433d6423SLionel Sambuc 1478433d6423SLionel Sambuc usbuf = alloc_block(); 1479433d6423SLionel Sambuc get_super_block(usbuf); 1480433d6423SLionel Sambuc printf("\nSuperblock: "); 1481433d6423SLionel Sambuc for (i = 0; i < 8; i++) printf("%06ho ", usbuf[i]); 1482433d6423SLionel Sambuc printf("\n "); 1483433d6423SLionel Sambuc for (i = 0; i < 8; i++) printf("%#04hX ", usbuf[i]); 1484433d6423SLionel Sambuc printf("\n "); 1485433d6423SLionel Sambuc for (i = 8; i < 15; i++) printf("%06ho ", usbuf[i]); 1486433d6423SLionel Sambuc printf("\n "); 1487433d6423SLionel Sambuc for (i = 8; i < 15; i++) printf("%#04hX ", usbuf[i]); 1488433d6423SLionel Sambuc get_block((block_t) INODE_MAP, usbuf); 1489433d6423SLionel Sambuc printf("...\nInode map: "); 1490433d6423SLionel Sambuc for (i = 0; i < 9; i++) printf("%06ho ", usbuf[i]); 1491433d6423SLionel Sambuc get_block((block_t) zone_map, usbuf); 1492433d6423SLionel Sambuc printf("...\nZone map: "); 1493433d6423SLionel Sambuc for (i = 0; i < 9; i++) printf("%06ho ", usbuf[i]); 1494433d6423SLionel Sambuc printf("...\n"); 1495433d6423SLionel Sambuc 1496433d6423SLionel Sambuc free(usbuf); 1497433d6423SLionel Sambuc usbuf = NULL; 1498433d6423SLionel Sambuc 1499433d6423SLionel Sambuc k = 0; 1500433d6423SLionel Sambuc for (b = inode_offset; k < nrinodes; b++) { 1501433d6423SLionel Sambuc get_block(b, inode2); 1502433d6423SLionel Sambuc for (i = 0; i < inodes_per_block; i++) { 1503433d6423SLionel Sambuc k = inodes_per_block * (int) (b - inode_offset) + i + 1; 1504433d6423SLionel Sambuc /* Lint but OK */ 1505433d6423SLionel Sambuc if (k > nrinodes) break; 1506433d6423SLionel Sambuc { 1507433d6423SLionel Sambuc if (inode2[i].i_mode != 0) { 1508433d6423SLionel Sambuc printf("Inode %3u: mode=", (unsigned)k); 1509433d6423SLionel Sambuc printf("%06o", (unsigned)inode2[i].i_mode); 1510433d6423SLionel Sambuc printf(" uid=%2d gid=%2d size=", 1511433d6423SLionel Sambuc (int)inode2[i].i_uid, (int)inode2[i].i_gid); 1512433d6423SLionel Sambuc printf("%6ld", (long)inode2[i].i_size); 1513433d6423SLionel Sambuc printf(" zone[0]=%u\n", (unsigned)inode2[i].i_zone[0]); 1514433d6423SLionel Sambuc } 1515433d6423SLionel Sambuc if ((inode2[i].i_mode & S_IFMT) == S_IFDIR) { 1516433d6423SLionel Sambuc /* This is a directory */ 1517433d6423SLionel Sambuc get_block(inode2[i].i_zone[0] << zone_shift, dir); 1518433d6423SLionel Sambuc for (j = 0; j < NR_DIR_ENTRIES(block_size); j++) 1519433d6423SLionel Sambuc if (dir[j].d_ino) 1520433d6423SLionel Sambuc printf("\tInode %2u: %s\n", 1521433d6423SLionel Sambuc (unsigned)dir[j].d_ino, 1522433d6423SLionel Sambuc dir[j].d_name); 1523433d6423SLionel Sambuc } 1524433d6423SLionel Sambuc } 1525433d6423SLionel Sambuc } 1526433d6423SLionel Sambuc } 1527433d6423SLionel Sambuc 1528433d6423SLionel Sambuc if (zone_shift) 1529433d6423SLionel Sambuc printf("%d inodes used. %u zones (%u blocks) used.\n", 1530433d6423SLionel Sambuc (int)next_inode-1, next_zone, next_zone*zone_per_block); 1531433d6423SLionel Sambuc else 1532433d6423SLionel Sambuc printf("%d inodes used. %u zones used.\n", (int)next_inode-1, next_zone); 1533433d6423SLionel Sambuc free(dir); 1534433d6423SLionel Sambuc free(inode2); 1535433d6423SLionel Sambuc } 1536433d6423SLionel Sambuc 1537433d6423SLionel Sambuc 1538433d6423SLionel Sambuc /* 1539433d6423SLionel Sambuc * The first time a block is read, it returns all 0s, unless there has 1540433d6423SLionel Sambuc * been a write. This routine checks to see if a block has been accessed. 1541433d6423SLionel Sambuc */ 1542433d6423SLionel Sambuc int 1543433d6423SLionel Sambuc read_and_set(block_t n) 1544433d6423SLionel Sambuc { 1545433d6423SLionel Sambuc int w, s, mask, r; 1546433d6423SLionel Sambuc 1547433d6423SLionel Sambuc w = n / 8; 1548433d6423SLionel Sambuc 1549433d6423SLionel Sambuc assert(n < nrblocks); 1550433d6423SLionel Sambuc if(w >= umap_array_elements) { 1551433d6423SLionel Sambuc errx(1, "umap array too small - this can't happen"); 1552433d6423SLionel Sambuc } 1553433d6423SLionel Sambuc s = n % 8; 1554433d6423SLionel Sambuc mask = 1 << s; 1555433d6423SLionel Sambuc r = (umap_array[w] & mask ? 1 : 0); 1556433d6423SLionel Sambuc umap_array[w] |= mask; 1557433d6423SLionel Sambuc return(r); 1558433d6423SLionel Sambuc } 1559433d6423SLionel Sambuc 1560433d6423SLionel Sambuc __dead void 1561433d6423SLionel Sambuc usage(void) 1562433d6423SLionel Sambuc { 1563433d6423SLionel Sambuc fprintf(stderr, "Usage: %s [-dltv] [-b blocks] [-i inodes]\n" 1564433d6423SLionel Sambuc "\t[-z zone_shift] [-I offset] [-x extra] [-B blocksize] special [proto]\n", 1565433d6423SLionel Sambuc progname); 1566433d6423SLionel Sambuc exit(4); 1567433d6423SLionel Sambuc } 1568433d6423SLionel Sambuc 1569433d6423SLionel Sambuc void 1570433d6423SLionel Sambuc special(char * string, int insertmode) 1571433d6423SLionel Sambuc { 1572433d6423SLionel Sambuc int openmode = O_RDWR; 1573433d6423SLionel Sambuc if(!insertmode) openmode |= O_TRUNC; 1574433d6423SLionel Sambuc fd = open(string, O_RDWR | O_CREAT, 0644); 1575433d6423SLionel Sambuc if (fd < 0) err(1, "Can't open special file %s", string); 1576433d6423SLionel Sambuc mkfs_seek(0, SEEK_SET); 1577433d6423SLionel Sambuc } 1578433d6423SLionel Sambuc 1579433d6423SLionel Sambuc 1580433d6423SLionel Sambuc 1581433d6423SLionel Sambuc /* Read a block. */ 1582433d6423SLionel Sambuc void 1583433d6423SLionel Sambuc get_block(block_t n, void *buf) 1584433d6423SLionel Sambuc { 1585433d6423SLionel Sambuc ssize_t k; 1586433d6423SLionel Sambuc 1587433d6423SLionel Sambuc /* First access returns a zero block */ 1588433d6423SLionel Sambuc if (read_and_set(n) == 0) { 1589433d6423SLionel Sambuc memcpy(buf, zero, block_size); 1590433d6423SLionel Sambuc return; 1591433d6423SLionel Sambuc } 1592433d6423SLionel Sambuc mkfs_seek((uint64_t)(n) * block_size, SEEK_SET); 1593433d6423SLionel Sambuc k = read(fd, buf, block_size); 1594433d6423SLionel Sambuc if (k != block_size) 1595433d6423SLionel Sambuc pexit("get_block couldn't read block #%u", (unsigned)n); 1596433d6423SLionel Sambuc } 1597433d6423SLionel Sambuc 1598433d6423SLionel Sambuc /* Read the super block. */ 1599433d6423SLionel Sambuc void 1600433d6423SLionel Sambuc get_super_block(void *buf) 1601433d6423SLionel Sambuc { 1602433d6423SLionel Sambuc ssize_t k; 1603433d6423SLionel Sambuc 1604433d6423SLionel Sambuc mkfs_seek((off_t) SUPER_BLOCK_BYTES, SEEK_SET); 1605433d6423SLionel Sambuc k = read(fd, buf, SUPER_BLOCK_BYTES); 1606433d6423SLionel Sambuc if (k != SUPER_BLOCK_BYTES) 1607433d6423SLionel Sambuc err(1, "get_super_block couldn't read super block"); 1608433d6423SLionel Sambuc } 1609433d6423SLionel Sambuc 1610433d6423SLionel Sambuc /* Write a block. */ 1611433d6423SLionel Sambuc void 1612433d6423SLionel Sambuc put_block(block_t n, void *buf) 1613433d6423SLionel Sambuc { 1614433d6423SLionel Sambuc 1615433d6423SLionel Sambuc (void) read_and_set(n); 1616433d6423SLionel Sambuc 1617433d6423SLionel Sambuc mkfs_seek((uint64_t)(n) * block_size, SEEK_SET); 1618433d6423SLionel Sambuc mkfs_write(buf, block_size); 1619433d6423SLionel Sambuc } 1620433d6423SLionel Sambuc 1621433d6423SLionel Sambuc static ssize_t 1622433d6423SLionel Sambuc mkfs_write(void * buf, size_t count) 1623433d6423SLionel Sambuc { 1624433d6423SLionel Sambuc uint64_t fssize; 1625433d6423SLionel Sambuc ssize_t w; 1626433d6423SLionel Sambuc 1627433d6423SLionel Sambuc /* Perform & check write */ 1628433d6423SLionel Sambuc w = write(fd, buf, count); 1629433d6423SLionel Sambuc if(w < 0) 1630433d6423SLionel Sambuc err(1, "mkfs_write: write failed"); 1631433d6423SLionel Sambuc if(w != count) 1632*cd34841dSBen Gras errx(1, "mkfs_write: short write: %zd != %zu", w, count); 1633433d6423SLionel Sambuc 1634433d6423SLionel Sambuc /* Check if this has made the FS any bigger; count bytes after offset */ 1635433d6423SLionel Sambuc fssize = mkfs_seek(0, SEEK_CUR); 1636433d6423SLionel Sambuc 1637433d6423SLionel Sambuc assert(fssize >= fs_offset_bytes); 1638433d6423SLionel Sambuc fssize -= fs_offset_bytes; 1639433d6423SLionel Sambuc fssize = roundup(fssize, block_size); 1640433d6423SLionel Sambuc if(fssize > written_fs_size) 1641433d6423SLionel Sambuc written_fs_size = fssize; 1642433d6423SLionel Sambuc 1643433d6423SLionel Sambuc return w; 1644433d6423SLionel Sambuc } 1645433d6423SLionel Sambuc 1646433d6423SLionel Sambuc /* Seek to position in FS we're creating. */ 1647433d6423SLionel Sambuc static uint64_t 1648433d6423SLionel Sambuc mkfs_seek(uint64_t pos, int whence) 1649433d6423SLionel Sambuc { 1650433d6423SLionel Sambuc if(whence == SEEK_SET) pos += fs_offset_bytes; 1651433d6423SLionel Sambuc off_t newpos; 1652433d6423SLionel Sambuc if((newpos=lseek(fd, pos, whence)) == (off_t) -1) 1653433d6423SLionel Sambuc err(1, "mkfs_seek: lseek failed"); 1654433d6423SLionel Sambuc return newpos; 1655433d6423SLionel Sambuc } 1656