type.c revision 207141
1230557Sjimharris/* 2230557Sjimharris * Copyright (c) 2002 Juli Mallett. All rights reserved. 3230557Sjimharris * 4230557Sjimharris * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the 5230557Sjimharris * FreeBSD project. Redistribution and use in source and binary forms, with 6230557Sjimharris * or without modification, are permitted provided that the following 7230557Sjimharris * conditions are met: 8230557Sjimharris * 9230557Sjimharris * 1. Redistribution of source code must retain the above copyright notice, 10230557Sjimharris * this list of conditions and the following disclaimer. 11230557Sjimharris * 2. Redistribution in binary form must reproduce the above copyright 12230557Sjimharris * notice, this list of conditions and the following disclaimer in the 13230557Sjimharris * documentation and/or other materials provided with the distribution. 14230557Sjimharris * 15230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16230557Sjimharris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17230557Sjimharris * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18230557Sjimharris * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19230557Sjimharris * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20230557Sjimharris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21230557Sjimharris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22230557Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23230557Sjimharris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24230557Sjimharris * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25230557Sjimharris * POSSIBILITY OF SUCH DAMAGE. 26230557Sjimharris */ 27230557Sjimharris 28230557Sjimharris#include <sys/cdefs.h> 29230557Sjimharris__FBSDID("$FreeBSD: head/lib/libufs/type.c 207141 2010-04-24 07:05:35Z jeff $"); 30230557Sjimharris 31230557Sjimharris#include <sys/param.h> 32230557Sjimharris#include <sys/mount.h> 33230557Sjimharris#include <sys/disklabel.h> 34230557Sjimharris#include <sys/stat.h> 35230557Sjimharris 36230557Sjimharris#include <ufs/ufs/ufsmount.h> 37230557Sjimharris#include <ufs/ufs/dinode.h> 38230557Sjimharris#include <ufs/ffs/fs.h> 39230557Sjimharris 40230557Sjimharris#include <errno.h> 41230557Sjimharris#include <fcntl.h> 42230557Sjimharris#include <fstab.h> 43230557Sjimharris#include <paths.h> 44230557Sjimharris#include <stdio.h> 45230557Sjimharris#include <stdlib.h> 46230557Sjimharris#include <string.h> 47230557Sjimharris#include <unistd.h> 48230557Sjimharris 49230557Sjimharris#include <libufs.h> 50230557Sjimharris 51230557Sjimharris/* Internally, track the 'name' value, it's ours. */ 52230557Sjimharris#define MINE_NAME 0x01 53230557Sjimharris/* Track if its fd points to a writable device. */ 54230557Sjimharris#define MINE_WRITE 0x02 55230557Sjimharris 56230557Sjimharrisint 57230557Sjimharrisufs_disk_close(struct uufsd *disk) 58230557Sjimharris{ 59230557Sjimharris ERROR(disk, NULL); 60230557Sjimharris close(disk->d_fd); 61230557Sjimharris if (disk->d_inoblock != NULL) { 62230557Sjimharris free(disk->d_inoblock); 63230557Sjimharris disk->d_inoblock = NULL; 64230557Sjimharris } 65230557Sjimharris if (disk->d_mine & MINE_NAME) { 66230557Sjimharris free((char *)(uintptr_t)disk->d_name); 67230557Sjimharris disk->d_name = NULL; 68230557Sjimharris } 69230557Sjimharris if (disk->d_sbcsum != NULL) { 70230557Sjimharris free(disk->d_sbcsum); 71230557Sjimharris disk->d_sbcsum = NULL; 72230557Sjimharris } 73230557Sjimharris return (0); 74230557Sjimharris} 75230557Sjimharris 76230557Sjimharrisint 77230557Sjimharrisufs_disk_fillout(struct uufsd *disk, const char *name) 78230557Sjimharris{ 79230557Sjimharris if (ufs_disk_fillout_blank(disk, name) == -1) { 80230557Sjimharris return (-1); 81230557Sjimharris } 82230557Sjimharris if (sbread(disk) == -1) { 83230557Sjimharris ERROR(disk, "could not read superblock to fill out disk"); 84230557Sjimharris return (-1); 85230557Sjimharris } 86230557Sjimharris return (0); 87230557Sjimharris} 88230557Sjimharris 89230557Sjimharrisint 90230557Sjimharrisufs_disk_fillout_blank(struct uufsd *disk, const char *name) 91230557Sjimharris{ 92230557Sjimharris struct stat st; 93230557Sjimharris struct fstab *fs; 94230557Sjimharris struct statfs sfs; 95230557Sjimharris const char *oname; 96230557Sjimharris char dev[MAXPATHLEN]; 97230557Sjimharris int fd, ret; 98230557Sjimharris 99230557Sjimharris ERROR(disk, NULL); 100230557Sjimharris 101230557Sjimharris oname = name; 102230557Sjimharrisagain: if ((ret = stat(name, &st)) < 0) { 103230557Sjimharris if (*name != '/') { 104230557Sjimharris snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name); 105230557Sjimharris name = dev; 106230557Sjimharris goto again; 107230557Sjimharris } 108230557Sjimharris /* 109230557Sjimharris * The given object doesn't exist, but don't panic just yet - 110230557Sjimharris * it may be still mount point listed in /etc/fstab, but without 111230557Sjimharris * existing corresponding directory. 112230557Sjimharris */ 113230557Sjimharris name = oname; 114230557Sjimharris } 115230557Sjimharris if (ret >= 0 && S_ISREG(st.st_mode)) { 116230557Sjimharris /* Possibly a disk image, give it a try. */ 117230557Sjimharris ; 118230557Sjimharris } else if (ret >= 0 && S_ISCHR(st.st_mode)) { 119230557Sjimharris /* This is what we need, do nothing. */ 120230557Sjimharris ; 121230557Sjimharris } else if ((fs = getfsfile(name)) != NULL) { 122230557Sjimharris /* 123230557Sjimharris * The given mount point is listed in /etc/fstab. 124230557Sjimharris * It is possible that someone unmounted file system by hand 125230557Sjimharris * and different file system is mounted on this mount point, 126230557Sjimharris * but we still prefer /etc/fstab entry, because on the other 127230557Sjimharris * hand, there could be /etc/fstab entry for this mount 128230557Sjimharris * point, but file system is not mounted yet (eg. noauto) and 129230557Sjimharris * statfs(2) will point us at different file system. 130230557Sjimharris */ 131230557Sjimharris name = fs->fs_spec; 132230557Sjimharris } else if (ret >= 0 && S_ISDIR(st.st_mode)) { 133230557Sjimharris /* 134230557Sjimharris * The mount point is not listed in /etc/fstab, so it may be 135230557Sjimharris * file system mounted by hand. 136230557Sjimharris */ 137230557Sjimharris if (statfs(name, &sfs) < 0) { 138230557Sjimharris ERROR(disk, "could not find special device"); 139230557Sjimharris return (-1); 140230557Sjimharris } 141230557Sjimharris strlcpy(dev, sfs.f_mntfromname, sizeof(dev)); 142230557Sjimharris name = dev; 143230557Sjimharris } else { 144230557Sjimharris ERROR(disk, "could not find special device"); 145230557Sjimharris return (-1); 146230557Sjimharris } 147230557Sjimharris fd = open(name, O_RDONLY); 148230557Sjimharris if (fd == -1) { 149230557Sjimharris ERROR(disk, "could not open special device"); 150230557Sjimharris return (-1); 151230557Sjimharris } 152230557Sjimharris 153230557Sjimharris disk->d_bsize = 1; 154230557Sjimharris disk->d_ccg = 0; 155230557Sjimharris disk->d_fd = fd; 156230557Sjimharris disk->d_inoblock = NULL; 157230557Sjimharris disk->d_inomin = 0; 158230557Sjimharris disk->d_inomax = 0; 159230557Sjimharris disk->d_lcg = 0; 160230557Sjimharris disk->d_mine = 0; 161230557Sjimharris disk->d_ufs = 0; 162230557Sjimharris disk->d_error = NULL; 163230557Sjimharris disk->d_sbcsum = NULL; 164230557Sjimharris 165230557Sjimharris if (oname != name) { 166230557Sjimharris name = strdup(name); 167230557Sjimharris if (name == NULL) { 168230557Sjimharris ERROR(disk, "could not allocate memory for disk name"); 169230557Sjimharris return (-1); 170230557Sjimharris } 171230557Sjimharris disk->d_mine |= MINE_NAME; 172230557Sjimharris } 173230557Sjimharris disk->d_name = name; 174230557Sjimharris 175230557Sjimharris return (0); 176230557Sjimharris} 177230557Sjimharris 178230557Sjimharrisint 179230557Sjimharrisufs_disk_write(struct uufsd *disk) 180230557Sjimharris{ 181230557Sjimharris ERROR(disk, NULL); 182 183 if (disk->d_mine & MINE_WRITE) 184 return (0); 185 186 close(disk->d_fd); 187 188 disk->d_fd = open(disk->d_name, O_RDWR); 189 if (disk->d_fd < 0) { 190 ERROR(disk, "failed to open disk for writing"); 191 return (-1); 192 } 193 194 disk->d_mine |= MINE_WRITE; 195 196 return (0); 197} 198