a31833f32e4f8d93687dcdba93b1d6e4a4e01e3e
[openafs.git] / src / kopenafs / kopenafs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Glue code for the kopenafs API.  Mostly just wrappers around the functions
12  * included in the libsys code.
13  */
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 #include <roken.h>
18
19 #ifdef AFS_AIX51_ENV
20 # include <sys/cred.h>
21 # ifdef HAVE_SYS_PAG_H
22 #  include <sys/pag.h>
23 # endif
24 #endif
25
26 #include <afs/afssyscalls.h>
27 #include <kopenafs.h>
28
29 static volatile sig_atomic_t syscall_okay = 1;
30
31 /* Signal handler to catch failed system calls and change the okay flag. */
32 #ifdef SIGSYS
33 static RETSIGTYPE
34 sigsys_handler(int s)
35 {
36     syscall_okay = 0;
37     signal(SIGSYS, sigsys_handler);
38 }
39 #endif /* SIGSYS */
40
41 int
42 k_hasafs(void)
43 {
44     struct ViceIoctl iob;
45     int okay, saved_errno;
46     RETSIGTYPE (*saved_func)(int);
47
48     saved_errno = errno;
49
50 #ifdef SIGSYS
51     saved_func = signal(SIGSYS, sigsys_handler);
52 #endif
53
54     iob.in = NULL;
55     iob.in_size = 0;
56     iob.out = NULL;
57     iob.out_size = 0;
58     lpioctl(NULL, VIOCSETTOK, &iob, 0);
59
60 #ifdef SIGSYS
61     signal(SIGSYS, saved_func);
62 #endif
63
64     okay = 1;
65     if (!syscall_okay || errno != EINVAL)
66         okay = 0;
67     errno = saved_errno;
68     return okay;
69 }
70
71 int
72 k_setpag(void)
73 {
74     return lsetpag();
75 }
76
77 int
78 k_pioctl(char *path, int cmd, struct ViceIoctl *cmarg, int follow)
79 {
80     return lpioctl(path, cmd, cmarg, follow);
81 }
82
83 int
84 k_unlog(void)
85 {
86     struct ViceIoctl iob;
87
88     iob.in = NULL;
89     iob.in_size = 0;
90     iob.out = NULL;
91     iob.out_size = 0;
92     return lpioctl(NULL, VIOCUNLOG, &iob, 0);
93 }
94
95
96 /*
97  * If we don't have the VIOC_GETPAG pioctl, we try to determine whether we're
98  * in a PAG by using either a special OS call (AIX 5.2 and later) or by
99  * walking the group list, which works differently for current versions of
100  * Linux.
101  *
102  * These OS differences are encapsulated in the following OS-specific haspag
103  * helper functions.
104  *
105  * This is largely copied from auth/ktc.c and should be merged with that
106  * version, but that version calls through the pioctl() interface right now
107  * and therefore pulls in Rx for NFS translator support.  This avoids an Rx
108  * dependency in the standalone libkopenafs interface.
109  */
110 #if defined(AFS_AIX52_ENV)
111 static int
112 os_haspag(void)
113 {
114     return (getpagvalue("afs") < 0) ? 0 : 1;
115 }
116 #elif defined(AFS_AIX51_ENV)
117 static int
118 os_haspag(void)
119 {
120     return 0;
121 }
122 #else
123 static int
124 os_haspag(void)
125 {
126     int ngroups;
127     gid_t *groups;
128     afs_uint32 g0, g1;
129     afs_uint32 h, l, pag;
130 # ifdef AFS_LINUX26_ENV
131     int i;
132 # endif
133
134     ngroups = getgroups(0, NULL);
135     groups = malloc(sizeof(*groups) * ngroups);
136     if (groups == NULL)
137         return 0;
138     ngroups = getgroups(ngroups, groups);
139
140     /* Check for AFS_LINUX26_ONEGROUP_ENV PAGs. */
141 # ifdef AFS_LINUX26_ENV
142     for (i = 0; i < ngroups; i++)
143         if (((groups[i] >> 24) & 0xff) == 'A') {
144             free(groups);
145             return 1;
146         }
147 # endif
148
149     /* Check for the PAG group pair. */
150     if (ngroups < 2) {
151         free(groups);
152         return 0;
153     }
154     g0 = groups[0] & 0xffff;
155     g1 = groups[1] & 0xffff;
156     free(groups);
157     g0 -= 0x3f00;
158     g1 -= 0x3f00;
159     if (g0 < 0xc000 && g1 < 0xc000) {
160         l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
161         h = (g0 >> 14);
162         h = (g1 >> 14) + h + h + h;
163         pag = ((h << 28) | l);
164         if (((pag >> 24) & 0xff) == 'A')
165             return 1;
166         else
167             return 0;
168     }
169     return 0;
170 }
171 #endif /* !AFS_AIX51_ENV */
172
173 int
174 k_haspag(void)
175 {
176     int code;
177     struct ViceIoctl iob;
178     afs_uint32 pag;
179
180     iob.in = NULL;
181     iob.in_size = 0;
182     iob.out = (caddr_t) &pag;
183     iob.out_size = sizeof(afs_uint32);
184     code = lpioctl(NULL, VIOC_GETPAG, &iob, 0);
185     if (code == 0)
186         return pag != (afs_uint32) -1;
187     else
188         return os_haspag();
189 }