xref: /freebsd/lib/libufs/sblock.c (revision 3a3af6b2a160bea72509a9d5ef84e25906b0478a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2002 Juli Mallett.  All rights reserved.
5  *
6  * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
7  * FreeBSD project.  Redistribution and use in source and binary forms, with
8  * or without modification, are permitted provided that the following
9  * conditions are met:
10  *
11  * 1. Redistribution of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistribution in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/mount.h>
35 #include <sys/disklabel.h>
36 #include <sys/stat.h>
37 
38 #include <ufs/ufs/extattr.h>
39 #include <ufs/ufs/quota.h>
40 #include <ufs/ufs/ufsmount.h>
41 #include <ufs/ufs/dinode.h>
42 #include <ufs/ffs/fs.h>
43 
44 #include <errno.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 
50 #include <libufs.h>
51 
52 static int handle_disk_read(struct uufsd *, struct fs *, int);
53 
54 /*
55  * Read the standard superblock.
56  *
57  * The following option flags can be or'ed into disk->d_lookupflags:
58  *
59  * UFS_NOMSG indicates that superblock inconsistency error messages
60  *    should not be printed.
61  *
62  * UFS_NOCSUM causes only the superblock itself to be returned, but does
63  *    not read in any auxillary data structures like the cylinder group
64  *    summary information.
65  */
66 int
67 sbread(struct uufsd *disk)
68 {
69 	struct fs *fs;
70 	int error;
71 
72 	error = sbget(disk->d_fd, &fs, disk->d_sblockloc, disk->d_lookupflags);
73 	return (handle_disk_read(disk, fs, error));
74 }
75 
76 static int
77 handle_disk_read(struct uufsd *disk, struct fs *fs, int error)
78 {
79 
80 	ERROR(disk, NULL);
81 	if (error != 0) {
82 		switch (error) {
83 		case EIO:
84 			ERROR(disk, "non-existent or truncated superblock");
85 			break;
86 		case ENOENT:
87 			ERROR(disk, "no usable known superblock found");
88 			break;
89 		case EINTEGRITY:
90 			ERROR(disk, "superblock check-hash failure");
91 			break;
92 		case ENOSPC:
93 			ERROR(disk, "failed to allocate space for superblock "
94 			    "information");
95 			break;
96 		case EINVAL:
97 			ERROR(disk, "The previous newfs operation on this "
98 			    "volume did not complete.\nYou must complete "
99 			    "newfs before using this volume.");
100 			break;
101 		default:
102 			ERROR(disk, "unknown superblock read error");
103 			errno = EIO;
104 			break;
105 		}
106 		disk->d_ufs = 0;
107 		return (-1);
108 	}
109 	memcpy(&disk->d_fs, fs, fs->fs_sbsize);
110 	free(fs);
111 	fs = &disk->d_fs;
112 	if (fs->fs_magic == FS_UFS1_MAGIC)
113 		disk->d_ufs = 1;
114 	if (fs->fs_magic == FS_UFS2_MAGIC)
115 		disk->d_ufs = 2;
116 	disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1);
117 	disk->d_sblock = fs->fs_sblockloc / disk->d_bsize;
118 	disk->d_si = fs->fs_si;
119 	return (0);
120 }
121 
122 int
123 sbwrite(struct uufsd *disk, int all)
124 {
125 	struct fs *fs;
126 	int rv;
127 
128 	ERROR(disk, NULL);
129 
130 	rv = ufs_disk_write(disk);
131 	if (rv == -1) {
132 		ERROR(disk, "failed to open disk for writing");
133 		return (-1);
134 	}
135 
136 	fs = &disk->d_fs;
137 	if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) {
138 		switch (errno) {
139 		case EIO:
140 			ERROR(disk, "failed to write superblock");
141 			break;
142 		default:
143 			ERROR(disk, "unknown superblock write error");
144 			errno = EIO;
145 			break;
146 		}
147 		return (-1);
148 	}
149 	return (0);
150 }
151 
152 /*
153  * These are the low-level functions that actually read and write
154  * the superblock and its associated data. The actual work is done by
155  * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c.
156  */
157 static int use_pread(void *devfd, off_t loc, void **bufp, int size);
158 static int use_pwrite(void *devfd, off_t loc, void *buf, int size);
159 
160 /*
161  * The following two functions read a superblock. Their flags
162  * parameter are made up of the following or'ed together options:
163  *
164  * UFS_NOMSG indicates that superblock inconsistency error messages
165  *    should not be printed.
166  *
167  * UFS_NOCSUM causes only the superblock itself to be returned, but does
168  *    not read in any auxillary data structures like the cylinder group
169  *    summary information.
170  *
171  * Read a superblock from the devfd device allocating memory returned
172  * in fsp.
173  */
174 int
175 sbget(int devfd, struct fs **fsp, off_t sblockloc, int flags)
176 {
177 
178 	return (ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread));
179 }
180 
181 /*
182  * A read function for use by user-level programs using libufs.
183  */
184 static int
185 use_pread(void *devfd, off_t loc, void **bufp, int size)
186 {
187 	int fd;
188 
189 	fd = *(int *)devfd;
190 	if ((*bufp = malloc(size)) == NULL)
191 		return (ENOSPC);
192 	if (pread(fd, *bufp, size, loc) != size)
193 		return (EIO);
194 	return (0);
195 }
196 
197 /*
198  * Write a superblock to the devfd device from the memory pointed to by fs.
199  * Also write out the superblock summary information but do not free the
200  * summary information memory.
201  *
202  * Additionally write out numaltwrite of the alternate superblocks. Use
203  * fs->fs_ncg to write out all of the alternate superblocks.
204  */
205 int
206 sbput(int devfd, struct fs *fs, int numaltwrite)
207 {
208 	struct csum *savedcsp;
209 	off_t savedactualloc;
210 	int i, error;
211 
212 	if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
213 	     use_pwrite)) != 0)
214 		return (error);
215 	if (numaltwrite == 0)
216 		return (0);
217 	savedactualloc = fs->fs_sblockactualloc;
218 	if (fs->fs_si != NULL) {
219 		savedcsp = fs->fs_csp;
220 		fs->fs_csp = NULL;
221 	}
222 	for (i = 0; i < numaltwrite; i++) {
223 		fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i)));
224 		if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
225 		     use_pwrite)) != 0) {
226 			fs->fs_sblockactualloc = savedactualloc;
227 			fs->fs_csp = savedcsp;
228 			return (error);
229 		}
230 	}
231 	fs->fs_sblockactualloc = savedactualloc;
232 	if (fs->fs_si != NULL)
233 		fs->fs_csp = savedcsp;
234 	return (0);
235 }
236 
237 /*
238  * A write function for use by user-level programs using sbput in libufs.
239  */
240 static int
241 use_pwrite(void *devfd, off_t loc, void *buf, int size)
242 {
243 	int fd;
244 
245 	fd = *(int *)devfd;
246 	if (pwrite(fd, buf, size, loc) != size)
247 		return (EIO);
248 	return (0);
249 }
250