1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * l_misc.c : 28 * This file contains the miscelleneous routines for libsm.so 29 */ 30 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <sys/utsname.h> 34 #include <fcntl.h> 35 #include <sys/dkio.h> 36 #include <sys/vtoc.h> 37 #include <sys/dktp/fdisk.h> 38 #include <dirent.h> 39 #include <dlfcn.h> 40 #include <stdlib.h> 41 #include <sys/stat.h> 42 #include <strings.h> 43 #include "l_defines.h" 44 #include <rpc/rpc.h> 45 #include "smed.h" 46 #include <sys/smedia.h> 47 #include "../inc/rmedia.h" 48 #include <smserver.h> 49 #include <sys/mman.h> 50 #include <utmpx.h> 51 #include <limits.h> 52 53 #ifdef _LP64 54 #ifdef __sparc 55 #define PATHNAME "/usr/lib/smedia/sparcv9" 56 #else 57 #define PATHNAME "/usr/lib/smedia/amd64" 58 #endif 59 #else 60 #define PATHNAME "/usr/lib/smedia" 61 #endif 62 63 #define PERROR(string) my_perror(gettext(string)) 64 #define RUN_LIBSMEDIA_SERVER " /usr/lib/smedia/rpc.smserverd &\n" 65 66 static void 67 my_perror(char *err_string) 68 { 69 70 int error_no; 71 if (errno == 0) 72 return; 73 74 error_no = errno; 75 (void) fprintf(stderr, gettext(err_string)); 76 (void) fprintf(stderr, gettext(" : ")); 77 errno = error_no; 78 perror(""); 79 } 80 81 static int 82 is_server_running(rmedia_handle_t *handle) 83 { 84 door_arg_t door_args; 85 smedia_reqping_t reqping; 86 smedia_retping_t *retping; 87 int ret_val; 88 int door_fd; 89 CLIENT *clnt; 90 char rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)]; 91 smserver_info *server_info; 92 93 /* 94 * We will assume that we are running at level 2 or greater 95 * and attempt to contact the server using RPC mecahnisms. 96 * If that fails then we will attempt to contact the server 97 * using non-rpc mechanism. This will enable the libsmedia 98 * to be used in SINGLE user mode when inetd is not running. 99 * We expect the server to have been started manually by user. 100 * 101 * Note that "localhost" is used (vs hostname (eg, "uname -n")), 102 * as this minimizes interference with common IPSec rules. 103 */ 104 105 clnt = clnt_create("localhost", SMSERVERPROG, SMSERVERVERS, 106 "circuit_v"); 107 if (clnt == (CLIENT *)NULL) { 108 /* 109 * The failure could be that we are running at level 1 110 */ 111 door_fd = open(smedia_service, O_RDONLY, 0644); 112 if (door_fd < 0) { 113 DPRINTF1("Error in opening %s\n", 114 smedia_service); 115 return (0); 116 } 117 118 DPRINTF1("rbuf address=%p\n", rbuf); 119 reqping.cnum = SMEDIA_CNUM_PING; 120 door_args.data_ptr = (char *)&reqping; 121 door_args.data_size = sizeof (smedia_services_t); 122 door_args.desc_ptr = NULL; 123 door_args.desc_num = 0; 124 door_args.rbuf = rbuf; 125 door_args.rsize = sizeof (rbuf); 126 127 ret_val = door_call(door_fd, &door_args); 128 (void) close(door_fd); 129 if (ret_val < 0) { 130 return (0); 131 } 132 DPRINTF3("rsize = %d data_size = %d data_ptr = %p \n", 133 door_args.rsize, door_args.data_size, 134 door_args.data_ptr); 135 retping = (smedia_retping_t *)( 136 (void *)door_args.data_ptr); 137 if (retping->cnum != SMEDIA_CNUM_PING) { 138 DPRINTF1("*** door call failed *** cnum " 139 "returned = 0x%x\n", retping->cnum); 140 return (0); 141 } 142 return (1); 143 } 144 server_info = smserverproc_get_serverinfo_1(NULL, clnt); 145 if (server_info == NULL) { 146 if (clnt) 147 clnt_destroy(clnt); 148 return (0); 149 } 150 if (server_info->status != 0) { 151 if (clnt) 152 clnt_destroy(clnt); 153 DPRINTF1("get server_info call failed. " 154 "status = %d\n", server_info->status); 155 return (0); 156 } 157 if (server_info->vernum != SMSERVERVERS) { 158 if (clnt) 159 clnt_destroy(clnt); 160 DPRINTF2("version expected = %d version " 161 "returned = %d\n", SMSERVERVERS, 162 server_info->vernum); 163 return (0); 164 } 165 166 door_fd = open(smedia_service, O_RDONLY, 0644); 167 if (door_fd < 0) { 168 DPRINTF1("Error in opening %s\n", smedia_service); 169 return (0); 170 } 171 172 DPRINTF1("rbuf address=%p\n", rbuf); 173 reqping.cnum = SMEDIA_CNUM_PING; 174 door_args.data_ptr = (char *)&reqping; 175 door_args.data_size = sizeof (smedia_services_t); 176 door_args.desc_ptr = NULL; 177 door_args.desc_num = 0; 178 door_args.rbuf = rbuf; 179 door_args.rsize = sizeof (rbuf); 180 181 ret_val = door_call(door_fd, &door_args); 182 (void) close(door_fd); 183 if (ret_val < 0) { 184 return (0); 185 } 186 DPRINTF3("rsize = %d data_size = %d data_ptr = %p \n", 187 door_args.rsize, door_args.data_size, 188 door_args.data_ptr); 189 retping = (smedia_retping_t *)((void *)door_args.data_ptr); 190 if (retping->cnum != SMEDIA_CNUM_PING) { 191 DPRINTF1("*** door call failed *** cnum returned " 192 "= 0x%x\n", retping->cnum); 193 return (0); 194 } 195 handle->sm_clnt = clnt; 196 return (1); 197 } 198 199 static void * 200 get_dev_library_handle(int32_t fd) 201 { 202 void *handle; 203 void *old_handle = NULL; 204 struct dk_cinfo dkinfo; 205 DIR *dirp; 206 struct dirent *dp; 207 char *pathname; 208 int32_t (*d_fcn_ptr)(ushort_t, ushort_t); 209 int32_t (*v_fcn_ptr)(void); 210 int32_t ret_val; 211 212 if (ioctl(fd, DKIOCINFO, &dkinfo) == -1) { 213 PERROR("DKIOCINFO failed"); 214 return (NULL); 215 } 216 DPRINTF1("dki_ctype = 0x%x\n", dkinfo.dki_ctype); 217 218 if ((pathname = malloc(PATH_MAX)) == NULL) { 219 PERROR("malloc failed"); 220 return (NULL); 221 } 222 223 dirp = opendir(PATHNAME); 224 if (dirp == NULL) { 225 (void) fprintf(stderr, gettext("Couldnot open %s\n"), PATHNAME); 226 free(pathname); 227 return (NULL); 228 } 229 230 while ((dp = readdir(dirp)) != NULL) { 231 if (strncmp("sm_", dp->d_name, 3) != 0) { 232 DPRINTF1("not a library %s\n", dp->d_name); 233 continue; 234 } 235 if (snprintf(pathname, PATH_MAX, "%s/%s", 236 PATHNAME, dp->d_name) >= PATH_MAX) { 237 continue; 238 } 239 240 handle = dlopen(pathname, RTLD_LAZY); 241 if (handle == NULL) { 242 PERROR("Error opening library file"); 243 continue; 244 } 245 d_fcn_ptr = (int32_t (*)(ushort_t, ushort_t))dlsym(handle, 246 "_m_device_type"); 247 if (d_fcn_ptr == NULL) { 248 DPRINTF("Could not find _m_device_type\n"); 249 (void) dlclose(handle); 250 continue; 251 } 252 ret_val = (*d_fcn_ptr)(dkinfo.dki_ctype, 0); 253 if (ret_val == 0) { 254 DPRINTF1("NAME %s\n", dp->d_name); 255 v_fcn_ptr = (int32_t (*)(void))dlsym(handle, 256 "_m_version_no"); 257 if (v_fcn_ptr == NULL) { 258 DPRINTF("Could not find _m_version_no\n"); 259 (void) dlclose(handle); 260 continue; 261 } 262 ret_val = (*v_fcn_ptr)(); 263 if ((ret_val >= 0) && 264 (ret_val >= SM_PLUGIN_VERSION)) { 265 if (old_handle != NULL) 266 (void) dlclose(old_handle); 267 old_handle = handle; 268 continue; 269 } else { 270 (void) dlclose(handle); 271 } 272 } else { 273 (void) dlclose(handle); 274 } 275 } 276 free(pathname); 277 (void) closedir(dirp); 278 return (old_handle); 279 } 280 281 int32_t 282 call_function(rmedia_handle_t *handle, void *ip, char *func_name) 283 { 284 285 int32_t ret_val; 286 int32_t (*fcn_ptr)(rmedia_handle_t *handle, void *ip); 287 void *lib_handle; 288 289 if (handle == NULL) { 290 DPRINTF("Handle is NULL\n"); 291 errno = EINVAL; 292 return (-1); 293 } 294 lib_handle = handle->sm_lib_handle; 295 if (handle->sm_signature != LIBSMEDIA_SIGNATURE) { 296 DPRINTF2("call_function:signature expected=0x%x, found=0x%x\n", 297 LIBSMEDIA_SIGNATURE, handle->sm_signature); 298 errno = EINVAL; 299 return (-1); 300 } 301 302 fcn_ptr = (int32_t (*)(rmedia_handle_t *, void*)) 303 dlsym(lib_handle, func_name); 304 if (fcn_ptr == NULL) { 305 DPRINTF1("Could not find %s\n", func_name); 306 errno = ENOTSUP; 307 return (-1); 308 } 309 ret_val = (*fcn_ptr)(handle, ip); 310 return (ret_val); 311 } 312 313 int32_t 314 release_handle(rmedia_handle_t *handle) 315 { 316 if (handle == NULL) { 317 DPRINTF("Handle is NULL\n"); 318 errno = EINVAL; 319 return (-1); 320 } 321 if ((handle->sm_dkinfo.dki_ctype == DKC_SCSI_CCS) || 322 (handle->sm_dkinfo.dki_ctype == DKC_MD21) || 323 (handle->sm_dkinfo.dki_ctype == DKC_CDROM)) { 324 (void) close(handle->sm_door); 325 (void) close(handle->sm_death_door); 326 if (handle->sm_buf != NULL) 327 (void) munmap(handle->sm_buf, handle->sm_bufsize); 328 if (handle->sm_clnt != NULL) 329 clnt_destroy(handle->sm_clnt); 330 } 331 (void) close(handle->sm_buffd); 332 handle->sm_signature = 0; 333 (void) dlclose(handle->sm_lib_handle); 334 free(handle); 335 return (0); 336 } 337 338 smedia_handle_t 339 get_handle_from_fd(int32_t fd) 340 { 341 rmedia_handle_t *handle; 342 void *lib_handle; 343 int door_fd, door_server; 344 int ret_val; 345 door_arg_t door_args; 346 smedia_reqopen_t reqopen; 347 smedia_reterror_t *reterror; 348 door_desc_t ddesc[2]; 349 char rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)]; 350 struct stat stat; 351 352 DPRINTF("smedia_get_handle called\n"); 353 handle = (rmedia_handle_t *)malloc(sizeof (rmedia_handle_t)); 354 if (handle == NULL) { 355 DPRINTF("Could not allocate memory for handle\n"); 356 return (NULL); 357 } 358 (void) memset((void *) handle, 0, sizeof (rmedia_handle_t)); 359 handle->sm_fd = -1; 360 handle->sm_door = -1; 361 handle->sm_death_door = -1; 362 handle->sm_buffd = -1; 363 handle->sm_buf = NULL; 364 handle->sm_bufsize = 0; 365 366 if (ioctl(fd, DKIOCINFO, &handle->sm_dkinfo) == -1) { 367 free(handle); 368 PERROR("DKIOCINFO failed"); 369 return (NULL); 370 } 371 lib_handle = get_dev_library_handle(fd); 372 if (lib_handle == NULL) { 373 free(handle); 374 DPRINTF("lib_Handle is NULL\n"); 375 errno = ENOTSUP; 376 return (NULL); 377 } 378 DPRINTF("Handle initialised successfully.\n"); 379 /* Initialise the handle elements */ 380 handle->sm_lib_handle = lib_handle; 381 handle->sm_signature = LIBSMEDIA_SIGNATURE; 382 DPRINTF2("fd=%d signature=0x%x\n", handle->sm_fd, handle->sm_signature); 383 384 if ((handle->sm_dkinfo.dki_ctype == DKC_SCSI_CCS) || 385 (handle->sm_dkinfo.dki_ctype == DKC_MD21) || 386 (handle->sm_dkinfo.dki_ctype == DKC_CDROM)) { 387 388 ret_val = is_server_running(handle); 389 if (ret_val == 0) { 390 (void) dlclose(handle->sm_lib_handle); 391 free(handle); 392 return (NULL); 393 } 394 door_fd = open(smedia_service, O_RDONLY, 0644); 395 if (door_fd < 0) { 396 (void) dlclose(handle->sm_lib_handle); 397 free(handle); 398 if (handle->sm_clnt) 399 clnt_destroy(handle->sm_clnt); 400 DPRINTF1("Error in opening %s\n", smedia_service); 401 PERROR(smedia_service); 402 return (NULL); 403 } 404 405 DPRINTF1("rbuf address=%p\n", rbuf); 406 ddesc[0].d_data.d_desc.d_descriptor = fd; 407 ddesc[0].d_attributes = DOOR_DESCRIPTOR; 408 reqopen.cnum = SMEDIA_CNUM_OPEN_FD; 409 door_args.data_ptr = (char *)&reqopen; 410 door_args.data_size = sizeof (smedia_services_t); 411 door_args.desc_ptr = &ddesc[0]; 412 door_args.desc_num = 1; 413 door_args.rbuf = rbuf; 414 door_args.rsize = sizeof (rbuf); 415 416 ret_val = door_call(door_fd, &door_args); 417 (void) close(door_fd); 418 if (ret_val < 0) { 419 (void) dlclose(handle->sm_lib_handle); 420 free(handle); 421 if (handle->sm_clnt) 422 clnt_destroy(handle->sm_clnt); 423 PERROR("door_call"); 424 return (NULL); 425 } 426 DPRINTF3("rsize = %d data_size = %d data_ptr = %p \n", 427 door_args.rsize, door_args.data_size, 428 door_args.data_ptr); 429 reterror = (smedia_reterror_t *)((void *)door_args.data_ptr); 430 if (reterror->cnum != SMEDIA_CNUM_OPEN_FD) { 431 (void) dlclose(handle->sm_lib_handle); 432 free(handle); 433 if (handle->sm_clnt) 434 clnt_destroy(handle->sm_clnt); 435 DPRINTF1( 436 "*** door call failed *** cnum returned = 0x%x\n", reterror->cnum); 437 errno = reterror->errnum; 438 return (NULL); 439 } 440 /* 441 * 2 door descriptors are returned after the above door call. 442 * The first door descriptor is the one that will be used 443 * in subsequent smedia calls. A dedicated thread is 444 * associated with this door to handle client calls. 445 * The second door descriptor is needed to signal unexpected 446 * death of the client to the server. This will help the server 447 * to do the necessary cleanup. 448 */ 449 if (door_args.desc_num != 2) { 450 (void) dlclose(handle->sm_lib_handle); 451 free(handle); 452 if (handle->sm_clnt) 453 clnt_destroy(handle->sm_clnt); 454 DPRINTF("Num of door descriptors returned by " 455 "server is not 2"); 456 if (door_args.desc_num) 457 (void) close(door_args.desc_ptr->\ 458 d_data.d_desc.d_descriptor); 459 return (NULL); 460 } 461 door_server = door_args.desc_ptr->d_data.d_desc.d_descriptor; 462 /* Check if the descriptor returned is S_IFDOOR */ 463 if (fstat(door_server, &stat) < 0) { 464 PERROR("fstat"); 465 (void) dlclose(handle->sm_lib_handle); 466 free(handle); 467 if (handle->sm_clnt) 468 clnt_destroy(handle->sm_clnt); 469 return (NULL); 470 } 471 if (!S_ISDOOR(stat.st_mode)) { 472 DPRINTF( 473 "Descriptor returned by door_call is not of type DOOR\n"); 474 (void) dlclose(handle->sm_lib_handle); 475 free(handle); 476 if (handle->sm_clnt) 477 clnt_destroy(handle->sm_clnt); 478 return (NULL); 479 } 480 handle->sm_door = door_server; 481 handle->sm_fd = fd; 482 door_args.desc_ptr++; 483 handle->sm_death_door = 484 door_args.desc_ptr->d_data.d_desc.d_descriptor; 485 DPRINTF("door call succeeded.\n"); 486 return ((smedia_handle_t)handle); 487 488 } else { 489 handle->sm_fd = fd; 490 return ((smedia_handle_t)handle); 491 } 492 493 } 494