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"
41 unsigned long syscall
;
43 #define VIOC_SYSCALL_PROC _IOW('C', 1, void *)
46 unsigned long syscall
;
56 #define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata)
57 #define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata)
61 int _kafs_debug
; /* this should be done in a better way */
63 #define UNKNOWN_ENTRY_POINT (-1)
64 #define NO_ENTRY_POINT 0
65 #define SINGLE_ENTRY_POINT 1
66 #define MULTIPLE_ENTRY_POINT 2
67 #define SINGLE_ENTRY_POINT2 3
68 #define SINGLE_ENTRY_POINT3 4
69 #define LINUX_PROC_POINT 5
70 #define AIX_ENTRY_POINTS 6
71 #define MACOS_DEV_POINT 7
73 static int afs_entry_point
= UNKNOWN_ENTRY_POINT
;
74 static int afs_syscalls
[2];
75 static char *afs_ioctlpath
;
76 static unsigned long afs_ioctlnum
;
78 /* Magic to get AIX syscalls to work */
81 static int (*Pioctl
)(char*, int, struct ViceIoctl
*, int);
82 static int (*Setpag
)(void);
93 #ifdef STATIC_AFS_SYSCALLS
98 char path
[MaxPathLen
], *p
;
100 * If we are root or running setuid don't trust AFSLIBPATH!
102 if (getuid() != 0 && !issuid() && (p
= getenv("AFSLIBPATH")) != NULL
)
103 strlcpy(path
, p
, sizeof(path
));
105 snprintf(path
, sizeof(path
), "%s/afslib.so", LIBDIR
);
107 ptr
= dlopen(path
, RTLD_NOW
);
110 if(errno
== ENOEXEC
&& (p
= dlerror()) != NULL
)
111 fprintf(stderr
, "dlopen(%s): %s\n", path
, p
);
112 else if (errno
!= ENOENT
)
113 fprintf(stderr
, "dlopen(%s): %s\n", path
, strerror(errno
));
117 Setpag
= (int (*)(void))dlsym(ptr
, "aix_setpag");
118 Pioctl
= (int (*)(char*, int,
119 struct ViceIoctl
*, int))dlsym(ptr
, "aix_pioctl");
121 afs_entry_point
= AIX_ENTRY_POINTS
;
127 * This probably only works under Solaris and could get confused if
128 * there's a /etc/name_to_sysnum file.
131 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
133 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
136 map_syscall_name_to_number (const char *str
, int *res
)
140 size_t str_len
= strlen (str
);
142 f
= fopen (_PATH_ETC_NAME_TO_SYSNUM
, "r");
145 while (fgets (buf
, sizeof(buf
), f
) != NULL
) {
149 if (strncmp (str
, buf
, str_len
) == 0) {
150 char *begptr
= buf
+ str_len
;
152 long val
= strtol (begptr
, &endptr
, 0);
154 if (val
!= 0 && endptr
!= begptr
) {
167 try_ioctlpath(const char *path
, unsigned long ioctlnum
, int entrypoint
)
169 int fd
, ret
, saved_errno
;
171 fd
= open(path
, O_RDWR
);
174 switch (entrypoint
) {
175 case LINUX_PROC_POINT
: {
176 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
177 data
.param2
= (unsigned long)VIOCGETTOK
;
178 ret
= ioctl(fd
, ioctlnum
, &data
);
181 case MACOS_DEV_POINT
: {
182 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
183 data
.param2
= (unsigned long)VIOCGETTOK
;
184 ret
= ioctl(fd
, ioctlnum
, &data
);
193 * Be quite liberal in what error are ok, the first is the one
194 * that should trigger given that params is NULL.
197 (saved_errno
!= EFAULT
&&
198 saved_errno
!= EDOM
&&
199 saved_errno
!= ENOTCONN
))
201 afs_ioctlnum
= ioctlnum
;
202 afs_ioctlpath
= strdup(path
);
203 if (afs_ioctlpath
== NULL
)
205 afs_entry_point
= entrypoint
;
212 int fd
, ret
, saved_errno
;
213 fd
= open(afs_ioctlpath
, O_RDWR
);
218 ret
= ioctl(fd
, afs_ioctlnum
, data
);
226 k_pioctl(char *a_path
,
228 struct ViceIoctl
*a_paramsP
,
229 int a_followSymlinks
)
232 switch(afs_entry_point
){
233 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
234 case SINGLE_ENTRY_POINT
:
235 case SINGLE_ENTRY_POINT2
:
236 case SINGLE_ENTRY_POINT3
:
237 return syscall(afs_syscalls
[0], AFSCALL_PIOCTL
,
238 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
240 #if defined(AFS_PIOCTL)
241 case MULTIPLE_ENTRY_POINT
:
242 return syscall(afs_syscalls
[0],
243 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
245 case LINUX_PROC_POINT
: {
246 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
247 data
.param1
= (unsigned long)a_path
;
248 data
.param2
= (unsigned long)o_opcode
;
249 data
.param3
= (unsigned long)a_paramsP
;
250 data
.param4
= (unsigned long)a_followSymlinks
;
251 return do_ioctl(&data
);
253 case MACOS_DEV_POINT
: {
254 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
257 data
.param1
= (unsigned long)a_path
;
258 data
.param2
= (unsigned long)o_opcode
;
259 data
.param3
= (unsigned long)a_paramsP
;
260 data
.param4
= (unsigned long)a_followSymlinks
;
262 ret
= do_ioctl(&data
);
269 case AIX_ENTRY_POINTS
:
270 return Pioctl(a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
275 kill(getpid(), SIGSYS
); /* You lose! */
282 k_afs_cell_of_file(const char *path
, char *cell
, int len
)
284 struct ViceIoctl parms
;
288 parms
.out_size
= len
;
289 return k_pioctl(rk_UNCONST(path
), VIOC_FILE_CELL_NAME
, &parms
, 1);
295 struct ViceIoctl parms
;
296 memset(&parms
, 0, sizeof(parms
));
297 return k_pioctl(0, VIOCUNLOG
, &parms
, 0);
304 switch(afs_entry_point
){
305 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
306 case SINGLE_ENTRY_POINT
:
307 case SINGLE_ENTRY_POINT2
:
308 case SINGLE_ENTRY_POINT3
:
309 return syscall(afs_syscalls
[0], AFSCALL_SETPAG
);
311 #if defined(AFS_PIOCTL)
312 case MULTIPLE_ENTRY_POINT
:
313 return syscall(afs_syscalls
[1]);
315 case LINUX_PROC_POINT
: {
316 struct procdata data
= { 0, 0, 0, 0, AFSCALL_SETPAG
};
317 return do_ioctl(&data
);
319 case MACOS_DEV_POINT
: {
320 struct devdata data
= { AFSCALL_SETPAG
, 0, 0, 0, 0, 0, 0, 0 };
321 int ret
= do_ioctl(&data
);
327 case AIX_ENTRY_POINTS
:
334 kill(getpid(), SIGSYS
); /* You lose! */
340 static jmp_buf catch_SIGSYS
;
345 SIGSYS_handler(int sig
)
348 signal(SIGSYS
, SIGSYS_handler
); /* Need to reinstall handler on SYSV */
349 longjmp(catch_SIGSYS
, 1);
355 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
358 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
360 try_one (int syscall_num
)
362 struct ViceIoctl parms
;
363 memset(&parms
, 0, sizeof(parms
));
365 if (setjmp(catch_SIGSYS
) == 0) {
366 syscall(syscall_num
, AFSCALL_PIOCTL
,
367 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
368 if (errno
== EINVAL
) {
369 afs_entry_point
= SINGLE_ENTRY_POINT
;
370 afs_syscalls
[0] = syscall_num
;
379 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
386 try_two (int syscall_pioctl
, int syscall_setpag
)
388 struct ViceIoctl parms
;
389 memset(&parms
, 0, sizeof(parms
));
391 if (setjmp(catch_SIGSYS
) == 0) {
392 syscall(syscall_pioctl
,
393 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
394 if (errno
== EINVAL
) {
395 afs_entry_point
= MULTIPLE_ENTRY_POINT
;
396 afs_syscalls
[0] = syscall_pioctl
;
397 afs_syscalls
[1] = syscall_setpag
;
408 #if !defined(NO_AFS) && defined(SIGSYS)
409 RETSIGTYPE (*saved_func
)(int);
411 int saved_errno
, ret
;
415 env
= getenv ("AFS_SYSCALL");
418 * Already checked presence of AFS syscalls?
420 if (afs_entry_point
!= UNKNOWN_ENTRY_POINT
)
421 return afs_entry_point
!= NO_ENTRY_POINT
;
424 * Probe kernel for AFS specific syscalls,
425 * they (currently) come in two flavors.
426 * If the syscall is absent we recive a SIGSYS.
428 afs_entry_point
= NO_ENTRY_POINT
;
433 saved_func
= signal(SIGSYS
, SIGSYS_handler
);
435 if (env
&& strstr(env
, "..") == NULL
) {
437 if (strncmp("/proc/", env
, 6) == 0) {
438 if (try_ioctlpath(env
, VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
) == 0)
441 if (strncmp("/dev/", env
, 5) == 0) {
442 #ifdef VIOC_SYSCALL_DEV
443 if (try_ioctlpath(env
, VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
) == 0)
446 #ifdef VIOC_SYSCALL_DEV_OPENAFS
447 if (try_ioctlpath(env
,VIOC_SYSCALL_DEV_OPENAFS
,MACOS_DEV_POINT
) ==0)
453 ret
= try_ioctlpath("/proc/fs/openafs/afs_ioctl",
454 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
457 ret
= try_ioctlpath("/proc/fs/nnpfs/afs_ioctl",
458 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
462 #ifdef VIOC_SYSCALL_DEV_OPENAFS
463 ret
= try_ioctlpath("/dev/openafs_ioctl",
464 VIOC_SYSCALL_DEV_OPENAFS
, MACOS_DEV_POINT
);
468 #ifdef VIOC_SYSCALL_DEV
469 ret
= try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
);
474 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
479 if (sscanf (env
, "%d", &tmp
) == 1) {
480 if (try_one (tmp
) == 0)
485 char *s
= strdup (env
);
488 for (p
= strtok_r (s
, ",", &end
);
490 p
= strtok_r (NULL
, ",", &end
)) {
491 if (map_syscall_name_to_number (p
, &tmp
) == 0)
492 if (try_one (tmp
) == 0) {
502 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
505 if (try_one (AFS_SYSCALL
) == 0)
507 #endif /* AFS_SYSCALL */
513 if (env
!= NULL
&& sscanf (env
, "%d%d", &tmp
[0], &tmp
[1]) == 2)
514 if (try_two (tmp
[0], tmp
[1]) == 2)
517 #endif /* AFS_PIOCTL */
520 if (try_two (AFS_PIOCTL
, AFS_SETPAG
) == 0)
522 #endif /* AFS_PIOCTL */
525 if (try_one (AFS_SYSCALL2
) == 0)
527 #endif /* AFS_SYSCALL2 */
530 if (try_one (AFS_SYSCALL3
) == 0)
532 #endif /* AFS_SYSCALL3 */
541 pioctl_name
= strtok_r (env
, ", \t", &pos
);
542 if (pioctl_name
!= NULL
) {
543 setpag_name
= strtok_r (NULL
, ", \t", &pos
);
544 if (setpag_name
!= NULL
)
545 if (try_aix (pioctl_name
, setpag_name
) == 0)
558 signal(SIGSYS
, saved_func
);
562 return afs_entry_point
!= NO_ENTRY_POINT
;
566 k_hasafs_recheck(void)
568 afs_entry_point
= UNKNOWN_ENTRY_POINT
;