afssys.c revision 55682
1/* 2 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 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. 16 * 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. 20 * 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 31 * SUCH DAMAGE. 32 */ 33 34#include "kafs_locl.h" 35 36RCSID("$Id: afssys.c,v 1.65 1999/12/02 16:58:40 joda Exp $"); 37 38int _kafs_debug; /* this should be done in a better way */ 39 40#define NO_ENTRY_POINT 0 41#define SINGLE_ENTRY_POINT 1 42#define MULTIPLE_ENTRY_POINT 2 43#define SINGLE_ENTRY_POINT2 3 44#define SINGLE_ENTRY_POINT3 4 45#define AIX_ENTRY_POINTS 5 46#define UNKNOWN_ENTRY_POINT 6 47static int afs_entry_point = UNKNOWN_ENTRY_POINT; 48static int afs_syscalls[2]; 49 50/* Magic to get AIX syscalls to work */ 51#ifdef _AIX 52 53static int (*Pioctl)(char*, int, struct ViceIoctl*, int); 54static int (*Setpag)(void); 55 56#include "dlfcn.h" 57 58/* 59 * 60 */ 61 62static int 63try_aix(void) 64{ 65#ifdef STATIC_AFS_SYSCALLS 66 Pioctl = aix_pioctl; 67 Setpag = aix_setpag; 68#else 69 void *ptr; 70 char path[MaxPathLen], *p; 71 /* 72 * If we are root or running setuid don't trust AFSLIBPATH! 73 */ 74 if (getuid() != 0 && !issuid() && (p = getenv("AFSLIBPATH")) != NULL) 75 strlcpy(path, p, sizeof(path)); 76 else 77 snprintf(path, sizeof(path), "%s/afslib.so", LIBDIR); 78 79 ptr = dlopen(path, RTLD_NOW); 80 if(ptr == NULL) { 81 if(_kafs_debug) { 82 if(errno == ENOEXEC && (p = dlerror()) != NULL) 83 fprintf(stderr, "dlopen(%s): %s\n", path, p); 84 else if (errno != ENOENT) 85 fprintf(stderr, "dlopen(%s): %s\n", path, strerror(errno)); 86 } 87 return 1; 88 } 89 Setpag = (int (*)(void))dlsym(ptr, "aix_setpag"); 90 Pioctl = (int (*)(char*, int, 91 struct ViceIoctl*, int))dlsym(ptr, "aix_pioctl"); 92#endif 93 afs_entry_point = AIX_ENTRY_POINTS; 94 return 0; 95} 96#endif /* _AIX */ 97 98/* 99 * This probably only works under Solaris and could get confused if 100 * there's a /etc/name_to_sysnum file. 101 */ 102 103#define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum" 104 105static int 106map_syscall_name_to_number (const char *str, int *res) 107{ 108 FILE *f; 109 char buf[256]; 110 size_t str_len = strlen (str); 111 112 f = fopen (_PATH_ETC_NAME_TO_SYSNUM, "r"); 113 if (f == NULL) 114 return -1; 115 while (fgets (buf, sizeof(buf), f) != NULL) { 116 if (strncmp (str, buf, str_len) == 0) { 117 char *begptr = buf + str_len; 118 char *endptr; 119 long val = strtol (begptr, &endptr, 0); 120 121 if (val != 0 && endptr != begptr) { 122 fclose (f); 123 *res = val; 124 return 0; 125 } 126 } 127 } 128 fclose (f); 129 return -1; 130} 131 132int 133k_pioctl(char *a_path, 134 int o_opcode, 135 struct ViceIoctl *a_paramsP, 136 int a_followSymlinks) 137{ 138#ifndef NO_AFS 139 switch(afs_entry_point){ 140#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 141 case SINGLE_ENTRY_POINT: 142 case SINGLE_ENTRY_POINT2: 143 case SINGLE_ENTRY_POINT3: 144 return syscall(afs_syscalls[0], AFSCALL_PIOCTL, 145 a_path, o_opcode, a_paramsP, a_followSymlinks); 146#endif 147#if defined(AFS_PIOCTL) 148 case MULTIPLE_ENTRY_POINT: 149 return syscall(afs_syscalls[0], 150 a_path, o_opcode, a_paramsP, a_followSymlinks); 151#endif 152#ifdef _AIX 153 case AIX_ENTRY_POINTS: 154 return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks); 155#endif 156 } 157 158 errno = ENOSYS; 159#ifdef SIGSYS 160 kill(getpid(), SIGSYS); /* You loose! */ 161#endif 162#endif /* NO_AFS */ 163 return -1; 164} 165 166int 167k_afs_cell_of_file(const char *path, char *cell, int len) 168{ 169 struct ViceIoctl parms; 170 parms.in = NULL; 171 parms.in_size = 0; 172 parms.out = cell; 173 parms.out_size = len; 174 return k_pioctl((char*)path, VIOC_FILE_CELL_NAME, &parms, 1); 175} 176 177int 178k_unlog(void) 179{ 180 struct ViceIoctl parms; 181 memset(&parms, 0, sizeof(parms)); 182 return k_pioctl(0, VIOCUNLOG, &parms, 0); 183} 184 185int 186k_setpag(void) 187{ 188#ifndef NO_AFS 189 switch(afs_entry_point){ 190#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 191 case SINGLE_ENTRY_POINT: 192 case SINGLE_ENTRY_POINT2: 193 case SINGLE_ENTRY_POINT3: 194 return syscall(afs_syscalls[0], AFSCALL_SETPAG); 195#endif 196#if defined(AFS_PIOCTL) 197 case MULTIPLE_ENTRY_POINT: 198 return syscall(afs_syscalls[1]); 199#endif 200#ifdef _AIX 201 case AIX_ENTRY_POINTS: 202 return Setpag(); 203#endif 204 } 205 206 errno = ENOSYS; 207#ifdef SIGSYS 208 kill(getpid(), SIGSYS); /* You loose! */ 209#endif 210#endif /* NO_AFS */ 211 return -1; 212} 213 214static jmp_buf catch_SIGSYS; 215 216#ifdef SIGSYS 217 218static RETSIGTYPE 219SIGSYS_handler(int sig) 220{ 221 errno = 0; 222 signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */ 223 longjmp(catch_SIGSYS, 1); 224} 225 226#endif 227 228/* 229 * Try to see if `syscall' is a pioctl. Return 0 iff succesful. 230 */ 231 232#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 233static int 234try_one (int syscall_num) 235{ 236 struct ViceIoctl parms; 237 memset(&parms, 0, sizeof(parms)); 238 239 if (setjmp(catch_SIGSYS) == 0) { 240 syscall(syscall_num, AFSCALL_PIOCTL, 241 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 242 if (errno == EINVAL) { 243 afs_entry_point = SINGLE_ENTRY_POINT; 244 afs_syscalls[0] = syscall_num; 245 return 0; 246 } 247 } 248 return 1; 249} 250#endif 251 252/* 253 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff 254 * succesful. 255 * 256 */ 257 258#ifdef AFS_PIOCTL 259static int 260try_two (int syscall_pioctl, int syscall_setpag) 261{ 262 struct ViceIoctl parms; 263 memset(&parms, 0, sizeof(parms)); 264 265 if (setjmp(catch_SIGSYS) == 0) { 266 syscall(syscall_pioctl, 267 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 268 if (errno == EINVAL) { 269 afs_entry_point = MULTIPLE_ENTRY_POINT; 270 afs_syscalls[0] = syscall_pioctl; 271 afs_syscalls[1] = syscall_setpag; 272 return 0; 273 } 274 } 275 return 1; 276} 277#endif 278 279int 280k_hasafs(void) 281{ 282#if !defined(NO_AFS) && defined(SIGSYS) 283 RETSIGTYPE (*saved_func)(); 284#endif 285 int saved_errno; 286 char *env = getenv ("AFS_SYSCALL"); 287 288 /* 289 * Already checked presence of AFS syscalls? 290 */ 291 if (afs_entry_point != UNKNOWN_ENTRY_POINT) 292 return afs_entry_point != NO_ENTRY_POINT; 293 294 /* 295 * Probe kernel for AFS specific syscalls, 296 * they (currently) come in two flavors. 297 * If the syscall is absent we recive a SIGSYS. 298 */ 299 afs_entry_point = NO_ENTRY_POINT; 300 301 saved_errno = errno; 302#ifndef NO_AFS 303#ifdef SIGSYS 304 saved_func = signal(SIGSYS, SIGSYS_handler); 305#endif 306 307#if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 308 { 309 int tmp; 310 311 if (env != NULL) { 312 if (sscanf (env, "%d", &tmp) == 1) { 313 if (try_one (tmp) == 0) 314 goto done; 315 } else { 316 char *end = NULL; 317 char *p; 318 char *s = strdup (env); 319 320 if (s != NULL) { 321 for (p = strtok_r (s, ",", &end); 322 p != NULL; 323 p = strtok_r (NULL, ",", &end)) { 324 if (map_syscall_name_to_number (p, &tmp) == 0) 325 if (try_one (tmp) == 0) { 326 free (s); 327 goto done; 328 } 329 } 330 free (s); 331 } 332 } 333 } 334 } 335#endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */ 336 337#ifdef AFS_SYSCALL 338 if (try_one (AFS_SYSCALL) == 0) 339 goto done; 340#endif /* AFS_SYSCALL */ 341 342#ifdef AFS_PIOCTL 343 { 344 int tmp[2]; 345 346 if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2) 347 if (try_two (tmp[0], tmp[1]) == 2) 348 goto done; 349 } 350#endif /* AFS_PIOCTL */ 351 352#ifdef AFS_PIOCTL 353 if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0) 354 goto done; 355#endif /* AFS_PIOCTL */ 356 357#ifdef AFS_SYSCALL2 358 if (try_one (AFS_SYSCALL2) == 0) 359 goto done; 360#endif /* AFS_SYSCALL2 */ 361 362#ifdef AFS_SYSCALL3 363 if (try_one (AFS_SYSCALL3) == 0) 364 goto done; 365#endif /* AFS_SYSCALL3 */ 366 367#ifdef _AIX 368#if 0 369 if (env != NULL) { 370 char *pos = NULL; 371 char *pioctl_name; 372 char *setpag_name; 373 374 pioctl_name = strtok_r (env, ", \t", &pos); 375 if (pioctl_name != NULL) { 376 setpag_name = strtok_r (NULL, ", \t", &pos); 377 if (setpag_name != NULL) 378 if (try_aix (pioctl_name, setpag_name) == 0) 379 goto done; 380 } 381 } 382#endif 383 384 if(try_aix() == 0) 385 goto done; 386#endif 387 388done: 389#ifdef SIGSYS 390 signal(SIGSYS, saved_func); 391#endif 392#endif /* NO_AFS */ 393 errno = saved_errno; 394 return afs_entry_point != NO_ENTRY_POINT; 395} 396