type.c revision 194030
199193Sjmallett/*
299193Sjmallett * Copyright (c) 2002 Juli Mallett.  All rights reserved.
399193Sjmallett *
499193Sjmallett * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
599193Sjmallett * FreeBSD project.  Redistribution and use in source and binary forms, with
699193Sjmallett * or without modification, are permitted provided that the following
799193Sjmallett * conditions are met:
899193Sjmallett *
999193Sjmallett * 1. Redistribution of source code must retain the above copyright notice,
1099193Sjmallett *    this list of conditions and the following disclaimer.
1199193Sjmallett * 2. Redistribution in binary form must reproduce the above copyright
1299193Sjmallett *    notice, this list of conditions and the following disclaimer in the
1399193Sjmallett *    documentation and/or other materials provided with the distribution.
1499193Sjmallett *
1599193Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1699193Sjmallett * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1799193Sjmallett * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1899193Sjmallett * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
1999193Sjmallett * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2099193Sjmallett * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2199193Sjmallett * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2299193Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2399193Sjmallett * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2499193Sjmallett * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2599193Sjmallett * POSSIBILITY OF SUCH DAMAGE.
2699193Sjmallett */
2799193Sjmallett
2899193Sjmallett#include <sys/cdefs.h>
2999193Sjmallett__FBSDID("$FreeBSD: head/lib/libufs/type.c 194030 2009-06-11 18:04:57Z jmallett $");
3099193Sjmallett
3199193Sjmallett#include <sys/param.h>
3299193Sjmallett#include <sys/mount.h>
3399193Sjmallett#include <sys/disklabel.h>
3499193Sjmallett#include <sys/stat.h>
3599193Sjmallett
3699193Sjmallett#include <ufs/ufs/ufsmount.h>
3799193Sjmallett#include <ufs/ufs/dinode.h>
3899193Sjmallett#include <ufs/ffs/fs.h>
3999193Sjmallett
4099193Sjmallett#include <errno.h>
4199193Sjmallett#include <fcntl.h>
42109506Sjmallett#include <fstab.h>
43109506Sjmallett#include <paths.h>
4499193Sjmallett#include <stdio.h>
4599193Sjmallett#include <stdlib.h>
4699193Sjmallett#include <string.h>
4799193Sjmallett#include <unistd.h>
4899193Sjmallett
4999193Sjmallett#include <libufs.h>
5099193Sjmallett
51109506Sjmallett/* Internally, track the 'name' value, it's ours. */
52109506Sjmallett#define	MINE_NAME	0x01
53110066Sjmallett/* Track if its fd points to a writable device. */
54110066Sjmallett#define	MINE_WRITE	0x02
55109506Sjmallett
5699193Sjmallettint
5799193Sjmallettufs_disk_close(struct uufsd *disk)
5899193Sjmallett{
59109462Sjmallett	ERROR(disk, NULL);
6099193Sjmallett	close(disk->d_fd);
6199193Sjmallett	if (disk->d_inoblock != NULL) {
6299193Sjmallett		free(disk->d_inoblock);
6399193Sjmallett		disk->d_inoblock = NULL;
6499193Sjmallett	}
65109506Sjmallett	if (disk->d_mine & MINE_NAME) {
66109506Sjmallett		free((char *)(uintptr_t)disk->d_name);
67109506Sjmallett		disk->d_name = NULL;
68109506Sjmallett	}
69116084Sjmallett	return (0);
7099193Sjmallett}
7199193Sjmallett
7299193Sjmallettint
7399193Sjmallettufs_disk_fillout(struct uufsd *disk, const char *name)
7499193Sjmallett{
75109755Sjmallett	if (ufs_disk_fillout_blank(disk, name) == -1) {
76116084Sjmallett		return (-1);
77109755Sjmallett	}
78109755Sjmallett	if (sbread(disk) == -1) {
79109755Sjmallett		ERROR(disk, "could not read superblock to fill out disk");
80116084Sjmallett		return (-1);
81109755Sjmallett	}
82116084Sjmallett	return (0);
83109755Sjmallett}
84109755Sjmallett
85109755Sjmallettint
86109755Sjmallettufs_disk_fillout_blank(struct uufsd *disk, const char *name)
87109755Sjmallett{
88109506Sjmallett	struct stat st;
89109506Sjmallett	struct fstab *fs;
90167625Spjd	struct statfs sfs;
91109506Sjmallett	const char *oname;
92109506Sjmallett	char dev[MAXPATHLEN];
93167625Spjd	int fd, ret;
9499193Sjmallett
95109462Sjmallett	ERROR(disk, NULL);
9699222Sjmallett
97109506Sjmallett	oname = name;
98167625Spjdagain:	if ((ret = stat(name, &st)) < 0) {
99109506Sjmallett		if (*name != '/') {
100109506Sjmallett			snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name);
101109506Sjmallett			name = dev;
102109506Sjmallett			goto again;
103109506Sjmallett		}
104167625Spjd		/*
105167625Spjd		 * The given object doesn't exist, but don't panic just yet -
106167625Spjd		 * it may be still mount point listed in /etc/fstab, but without
107167625Spjd		 * existing corresponding directory.
108167625Spjd		 */
109167625Spjd		name = oname;
110167625Spjd	}
111194030Sjmallett	if (ret >= 0 && S_ISREG(st.st_mode)) {
112194030Sjmallett		/* Possibly a disk image, give it a try.  */
113194030Sjmallett		;
114194030Sjmallett	} else if (ret >= 0 && S_ISCHR(st.st_mode)) {
115167625Spjd		/* This is what we need, do nothing. */
116167625Spjd		;
117167625Spjd	} else if ((fs = getfsfile(name)) != NULL) {
118167625Spjd		/*
119167625Spjd		 * The given mount point is listed in /etc/fstab.
120167625Spjd		 * It is possible that someone unmounted file system by hand
121167625Spjd		 * and different file system is mounted on this mount point,
122167625Spjd		 * but we still prefer /etc/fstab entry, because on the other
123167625Spjd		 * hand, there could be /etc/fstab entry for this mount
124167625Spjd		 * point, but file system is not mounted yet (eg. noauto) and
125167625Spjd		 * statfs(2) will point us at different file system.
126167625Spjd		 */
127167625Spjd		name = fs->fs_spec;
128167625Spjd	} else if (ret >= 0 && S_ISDIR(st.st_mode)) {
129167625Spjd		/*
130167625Spjd		 * The mount point is not listed in /etc/fstab, so it may be
131167625Spjd		 * file system mounted by hand.
132167625Spjd		 */
133167625Spjd		if (statfs(name, &sfs) < 0) {
134167625Spjd			ERROR(disk, "could not find special device");
135167625Spjd			return (-1);
136167625Spjd		}
137167625Spjd		strlcpy(dev, sfs.f_mntfromname, sizeof(dev));
138167625Spjd		name = dev;
139167625Spjd	} else {
140109506Sjmallett		ERROR(disk, "could not find special device");
141116084Sjmallett		return (-1);
142109506Sjmallett	}
14399193Sjmallett	fd = open(name, O_RDONLY);
14499193Sjmallett	if (fd == -1) {
145109506Sjmallett		ERROR(disk, "could not open special device");
146116084Sjmallett		return (-1);
14799193Sjmallett	}
14899193Sjmallett
14999193Sjmallett	disk->d_bsize = 1;
150109509Sjmallett	disk->d_ccg = 0;
15199193Sjmallett	disk->d_fd = fd;
15299193Sjmallett	disk->d_inoblock = NULL;
15399823Sjmallett	disk->d_inomin = 0;
15499823Sjmallett	disk->d_inomax = 0;
155109518Sjmallett	disk->d_lcg = 0;
156109506Sjmallett	disk->d_mine = 0;
157101687Sjmallett	disk->d_ufs = 0;
158105737Sjmallett	disk->d_error = NULL;
15999193Sjmallett
160109506Sjmallett	if (oname != name) {
161109506Sjmallett		name = strdup(name);
162109506Sjmallett		if (name == NULL) {
163109506Sjmallett			ERROR(disk, "could not allocate memory for disk name");
164116084Sjmallett			return (-1);
165109506Sjmallett		}
166109506Sjmallett		disk->d_mine |= MINE_NAME;
167109506Sjmallett	}
168109506Sjmallett	disk->d_name = name;
169109506Sjmallett
170116084Sjmallett	return (0);
17199193Sjmallett}
172110066Sjmallett
173110066Sjmallettint
174110066Sjmallettufs_disk_write(struct uufsd *disk)
175110066Sjmallett{
176110066Sjmallett	ERROR(disk, NULL);
177110066Sjmallett
178110066Sjmallett	if (disk->d_mine & MINE_WRITE)
179116084Sjmallett		return (0);
180110066Sjmallett
181112730Sjmallett	close(disk->d_fd);
182110066Sjmallett
183110066Sjmallett	disk->d_fd = open(disk->d_name, O_RDWR);
184110066Sjmallett	if (disk->d_fd < 0) {
185110066Sjmallett		ERROR(disk, "failed to open disk for writing");
186116084Sjmallett		return (-1);
187110066Sjmallett	}
188110066Sjmallett
189110066Sjmallett	disk->d_mine |= MINE_WRITE;
190110066Sjmallett
191116084Sjmallett	return (0);
192110066Sjmallett}
193