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