1331722Seadler/*
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: stable/11/lib/libufs/type.c 332638 2018-04-17 00:03:32Z mckusick $");
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);
61332638Smckusick	disk->d_fd = -1;
6299193Sjmallett	if (disk->d_inoblock != NULL) {
6399193Sjmallett		free(disk->d_inoblock);
6499193Sjmallett		disk->d_inoblock = NULL;
6599193Sjmallett	}
66109506Sjmallett	if (disk->d_mine & MINE_NAME) {
67109506Sjmallett		free((char *)(uintptr_t)disk->d_name);
68109506Sjmallett		disk->d_name = NULL;
69109506Sjmallett	}
70207141Sjeff	if (disk->d_sbcsum != NULL) {
71207141Sjeff		free(disk->d_sbcsum);
72207141Sjeff		disk->d_sbcsum = NULL;
73207141Sjeff	}
74116084Sjmallett	return (0);
7599193Sjmallett}
7699193Sjmallett
7799193Sjmallettint
7899193Sjmallettufs_disk_fillout(struct uufsd *disk, const char *name)
7999193Sjmallett{
80109755Sjmallett	if (ufs_disk_fillout_blank(disk, name) == -1) {
81116084Sjmallett		return (-1);
82109755Sjmallett	}
83109755Sjmallett	if (sbread(disk) == -1) {
84109755Sjmallett		ERROR(disk, "could not read superblock to fill out disk");
85116084Sjmallett		return (-1);
86109755Sjmallett	}
87116084Sjmallett	return (0);
88109755Sjmallett}
89109755Sjmallett
90109755Sjmallettint
91109755Sjmallettufs_disk_fillout_blank(struct uufsd *disk, const char *name)
92109755Sjmallett{
93109506Sjmallett	struct stat st;
94109506Sjmallett	struct fstab *fs;
95167625Spjd	struct statfs sfs;
96109506Sjmallett	const char *oname;
97109506Sjmallett	char dev[MAXPATHLEN];
98167625Spjd	int fd, ret;
9999193Sjmallett
100109462Sjmallett	ERROR(disk, NULL);
10199222Sjmallett
102109506Sjmallett	oname = name;
103167625Spjdagain:	if ((ret = stat(name, &st)) < 0) {
104109506Sjmallett		if (*name != '/') {
105109506Sjmallett			snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name);
106109506Sjmallett			name = dev;
107109506Sjmallett			goto again;
108109506Sjmallett		}
109167625Spjd		/*
110167625Spjd		 * The given object doesn't exist, but don't panic just yet -
111167625Spjd		 * it may be still mount point listed in /etc/fstab, but without
112167625Spjd		 * existing corresponding directory.
113167625Spjd		 */
114167625Spjd		name = oname;
115167625Spjd	}
116194030Sjmallett	if (ret >= 0 && S_ISREG(st.st_mode)) {
117194030Sjmallett		/* Possibly a disk image, give it a try.  */
118194030Sjmallett		;
119194030Sjmallett	} else if (ret >= 0 && S_ISCHR(st.st_mode)) {
120167625Spjd		/* This is what we need, do nothing. */
121167625Spjd		;
122167625Spjd	} else if ((fs = getfsfile(name)) != NULL) {
123167625Spjd		/*
124167625Spjd		 * The given mount point is listed in /etc/fstab.
125167625Spjd		 * It is possible that someone unmounted file system by hand
126167625Spjd		 * and different file system is mounted on this mount point,
127167625Spjd		 * but we still prefer /etc/fstab entry, because on the other
128167625Spjd		 * hand, there could be /etc/fstab entry for this mount
129167625Spjd		 * point, but file system is not mounted yet (eg. noauto) and
130167625Spjd		 * statfs(2) will point us at different file system.
131167625Spjd		 */
132167625Spjd		name = fs->fs_spec;
133167625Spjd	} else if (ret >= 0 && S_ISDIR(st.st_mode)) {
134167625Spjd		/*
135167625Spjd		 * The mount point is not listed in /etc/fstab, so it may be
136167625Spjd		 * file system mounted by hand.
137167625Spjd		 */
138167625Spjd		if (statfs(name, &sfs) < 0) {
139167625Spjd			ERROR(disk, "could not find special device");
140167625Spjd			return (-1);
141167625Spjd		}
142167625Spjd		strlcpy(dev, sfs.f_mntfromname, sizeof(dev));
143167625Spjd		name = dev;
144167625Spjd	} else {
145109506Sjmallett		ERROR(disk, "could not find special device");
146116084Sjmallett		return (-1);
147109506Sjmallett	}
14899193Sjmallett	fd = open(name, O_RDONLY);
14999193Sjmallett	if (fd == -1) {
150109506Sjmallett		ERROR(disk, "could not open special device");
151116084Sjmallett		return (-1);
15299193Sjmallett	}
15399193Sjmallett
15499193Sjmallett	disk->d_bsize = 1;
155109509Sjmallett	disk->d_ccg = 0;
15699193Sjmallett	disk->d_fd = fd;
15799193Sjmallett	disk->d_inoblock = NULL;
15899823Sjmallett	disk->d_inomin = 0;
15999823Sjmallett	disk->d_inomax = 0;
160109518Sjmallett	disk->d_lcg = 0;
161109506Sjmallett	disk->d_mine = 0;
162101687Sjmallett	disk->d_ufs = 0;
163105737Sjmallett	disk->d_error = NULL;
164207141Sjeff	disk->d_sbcsum = NULL;
16599193Sjmallett
166109506Sjmallett	if (oname != name) {
167109506Sjmallett		name = strdup(name);
168109506Sjmallett		if (name == NULL) {
169109506Sjmallett			ERROR(disk, "could not allocate memory for disk name");
170116084Sjmallett			return (-1);
171109506Sjmallett		}
172109506Sjmallett		disk->d_mine |= MINE_NAME;
173109506Sjmallett	}
174109506Sjmallett	disk->d_name = name;
175109506Sjmallett
176116084Sjmallett	return (0);
17799193Sjmallett}
178110066Sjmallett
179110066Sjmallettint
180110066Sjmallettufs_disk_write(struct uufsd *disk)
181110066Sjmallett{
182332638Smckusick	int fd;
183332638Smckusick
184110066Sjmallett	ERROR(disk, NULL);
185110066Sjmallett
186110066Sjmallett	if (disk->d_mine & MINE_WRITE)
187116084Sjmallett		return (0);
188110066Sjmallett
189332638Smckusick	fd = open(disk->d_name, O_RDWR);
190332638Smckusick	if (fd < 0) {
191110066Sjmallett		ERROR(disk, "failed to open disk for writing");
192116084Sjmallett		return (-1);
193110066Sjmallett	}
194110066Sjmallett
195332638Smckusick	close(disk->d_fd);
196332638Smckusick	disk->d_fd = fd;
197110066Sjmallett	disk->d_mine |= MINE_WRITE;
198110066Sjmallett
199116084Sjmallett	return (0);
200110066Sjmallett}
201