1209139Srpaulo/*
2209139Srpaulo * Copyright (c) 2002 Juli Mallett.  All rights reserved.
3209139Srpaulo *
4209139Srpaulo * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
5252726Srpaulo * FreeBSD project.  Redistribution and use in source and binary forms, with
6252726Srpaulo * or without modification, are permitted provided that the following
7209139Srpaulo * conditions are met:
8209139Srpaulo *
9209139Srpaulo * 1. Redistribution of source code must retain the above copyright notice,
10209139Srpaulo *    this list of conditions and the following disclaimer.
11209139Srpaulo * 2. Redistribution in binary form must reproduce the above copyright
12209139Srpaulo *    notice, this list of conditions and the following disclaimer in the
13209139Srpaulo *    documentation and/or other materials provided with the distribution.
14209139Srpaulo *
15209139Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16209139Srpaulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17209139Srpaulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18209139Srpaulo * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19209139Srpaulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20209139Srpaulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21209139Srpaulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22209139Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23209139Srpaulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24209139Srpaulo * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25209139Srpaulo * POSSIBILITY OF SUCH DAMAGE.
26209139Srpaulo */
27209139Srpaulo
28209139Srpaulo#include <sys/cdefs.h>
29209139Srpaulo__FBSDID("$FreeBSD$");
30209139Srpaulo
31209139Srpaulo#include <sys/param.h>
32209139Srpaulo#include <sys/mount.h>
33209139Srpaulo#include <sys/disklabel.h>
34209139Srpaulo#include <sys/stat.h>
35209139Srpaulo
36209139Srpaulo#include <ufs/ufs/ufsmount.h>
37209139Srpaulo#include <ufs/ufs/dinode.h>
38209139Srpaulo#include <ufs/ffs/fs.h>
39209139Srpaulo
40209139Srpaulo#include <errno.h>
41209139Srpaulo#include <fcntl.h>
42209139Srpaulo#include <fstab.h>
43209139Srpaulo#include <paths.h>
44209139Srpaulo#include <stdio.h>
45209139Srpaulo#include <stdlib.h>
46209139Srpaulo#include <string.h>
47209139Srpaulo#include <unistd.h>
48209139Srpaulo
49209139Srpaulo#include <libufs.h>
50209139Srpaulo
51209139Srpaulo/* Internally, track the 'name' value, it's ours. */
52209139Srpaulo#define	MINE_NAME	0x01
53209139Srpaulo/* Track if its fd points to a writable device. */
54209139Srpaulo#define	MINE_WRITE	0x02
55209139Srpaulo
56209139Srpauloint
57209139Srpauloufs_disk_close(struct uufsd *disk)
58209139Srpaulo{
59209139Srpaulo	ERROR(disk, NULL);
60209139Srpaulo	close(disk->d_fd);
61209139Srpaulo	if (disk->d_inoblock != NULL) {
62209139Srpaulo		free(disk->d_inoblock);
63209139Srpaulo		disk->d_inoblock = NULL;
64209139Srpaulo	}
65209139Srpaulo	if (disk->d_mine & MINE_NAME) {
66209139Srpaulo		free((char *)(uintptr_t)disk->d_name);
67209139Srpaulo		disk->d_name = NULL;
68209139Srpaulo	}
69209139Srpaulo	if (disk->d_sbcsum != NULL) {
70209139Srpaulo		free(disk->d_sbcsum);
71209139Srpaulo		disk->d_sbcsum = NULL;
72209139Srpaulo	}
73209139Srpaulo	return (0);
74214734Srpaulo}
75209139Srpaulo
76209139Srpauloint
77209139Srpauloufs_disk_fillout(struct uufsd *disk, const char *name)
78209139Srpaulo{
79209139Srpaulo	if (ufs_disk_fillout_blank(disk, name) == -1) {
80209139Srpaulo		return (-1);
81209139Srpaulo	}
82209139Srpaulo	if (sbread(disk) == -1) {
83209139Srpaulo		ERROR(disk, "could not read superblock to fill out disk");
84209139Srpaulo		return (-1);
85209139Srpaulo	}
86209139Srpaulo	return (0);
87209139Srpaulo}
88209139Srpaulo
89209139Srpauloint
90209139Srpauloufs_disk_fillout_blank(struct uufsd *disk, const char *name)
91209139Srpaulo{
92209139Srpaulo	struct stat st;
93209139Srpaulo	struct fstab *fs;
94209139Srpaulo	struct statfs sfs;
95209139Srpaulo	const char *oname;
96209139Srpaulo	char dev[MAXPATHLEN];
97209139Srpaulo	int fd, ret;
98209139Srpaulo
99209139Srpaulo	ERROR(disk, NULL);
100209139Srpaulo
101252726Srpaulo	oname = name;
102252726Srpauloagain:	if ((ret = stat(name, &st)) < 0) {
103209139Srpaulo		if (*name != '/') {
104209139Srpaulo			snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name);
105209139Srpaulo			name = dev;
106209139Srpaulo			goto again;
107209139Srpaulo		}
108209139Srpaulo		/*
109209139Srpaulo		 * The given object doesn't exist, but don't panic just yet -
110209139Srpaulo		 * it may be still mount point listed in /etc/fstab, but without
111209139Srpaulo		 * existing corresponding directory.
112209139Srpaulo		 */
113209139Srpaulo		name = oname;
114209139Srpaulo	}
115209139Srpaulo	if (ret >= 0 && S_ISREG(st.st_mode)) {
116209139Srpaulo		/* Possibly a disk image, give it a try.  */
117209139Srpaulo		;
118209139Srpaulo	} else if (ret >= 0 && S_ISCHR(st.st_mode)) {
119209139Srpaulo		/* This is what we need, do nothing. */
120209139Srpaulo		;
121209139Srpaulo	} else if ((fs = getfsfile(name)) != NULL) {
122209139Srpaulo		/*
123209139Srpaulo		 * The given mount point is listed in /etc/fstab.
124209139Srpaulo		 * It is possible that someone unmounted file system by hand
125209139Srpaulo		 * and different file system is mounted on this mount point,
126209139Srpaulo		 * but we still prefer /etc/fstab entry, because on the other
127209139Srpaulo		 * hand, there could be /etc/fstab entry for this mount
128209139Srpaulo		 * point, but file system is not mounted yet (eg. noauto) and
129209139Srpaulo		 * statfs(2) will point us at different file system.
130209139Srpaulo		 */
131252726Srpaulo		name = fs->fs_spec;
132252726Srpaulo	} else if (ret >= 0 && S_ISDIR(st.st_mode)) {
133209139Srpaulo		/*
134209139Srpaulo		 * The mount point is not listed in /etc/fstab, so it may be
135209139Srpaulo		 * file system mounted by hand.
136209139Srpaulo		 */
137209139Srpaulo		if (statfs(name, &sfs) < 0) {
138209139Srpaulo			ERROR(disk, "could not find special device");
139209139Srpaulo			return (-1);
140209139Srpaulo		}
141209139Srpaulo		strlcpy(dev, sfs.f_mntfromname, sizeof(dev));
142209139Srpaulo		name = dev;
143209139Srpaulo	} else {
144209139Srpaulo		ERROR(disk, "could not find special device");
145209139Srpaulo		return (-1);
146209139Srpaulo	}
147209139Srpaulo	fd = open(name, O_RDONLY);
148209139Srpaulo	if (fd == -1) {
149209139Srpaulo		ERROR(disk, "could not open special device");
150209139Srpaulo		return (-1);
151209139Srpaulo	}
152209139Srpaulo
153209139Srpaulo	disk->d_bsize = 1;
154209139Srpaulo	disk->d_ccg = 0;
155209139Srpaulo	disk->d_fd = fd;
156209139Srpaulo	disk->d_inoblock = NULL;
157209139Srpaulo	disk->d_inomin = 0;
158209139Srpaulo	disk->d_inomax = 0;
159209139Srpaulo	disk->d_lcg = 0;
160209139Srpaulo	disk->d_mine = 0;
161209139Srpaulo	disk->d_ufs = 0;
162209139Srpaulo	disk->d_error = NULL;
163209139Srpaulo	disk->d_sbcsum = NULL;
164209139Srpaulo
165209139Srpaulo	if (oname != name) {
166209139Srpaulo		name = strdup(name);
167209139Srpaulo		if (name == NULL) {
168209139Srpaulo			ERROR(disk, "could not allocate memory for disk name");
169209139Srpaulo			return (-1);
170209139Srpaulo		}
171209139Srpaulo		disk->d_mine |= MINE_NAME;
172209139Srpaulo	}
173209139Srpaulo	disk->d_name = name;
174209139Srpaulo
175209139Srpaulo	return (0);
176209139Srpaulo}
177209139Srpaulo
178209139Srpauloint
179209139Srpauloufs_disk_write(struct uufsd *disk)
180209139Srpaulo{
181209139Srpaulo	ERROR(disk, NULL);
182209139Srpaulo
183209139Srpaulo	if (disk->d_mine & MINE_WRITE)
184209139Srpaulo		return (0);
185209139Srpaulo
186209139Srpaulo	close(disk->d_fd);
187209139Srpaulo
188209139Srpaulo	disk->d_fd = open(disk->d_name, O_RDWR);
189209139Srpaulo	if (disk->d_fd < 0) {
190209139Srpaulo		ERROR(disk, "failed to open disk for writing");
191209139Srpaulo		return (-1);
192209139Srpaulo	}
193209139Srpaulo
194252726Srpaulo	disk->d_mine |= MINE_WRITE;
195252726Srpaulo
196209139Srpaulo	return (0);
197209139Srpaulo}
198209139Srpaulo