fstests: Add an auxiliary program to create an AF_UNIX socket
[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  *   -o  report a number of online cpus
34  *   -s  report pagesize
35  *   -w  report bits per long
36  */
37
38 #include "global.h"
39
40 #include <sys/quota.h>
41 #include <sys/resource.h>
42 #include <signal.h>
43 #include <unistd.h>
44
45 #ifdef HAVE_XFS_XQM_H
46 #include <xfs/xqm.h>
47 #endif
48
49 #ifndef USRQUOTA
50 #define USRQUOTA  0
51 #endif
52
53 #ifndef GRPQUOTA
54 #define GRPQUOTA  1
55 #endif
56
57 #ifndef PRJQUOTA
58 #define PRJQUOTA  2
59 #endif
60
61 int verbose = 0;
62
63 void
64 usage(void)
65 {
66         fprintf(stderr, "Usage: feature [-v] -<q|u|g|p|U|G|P> <filesystem>\n");
67         fprintf(stderr, "       feature [-v] -c <file>\n");
68         fprintf(stderr, "       feature [-v] -t <file>\n");
69         fprintf(stderr, "       feature -o | -s | -w\n");
70         exit(1);
71 }
72
73 int check_big_ID(char *filename)
74 {
75         struct stat64   sbuf;
76
77         memset(&sbuf, 0, sizeof(struct stat64));
78         if (lstat64(filename, &sbuf) < 0) {
79                 fprintf(stderr, "lstat64 failed on ");
80                 perror(filename);
81                 return(1);
82         }
83
84         /* 98789 is greater than 2^16 (65536) */
85         if ((__uint32_t)sbuf.st_uid == 98789 || (__uint32_t)sbuf.st_gid == 98789)
86                 return(0);
87         if (verbose)
88                 fprintf(stderr, "lstat64 on %s gave uid=%d, gid=%d\n",
89                         filename, (int)sbuf.st_uid, (int)sbuf.st_gid);
90         return(1);
91 }
92
93 int
94 haschown32(char *filename)
95 {
96         if (check_big_ID(filename) == 0)
97                 return(0);
98
99         if (chown(filename, 98789, 98789) < 0) {
100                 fprintf(stderr, "chown failed on ");
101                 perror(filename);
102                 return(1);
103         }
104
105         if (check_big_ID(filename) == 0)
106                 return(0);
107         return (1);
108 }
109
110 int
111 hastruncate64(char *filename)
112 {
113         struct rlimit64 rlimit64;
114         off64_t bigoff = 4294967307LL;  /* > 2^32 */
115         struct stat64 bigst;
116         int fd;
117
118         getrlimit64(RLIMIT_FSIZE, &rlimit64);
119         rlimit64.rlim_cur = RLIM64_INFINITY;
120         setrlimit64(RLIMIT_FSIZE, &rlimit64);
121
122         signal(SIGXFSZ, SIG_IGN);
123
124         if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
125                 fprintf(stderr, "open failed on ");
126                 perror(filename);
127                 return(1);
128         }
129
130         if (ftruncate64(fd, bigoff) < 0)
131                 return(1);
132
133         if (fstat64(fd, &bigst) < 0) {
134                 fprintf(stderr, "fstat64 failed on ");
135                 perror(filename);
136                 return(1);
137         }
138
139         if (verbose)
140                 fprintf(stderr, "fstat64 on %s gave sz=%lld (truncsz=%lld)\n",
141                         filename, (long long)bigst.st_size, (long long)bigoff);
142
143         if (bigst.st_size != bigoff)
144                 return(1);
145         return(0);
146 }
147
148 int
149 hasxfsquota(int type, int q, char *device)
150 {
151         fs_quota_stat_t qstat;
152         int             qcmd;
153
154         memset(&qstat, 0, sizeof(fs_quota_stat_t));
155
156 #ifdef QCMD
157         if (q == 0) {
158                 if (access("/proc/fs/xfs/xqm", F_OK) < 0) {
159                         if (verbose) {
160                                 fprintf(stderr, "can't access /proc/fs/xfs/xqm\n");
161                         }
162                         return 1;
163                 }
164                 return 0;
165         }
166         qcmd = QCMD(Q_XGETQSTAT, type);
167 #else
168         if (q == 0) {
169                 if (quotactl(Q_SYNC, device, 0, (caddr_t)&qstat) == ENOPKG) {
170                         if (verbose) {
171                                 fprintf(stderr, "Q_SYNC not supported\n");
172                         }
173                         return 1;
174                 }
175                 return 0;
176         }
177         qcmd = Q_GETQSTAT;
178 #endif
179
180         if (quotactl(qcmd, device, 0, (caddr_t)&qstat) < 0) {
181                 if (verbose)
182                         perror("quotactl");
183                 return (1);
184         }
185         else if (q == XFS_QUOTA_UDQ_ENFD && qstat.qs_flags & XFS_QUOTA_UDQ_ENFD)
186                 return (0);
187         else if (q == XFS_QUOTA_GDQ_ENFD && qstat.qs_flags & XFS_QUOTA_GDQ_ENFD)
188                 return (0);
189         else if (q == XFS_QUOTA_PDQ_ENFD && qstat.qs_flags & XFS_QUOTA_PDQ_ENFD)
190                 return (0);
191         else if (q == XFS_QUOTA_UDQ_ACCT && qstat.qs_flags & XFS_QUOTA_UDQ_ACCT)
192                 return (0);
193         else if (q == XFS_QUOTA_GDQ_ACCT && qstat.qs_flags & XFS_QUOTA_GDQ_ACCT)
194                 return (0);
195         else if (q == XFS_QUOTA_PDQ_ACCT && qstat.qs_flags & XFS_QUOTA_PDQ_ACCT)
196                 return (0);
197         if (verbose)
198                 fprintf(stderr, "quota type (%d) not available\n", q);
199         return (1);
200 }
201
202 int
203 main(int argc, char **argv)
204 {
205         int     c;
206         int     cflag = 0;
207         int     tflag = 0;
208         int     gflag = 0;
209         int     Gflag = 0;
210         int     pflag = 0;
211         int     Pflag = 0;
212         int     qflag = 0;
213         int     sflag = 0;
214         int     uflag = 0;
215         int     Uflag = 0;
216         int     wflag = 0;
217         int     oflag = 0;
218         char    *fs = NULL;
219
220         while ((c = getopt(argc, argv, "ctgGopPqsuUvw")) != EOF) {
221                 switch (c) {
222                 case 'c':
223                         cflag++;
224                         break;
225                 case 't':
226                         tflag++;
227                         break;
228                 case 'g':
229                         gflag++;
230                         break;
231                 case 'G':
232                         Gflag++;
233                         break;
234                 case 'o':
235                         oflag++;
236                         break;
237                 case 'p':
238                         pflag++;
239                         break;
240                 case 'P':
241                         Pflag++;
242                         break;
243                 case 'q':
244                         qflag++;
245                         break;
246                 case 's':
247                         sflag++;
248                         break;
249                 case 'u':
250                         uflag++;
251                         break;
252                 case 'U':
253                         Uflag++;
254                         break;
255                 case 'w':
256                         wflag++;
257                         break;
258                 case 'v':
259                         verbose++;
260                         break;
261                 default:
262                         usage();
263                 }
264         }
265
266         /* filesystem features */
267         if (cflag|tflag|uflag|gflag|pflag|qflag|Uflag|Gflag|Pflag) {
268                 if (optind != argc-1)   /* need a device */
269                         usage();
270                 fs = argv[argc-1];
271         } else if (wflag || sflag || oflag) {
272                 if (optind != argc)
273                         usage();
274         } else 
275                 usage();
276
277         if (cflag)
278                 return(haschown32(fs));
279         if (tflag)
280                 return(hastruncate64(fs));
281         if (qflag)
282                 return(hasxfsquota(0, 0, fs));
283         if (gflag)
284                 return(hasxfsquota(GRPQUOTA, XFS_QUOTA_GDQ_ENFD, fs));
285         if (pflag)
286                 return(hasxfsquota(PRJQUOTA, XFS_QUOTA_PDQ_ENFD, fs));
287         if (uflag)
288                 return(hasxfsquota(USRQUOTA, XFS_QUOTA_UDQ_ENFD, fs));
289         if (Gflag)
290                 return(hasxfsquota(GRPQUOTA, XFS_QUOTA_GDQ_ACCT, fs));
291         if (Pflag)
292                 return(hasxfsquota(PRJQUOTA, XFS_QUOTA_PDQ_ACCT, fs));
293         if (Uflag)
294                 return(hasxfsquota(USRQUOTA, XFS_QUOTA_UDQ_ACCT, fs));
295
296         if (sflag) {
297                 printf("%d\n", getpagesize());
298                 exit(0);
299         }
300         if (wflag) {
301 #ifdef BITS_PER_LONG
302                 printf("%d\n", BITS_PER_LONG);
303 #else
304 #ifdef NBBY
305                 /* This can change under IRIX depending on whether we compile
306                  * with -n32/-32 or -64
307                  */
308                 printf("%d\n", (int)(NBBY * sizeof(long)));
309 #else
310 bozo!
311 #endif
312 #endif
313                 exit(0);
314         }
315         if (oflag) {
316                 long ncpus = -1;
317
318 #if defined(_SC_NPROCESSORS_ONLN)
319                 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
320 #elif defined(_SC_NPROC_ONLN)
321                 ncpus = sysconf(_SC_NPROC_ONLN);
322 #endif
323                 if (ncpus == -1)
324                         ncpus = 1;
325
326                 printf("%ld\n", ncpus);
327
328                 exit(0);
329         }
330
331         fprintf(stderr, "feature: dunno what you're after.\n");
332         return(1);
333 }