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"
36 __RCSID("$Heimdal: afssys.c 17050 2006-04-11 08:12:29Z lha $"
44 unsigned long syscall
;
46 #define VIOC_SYSCALL_PROC _IOW('C', 1, void *)
49 unsigned long syscall
;
58 #define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata)
59 #define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata)
62 int _kafs_debug
; /* this should be done in a better way */
64 #define UNKNOWN_ENTRY_POINT (-1)
65 #define NO_ENTRY_POINT 0
66 #define SINGLE_ENTRY_POINT 1
67 #define MULTIPLE_ENTRY_POINT 2
68 #define SINGLE_ENTRY_POINT2 3
69 #define SINGLE_ENTRY_POINT3 4
70 #define LINUX_PROC_POINT 5
71 #define AIX_ENTRY_POINTS 6
72 #define MACOS_DEV_POINT 7
74 static int afs_entry_point
= UNKNOWN_ENTRY_POINT
;
75 static int afs_syscalls
[2];
76 static char *afs_ioctlpath
;
77 static unsigned long afs_ioctlnum
;
79 /* Magic to get AIX syscalls to work */
82 static int (*Pioctl
)(char*, int, struct ViceIoctl
*, int);
83 static int (*Setpag
)(void);
94 #ifdef STATIC_AFS_SYSCALLS
99 char path
[MaxPathLen
], *p
;
101 * If we are root or running setuid don't trust AFSLIBPATH!
103 if (getuid() != 0 && !issuid() && (p
= getenv("AFSLIBPATH")) != NULL
)
104 strlcpy(path
, p
, sizeof(path
));
106 snprintf(path
, sizeof(path
), "%s/afslib.so", LIBDIR
);
108 ptr
= dlopen(path
, RTLD_NOW
);
111 if(errno
== ENOEXEC
&& (p
= dlerror()) != NULL
)
112 fprintf(stderr
, "dlopen(%s): %s\n", path
, p
);
113 else if (errno
!= ENOENT
)
114 fprintf(stderr
, "dlopen(%s): %s\n", path
, strerror(errno
));
118 Setpag
= (int (*)(void))dlsym(ptr
, "aix_setpag");
119 Pioctl
= (int (*)(char*, int,
120 struct ViceIoctl
*, int))dlsym(ptr
, "aix_pioctl");
122 afs_entry_point
= AIX_ENTRY_POINTS
;
128 * This probably only works under Solaris and could get confused if
129 * there's a /etc/name_to_sysnum file.
132 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
134 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
137 map_syscall_name_to_number (const char *str
, int *res
)
141 size_t str_len
= strlen (str
);
143 f
= fopen (_PATH_ETC_NAME_TO_SYSNUM
, "r");
146 while (fgets (buf
, sizeof(buf
), f
) != NULL
) {
150 if (strncmp (str
, buf
, str_len
) == 0) {
151 char *begptr
= buf
+ str_len
;
153 long val
= strtol (begptr
, &endptr
, 0);
155 if (val
!= 0 && endptr
!= begptr
) {
168 try_ioctlpath(const char *path
, unsigned long ioctlnum
, int entrypoint
)
170 int fd
, ret
, saved_errno
;
172 fd
= open(path
, O_RDWR
);
175 switch (entrypoint
) {
176 case LINUX_PROC_POINT
: {
177 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
178 data
.param2
= (unsigned long)VIOCGETTOK
;
179 ret
= ioctl(fd
, ioctlnum
, &data
);
182 case MACOS_DEV_POINT
: {
183 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
184 data
.param2
= (unsigned long)VIOCGETTOK
;
185 ret
= ioctl(fd
, ioctlnum
, &data
);
194 * Be quite liberal in what error are ok, the first is the one
195 * that should trigger given that params is NULL.
198 (saved_errno
!= EFAULT
&&
199 saved_errno
!= EDOM
&&
200 saved_errno
!= ENOTCONN
))
202 afs_ioctlnum
= ioctlnum
;
203 afs_ioctlpath
= strdup(path
);
204 if (afs_ioctlpath
== NULL
)
206 afs_entry_point
= entrypoint
;
213 int fd
, ret
, saved_errno
;
214 fd
= open(afs_ioctlpath
, O_RDWR
);
219 ret
= ioctl(fd
, afs_ioctlnum
, data
);
227 k_pioctl(char *a_path
,
229 struct ViceIoctl
*a_paramsP
,
230 int a_followSymlinks
)
233 switch(afs_entry_point
){
234 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
235 case SINGLE_ENTRY_POINT
:
236 case SINGLE_ENTRY_POINT2
:
237 case SINGLE_ENTRY_POINT3
:
238 return syscall(afs_syscalls
[0], AFSCALL_PIOCTL
,
239 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
241 #if defined(AFS_PIOCTL)
242 case MULTIPLE_ENTRY_POINT
:
243 return syscall(afs_syscalls
[0],
244 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
246 case LINUX_PROC_POINT
: {
247 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
248 data
.param1
= (unsigned long)a_path
;
249 data
.param2
= (unsigned long)o_opcode
;
250 data
.param3
= (unsigned long)a_paramsP
;
251 data
.param4
= (unsigned long)a_followSymlinks
;
252 return do_ioctl(&data
);
254 case MACOS_DEV_POINT
: {
255 struct devdata data
= { AFSCALL_PIOCTL
, 0, 0, 0, 0, 0, 0, 0 };
258 data
.param1
= (unsigned long)a_path
;
259 data
.param2
= (unsigned long)o_opcode
;
260 data
.param3
= (unsigned long)a_paramsP
;
261 data
.param4
= (unsigned long)a_followSymlinks
;
263 ret
= do_ioctl(&data
);
270 case AIX_ENTRY_POINTS
:
271 return Pioctl(a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
276 kill(getpid(), SIGSYS
); /* You lose! */
283 k_afs_cell_of_file(const char *path
, char *cell
, int len
)
285 struct ViceIoctl parms
;
289 parms
.out_size
= len
;
290 return k_pioctl(rk_UNCONST(path
), VIOC_FILE_CELL_NAME
, &parms
, 1);
296 struct ViceIoctl parms
;
297 memset(&parms
, 0, sizeof(parms
));
298 return k_pioctl(0, VIOCUNLOG
, &parms
, 0);
305 switch(afs_entry_point
){
306 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
307 case SINGLE_ENTRY_POINT
:
308 case SINGLE_ENTRY_POINT2
:
309 case SINGLE_ENTRY_POINT3
:
310 return syscall(afs_syscalls
[0], AFSCALL_SETPAG
);
312 #if defined(AFS_PIOCTL)
313 case MULTIPLE_ENTRY_POINT
:
314 return syscall(afs_syscalls
[1]);
316 case LINUX_PROC_POINT
: {
317 struct procdata data
= { 0, 0, 0, 0, AFSCALL_SETPAG
};
318 return do_ioctl(&data
);
320 case MACOS_DEV_POINT
: {
321 struct devdata data
= { AFSCALL_SETPAG
, 0, 0, 0, 0, 0, 0, 0 };
322 int ret
= do_ioctl(&data
);
328 case AIX_ENTRY_POINTS
:
335 kill(getpid(), SIGSYS
); /* You lose! */
341 static jmp_buf catch_SIGSYS
;
346 SIGSYS_handler(int sig
)
349 signal(SIGSYS
, SIGSYS_handler
); /* Need to reinstall handler on SYSV */
350 longjmp(catch_SIGSYS
, 1);
356 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
359 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
361 try_one (int syscall_num
)
363 struct ViceIoctl parms
;
364 memset(&parms
, 0, sizeof(parms
));
366 if (setjmp(catch_SIGSYS
) == 0) {
367 syscall(syscall_num
, AFSCALL_PIOCTL
,
368 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
369 if (errno
== EINVAL
) {
370 afs_entry_point
= SINGLE_ENTRY_POINT
;
371 afs_syscalls
[0] = syscall_num
;
380 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
387 try_two (int syscall_pioctl
, int syscall_setpag
)
389 struct ViceIoctl parms
;
390 memset(&parms
, 0, sizeof(parms
));
392 if (setjmp(catch_SIGSYS
) == 0) {
393 syscall(syscall_pioctl
,
394 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
395 if (errno
== EINVAL
) {
396 afs_entry_point
= MULTIPLE_ENTRY_POINT
;
397 afs_syscalls
[0] = syscall_pioctl
;
398 afs_syscalls
[1] = syscall_setpag
;
409 #if !defined(NO_AFS) && defined(SIGSYS)
410 RETSIGTYPE (*saved_func
)(int);
412 int saved_errno
, ret
;
416 env
= getenv ("AFS_SYSCALL");
419 * Already checked presence of AFS syscalls?
421 if (afs_entry_point
!= UNKNOWN_ENTRY_POINT
)
422 return afs_entry_point
!= NO_ENTRY_POINT
;
425 * Probe kernel for AFS specific syscalls,
426 * they (currently) come in two flavors.
427 * If the syscall is absent we recive a SIGSYS.
429 afs_entry_point
= NO_ENTRY_POINT
;
434 saved_func
= signal(SIGSYS
, SIGSYS_handler
);
436 if (env
&& strstr(env
, "..") == NULL
) {
438 if (strncmp("/proc/", env
, 6) == 0) {
439 if (try_ioctlpath(env
, VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
) == 0)
442 if (strncmp("/dev/", env
, 5) == 0) {
443 if (try_ioctlpath(env
, VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
) == 0)
445 if (try_ioctlpath(env
,VIOC_SYSCALL_DEV_OPENAFS
,MACOS_DEV_POINT
) ==0)
450 ret
= try_ioctlpath("/proc/fs/openafs/afs_ioctl",
451 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
454 ret
= try_ioctlpath("/proc/fs/nnpfs/afs_ioctl",
455 VIOC_SYSCALL_PROC
, LINUX_PROC_POINT
);
459 ret
= try_ioctlpath("/dev/openafs_ioctl",
460 VIOC_SYSCALL_DEV_OPENAFS
, MACOS_DEV_POINT
);
463 ret
= try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV
, MACOS_DEV_POINT
);
467 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
472 if (sscanf (env
, "%d", &tmp
) == 1) {
473 if (try_one (tmp
) == 0)
478 char *s
= strdup (env
);
481 for (p
= strtok_r (s
, ",", &end
);
483 p
= strtok_r (NULL
, ",", &end
)) {
484 if (map_syscall_name_to_number (p
, &tmp
) == 0)
485 if (try_one (tmp
) == 0) {
495 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
498 if (try_one (AFS_SYSCALL
) == 0)
500 #endif /* AFS_SYSCALL */
506 if (env
!= NULL
&& sscanf (env
, "%d%d", &tmp
[0], &tmp
[1]) == 2)
507 if (try_two (tmp
[0], tmp
[1]) == 2)
510 #endif /* AFS_PIOCTL */
513 if (try_two (AFS_PIOCTL
, AFS_SETPAG
) == 0)
515 #endif /* AFS_PIOCTL */
518 if (try_one (AFS_SYSCALL2
) == 0)
520 #endif /* AFS_SYSCALL2 */
523 if (try_one (AFS_SYSCALL3
) == 0)
525 #endif /* AFS_SYSCALL3 */
534 pioctl_name
= strtok_r (env
, ", \t", &pos
);
535 if (pioctl_name
!= NULL
) {
536 setpag_name
= strtok_r (NULL
, ", \t", &pos
);
537 if (setpag_name
!= NULL
)
538 if (try_aix (pioctl_name
, setpag_name
) == 0)
551 signal(SIGSYS
, saved_func
);
555 return afs_entry_point
!= NO_ENTRY_POINT
;
559 k_hasafs_recheck(void)
561 afs_entry_point
= UNKNOWN_ENTRY_POINT
;