2 * Copyright (c) 1995 - 200 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "kafs_locl.h"
36 RCSID("$Id: afssys.c,v 1.67 2000/07/08 12:06:03 assar Exp $");
38 int _kafs_debug; /* this should be done in a better way */
40 #define NO_ENTRY_POINT 0
41 #define SINGLE_ENTRY_POINT 1
42 #define MULTIPLE_ENTRY_POINT 2
43 #define SINGLE_ENTRY_POINT2 3
44 #define SINGLE_ENTRY_POINT3 4
45 #define AIX_ENTRY_POINTS 5
46 #define UNKNOWN_ENTRY_POINT 6
47 static int afs_entry_point = UNKNOWN_ENTRY_POINT;
48 static int afs_syscalls[2];
50 /* Magic to get AIX syscalls to work */
53 static int (*Pioctl)(char*, int, struct ViceIoctl*, int);
54 static int (*Setpag)(void);
65 #ifdef STATIC_AFS_SYSCALLS
70 char path[MaxPathLen], *p;
72 * If we are root or running setuid don't trust AFSLIBPATH!
74 if (getuid() != 0 && !issuid() && (p = getenv("AFSLIBPATH")) != NULL)
75 strlcpy(path, p, sizeof(path));
77 snprintf(path, sizeof(path), "%s/afslib.so", LIBDIR);
79 ptr = dlopen(path, RTLD_NOW);
82 if(errno == ENOEXEC && (p = dlerror()) != NULL)
83 fprintf(stderr, "dlopen(%s): %s\n", path, p);
84 else if (errno != ENOENT)
85 fprintf(stderr, "dlopen(%s): %s\n", path, strerror(errno));
89 Setpag = (int (*)(void))dlsym(ptr, "aix_setpag");
90 Pioctl = (int (*)(char*, int,
91 struct ViceIoctl*, int))dlsym(ptr, "aix_pioctl");
93 afs_entry_point = AIX_ENTRY_POINTS;
99 * This probably only works under Solaris and could get confused if
100 * there's a /etc/name_to_sysnum file.
103 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
106 map_syscall_name_to_number (const char *str, int *res)
110 size_t str_len = strlen (str);
112 f = fopen (_PATH_ETC_NAME_TO_SYSNUM, "r");
115 while (fgets (buf, sizeof(buf), f) != NULL) {
119 if (strncmp (str, buf, str_len) == 0) {
120 char *begptr = buf + str_len;
122 long val = strtol (begptr, &endptr, 0);
124 if (val != 0 && endptr != begptr) {
136 k_pioctl(char *a_path,
138 struct ViceIoctl *a_paramsP,
139 int a_followSymlinks)
142 switch(afs_entry_point){
143 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
144 case SINGLE_ENTRY_POINT:
145 case SINGLE_ENTRY_POINT2:
146 case SINGLE_ENTRY_POINT3:
147 return syscall(afs_syscalls[0], AFSCALL_PIOCTL,
148 a_path, o_opcode, a_paramsP, a_followSymlinks);
150 #if defined(AFS_PIOCTL)
151 case MULTIPLE_ENTRY_POINT:
152 return syscall(afs_syscalls[0],
153 a_path, o_opcode, a_paramsP, a_followSymlinks);
156 case AIX_ENTRY_POINTS:
157 return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks);
163 kill(getpid(), SIGSYS); /* You loose! */
170 k_afs_cell_of_file(const char *path, char *cell, int len)
172 struct ViceIoctl parms;
176 parms.out_size = len;
177 return k_pioctl((char*)path, VIOC_FILE_CELL_NAME, &parms, 1);
183 struct ViceIoctl parms;
184 memset(&parms, 0, sizeof(parms));
185 return k_pioctl(0, VIOCUNLOG, &parms, 0);
192 switch(afs_entry_point){
193 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
194 case SINGLE_ENTRY_POINT:
195 case SINGLE_ENTRY_POINT2:
196 case SINGLE_ENTRY_POINT3:
197 return syscall(afs_syscalls[0], AFSCALL_SETPAG);
199 #if defined(AFS_PIOCTL)
200 case MULTIPLE_ENTRY_POINT:
201 return syscall(afs_syscalls[1]);
204 case AIX_ENTRY_POINTS:
211 kill(getpid(), SIGSYS); /* You loose! */
217 static jmp_buf catch_SIGSYS;
222 SIGSYS_handler(int sig)
225 signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */
226 longjmp(catch_SIGSYS, 1);
232 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
235 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
237 try_one (int syscall_num)
239 struct ViceIoctl parms;
240 memset(&parms, 0, sizeof(parms));
242 if (setjmp(catch_SIGSYS) == 0) {
243 syscall(syscall_num, AFSCALL_PIOCTL,
244 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
245 if (errno == EINVAL) {
246 afs_entry_point = SINGLE_ENTRY_POINT;
247 afs_syscalls[0] = syscall_num;
256 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
263 try_two (int syscall_pioctl, int syscall_setpag)
265 struct ViceIoctl parms;
266 memset(&parms, 0, sizeof(parms));
268 if (setjmp(catch_SIGSYS) == 0) {
269 syscall(syscall_pioctl,
270 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
271 if (errno == EINVAL) {
272 afs_entry_point = MULTIPLE_ENTRY_POINT;
273 afs_syscalls[0] = syscall_pioctl;
274 afs_syscalls[1] = syscall_setpag;
285 #if !defined(NO_AFS) && defined(SIGSYS)
286 RETSIGTYPE (*saved_func)(int);
289 char *env = getenv ("AFS_SYSCALL");
292 * Already checked presence of AFS syscalls?
294 if (afs_entry_point != UNKNOWN_ENTRY_POINT)
295 return afs_entry_point != NO_ENTRY_POINT;
298 * Probe kernel for AFS specific syscalls,
299 * they (currently) come in two flavors.
300 * If the syscall is absent we recive a SIGSYS.
302 afs_entry_point = NO_ENTRY_POINT;
307 saved_func = signal(SIGSYS, SIGSYS_handler);
310 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
315 if (sscanf (env, "%d", &tmp) == 1) {
316 if (try_one (tmp) == 0)
321 char *s = strdup (env);
324 for (p = strtok_r (s, ",", &end);
326 p = strtok_r (NULL, ",", &end)) {
327 if (map_syscall_name_to_number (p, &tmp) == 0)
328 if (try_one (tmp) == 0) {
338 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
341 if (try_one (AFS_SYSCALL) == 0)
343 #endif /* AFS_SYSCALL */
349 if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2)
350 if (try_two (tmp[0], tmp[1]) == 2)
353 #endif /* AFS_PIOCTL */
356 if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0)
358 #endif /* AFS_PIOCTL */
361 if (try_one (AFS_SYSCALL2) == 0)
363 #endif /* AFS_SYSCALL2 */
366 if (try_one (AFS_SYSCALL3) == 0)
368 #endif /* AFS_SYSCALL3 */
377 pioctl_name = strtok_r (env, ", \t", &pos);
378 if (pioctl_name != NULL) {
379 setpag_name = strtok_r (NULL, ", \t", &pos);
380 if (setpag_name != NULL)
381 if (try_aix (pioctl_name, setpag_name) == 0)
393 signal(SIGSYS, saved_func);
397 return afs_entry_point != NO_ENTRY_POINT;