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