LINUX: defer afs_remunlink when current->fs==NULL
[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 void
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     void (*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     int code;
75
76     do {
77         code = lsetpag();
78     } while (code && errno == EINTR);
79
80     return code;
81 }
82
83 int
84 k_pioctl(char *path, int cmd, struct ViceIoctl *cmarg, int follow)
85 {
86     return lpioctl(path, cmd, cmarg, follow);
87 }
88
89 int
90 k_unlog(void)
91 {
92     struct ViceIoctl iob;
93
94     iob.in = NULL;
95     iob.in_size = 0;
96     iob.out = NULL;
97     iob.out_size = 0;
98     return lpioctl(NULL, VIOCUNLOG, &iob, 0);
99 }
100
101
102 /*
103  * If we don't have the VIOC_GETPAG pioctl, we try to determine whether we're
104  * in a PAG by using either a special OS call (AIX 5.2 and later) or by
105  * walking the group list, which works differently for current versions of
106  * Linux.
107  *
108  * These OS differences are encapsulated in the following OS-specific haspag
109  * helper functions.
110  *
111  * This is largely copied from auth/ktc.c and should be merged with that
112  * version, but that version calls through the pioctl() interface right now
113  * and therefore pulls in Rx for NFS translator support.  This avoids an Rx
114  * dependency in the standalone libkopenafs interface.
115  */
116 #if defined(AFS_AIX52_ENV)
117 static int
118 os_haspag(void)
119 {
120     return (getpagvalue("afs") < 0) ? 0 : 1;
121 }
122 #elif defined(AFS_AIX51_ENV)
123 static int
124 os_haspag(void)
125 {
126     return 0;
127 }
128 #else
129 static int
130 os_haspag(void)
131 {
132     int ngroups;
133     gid_t *groups;
134     afs_uint32 g0, g1;
135     afs_uint32 h, l, pag;
136 # ifdef AFS_PAG_ONEGROUP_ENV
137     int i;
138 # endif
139
140     ngroups = getgroups(0, NULL);
141     groups = malloc(sizeof(*groups) * ngroups);
142     if (groups == NULL)
143         return 0;
144     ngroups = getgroups(ngroups, groups);
145
146     /* Check for one-group PAGs. */
147 # ifdef AFS_PAG_ONEGROUP_ENV
148     for (i = 0; i < ngroups; i++)
149         if (((groups[i] >> 24) & 0xff) == 'A') {
150             free(groups);
151             return 1;
152         }
153 # endif
154
155     /* Check for the PAG group pair. */
156     if (ngroups < 2) {
157         free(groups);
158         return 0;
159     }
160     g0 = groups[0] & 0xffff;
161     g1 = groups[1] & 0xffff;
162     free(groups);
163     g0 -= 0x3f00;
164     g1 -= 0x3f00;
165     if (g0 < 0xc000 && g1 < 0xc000) {
166         l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
167         h = (g0 >> 14);
168         h = (g1 >> 14) + h + h + h;
169         pag = ((h << 28) | l);
170         if (((pag >> 24) & 0xff) == 'A')
171             return 1;
172         else
173             return 0;
174     }
175     return 0;
176 }
177 #endif /* !AFS_AIX51_ENV */
178
179 int
180 k_haspag(void)
181 {
182     int code;
183     struct ViceIoctl iob;
184     afs_uint32 pag;
185
186     iob.in = NULL;
187     iob.in_size = 0;
188     iob.out = (caddr_t) &pag;
189     iob.out_size = sizeof(afs_uint32);
190     code = lpioctl(NULL, VIOC_GETPAG, &iob, 0);
191     if (code == 0)
192         return pag != (afs_uint32) -1;
193     else
194         return os_haspag();
195 }