1 /* $NetBSD: main.c,v 1.10 2011/08/10 11:31:49 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #if HAVE_NBTOOL_CONFIG_H 33 #include "nbtool_config.h" 34 #endif 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __RCSID("$NetBSD: main.c,v 1.10 2011/08/10 11:31:49 uch Exp $"); 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <stdio.h> 43 #include <string.h> 44 #include <errno.h> 45 #include <time.h> 46 #include <err.h> 47 48 #include "v7fs.h" 49 #include "v7fs_impl.h" 50 #include "v7fs_endian.h" 51 #include "v7fs_superblock.h" 52 #include "v7fs_inode.h" 53 #include "v7fs_datablock.h" /*v7fs_datablock_expand/last */ 54 #include "newfs_v7fs.h" 55 #include "progress.h" /*../sbin/fsck */ 56 57 #define VPRINTF(lv, fmt, args...) { if (v7fs_newfs_verbose >= lv) \ 58 printf(fmt, ##args); } 59 60 static v7fs_daddr_t 61 determine_ilist_size(v7fs_daddr_t volume_size, int32_t files) 62 { 63 v7fs_daddr_t ilist_size; 64 65 if (files) 66 ilist_size = howmany(files, V7FS_INODE_PER_BLOCK); 67 else 68 ilist_size = volume_size / 25; /* 4% */ 69 if (ilist_size > (v7fs_daddr_t)V7FS_ILISTBLK_MAX) 70 ilist_size = V7FS_ILISTBLK_MAX; 71 72 return ilist_size; 73 } 74 75 static int 76 partition_check(struct v7fs_self *fs) 77 { 78 struct v7fs_superblock *sb = &fs->superblock; 79 int error; 80 81 if ((error = v7fs_superblock_load(fs))) { 82 if (error != EINVAL) { 83 /* Invalid superblock information is OK. */ 84 warnx("Can't read superblock sector."); 85 } 86 } 87 sb->modified = 1; 88 if ((error = v7fs_superblock_writeback(fs))) { 89 if (errno == EROFS) { 90 warnx("Overwriting disk label? "); 91 } 92 warnx("Can't write superblock sector."); 93 } 94 95 return error; 96 } 97 98 static int 99 make_root(struct v7fs_self *fs) 100 { 101 struct v7fs_inode inode; 102 struct v7fs_dirent *dir; 103 int error; 104 105 /* INO 1 badblk (don't used) */ 106 memset(&inode, 0, sizeof(inode)); 107 inode.inode_number = 1; 108 inode.mode = V7FS_IFREG; /* V7 manner */ 109 v7fs_inode_writeback(fs, &inode); 110 111 /* INO 2 root */ 112 v7fs_ino_t ino; 113 if ((error = v7fs_inode_allocate(fs, &ino))) { 114 errno = error; 115 warn("Can't allocate / inode"); 116 return error; 117 } 118 119 memset(&inode, 0, sizeof(inode)); 120 inode.inode_number = ino; 121 inode.mode = 0777 | V7FS_IFDIR; 122 inode.uid = 0; 123 inode.gid = 0; 124 inode.nlink = 2; /* . + .. */ 125 inode.atime = inode.mtime = inode.ctime = time(0); 126 127 /* root dirent. */ 128 v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2); 129 v7fs_daddr_t blk = inode.addr[0]; 130 void *buf; 131 if (!(buf = scratch_read(fs, blk))) { 132 v7fs_inode_deallocate(fs, ino); 133 errno = error = EIO; 134 warn("Can't read / dirent."); 135 return error; 136 } 137 dir = (struct v7fs_dirent *)buf; /*disk endian */ 138 139 strcpy(dir[0].name, "."); 140 dir[0].inode_number = V7FS_VAL16(fs, ino); 141 strcpy(dir[1].name, ".."); 142 dir[1].inode_number = V7FS_VAL16(fs, ino); 143 if (!fs->io.write(fs->io.cookie, buf, blk)) {/*writeback */ 144 scratch_free(fs, buf); 145 errno = error = EIO; 146 warn("Can't write / dirent."); 147 return error; 148 } 149 scratch_free(fs, buf); 150 v7fs_inode_writeback(fs, &inode); 151 if ((error = v7fs_superblock_writeback(fs))) { 152 errno = error; 153 warnx("Can't write superblock."); 154 } 155 156 return error; 157 } 158 159 static v7fs_daddr_t 160 make_freeblocklist(struct v7fs_self *fs, v7fs_daddr_t listblk, uint8_t *buf) 161 { 162 uint32_t (*val32)(uint32_t) = fs->val.conv32; 163 uint16_t (*val16)(uint16_t) = fs->val.conv16; 164 struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf; 165 int i, j, k; 166 167 memset(buf, 0, V7FS_BSIZE); 168 169 for (i = V7FS_MAX_FREEBLOCK - 1, j = listblk + 1, k = 0; i >= 0; 170 i--, j++, k++) { 171 progress(0); 172 if (j == (int32_t)fs->superblock.volume_size) 173 { 174 VPRINTF(4, "\nlast freeblock #%d\n", 175 (*val32)(fb->freeblock[i + 1])); 176 177 memmove(fb->freeblock + 1, fb->freeblock + i + 1, k * 178 sizeof(v7fs_daddr_t)); 179 fb->freeblock[0] = 0; /* Terminate link; */ 180 fb->nfreeblock = (*val16)(k + 1); 181 VPRINTF(4, "last freeblock contains #%d\n", 182 (*val16)(fb->nfreeblock)); 183 fs->io.write(fs->io.cookie, buf, listblk); 184 return 0; 185 } 186 fb->freeblock[i] = (*val32)(j); 187 } 188 fb->nfreeblock = (*val16)(k); 189 190 if (!fs->io.write(fs->io.cookie, buf, listblk)) { 191 errno = EIO; 192 warn("blk=%ld", (long)listblk); 193 return 0; 194 } 195 196 /* Return next link block */ 197 return (*val32)(fb->freeblock[0]); 198 } 199 200 static int 201 make_filesystem(struct v7fs_self *fs, v7fs_daddr_t volume_size, 202 v7fs_daddr_t ilist_size) 203 { 204 struct v7fs_superblock *sb; 205 v7fs_daddr_t blk; 206 uint8_t buf[V7FS_BSIZE]; 207 int error = 0; 208 int32_t i, j; 209 210 /* Setup ilist. (ilist must be zero filled. becuase of they are free) */ 211 VPRINTF(4, "Zero clear ilist.\n"); 212 progress(&(struct progress_arg){ .label = "zero ilist", .tick = 213 ilist_size / PROGRESS_BAR_GRANULE }); 214 memset(buf, 0, sizeof buf); 215 for (i = V7FS_ILIST_SECTOR; i < (int32_t)ilist_size; i++) { 216 fs->io.write(fs->io.cookie, buf, i); 217 progress(0); 218 } 219 #ifndef HAVE_NBTOOL_CONFIG_H 220 progress_done(); 221 #endif 222 VPRINTF(4, "\n"); 223 224 /* Construct superblock */ 225 sb = &fs->superblock; 226 sb->volume_size = volume_size; 227 sb->datablock_start_sector = ilist_size + V7FS_ILIST_SECTOR; 228 sb->update_time = time(NULL); 229 230 /* fill free inode cache. */ 231 VPRINTF(4, "Setup inode cache.\n"); 232 sb->nfreeinode = V7FS_MAX_FREEINODE; 233 for (i = V7FS_MAX_FREEINODE - 1, j = V7FS_ROOT_INODE; i >= 0; i--, j++) 234 sb->freeinode[i] = j; 235 sb->total_freeinode = ilist_size * V7FS_INODE_PER_BLOCK - 1; 236 237 /* fill free block cache. */ 238 VPRINTF(4, "Setup free block cache.\n"); 239 sb->nfreeblock = V7FS_MAX_FREEBLOCK; 240 for (i = V7FS_MAX_FREEBLOCK - 1, j = sb->datablock_start_sector; i >= 0; 241 i--, j++) 242 sb->freeblock[i] = j; 243 244 sb->total_freeblock = volume_size - sb->datablock_start_sector; 245 246 /* Write superblock. */ 247 sb->modified = 1; 248 if ((error = v7fs_superblock_writeback(fs))) { 249 errno = error; 250 warn("Can't write back superblock."); 251 return error; 252 } 253 254 /* Construct freeblock list */ 255 VPRINTF(4, "Setup whole freeblock list.\n"); 256 progress(&(struct progress_arg){ .label = "freeblock list", .tick = 257 (volume_size - sb->datablock_start_sector) / PROGRESS_BAR_GRANULE}); 258 blk = sb->freeblock[0]; 259 while ((blk = make_freeblocklist(fs, blk, buf))) 260 continue; 261 #ifndef HAVE_NBTOOL_CONFIG_H 262 progress_done(); 263 #endif 264 265 VPRINTF(4, "done.\n"); 266 267 return 0; 268 } 269 270 int 271 v7fs_newfs(const struct v7fs_mount_device *mount, int32_t maxfile) 272 { 273 struct v7fs_self *fs; 274 v7fs_daddr_t ilist_size; 275 int error; 276 v7fs_daddr_t volume_size = mount->sectors; 277 278 /* Check and determine ilistblock, datablock size. */ 279 if (volume_size > V7FS_DADDR_MAX + 1) { 280 warnx("volume size %d over v7fs limit %d. truncated.", 281 volume_size, V7FS_DADDR_MAX + 1); 282 volume_size = V7FS_DADDR_MAX + 1; 283 } 284 285 ilist_size = determine_ilist_size(volume_size, maxfile); 286 287 VPRINTF(1, "volume size=%d, ilist size=%d, endian=%d, NAME_MAX=%d\n", 288 volume_size, ilist_size, mount->endian, V7FS_NAME_MAX); 289 290 /* Setup I/O ops. */ 291 if ((error = v7fs_io_init(&fs, mount, V7FS_BSIZE))) { 292 errno = error; 293 warn("I/O setup failed."); 294 return error; 295 } 296 fs->endian = mount->endian; 297 v7fs_endian_init(fs); 298 299 if ((error = partition_check(fs))) { 300 return error; 301 } 302 303 /* Construct filesystem. */ 304 if ((error = make_filesystem(fs, volume_size, ilist_size))) { 305 return error; 306 } 307 308 /* Setup root. */ 309 if ((error = make_root(fs))) { 310 return error; 311 } 312 313 v7fs_io_fini(fs); 314 315 return 0; 316 } 317