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