2 * Copyright (c) 1995 - 2000, 2002, 2004 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 _IOW('C', 1, void *)
48 int _kafs_debug
; /* this should be done in a better way */
50 #define NO_ENTRY_POINT 0
51 #define SINGLE_ENTRY_POINT 1
52 #define MULTIPLE_ENTRY_POINT 2
53 #define SINGLE_ENTRY_POINT2 3
54 #define SINGLE_ENTRY_POINT3 4
55 #define LINUX_PROC_POINT 5
56 #define AIX_ENTRY_POINTS 6
57 #define UNKNOWN_ENTRY_POINT 7
58 static int afs_entry_point
= UNKNOWN_ENTRY_POINT
;
59 static int afs_syscalls
[2];
60 static char *afs_procpath
;
62 /* Magic to get AIX syscalls to work */
65 static int (*Pioctl
)(char*, int, struct ViceIoctl
*, int);
66 static int (*Setpag
)(void);
77 #ifdef STATIC_AFS_SYSCALLS
82 char path
[MaxPathLen
], *p
;
84 * If we are root or running setuid don't trust AFSLIBPATH!
86 if (getuid() != 0 && !issuid() && (p
= getenv("AFSLIBPATH")) != NULL
)
87 strlcpy(path
, p
, sizeof(path
));
89 snprintf(path
, sizeof(path
), "%s/afslib.so", LIBDIR
);
91 ptr
= dlopen(path
, RTLD_NOW
);
94 if(errno
== ENOEXEC
&& (p
= dlerror()) != NULL
)
95 fprintf(stderr
, "dlopen(%s): %s\n", path
, p
);
96 else if (errno
!= ENOENT
)
97 fprintf(stderr
, "dlopen(%s): %s\n", path
, strerror(errno
));
101 Setpag
= (int (*)(void))dlsym(ptr
, "aix_setpag");
102 Pioctl
= (int (*)(char*, int,
103 struct ViceIoctl
*, int))dlsym(ptr
, "aix_pioctl");
105 afs_entry_point
= AIX_ENTRY_POINTS
;
111 * This probably only works under Solaris and could get confused if
112 * there's a /etc/name_to_sysnum file.
115 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
118 map_syscall_name_to_number (const char *str
, int *res
)
122 size_t str_len
= strlen (str
);
124 f
= fopen (_PATH_ETC_NAME_TO_SYSNUM
, "r");
127 while (fgets (buf
, sizeof(buf
), f
) != NULL
) {
131 if (strncmp (str
, buf
, str_len
) == 0) {
132 char *begptr
= buf
+ str_len
;
134 long val
= strtol (begptr
, &endptr
, 0);
136 if (val
!= 0 && endptr
!= begptr
) {
148 try_proc(const char *path
)
151 fd
= open(path
, O_RDWR
);
155 afs_procpath
= strdup(path
);
156 if (afs_procpath
== NULL
)
158 afs_entry_point
= LINUX_PROC_POINT
;
163 do_proc(struct procdata
*data
)
165 int fd
, ret
, saved_errno
;
166 fd
= open(afs_procpath
, O_RDWR
);
171 ret
= ioctl(fd
, VIOC_SYSCALL
, data
);
179 k_pioctl(char *a_path
,
181 struct ViceIoctl
*a_paramsP
,
182 int a_followSymlinks
)
185 switch(afs_entry_point
){
186 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
187 case SINGLE_ENTRY_POINT
:
188 case SINGLE_ENTRY_POINT2
:
189 case SINGLE_ENTRY_POINT3
:
190 return syscall(afs_syscalls
[0], AFSCALL_PIOCTL
,
191 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
193 #if defined(AFS_PIOCTL)
194 case MULTIPLE_ENTRY_POINT
:
195 return syscall(afs_syscalls
[0],
196 a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
198 case LINUX_PROC_POINT
: {
199 struct procdata data
= { 0, 0, 0, 0, AFSCALL_PIOCTL
};
200 data
.param1
= (unsigned long)a_path
;
201 data
.param2
= (unsigned long)o_opcode
;
202 data
.param3
= (unsigned long)a_paramsP
;
203 data
.param4
= (unsigned long)a_followSymlinks
;
204 return do_proc(&data
);
207 case AIX_ENTRY_POINTS
:
208 return Pioctl(a_path
, o_opcode
, a_paramsP
, a_followSymlinks
);
213 kill(getpid(), SIGSYS
); /* You lose! */
220 k_afs_cell_of_file(const char *path
, char *cell
, int len
)
222 struct ViceIoctl parms
;
226 parms
.out_size
= len
;
227 return k_pioctl((char*)path
, VIOC_FILE_CELL_NAME
, &parms
, 1);
233 struct ViceIoctl parms
;
234 memset(&parms
, 0, sizeof(parms
));
235 return k_pioctl(0, VIOCUNLOG
, &parms
, 0);
242 switch(afs_entry_point
){
243 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
244 case SINGLE_ENTRY_POINT
:
245 case SINGLE_ENTRY_POINT2
:
246 case SINGLE_ENTRY_POINT3
:
247 return syscall(afs_syscalls
[0], AFSCALL_SETPAG
);
249 #if defined(AFS_PIOCTL)
250 case MULTIPLE_ENTRY_POINT
:
251 return syscall(afs_syscalls
[1]);
253 case LINUX_PROC_POINT
: {
254 struct procdata data
= { 0, 0, 0, 0, AFSCALL_SETPAG
};
255 return do_proc(&data
);
258 case AIX_ENTRY_POINTS
:
265 kill(getpid(), SIGSYS
); /* You lose! */
271 static jmp_buf catch_SIGSYS
;
276 SIGSYS_handler(int sig
)
279 signal(SIGSYS
, SIGSYS_handler
); /* Need to reinstall handler on SYSV */
280 longjmp(catch_SIGSYS
, 1);
286 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
289 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
291 try_one (int syscall_num
)
293 struct ViceIoctl parms
;
294 memset(&parms
, 0, sizeof(parms
));
296 if (setjmp(catch_SIGSYS
) == 0) {
297 syscall(syscall_num
, AFSCALL_PIOCTL
,
298 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
299 if (errno
== EINVAL
) {
300 afs_entry_point
= SINGLE_ENTRY_POINT
;
301 afs_syscalls
[0] = syscall_num
;
310 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
317 try_two (int syscall_pioctl
, int syscall_setpag
)
319 struct ViceIoctl parms
;
320 memset(&parms
, 0, sizeof(parms
));
322 if (setjmp(catch_SIGSYS
) == 0) {
323 syscall(syscall_pioctl
,
324 0, VIOCSETTOK
, &parms
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
325 if (errno
== EINVAL
) {
326 afs_entry_point
= MULTIPLE_ENTRY_POINT
;
327 afs_syscalls
[0] = syscall_pioctl
;
328 afs_syscalls
[1] = syscall_setpag
;
339 #if !defined(NO_AFS) && defined(SIGSYS)
340 RETSIGTYPE (*saved_func
)(int);
343 char *env
= getenv ("AFS_SYSCALL");
346 * Already checked presence of AFS syscalls?
348 if (afs_entry_point
!= UNKNOWN_ENTRY_POINT
)
349 return afs_entry_point
!= NO_ENTRY_POINT
;
352 * Probe kernel for AFS specific syscalls,
353 * they (currently) come in two flavors.
354 * If the syscall is absent we recive a SIGSYS.
356 afs_entry_point
= NO_ENTRY_POINT
;
361 saved_func
= signal(SIGSYS
, SIGSYS_handler
);
364 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
369 if (sscanf (env
, "%d", &tmp
) == 1) {
370 if (try_one (tmp
) == 0)
375 char *s
= strdup (env
);
378 for (p
= strtok_r (s
, ",", &end
);
380 p
= strtok_r (NULL
, ",", &end
)) {
381 if (map_syscall_name_to_number (p
, &tmp
) == 0)
382 if (try_one (tmp
) == 0) {
392 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
395 if (try_one (AFS_SYSCALL
) == 0)
397 #endif /* AFS_SYSCALL */
403 if (env
!= NULL
&& sscanf (env
, "%d%d", &tmp
[0], &tmp
[1]) == 2)
404 if (try_two (tmp
[0], tmp
[1]) == 2)
407 #endif /* AFS_PIOCTL */
410 if (try_two (AFS_PIOCTL
, AFS_SETPAG
) == 0)
412 #endif /* AFS_PIOCTL */
415 if (try_one (AFS_SYSCALL2
) == 0)
417 #endif /* AFS_SYSCALL2 */
420 if (try_one (AFS_SYSCALL3
) == 0)
422 #endif /* AFS_SYSCALL3 */
431 pioctl_name
= strtok_r (env
, ", \t", &pos
);
432 if (pioctl_name
!= NULL
) {
433 setpag_name
= strtok_r (NULL
, ", \t", &pos
);
434 if (setpag_name
!= NULL
)
435 if (try_aix (pioctl_name
, setpag_name
) == 0)
445 if (try_proc("/proc/fs/openafs/afs_ioctl") == 0)
447 if (try_proc("/proc/fs/nnpfs/afs_ioctl") == 0)
449 if (env
&& try_proc(env
) == 0)
454 signal(SIGSYS
, saved_func
);
458 return afs_entry_point
!= NO_ENTRY_POINT
;