]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libfrog/linux.c
xfsprogs: Release v6.8.0
[thirdparty/xfsprogs-dev.git] / libfrog / linux.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include <mntent.h>
8 #include <sys/stat.h>
9 #include <sys/ioctl.h>
10 #include <sys/sysinfo.h>
11
12 #include "platform_defs.h"
13 #include "xfs.h"
14 #include "init.h"
15 #include "libfrog/platform.h"
16
17 extern char *progname;
18 static int max_block_alignment;
19
20 #ifndef BLKGETSIZE64
21 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
22 #endif
23 #ifndef BLKBSZSET
24 # define BLKBSZSET _IOW(0x12,113,size_t)
25 #endif
26 #ifndef BLKSSZGET
27 # define BLKSSZGET _IO(0x12,104)
28 #endif
29
30 #ifndef RAMDISK_MAJOR
31 #define RAMDISK_MAJOR 1 /* ramdisk major number */
32 #endif
33
34 #define PROC_MOUNTED "/proc/mounts"
35
36 /*
37 * Check if the filesystem is mounted. Be verbose if asked, and
38 * optionally restrict check to /writable/ mounts (i.e. RO is OK)
39 */
40 #define CHECK_MOUNT_VERBOSE 0x1
41 #define CHECK_MOUNT_WRITABLE 0x2
42
43 static int
44 platform_check_mount(char *name, char *block, struct stat *s, int flags)
45 {
46 FILE *f;
47 struct stat st, mst;
48 struct mntent *mnt;
49 char mounts[MAXPATHLEN];
50
51 if (!s) {
52 /* If either fails we are not mounted */
53 if (stat(block, &st) < 0)
54 return 0;
55 if ((st.st_mode & S_IFMT) != S_IFBLK)
56 return 0;
57 s = &st;
58 }
59
60 strcpy(mounts, (!access(PROC_MOUNTED, R_OK)) ? PROC_MOUNTED : MOUNTED);
61 if ((f = setmntent(mounts, "r")) == NULL) {
62 /* Unexpected failure, warn unconditionally */
63 fprintf(stderr,
64 _("%s: %s possibly contains a mounted filesystem\n"),
65 progname, name);
66 return 1;
67 }
68 /*
69 * This whole business is to work out if our block device is mounted
70 * after we lost ustat(2), see:
71 * 4e7a824 libxfs/linux.c: Replace use of ustat by stat
72 * We don't really want to stat every single mounted directory,
73 * as that may include tmpfs, cgroups, procfs or - worst - hung nfs
74 * servers. So first, a simple check: does the "dev" start with "/" ?
75 */
76 while ((mnt = getmntent(f)) != NULL) {
77 if (!strcmp(mnt->mnt_type, "autofs"))
78 continue;
79 if (mnt->mnt_fsname[0] != '/')
80 continue;
81 if (stat(mnt->mnt_dir, &mst) < 0)
82 continue;
83 if (mst.st_dev != s->st_rdev)
84 continue;
85 /* Found our device, is RO OK? */
86 if ((flags & CHECK_MOUNT_WRITABLE) && hasmntopt(mnt, MNTOPT_RO))
87 continue;
88 else
89 break;
90 }
91 endmntent(f);
92
93 /* No mounts contained the condition we were looking for */
94 if (mnt == NULL)
95 return 0;
96
97 if (flags & CHECK_MOUNT_VERBOSE) {
98 if (flags & CHECK_MOUNT_WRITABLE) {
99 fprintf(stderr,
100 _("%s: %s contains a mounted and writable filesystem\n"),
101 progname, name);
102 } else {
103 fprintf(stderr,
104 _("%s: %s contains a mounted filesystem\n"),
105 progname, name);
106 }
107 }
108 return 1;
109 }
110
111 int
112 platform_check_ismounted(char *name, char *block, struct stat *s, int verbose)
113 {
114 int flags;
115
116 flags = verbose ? CHECK_MOUNT_VERBOSE : 0;
117 return platform_check_mount(name, block, s, flags);
118 }
119
120 int
121 platform_check_iswritable(char *name, char *block, struct stat *s)
122 {
123 int flags;
124
125 /* Writable checks are always verbose */
126 flags = CHECK_MOUNT_WRITABLE | CHECK_MOUNT_VERBOSE;
127 return platform_check_mount(name, block, s, flags);
128 }
129
130 void
131 platform_set_blocksize(int fd, char *path, dev_t device, int blocksize,
132 bool fatal)
133 {
134 int error;
135
136 if (major(device) == RAMDISK_MAJOR)
137 return;
138 error = ioctl(fd, BLKBSZSET, &blocksize);
139 if (error < 0) {
140 fprintf(stderr, _("%s: %s - cannot set blocksize "
141 "%d on block device %s: %s\n"),
142 progname, fatal ? "error": "warning",
143 blocksize, path, strerror(errno));
144 if (fatal)
145 exit(1);
146 }
147 }
148
149 /*
150 * Flush dirty pagecache and disk write cache to stable media. Returns 0 for
151 * success or -1 (with errno set) for failure.
152 */
153 int
154 platform_flush_device(
155 int fd,
156 dev_t device)
157 {
158 struct stat st;
159 int ret;
160
161 if (major(device) == RAMDISK_MAJOR)
162 return 0;
163
164 ret = fsync(fd);
165 if (ret)
166 return ret;
167
168 ret = fstat(fd, &st);
169 if (ret)
170 return ret;
171
172 if (S_ISBLK(st.st_mode))
173 return ioctl(fd, BLKFLSBUF, 0);
174
175 return 0;
176 }
177
178 void
179 platform_findsizes(char *path, int fd, long long *sz, int *bsz)
180 {
181 struct stat st;
182 uint64_t size;
183 int error;
184
185 if (fstat(fd, &st) < 0) {
186 fprintf(stderr, _("%s: "
187 "cannot stat the device file \"%s\": %s\n"),
188 progname, path, strerror(errno));
189 exit(1);
190 }
191
192 if ((st.st_mode & S_IFMT) == S_IFREG) {
193 struct dioattr da;
194
195 *sz = (long long)(st.st_size >> 9);
196
197 if (ioctl(fd, XFS_IOC_DIOINFO, &da) < 0) {
198 /*
199 * fall back to BBSIZE; mkfs might fail if there's a
200 * size mismatch between the image & the host fs...
201 */
202 *bsz = BBSIZE;
203 } else
204 *bsz = da.d_miniosz;
205
206 if (*bsz > max_block_alignment)
207 max_block_alignment = *bsz;
208 return;
209 }
210
211 error = ioctl(fd, BLKGETSIZE64, &size);
212 if (error >= 0) {
213 /* BLKGETSIZE64 returns size in bytes not 512-byte blocks */
214 *sz = (long long)(size >> 9);
215 } else {
216 /* If BLKGETSIZE64 fails, try BLKGETSIZE */
217 unsigned long tmpsize;
218
219 error = ioctl(fd, BLKGETSIZE, &tmpsize);
220 if (error < 0) {
221 fprintf(stderr, _("%s: can't determine device size\n"),
222 progname);
223 exit(1);
224 }
225 *sz = (long long)tmpsize;
226 }
227
228 if (ioctl(fd, BLKSSZGET, bsz) < 0) {
229 fprintf(stderr, _("%s: warning - cannot get sector size "
230 "from block device %s: %s\n"),
231 progname, path, strerror(errno));
232 *bsz = BBSIZE;
233 }
234 if (*bsz > max_block_alignment)
235 max_block_alignment = *bsz;
236 }
237
238 int
239 platform_direct_blockdev(void)
240 {
241 return 1;
242 }
243
244 int
245 platform_align_blockdev(void)
246 {
247 if (!max_block_alignment)
248 return getpagesize();
249 return max_block_alignment;
250 }
251
252 /* How many CPUs are online? */
253 int
254 platform_nproc(void)
255 {
256 long nproc = sysconf(_SC_NPROCESSORS_ONLN);
257
258 if (nproc < 1)
259 return 1;
260 if (nproc >= INT_MAX)
261 return INT_MAX;
262 return nproc;
263 }
264
265 unsigned long
266 platform_physmem(void)
267 {
268 struct sysinfo si;
269
270 if (sysinfo(&si) < 0) {
271 fprintf(stderr, _("%s: can't determine memory size\n"),
272 progname);
273 exit(1);
274 }
275 return (si.totalram >> 10) * si.mem_unit; /* kilobytes */
276 }