xfs: no excessive warnings about dprecated mount options on remount
[xfstests-dev.git] / src / feature.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2003 Silicon Graphics, Inc.
4  * All Rights Reserved.
5  */
6
7 /*
8  * Test for filesystem features on given mount point or device
9  *   -c  test for 32bit chown support (via libc)
10  *   -t  test for working rlimit/ftruncate64 (via libc)
11  *   -q  test for quota support (kernel compile option)
12  *   -u  test for user quota enforcement support (mount option)
13  *   -p  test for project quota enforcement support (mount option)
14  *   -g  test for group quota enforcement support (mount option)
15  *   -U  test for user quota accounting support (mount option)
16  *   -G  test for group quota accounting support (mount option)
17  *   -P  test for project quota accounting support (mount option)
18  * Return code: 0 is true, anything else is error/not supported
19  *
20  * Test for machine features
21  *   -A  test whether AIO syscalls are available
22  *   -R  test whether IO_URING syscalls are available
23  *   -o  report a number of online cpus
24  *   -s  report pagesize
25  *   -w  report bits per long
26  */
27
28 #include "global.h"
29
30 #include <sys/quota.h>
31 #include <sys/resource.h>
32 #include <signal.h>
33 #include <unistd.h>
34
35 #ifdef HAVE_XFS_XQM_H
36 #include <xfs/xqm.h>
37 #endif
38
39 #ifdef HAVE_LIBAIO_H
40 #include <libaio.h>
41 #endif
42
43 #ifdef HAVE_LIBURING_H
44 #include <liburing.h>
45 #endif
46
47 #ifndef USRQUOTA
48 #define USRQUOTA  0
49 #endif
50
51 #ifndef GRPQUOTA
52 #define GRPQUOTA  1
53 #endif
54
55 #ifndef PRJQUOTA
56 #define PRJQUOTA  2
57 #endif
58
59 int verbose = 0;
60
61 void
62 usage(void)
63 {
64         fprintf(stderr, "Usage: feature [-v] -<q|u|g|p|U|G|P> <filesystem>\n");
65         fprintf(stderr, "       feature [-v] -c <file>\n");
66         fprintf(stderr, "       feature [-v] -t <file>\n");
67         fprintf(stderr, "       feature -A | -R | -o | -s | -w\n");
68         exit(1);
69 }
70
71 int check_big_ID(char *filename)
72 {
73         struct stat64   sbuf;
74
75         memset(&sbuf, 0, sizeof(struct stat64));
76         if (lstat64(filename, &sbuf) < 0) {
77                 fprintf(stderr, "lstat64 failed on ");
78                 perror(filename);
79                 return(1);
80         }
81
82         /* 98789 is greater than 2^16 (65536) */
83         if ((uint32_t)sbuf.st_uid == 98789 || (uint32_t)sbuf.st_gid == 98789)
84                 return(0);
85         if (verbose)
86                 fprintf(stderr, "lstat64 on %s gave uid=%d, gid=%d\n",
87                         filename, (int)sbuf.st_uid, (int)sbuf.st_gid);
88         return(1);
89 }
90
91 int
92 haschown32(char *filename)
93 {
94         if (check_big_ID(filename) == 0)
95                 return(0);
96
97         if (chown(filename, 98789, 98789) < 0) {
98                 fprintf(stderr, "chown failed on ");
99                 perror(filename);
100                 return(1);
101         }
102
103         if (check_big_ID(filename) == 0)
104                 return(0);
105         return (1);
106 }
107
108 int
109 hastruncate64(char *filename)
110 {
111         struct rlimit64 rlimit64;
112         off64_t bigoff = 4294967307LL;  /* > 2^32 */
113         struct stat64 bigst;
114         int fd;
115
116         getrlimit64(RLIMIT_FSIZE, &rlimit64);
117         rlimit64.rlim_cur = RLIM64_INFINITY;
118         setrlimit64(RLIMIT_FSIZE, &rlimit64);
119
120         signal(SIGXFSZ, SIG_IGN);
121
122         if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
123                 fprintf(stderr, "open failed on ");
124                 perror(filename);
125                 return(1);
126         }
127
128         if (ftruncate64(fd, bigoff) < 0)
129                 return(1);
130
131         if (fstat64(fd, &bigst) < 0) {
132                 fprintf(stderr, "fstat64 failed on ");
133                 perror(filename);
134                 return(1);
135         }
136
137         if (verbose)
138                 fprintf(stderr, "fstat64 on %s gave sz=%lld (truncsz=%lld)\n",
139                         filename, (long long)bigst.st_size, (long long)bigoff);
140
141         if (bigst.st_size != bigoff)
142                 return(1);
143         return(0);
144 }
145
146 int
147 hasxfsquota(int type, int q, char *device)
148 {
149         fs_quota_stat_t qstat;
150         int             qcmd;
151
152         memset(&qstat, 0, sizeof(fs_quota_stat_t));
153
154 #ifdef QCMD
155         if (q == 0) {
156                 if (access("/proc/fs/xfs/xqm", F_OK) < 0) {
157                         if (verbose) {
158                                 fprintf(stderr, "can't access /proc/fs/xfs/xqm\n");
159                         }
160                         return 1;
161                 }
162                 return 0;
163         }
164         qcmd = QCMD(Q_XGETQSTAT, type);
165 #else
166         if (q == 0) {
167                 if (quotactl(Q_SYNC, device, 0, (caddr_t)&qstat) == ENOPKG) {
168                         if (verbose) {
169                                 fprintf(stderr, "Q_SYNC not supported\n");
170                         }
171                         return 1;
172                 }
173                 return 0;
174         }
175         qcmd = Q_GETQSTAT;
176 #endif
177
178         if (quotactl(qcmd, device, 0, (caddr_t)&qstat) < 0) {
179                 if (verbose)
180                         perror("quotactl");
181                 return (1);
182         }
183         else if (q == XFS_QUOTA_UDQ_ENFD && qstat.qs_flags & XFS_QUOTA_UDQ_ENFD)
184                 return (0);
185         else if (q == XFS_QUOTA_GDQ_ENFD && qstat.qs_flags & XFS_QUOTA_GDQ_ENFD)
186                 return (0);
187         else if (q == XFS_QUOTA_PDQ_ENFD && qstat.qs_flags & XFS_QUOTA_PDQ_ENFD)
188                 return (0);
189         else if (q == XFS_QUOTA_UDQ_ACCT && qstat.qs_flags & XFS_QUOTA_UDQ_ACCT)
190                 return (0);
191         else if (q == XFS_QUOTA_GDQ_ACCT && qstat.qs_flags & XFS_QUOTA_GDQ_ACCT)
192                 return (0);
193         else if (q == XFS_QUOTA_PDQ_ACCT && qstat.qs_flags & XFS_QUOTA_PDQ_ACCT)
194                 return (0);
195         if (verbose)
196                 fprintf(stderr, "quota type (%d) not available\n", q);
197         return (1);
198 }
199
200 static int
201 check_aio_support(void)
202 {
203 #ifdef HAVE_LIBAIO_H
204         struct io_context *ctx = NULL;
205         int err;
206
207         err = io_setup(1, &ctx);
208         if (err == 0)
209                 return 0;
210
211         if (err == -ENOSYS) /* CONFIG_AIO=n */
212                 return 1;
213
214         fprintf(stderr, "unexpected error from io_setup(): %s\n",
215                 strerror(-err));
216         return 2;
217 #else
218         /* libaio was unavailable at build time; assume AIO is unsupported */
219         return 1;
220 #endif
221 }
222
223 static int
224 check_uring_support(void)
225 {
226 #ifdef HAVE_LIBURING_H
227         struct io_uring ring;
228         int err;
229
230         err = io_uring_queue_init(1, &ring, 0);
231         if (err == 0)
232                 return 0;
233
234         if (err == -ENOSYS) /* CONFIG_IO_URING=n */
235                 return 1;
236
237         fprintf(stderr, "unexpected error from io_uring_queue_init(): %s\n",
238                 strerror(-err));
239         return 2;
240 #else
241         /* liburing is unavailable, assume IO_URING is unsupported */
242         return 1;
243 #endif
244 }
245
246
247 int
248 main(int argc, char **argv)
249 {
250         int     c;
251         int     Aflag = 0;
252         int     cflag = 0;
253         int     tflag = 0;
254         int     gflag = 0;
255         int     Gflag = 0;
256         int     pflag = 0;
257         int     Pflag = 0;
258         int     qflag = 0;
259         int     Rflag = 0;
260         int     sflag = 0;
261         int     uflag = 0;
262         int     Uflag = 0;
263         int     wflag = 0;
264         int     oflag = 0;
265         char    *fs = NULL;
266
267         while ((c = getopt(argc, argv, "ActgGopPqRsuUvw")) != EOF) {
268                 switch (c) {
269                 case 'A':
270                         Aflag++;
271                         break;
272                 case 'c':
273                         cflag++;
274                         break;
275                 case 't':
276                         tflag++;
277                         break;
278                 case 'g':
279                         gflag++;
280                         break;
281                 case 'G':
282                         Gflag++;
283                         break;
284                 case 'o':
285                         oflag++;
286                         break;
287                 case 'p':
288                         pflag++;
289                         break;
290                 case 'P':
291                         Pflag++;
292                         break;
293                 case 'q':
294                         qflag++;
295                         break;
296                 case 'R':
297                         Rflag++;
298                         break;
299                 case 's':
300                         sflag++;
301                         break;
302                 case 'u':
303                         uflag++;
304                         break;
305                 case 'U':
306                         Uflag++;
307                         break;
308                 case 'w':
309                         wflag++;
310                         break;
311                 case 'v':
312                         verbose++;
313                         break;
314                 default:
315                         usage();
316                 }
317         }
318
319         /* filesystem features */
320         if (cflag|tflag|uflag|gflag|pflag|qflag|Uflag|Gflag|Pflag) {
321                 if (optind != argc-1)   /* need a device */
322                         usage();
323                 fs = argv[argc-1];
324         } else if (Aflag || Rflag || wflag || sflag || oflag) {
325                 if (optind != argc)
326                         usage();
327         } else 
328                 usage();
329
330         if (cflag)
331                 return(haschown32(fs));
332         if (tflag)
333                 return(hastruncate64(fs));
334         if (qflag)
335                 return(hasxfsquota(0, 0, fs));
336         if (gflag)
337                 return(hasxfsquota(GRPQUOTA, XFS_QUOTA_GDQ_ENFD, fs));
338         if (pflag)
339                 return(hasxfsquota(PRJQUOTA, XFS_QUOTA_PDQ_ENFD, fs));
340         if (uflag)
341                 return(hasxfsquota(USRQUOTA, XFS_QUOTA_UDQ_ENFD, fs));
342         if (Gflag)
343                 return(hasxfsquota(GRPQUOTA, XFS_QUOTA_GDQ_ACCT, fs));
344         if (Pflag)
345                 return(hasxfsquota(PRJQUOTA, XFS_QUOTA_PDQ_ACCT, fs));
346         if (Uflag)
347                 return(hasxfsquota(USRQUOTA, XFS_QUOTA_UDQ_ACCT, fs));
348
349         if (Aflag)
350                 return(check_aio_support());
351
352         if (Rflag)
353                 return(check_uring_support());
354
355         if (sflag) {
356                 printf("%d\n", getpagesize());
357                 exit(0);
358         }
359         if (wflag) {
360 #ifdef BITS_PER_LONG
361                 printf("%d\n", BITS_PER_LONG);
362 #else
363 #ifdef NBBY
364                 /* This can change under IRIX depending on whether we compile
365                  * with -n32/-32 or -64
366                  */
367                 printf("%d\n", (int)(NBBY * sizeof(long)));
368 #else
369 bozo!
370 #endif
371 #endif
372                 exit(0);
373         }
374         if (oflag) {
375                 long ncpus = -1;
376
377 #if defined(_SC_NPROCESSORS_ONLN)
378                 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
379 #elif defined(_SC_NPROC_ONLN)
380                 ncpus = sysconf(_SC_NPROC_ONLN);
381 #endif
382                 if (ncpus == -1)
383                         ncpus = 1;
384
385                 printf("%ld\n", ncpus);
386
387                 exit(0);
388         }
389
390         fprintf(stderr, "feature: dunno what you're after.\n");
391         return(1);
392 }