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
;
44 #define _IOT_procdata _IOT(_IOTS(long), 5, 0, 0, 0, 0)
45 #define VIOC_SYSCALL_PROC _IOW('C', 1, struct procdata)
47 #define VIOC_SYSCALL_PROC _IOW('C', 1, void *)
51 unsigned long syscall
;
61 #define _IOT_devdata _IOT(_IOTS(long), 8, 0, 0, 0, 0)
64 #define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata)
65 #define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata)
79 #define VIOC_SUN_SYSCALL_DEV _IOW('C', 2, struct sundevdata)
90 #define VIOC_SUN_SYSCALL_DEV _IOW('C', 1, struct sundevdata)
95 int _kafs_debug
; /* this should be done in a better way */
97 #define UNKNOWN_ENTRY_POINT (-1)
98 #define NO_ENTRY_POINT 0
99 #define SINGLE_ENTRY_POINT 1
100 #define MULTIPLE_ENTRY_POINT 2
101 #define SINGLE_ENTRY_POINT2 3
102 #define SINGLE_ENTRY_POINT3 4
103 #define LINUX_PROC_POINT 5
104 #define AIX_ENTRY_POINTS 6
105 #define MACOS_DEV_POINT 7
106 #define SUN_PROC_POINT 8
108 static int afs_entry_point
= UNKNOWN_ENTRY_POINT
;
109 static int afs_syscalls
[2];
110 static char *afs_ioctlpath
;
111 static unsigned long afs_ioctlnum
;
113 /* Magic to get AIX syscalls to work */
116 static int (*Pioctl
)(char*, int, struct ViceIoctl
*, int);
117 static int (*Setpag
)(void);
128 #ifdef STATIC_AFS_SYSCALLS
133 char path
[MaxPathLen
], *p
;
135 * If we are root or running setuid don't trust AFSLIBPATH!
137 if (getuid() != 0 && !issuid() && (p
= getenv("AFSLIBPATH")) != NULL
)
138 strlcpy(path
, p
, sizeof(path
));
140 snprintf(path
, sizeof(path
), "%s/afslib.so", LIBDIR
);
142 ptr
= dlopen(path
, RTLD_NOW
);
145 if(errno
== ENOEXEC
&& (p
= dlerror()) != NULL
)
146 fprintf(stderr
, "dlopen(%s): %s\n", path
, p
);
147 else if (errno
!= ENOENT
)
148 fprintf(stderr
, "dlopen(%s): %s\n", path
, strerror(errno
));
152 Setpag
= (int (*)(void))dlsym(ptr
, "aix_setpag");
153 Pioctl
= (int (*)(char*, int,
154 struct ViceIoctl
*, int))dlsym(ptr
, "aix_pioctl");
156 afs_entry_point
= AIX_ENTRY_POINTS
;
162 * This probably only works under Solaris and could get confused if
163 * there's a /etc/name_to_sysnum file.
166 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
168 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
171 map_syscall_name_to_number (const char *str
, int *res
)
175 size_t str_len
= strlen (str
);
177 f
= fopen (_PATH_ETC_NAME_TO_SYSNUM
, "r");
180 while (fgets (buf
, sizeof(buf
), f
) != NULL
) {
184 if (strncmp (str
, buf
, str_len
) == 0) {
185 char *begptr
= buf
+ str_len
;
187 long val
= strtol (begptr
, &endptr
, 0);
189 if (val
!= 0 && endptr
!= begptr
) {
202 try_ioctlpath(const char *path
, unsigned long ioctlnum
, int entrypoint
)
204 int fd
, ret
, saved_errno
;
206 fd
= open(path
, O_RDWR
);
209 switch (entrypoint
) {
210 case LINUX_PROC_POINT
: {
211 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
212 data
.param2
= (unsigned long)VIOCGETTOK
;
213 ret
= ioctl(fd
, ioctlnum
, &data
);
216 case MACOS_DEV_POINT
: {
217 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
218 data
.param2
= (unsigned long)VIOCGETTOK
;
219 ret
= ioctl(fd
, ioctlnum
, &data
);
222 case SUN_PROC_POINT
: {
223 struct sundevdata data
= { 0, 0, 0, 0, 0, 0, AFSCALL_PIOCTL
};
224 data
.param2
= (unsigned long)VIOCGETTOK
;
225 ret
= ioctl(fd
, ioctlnum
, &data
);
234 * Be quite liberal in what error are ok, the first is the one
235 * that should trigger given that params is NULL.
238 (saved_errno
!= EFAULT
&&
239 saved_errno
!= EDOM
&&
240 saved_errno
!= ENOTCONN
))
242 afs_ioctlnum
= ioctlnum
;
243 afs_ioctlpath
= strdup(path
);
244 if (afs_ioctlpath
== NULL
)
246 afs_entry_point
= entrypoint
;
253 int fd
, ret
, saved_errno
;
254 fd
= open(afs_ioctlpath
, O_RDWR
);
259 ret
= ioctl(fd
, afs_ioctlnum
, data
);
267 k_pioctl(char *a_path
,
269 struct ViceIoctl
*a_paramsP
,
270 int a_followSymlinks
)
273 switch(afs_entry_point
){
274 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
275 case SINGLE_ENTRY_POINT
:
276 case SINGLE_ENTRY_POINT2
:
277 case SINGLE_ENTRY_POINT3
:
278 return syscall(afs_syscalls
[0], AFSCALL_PIOCTL
,
279 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
281 #if defined(AFS_PIOCTL)
282 case MULTIPLE_ENTRY_POINT
:
283 return syscall(afs_syscalls
[0],
284 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
286 case LINUX_PROC_POINT
: {
287 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
288 data
.param1
= (unsigned long)a_path
;
289 data
.param2
= (unsigned long)o_opcode
;
290 data
.param3
= (unsigned long)a_paramsP
;
291 data
.param4
= (unsigned long)a_followSymlinks
;
292 return do_ioctl(&data
);
294 case MACOS_DEV_POINT
: {
295 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
298 data
.param1
= (unsigned long)a_path
;
299 data
.param2
= (unsigned long)o_opcode
;
300 data
.param3
= (unsigned long)a_paramsP
;
301 data
.param4
= (unsigned long)a_followSymlinks
;
303 ret
= do_ioctl(&data
);
309 case SUN_PROC_POINT
: {
310 struct sundevdata data
= { 0, 0, 0, 0, 0, 0, AFSCALL_PIOCTL
};
311 data
.param1
= (unsigned long)a_path
;
312 data
.param2
= (unsigned long)o_opcode
;
313 data
.param3
= (unsigned long)a_paramsP
;
314 data
.param4
= (unsigned long)a_followSymlinks
;
315 return do_ioctl(&data
);
318 case AIX_ENTRY_POINTS
:
319 return Pioctl(a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
324 kill(getpid(), SIGSYS
); /* You lose! */
331 k_afs_cell_of_file(const char *path
, char *cell
, int len
)
333 struct ViceIoctl parms
;
337 parms
.out_size
= len
;
338 return k_pioctl(rk_UNCONST(path
), VIOC_FILE_CELL_NAME
, &parms
, 1);
344 struct ViceIoctl parms
;
345 memset(&parms
, 0, sizeof(parms
));
346 return k_pioctl(0, VIOCUNLOG
, &parms
, 0);
353 switch(afs_entry_point
){
354 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
355 case SINGLE_ENTRY_POINT
:
356 case SINGLE_ENTRY_POINT2
:
357 case SINGLE_ENTRY_POINT3
:
358 return syscall(afs_syscalls
[0], AFSCALL_SETPAG
);
360 #if defined(AFS_PIOCTL)
361 case MULTIPLE_ENTRY_POINT
:
362 return syscall(afs_syscalls
[1]);
364 case LINUX_PROC_POINT
: {
365 struct procdata data
= { 0, 0, 0, 0, AFSCALL_SETPAG
};
366 return do_ioctl(&data
);
368 case MACOS_DEV_POINT
: {
369 struct devdata data
= { AFSCALL_SETPAG
, 0, 0, 0, 0, 0, 0, 0 };
370 int ret
= do_ioctl(&data
);
375 case SUN_PROC_POINT
: {
376 struct sundevdata data
= { 0, 0, 0, 0, 0, 0, AFSCALL_SETPAG
};
377 return do_ioctl(&data
);
380 case AIX_ENTRY_POINTS
:
387 kill(getpid(), SIGSYS
); /* You lose! */
393 static jmp_buf catch_SIGSYS
;
398 SIGSYS_handler(int sig
)
401 signal(SIGSYS
, SIGSYS_handler
); /* Need to reinstall handler on SYSV */
402 longjmp(catch_SIGSYS
, 1);
408 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
411 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
413 try_one (int syscall_num
)
415 struct ViceIoctl parms
;
416 memset(&parms
, 0, sizeof(parms
));
418 if (setjmp(catch_SIGSYS
) == 0) {
419 syscall(syscall_num
, AFSCALL_PIOCTL
,
420 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
421 if (errno
== EINVAL
) {
422 afs_entry_point
= SINGLE_ENTRY_POINT
;
423 afs_syscalls
[0] = syscall_num
;
432 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
439 try_two (int syscall_pioctl
, int syscall_setpag
)
441 struct ViceIoctl parms
;
442 memset(&parms
, 0, sizeof(parms
));
444 if (setjmp(catch_SIGSYS
) == 0) {
445 syscall(syscall_pioctl
,
446 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
447 if (errno
== EINVAL
) {
448 afs_entry_point
= MULTIPLE_ENTRY_POINT
;
449 afs_syscalls
[0] = syscall_pioctl
;
450 afs_syscalls
[1] = syscall_setpag
;
461 #if !defined(NO_AFS) && defined(SIGSYS)
462 RETSIGTYPE (*saved_func
)(int);
464 int saved_errno
, ret
;
468 env
= getenv ("AFS_SYSCALL");
471 * Already checked presence of AFS syscalls?
473 if (afs_entry_point
!= UNKNOWN_ENTRY_POINT
)
474 return afs_entry_point
!= NO_ENTRY_POINT
;
477 * Probe kernel for AFS specific syscalls,
478 * they (currently) come in two flavors.
479 * If the syscall is absent we recive a SIGSYS.
481 afs_entry_point
= NO_ENTRY_POINT
;
486 saved_func
= signal(SIGSYS
, SIGSYS_handler
);
488 if (env
&& strstr(env
, "..") == NULL
) {
490 if (strncmp("/proc/", env
, 6) == 0) {
491 if (try_ioctlpath(env
, VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
) == 0)
494 if (strncmp("/dev/", env
, 5) == 0) {
495 #ifdef VIOC_SYSCALL_DEV
496 if (try_ioctlpath(env
, VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
) == 0)
499 #ifdef VIOC_SYSCALL_DEV_OPENAFS
500 if (try_ioctlpath(env
,VIOC_SYSCALL_DEV_OPENAFS
,MACOS_DEV_POINT
) ==0)
506 ret
= try_ioctlpath("/proc/fs/openafs/afs_ioctl",
507 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
510 ret
= try_ioctlpath("/proc/fs/nnpfs/afs_ioctl",
511 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
515 #ifdef VIOC_SYSCALL_DEV_OPENAFS
516 ret
= try_ioctlpath("/dev/openafs_ioctl",
517 VIOC_SYSCALL_DEV_OPENAFS
, MACOS_DEV_POINT
);
521 #ifdef VIOC_SYSCALL_DEV
522 ret
= try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
);
526 #ifdef VIOC_SUN_SYSCALL_DEV
527 ret
= try_ioctlpath("/dev/afs", VIOC_SUN_SYSCALL_DEV
, SUN_PROC_POINT
);
533 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
538 if (sscanf (env
, "%d", &tmp
) == 1) {
539 if (try_one (tmp
) == 0)
544 char *s
= strdup (env
);
547 for (p
= strtok_r (s
, ",", &end
);
549 p
= strtok_r (NULL
, ",", &end
)) {
550 if (map_syscall_name_to_number (p
, &tmp
) == 0)
551 if (try_one (tmp
) == 0) {
561 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
564 if (try_one (AFS_SYSCALL
) == 0)
566 #endif /* AFS_SYSCALL */
572 if (env
!= NULL
&& sscanf (env
, "%d%d", &tmp
[0], &tmp
[1]) == 2)
573 if (try_two (tmp
[0], tmp
[1]) == 2)
576 #endif /* AFS_PIOCTL */
579 if (try_two (AFS_PIOCTL
, AFS_SETPAG
) == 0)
581 #endif /* AFS_PIOCTL */
584 if (try_one (AFS_SYSCALL2
) == 0)
586 #endif /* AFS_SYSCALL2 */
589 if (try_one (AFS_SYSCALL3
) == 0)
591 #endif /* AFS_SYSCALL3 */
600 pioctl_name
= strtok_r (env
, ", \t", &pos
);
601 if (pioctl_name
!= NULL
) {
602 setpag_name
= strtok_r (NULL
, ", \t", &pos
);
603 if (setpag_name
!= NULL
)
604 if (try_aix (pioctl_name
, setpag_name
) == 0)
617 signal(SIGSYS
, saved_func
);
621 return afs_entry_point
!= NO_ENTRY_POINT
;
625 k_hasafs_recheck(void)
627 afs_entry_point
= UNKNOWN_ENTRY_POINT
;