2 * Copyright (c) 1995 - 2000, 2002, 2004, 2005 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"
43 unsigned long syscall
;
45 #define VIOC_SYSCALL_PROC _IOW('C', 1, void *)
48 unsigned long syscall
;
58 #define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata)
59 #define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata)
63 int _kafs_debug
; /* this should be done in a better way */
65 #define UNKNOWN_ENTRY_POINT (-1)
66 #define NO_ENTRY_POINT 0
67 #define SINGLE_ENTRY_POINT 1
68 #define MULTIPLE_ENTRY_POINT 2
69 #define SINGLE_ENTRY_POINT2 3
70 #define SINGLE_ENTRY_POINT3 4
71 #define LINUX_PROC_POINT 5
72 #define AIX_ENTRY_POINTS 6
73 #define MACOS_DEV_POINT 7
75 static int afs_entry_point
= UNKNOWN_ENTRY_POINT
;
76 static int afs_syscalls
[2];
77 static char *afs_ioctlpath
;
78 static unsigned long afs_ioctlnum
;
80 /* Magic to get AIX syscalls to work */
83 static int (*Pioctl
)(char*, int, struct ViceIoctl
*, int);
84 static int (*Setpag
)(void);
95 #ifdef STATIC_AFS_SYSCALLS
100 char path
[MaxPathLen
], *p
;
102 * If we are root or running setuid don't trust AFSLIBPATH!
104 if (getuid() != 0 && !issuid() && (p
= getenv("AFSLIBPATH")) != NULL
)
105 strlcpy(path
, p
, sizeof(path
));
107 snprintf(path
, sizeof(path
), "%s/afslib.so", LIBDIR
);
109 ptr
= dlopen(path
, RTLD_NOW
);
112 if(errno
== ENOEXEC
&& (p
= dlerror()) != NULL
)
113 fprintf(stderr
, "dlopen(%s): %s\n", path
, p
);
114 else if (errno
!= ENOENT
)
115 fprintf(stderr
, "dlopen(%s): %s\n", path
, strerror(errno
));
119 Setpag
= (int (*)(void))dlsym(ptr
, "aix_setpag");
120 Pioctl
= (int (*)(char*, int,
121 struct ViceIoctl
*, int))dlsym(ptr
, "aix_pioctl");
123 afs_entry_point
= AIX_ENTRY_POINTS
;
129 * This probably only works under Solaris and could get confused if
130 * there's a /etc/name_to_sysnum file.
133 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
135 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
138 map_syscall_name_to_number (const char *str
, int *res
)
142 size_t str_len
= strlen (str
);
144 f
= fopen (_PATH_ETC_NAME_TO_SYSNUM
, "r");
147 while (fgets (buf
, sizeof(buf
), f
) != NULL
) {
151 if (strncmp (str
, buf
, str_len
) == 0) {
152 char *begptr
= buf
+ str_len
;
154 long val
= strtol (begptr
, &endptr
, 0);
156 if (val
!= 0 && endptr
!= begptr
) {
169 try_ioctlpath(const char *path
, unsigned long ioctlnum
, int entrypoint
)
171 int fd
, ret
, saved_errno
;
173 fd
= open(path
, O_RDWR
);
176 switch (entrypoint
) {
177 case LINUX_PROC_POINT
: {
178 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
179 data
.param2
= (unsigned long)VIOCGETTOK
;
180 ret
= ioctl(fd
, ioctlnum
, &data
);
183 case MACOS_DEV_POINT
: {
184 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
185 data
.param2
= (unsigned long)VIOCGETTOK
;
186 ret
= ioctl(fd
, ioctlnum
, &data
);
195 * Be quite liberal in what error are ok, the first is the one
196 * that should trigger given that params is NULL.
199 (saved_errno
!= EFAULT
&&
200 saved_errno
!= EDOM
&&
201 saved_errno
!= ENOTCONN
))
203 afs_ioctlnum
= ioctlnum
;
204 afs_ioctlpath
= strdup(path
);
205 if (afs_ioctlpath
== NULL
)
207 afs_entry_point
= entrypoint
;
214 int fd
, ret
, saved_errno
;
215 fd
= open(afs_ioctlpath
, O_RDWR
);
220 ret
= ioctl(fd
, afs_ioctlnum
, data
);
228 k_pioctl(char *a_path
,
230 struct ViceIoctl
*a_paramsP
,
231 int a_followSymlinks
)
234 switch(afs_entry_point
){
235 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
236 case SINGLE_ENTRY_POINT
:
237 case SINGLE_ENTRY_POINT2
:
238 case SINGLE_ENTRY_POINT3
:
239 return syscall(afs_syscalls
[0], AFSCALL_PIOCTL
,
240 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
242 #if defined(AFS_PIOCTL)
243 case MULTIPLE_ENTRY_POINT
:
244 return syscall(afs_syscalls
[0],
245 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
247 case LINUX_PROC_POINT
: {
248 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
249 data
.param1
= (unsigned long)a_path
;
250 data
.param2
= (unsigned long)o_opcode
;
251 data
.param3
= (unsigned long)a_paramsP
;
252 data
.param4
= (unsigned long)a_followSymlinks
;
253 return do_ioctl(&data
);
255 case MACOS_DEV_POINT
: {
256 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
259 data
.param1
= (unsigned long)a_path
;
260 data
.param2
= (unsigned long)o_opcode
;
261 data
.param3
= (unsigned long)a_paramsP
;
262 data
.param4
= (unsigned long)a_followSymlinks
;
264 ret
= do_ioctl(&data
);
271 case AIX_ENTRY_POINTS
:
272 return Pioctl(a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
277 kill(getpid(), SIGSYS
); /* You lose! */
284 k_afs_cell_of_file(const char *path
, char *cell
, int len
)
286 struct ViceIoctl parms
;
290 parms
.out_size
= len
;
291 return k_pioctl(rk_UNCONST(path
), VIOC_FILE_CELL_NAME
, &parms
, 1);
297 struct ViceIoctl parms
;
298 memset(&parms
, 0, sizeof(parms
));
299 return k_pioctl(0, VIOCUNLOG
, &parms
, 0);
306 switch(afs_entry_point
){
307 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
308 case SINGLE_ENTRY_POINT
:
309 case SINGLE_ENTRY_POINT2
:
310 case SINGLE_ENTRY_POINT3
:
311 return syscall(afs_syscalls
[0], AFSCALL_SETPAG
);
313 #if defined(AFS_PIOCTL)
314 case MULTIPLE_ENTRY_POINT
:
315 return syscall(afs_syscalls
[1]);
317 case LINUX_PROC_POINT
: {
318 struct procdata data
= { 0, 0, 0, 0, AFSCALL_SETPAG
};
319 return do_ioctl(&data
);
321 case MACOS_DEV_POINT
: {
322 struct devdata data
= { AFSCALL_SETPAG
, 0, 0, 0, 0, 0, 0, 0 };
323 int ret
= do_ioctl(&data
);
329 case AIX_ENTRY_POINTS
:
336 kill(getpid(), SIGSYS
); /* You lose! */
342 static jmp_buf catch_SIGSYS
;
347 SIGSYS_handler(int sig
)
350 signal(SIGSYS
, SIGSYS_handler
); /* Need to reinstall handler on SYSV */
351 longjmp(catch_SIGSYS
, 1);
357 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
360 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
362 try_one (int syscall_num
)
364 struct ViceIoctl parms
;
365 memset(&parms
, 0, sizeof(parms
));
367 if (setjmp(catch_SIGSYS
) == 0) {
368 syscall(syscall_num
, AFSCALL_PIOCTL
,
369 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
370 if (errno
== EINVAL
) {
371 afs_entry_point
= SINGLE_ENTRY_POINT
;
372 afs_syscalls
[0] = syscall_num
;
381 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
388 try_two (int syscall_pioctl
, int syscall_setpag
)
390 struct ViceIoctl parms
;
391 memset(&parms
, 0, sizeof(parms
));
393 if (setjmp(catch_SIGSYS
) == 0) {
394 syscall(syscall_pioctl
,
395 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
396 if (errno
== EINVAL
) {
397 afs_entry_point
= MULTIPLE_ENTRY_POINT
;
398 afs_syscalls
[0] = syscall_pioctl
;
399 afs_syscalls
[1] = syscall_setpag
;
410 #if !defined(NO_AFS) && defined(SIGSYS)
411 RETSIGTYPE (*saved_func
)(int);
413 int saved_errno
, ret
;
417 env
= getenv ("AFS_SYSCALL");
420 * Already checked presence of AFS syscalls?
422 if (afs_entry_point
!= UNKNOWN_ENTRY_POINT
)
423 return afs_entry_point
!= NO_ENTRY_POINT
;
426 * Probe kernel for AFS specific syscalls,
427 * they (currently) come in two flavors.
428 * If the syscall is absent we recive a SIGSYS.
430 afs_entry_point
= NO_ENTRY_POINT
;
435 saved_func
= signal(SIGSYS
, SIGSYS_handler
);
437 if (env
&& strstr(env
, "..") == NULL
) {
439 if (strncmp("/proc/", env
, 6) == 0) {
440 if (try_ioctlpath(env
, VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
) == 0)
443 if (strncmp("/dev/", env
, 5) == 0) {
444 #ifdef VIOC_SYSCALL_DEV
445 if (try_ioctlpath(env
, VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
) == 0)
448 #ifdef VIOC_SYSCALL_DEV_OPENAFS
449 if (try_ioctlpath(env
,VIOC_SYSCALL_DEV_OPENAFS
,MACOS_DEV_POINT
) ==0)
455 ret
= try_ioctlpath("/proc/fs/openafs/afs_ioctl",
456 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
459 ret
= try_ioctlpath("/proc/fs/nnpfs/afs_ioctl",
460 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
464 #ifdef VIOC_SYSCALL_DEV_OPENAFS
465 ret
= try_ioctlpath("/dev/openafs_ioctl",
466 VIOC_SYSCALL_DEV_OPENAFS
, MACOS_DEV_POINT
);
470 #ifdef VIOC_SYSCALL_DEV
471 ret
= try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
);
476 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
481 if (sscanf (env
, "%d", &tmp
) == 1) {
482 if (try_one (tmp
) == 0)
487 char *s
= strdup (env
);
490 for (p
= strtok_r (s
, ",", &end
);
492 p
= strtok_r (NULL
, ",", &end
)) {
493 if (map_syscall_name_to_number (p
, &tmp
) == 0)
494 if (try_one (tmp
) == 0) {
504 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
507 if (try_one (AFS_SYSCALL
) == 0)
509 #endif /* AFS_SYSCALL */
515 if (env
!= NULL
&& sscanf (env
, "%d%d", &tmp
[0], &tmp
[1]) == 2)
516 if (try_two (tmp
[0], tmp
[1]) == 2)
519 #endif /* AFS_PIOCTL */
522 if (try_two (AFS_PIOCTL
, AFS_SETPAG
) == 0)
524 #endif /* AFS_PIOCTL */
527 if (try_one (AFS_SYSCALL2
) == 0)
529 #endif /* AFS_SYSCALL2 */
532 if (try_one (AFS_SYSCALL3
) == 0)
534 #endif /* AFS_SYSCALL3 */
543 pioctl_name
= strtok_r (env
, ", \t", &pos
);
544 if (pioctl_name
!= NULL
) {
545 setpag_name
= strtok_r (NULL
, ", \t", &pos
);
546 if (setpag_name
!= NULL
)
547 if (try_aix (pioctl_name
, setpag_name
) == 0)
560 signal(SIGSYS
, saved_func
);
564 return afs_entry_point
!= NO_ENTRY_POINT
;
568 k_hasafs_recheck(void)
570 afs_entry_point
= UNKNOWN_ENTRY_POINT
;