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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <pwd.h> 29 #include <stdarg.h> 30 #include <ctype.h> 31 #include <strings.h> 32 #include <unistd.h> 33 #include <fcntl.h> 34 #include <unistd.h> 35 #include <sys/types.h> 36 #include <sys/mkdev.h> 37 #include <sys/stat.h> 38 #include <libgen.h> 39 #include <time.h> 40 #include <sys/varargs.h> 41 #include <pthread.h> 42 #include <sys/mkdev.h> 43 #include <sys/varargs.h> 44 #include <errno.h> 45 #include <sys/siginfo.h> 46 #include <sys/scsi/impl/uscsi.h> 47 #include <dlfcn.h> 48 #include <mms_network.h> 49 #include <mms_trace.h> 50 #include <mms_sym.h> 51 #include <dm_impl.h> 52 #include <mms_dmd.h> 53 #include <dm_msg.h> 54 #include <dm_proto.h> 55 #include <mms_strapp.h> 56 #include <mms_cat.h> 57 58 static char *_SrcFile = __FILE__; 59 60 /* 61 * Function name 62 * dm_bld_task(char *cmd) 63 * 64 * Parameters: 65 * cmd command name pointer 66 * 67 * Description: 68 * create a task id for use with a DMP command 69 * 70 * Return code: 71 * pointer to the task id. Caller must free after its use 72 * 73 * Note: 74 * 75 * 76 */ 77 78 char * 79 dm_bld_task(char *cmd) 80 { 81 char *task; 82 83 task = mms_strnew("%s:%s:%s:%s:%ld-%d", wka->dm_local_hostname, 84 DMNAME, DRVNAME, cmd, (long)wka->dm_pid, wka->dm_counter++); 85 return (task); 86 } 87 88 /* 89 * Function name 90 * dm_parse_err(mms_par_node_t *root, mms_list_t *err_list) 91 * 92 * Parameters: 93 * root root of parse tree 94 * err_list list of errors 95 * 96 * Description: 97 * trace parser error 98 * put the first error in the parse tree in the response 99 * 100 * Return code: 101 * none 102 * 103 * Note: 104 * 105 * 106 */ 107 108 void 109 dm_parse_err(mms_par_node_t *root, mms_list_t *err_list) 110 { 111 mms_par_node_t *node; 112 mms_par_err_t *err; 113 114 if (root == NULL) { 115 node = NULL; 116 } else { 117 node = mms_pn_lookup(root, NULL, MMS_PN_CMD, NULL); 118 } 119 mms_list_foreach(err_list, err) { 120 TRACE((MMS_ERR, "Parse error: %s command, line %d, col %d, " 121 "near token %s, err code %d, %s", 122 node == NULL ? "Unknown" : mms_pn_token(node), 123 err->pe_line, 124 err->pe_col, 125 err->pe_token, 126 err->pe_code, err->pe_msg)); 127 } 128 129 /* 130 * Return the first error message 131 */ 132 err = (mms_par_err_t *)mms_list_head(err_list); 133 DM_MSG_ADD((MMS_INVALID, MMS_E_SYNTAX_ERR, 134 "command %s, " 135 "line %d, " 136 "col %d, " 137 "token %s, " 138 "code %d, " 139 "%s", 140 node == NULL ? "unknown" : mms_pn_token(node), 141 err->pe_line, 142 err->pe_col, 143 err->pe_token, err->pe_code, err->pe_msg)); 144 145 dm_resp_unacceptable(DM_6500_MSG, DM_MSG_REASON); 146 } 147 148 149 /* 150 * Function name 151 * dm_reader(char **cmdbuf) 152 * 153 * Parameters: 154 * cmdbuf pointer to the buffer address 155 * 156 * Description: 157 * read a message from the socket connection to MM 158 * 159 * Return code: 160 * > 0 number of bytes of message 161 * 0 EOF 162 * -1 error 163 * 164 * Note: 165 * 166 * 167 */ 168 169 int 170 dm_reader(char **cmdbuf) 171 { 172 int rc; 173 int err; 174 175 pthread_mutex_lock(&wka->dm_io_mutex); 176 rc = mms_reader(&wka->dm_mms_conn, cmdbuf); 177 err = errno; 178 pthread_mutex_unlock(&wka->dm_io_mutex); 179 if (rc == 0) { 180 TRACE((MMS_INFO, "Socket EOF")); 181 } else if (rc > 0) { 182 TRACE((MMS_INFO, "input read: %s", *cmdbuf)); 183 } else { 184 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_IO, 185 "Read error: %s", strerror(err))); 186 } 187 return (rc); 188 } 189 190 /* 191 * Function name 192 * dm_writer_accept(char *cmdbuf) 193 * 194 * Parameters: 195 * cmdbuf command buffer 196 * 197 * Description: 198 * send accepted and unacceptable command 199 * 200 * Return code: 201 * 0 success 202 * -1 Error 203 * -2 incomplete write, write interrupted 204 * 205 * Note: 206 * 207 * 208 */ 209 210 int 211 dm_writer_accept(char *cmdbuf) 212 { 213 return (dm_writer_aux(cmdbuf, DM_WRITE_ACCEPT)); 214 } 215 216 /* 217 * Function name 218 * dm_writer(char *cmdbuf) 219 * 220 * Parameters: 221 * cmdbuf command buffer 222 * 223 * Description: 224 * send a command 225 * 226 * Return code: 227 * 0 success 228 * -1 Error 229 * -2 incomplete write, write interrupted 230 * 231 * Note: 232 * 233 * 234 */ 235 236 int 237 dm_writer(char *cmdbuf) 238 { 239 return (dm_writer_aux(cmdbuf, ~DM_WRITE_ACCEPT)); 240 } 241 242 /* 243 * Function name 244 * dm_writer_aux(char *cmdbuf) 245 * 246 * Parameters: 247 * cmdbuf command buffer 248 * 249 * Description: 250 * send a command 251 * wait until no outstanding accept before sending a command 252 * 253 * Return code: 254 * 0 success 255 * -1 Error 256 * -2 incomplete write, write interrupted 257 * 258 * Note: 259 * 260 * 261 */ 262 263 int 264 dm_writer_aux(char *cmdbuf, int accept) 265 { 266 int rc; 267 268 TRACE((MMS_INFO, "Sending cmd: %s", cmdbuf)); 269 270 if (accept == DM_WRITE_ACCEPT) { 271 /* write accept, just write it */ 272 pthread_mutex_lock(&wka->dm_io_mutex); 273 } else { 274 /* Wait for all accept is done */ 275 mms_trace_flush(); /* flush mms_trace buffer */ 276 pthread_mutex_lock(&wka->dm_queue_mutex); 277 while (!mms_list_empty(&wka->dm_pend_ack_queue)) { 278 pthread_cond_wait(&wka->dm_accept_cv, 279 &wka->dm_queue_mutex); 280 } 281 /* accept is sent */ 282 pthread_mutex_unlock(&wka->dm_queue_mutex); 283 pthread_mutex_lock(&wka->dm_io_mutex); 284 } 285 286 rc = mms_writer(&wka->dm_mms_conn, cmdbuf); 287 pthread_mutex_unlock(&wka->dm_io_mutex); 288 if (rc > 0) { 289 if (rc == strlen(cmdbuf)) { 290 /* success */ 291 rc = 0; 292 } else { 293 /* partial write */ 294 rc = -2; 295 } 296 } else { 297 /* error */ 298 rc = -1; 299 } 300 return (rc); 301 } 302 303 304 /* 305 * Function name 306 * dm_get_task(mms_par_node_t *root) 307 * 308 * Parameters: 309 * root root of parse tree 310 * 311 * Description: 312 * return the task id of a command from the parse tree 313 * 314 * Return code: 315 * task id string 316 * 317 * Note: 318 * 319 * 320 */ 321 322 char * 323 dm_get_task(mms_par_node_t *root) 324 { 325 mms_par_node_t *node; 326 mms_par_node_t *tasknode; 327 char *task; 328 329 if (root == NULL) { 330 return (NULL); /* no tree to lookup */ 331 } 332 333 node = mms_pn_lookup(root, "task", MMS_PN_CLAUSE, NULL); 334 if (node == NULL) { 335 DM_MSG_ADD((MMS_INVALID, MMS_DM_E_INTERNAL, 336 "No task clause")); 337 return (NULL); 338 } 339 tasknode = mms_pn_lookup(node, NULL, MMS_PN_STRING, NULL); 340 if (tasknode == NULL) { 341 DM_MSG_ADD((MMS_INVALID, MMS_DM_E_INTERNAL, "No task id")); 342 return (NULL); 343 } 344 task = strdup(mms_pn_token(tasknode)); 345 return (task); 346 } 347 348 /* 349 * Function name 350 * dm_get_hostpath 351 * 352 * Parameters: 353 * none 354 * 355 * Description: 356 * Get the host specific library path if it is set. 357 * 358 * Return code: 359 * 0 - good 360 * -1 - error 361 * 362 * Note: 363 * 364 * 365 */ 366 367 int 368 dm_get_hostpath(void) 369 { 370 char *show_cmd; 371 char *val; 372 char *task; 373 dm_command_t *cmd; 374 mms_par_node_t *root; 375 376 if (drv->drv_disk_libpath) { 377 free(drv->drv_disk_libpath); 378 drv->drv_disk_libpath = NULL; 379 } 380 381 task = dm_bld_task("show-hostpath"); 382 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 383 "match[ and( streq(DM.'DMName' '%s') " 384 "streq(LIBRARYACCESS.'HostName' '%s')) ] " 385 "report[ LIBRARYACCESS.'LibraryPath' ] " 386 ";", 387 task, drv->drv_dmname, wka->dm_local_hostname); 388 389 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 390 free(task); 391 free(show_cmd); 392 if (cmd == NULL || cmd->cmd_rc != 0) { 393 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 394 "send show hostpath error")); 395 goto error; 396 } 397 398 root = cmd->cmd_root; 399 val = dm_get_attr_value(root, "LIBRARYACCESS", "LibraryPath"); 400 if (val != NULL) { 401 drv->drv_disk_libpath = strdup(val); 402 } 403 404 dm_destroy_cmd(cmd); 405 return (0); 406 407 error: 408 if (cmd != NULL) { 409 dm_destroy_cmd(cmd); 410 } 411 return (-1); 412 } 413 414 /* 415 * Function name 416 * dm_get_default_lib_path 417 * 418 * Parameters: 419 * none 420 * 421 * Description: 422 * Get the default library path from the LIBRARY object the 423 * DM belongs to. 424 * 425 * Return code: 426 * 0 - OK 427 * -1 - error 428 * 429 * Note: 430 * 431 * 432 */ 433 434 int 435 dm_get_default_lib_path(void) 436 { 437 char *show_cmd; 438 char *val; 439 char *task; 440 dm_command_t *cmd; 441 mms_par_node_t *root; 442 int err; 443 444 if (drv->drv_disk_libpath) { 445 free(drv->drv_disk_libpath); 446 drv->drv_disk_libpath = NULL; 447 } 448 449 task = dm_bld_task("show-default_lib_path"); 450 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 451 "match[ streq(DM.'DMName' '%s') ] " 452 "report[ LIBRARY.'DefaultLibraryPath' ] " 453 ";", 454 task, drv->drv_dmname); 455 456 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 457 free(task); 458 free(show_cmd); 459 if (cmd == NULL || cmd->cmd_rc != 0) { 460 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 461 "send show default lib path error")); 462 goto error; 463 } 464 465 root = cmd->cmd_root; 466 val = dm_get_attr_value(root, "LIBRARY", "DefaultLibraryPath"); 467 if (val == NULL || val[0] == '\0') { 468 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 469 "no library path specified")); 470 goto error; 471 } 472 if (mkdirp(val, 0755) == 0) { 473 TRACE((MMS_DEBUG, "Created DISK lib %s", val)); 474 } else if (errno != EEXIST) { 475 err = errno; 476 /* Unable to create it */ 477 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 478 "unable to access library path %s: %s", 479 val, strerror(err))); 480 goto error; 481 } 482 drv->drv_disk_libpath = strdup(val); /* save lib path */ 483 484 dm_destroy_cmd(cmd); 485 return (0); 486 487 error: 488 if (cmd != NULL) { 489 dm_destroy_cmd(cmd); 490 } 491 return (-1); 492 } 493 494 /* 495 * Function name 496 * dm_get_cmd_by_task(char *task) 497 * 498 * Parameters: 499 * task task id 500 * 501 * Description: 502 * return the dm_command_t that has the task id 503 * 504 * Return code: 505 * dm_command_t pointer 506 * NULL can't find a command with matching task id 507 * 508 * Note: 509 * 510 * 511 */ 512 513 dm_command_t * 514 dm_get_cmd_by_task(char *task) 515 { 516 dm_command_t *cmd; 517 518 pthread_mutex_lock(&wka->dm_queue_mutex); 519 mms_list_foreach(&wka->dm_cmd_queue, cmd) { 520 if (strcmp(task, cmd->cmd_task) == 0) { 521 /* found cmd with matching task */ 522 pthread_mutex_unlock(&wka->dm_queue_mutex); 523 return (cmd); 524 } 525 } 526 /* Not found */ 527 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 528 "No command for task %s", task)); 529 pthread_mutex_unlock(&wka->dm_queue_mutex); 530 return (NULL); 531 } 532 533 /* 534 * Function name 535 * dm_read_input(void) 536 * 537 * Parameters: 538 * none 539 * 540 * Description: 541 * read commands from the connection socket. 542 * If a command from MM is read, put it in a dm_command_t and 543 * put it in the command list. 544 * If a response to a command sent to MM is read, then set the 545 * command dispatchable. 546 * 547 * Return code: 548 * none 549 * 550 * Note: 551 * 552 * 553 */ 554 555 /* 556 * dm_read_input 557 * Read input command from MM and put it on input list 558 */ 559 void 560 dm_read_input(void) 561 { 562 char *buf = NULL; 563 int rc; 564 dm_command_t *cmd; 565 mms_par_node_t *root; 566 mms_par_node_t *node; 567 mms_list_t err_list; 568 char *task; 569 570 rc = dm_reader(&buf); 571 if (rc > 0) { 572 /* 573 * Read a command 574 */ 575 rc = mms_dmpm_parse(&root, &err_list, buf); 576 if (rc == 1) { 577 dm_parse_err(root, &err_list); 578 mms_pe_destroy(&err_list); 579 mms_pn_destroy(root); 580 TRACE((MMS_ERR, "Command in error: %s", buf)); 581 free(buf); 582 return; 583 } 584 node = mms_pn_lookup(root, NULL, MMS_PN_CMD, NULL); 585 task = dm_get_task(node); 586 if (strcmp(mms_pn_token(node), "response") == 0) { 587 /* 588 * MM responded to a command sent by DM 589 */ 590 if (task != NULL) { 591 TRACE((MMS_DEBUG, "Get cmd by task %s", task)); 592 mms_trace_flush(); 593 cmd = dm_get_cmd_by_task(task); 594 free(task); 595 task = NULL; 596 } else { 597 /* Must be response unacceptable */ 598 TRACE((MMS_DEBUG, "Got unacceptable response")); 599 DM_EXIT(DM_RESTART); 600 } 601 mms_trace_flush(); 602 if (cmd == NULL) { 603 DM_MSG_SEND((DM_ADM_ERR, DM_6505_MSG, 604 DM_MSG_REASON)); 605 mms_pn_destroy(root); 606 free(buf); 607 return; 608 } 609 cmd->cmd_root = root; 610 TRACE((MMS_DEBUG, "Calling cmd function")); 611 mms_trace_flush(); 612 rc = (*cmd->cmd_func) (cmd); 613 TRACE((MMS_DEBUG, "Back from cmd function")); 614 mms_trace_flush(); 615 if (rc == DM_COMPLETE) { 616 /* 617 * Command completed 618 */ 619 pthread_mutex_lock(&cmd->cmd_done_mutex); 620 cmd->cmd_flags |= CMD_COMPLETE; 621 pthread_cond_broadcast(&cmd->cmd_done_cv); 622 pthread_mutex_unlock(&cmd->cmd_done_mutex); 623 } else { 624 /* 625 * Command not complete, free the parse tree 626 */ 627 mms_pn_destroy(root); 628 } 629 } else { 630 /* 631 * A new command from MM 632 */ 633 cmd = (dm_command_t *)malloc(sizeof (dm_command_t)); 634 if (cmd == NULL) { 635 DM_MSG_ADD((MMS_INTERNAL, 636 MMS_DM_E_INTERNAL, "Out of memory")); 637 dm_resp_unacceptable(DM_6506_MSG, 638 DM_MSG_REASON); 639 mms_pn_destroy(root); 640 free(buf); 641 return; 642 } 643 644 memset(cmd, 0, sizeof (dm_command_t)); 645 cmd->cmd_flags |= CMD_INCOMING; 646 cmd->cmd_root = root; 647 cmd->cmd_task = task; 648 if (dm_setup_incoming_cmd(cmd) != 0) { /* setup cmd */ 649 /* Failed */ 650 dm_resp_unacceptable(DM_6506_MSG, 651 DM_MSG_REASON); 652 dm_destroy_cmd(cmd); 653 free(buf); 654 return; 655 } else { 656 pthread_mutex_lock(&wka->dm_queue_mutex); 657 mms_list_insert_tail(&wka->dm_pend_ack_queue, 658 cmd); 659 pthread_mutex_unlock(&wka->dm_queue_mutex); 660 } 661 } 662 } else if (rc == 0) { 663 /* 664 * Hit end of file or connection closed by MM 665 */ 666 TRACE((MMS_WARN, "dm_read_input: mms_reader error: hit EOF", 667 strerror(errno))); 668 if (buf != NULL) { 669 TRACE((MMS_INFO, "cmd = %s", buf)); 670 } 671 672 /* 673 * Close current connection 674 */ 675 mms_close(&wka->dm_mms_conn); 676 wka->dm_mms_conn.mms_fd = -1; 677 wka->dm_flags &= ~DM_HAVE_SESSION; 678 TRACE((MMS_OPER, "Exiting DM")); 679 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 680 "Lost connection to MM")); 681 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 682 DM_EXIT(DM_RESTART); 683 } else { 684 /* 685 * Got an error 686 */ 687 TRACE((MMS_CRIT, "dm_read_input: mms_reader error: %s", 688 strerror(errno))); 689 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 690 "mms_reader error: %s", strerror(errno))); 691 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 692 DM_EXIT(DM_RESTART); 693 } 694 free(buf); 695 } 696 697 /* 698 * Function name 699 * dm_responded_with(dm_command_t *cmd, char *keyword) 700 * 701 * Parameters: 702 * cmd dm_command_t with the command 703 * keyword keyword of response type 704 * 705 * Description: 706 * Check to see if the response matches the input keyword 707 * 708 * Return code: 709 * 1 type matched 710 * 0 type not matched 711 * 712 * Note: 713 * 714 * 715 */ 716 717 int 718 dm_responded_with(dm_command_t *cmd, char *keyword) 719 { 720 if (mms_pn_lookup(cmd->cmd_root, keyword, MMS_PN_KEYWORD, NULL) || 721 mms_pn_lookup(cmd->cmd_root, keyword, MMS_PN_CLAUSE, NULL)) { 722 /* Found respond with keyword */ 723 return (1); 724 } else { 725 return (0); 726 } 727 } 728 729 /* 730 * Function name 731 * dm_accept_cmds(void) 732 * 733 * Parameters: 734 * none 735 * 736 * Description: 737 * send accepted commands to all commands that have not been accepted 738 * 739 * Return code: 740 * none 741 * 742 * Note: 743 * 744 * 745 */ 746 747 void 748 dm_accept_cmds(void) 749 { 750 dm_command_t *cmd; 751 dm_command_t *next; 752 int rc; 753 754 pthread_mutex_lock(&wka->dm_queue_mutex); 755 mms_list_foreach_safe(&wka->dm_pend_ack_queue, cmd, next) { 756 pthread_mutex_unlock(&wka->dm_queue_mutex); 757 rc = dm_accept_cmd_aux(cmd); 758 pthread_mutex_lock(&wka->dm_queue_mutex); 759 next = mms_list_next(&wka->dm_pend_ack_queue, cmd); 760 if (rc == 0) { 761 /* Accept sent, move cmd to dispatch list */ 762 mms_list_remove(&wka->dm_pend_ack_queue, cmd); 763 /* no error */ 764 mms_list_insert_tail(&wka->dm_cmd_queue, cmd); 765 pthread_mutex_lock(&wka->dm_worker_mutex); 766 /* wakeup worker thread to do work */ 767 cmd->cmd_flags |= CMD_DISPATCHABLE; 768 wka->dm_cmd_dispatchable = 1; 769 wka->dm_work_todo = 1; 770 pthread_cond_broadcast(&wka->dm_work_cv); 771 pthread_mutex_unlock(&wka->dm_worker_mutex); 772 } 773 } 774 if (mms_list_empty(&wka->dm_pend_ack_queue)) { 775 /* all commands accepted. enable writing commands */ 776 pthread_cond_broadcast(&wka->dm_accept_cv); 777 } 778 pthread_mutex_unlock(&wka->dm_queue_mutex); 779 } 780 781 /* 782 * Function name 783 * dm_accept_cmd_aux(dm_command_t *cmd) 784 * 785 * Parameters: 786 * cmd dm_command_t pointer 787 * 788 * Description: 789 * construct an accepted command and send it 790 * 791 * Return code: 792 * 0 success 793 * -1 error 794 * 795 * Note: 796 * 797 * 798 */ 799 800 int 801 dm_accept_cmd_aux(dm_command_t *cmd) 802 { 803 char *accept; 804 int rc; 805 int err; 806 807 if (cmd->cmd_task == NULL) { 808 cmd->cmd_task = dm_get_task(cmd->cmd_root); 809 } 810 811 accept = mms_strnew("response task [ '%s' ] accepted;", cmd->cmd_task); 812 rc = dm_writer_accept(accept); 813 err = errno; 814 if (rc != 0) { 815 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 816 "unable to send accept to task %s: %s", 817 cmd->cmd_task, strerror(err))); 818 dm_resp_unacceptable(DM_6507_MSG, DM_MSG_REASON); 819 free(accept); 820 return (-1); 821 } 822 free(accept); 823 return (0); 824 } 825 826 /* 827 * Function name 828 * dm_resp_unacceptable(int msgid, ...) 829 * 830 * Parameters: 831 * msgid message id 832 * ... argument list, terminated by NULL. 833 * 834 * Description: 835 * send response unacceptable command 836 * 837 * Return code: 838 * none 839 * 840 * Note: 841 * 842 * 843 */ 844 845 void 846 dm_resp_unacceptable(int msgid, ...) 847 { 848 char *msgcl; 849 char *unacc; 850 int rc; 851 va_list args; 852 853 /* 854 * Build a message clause 855 */ 856 va_start(args, msgid); 857 msgcl = mms_bld_msgcl(msgid, args); 858 va_end(args); 859 860 unacc = mms_strnew("response unacceptable %s ;", msgcl); 861 free(msgcl); 862 863 rc = dm_writer_accept(unacc); 864 if (rc == DM_ERROR) { 865 TRACE((MMS_ERR, "dm_accept_cmd: mms_writer error: %s", 866 strerror(errno))); 867 } else if (rc == DM_PARTIAL_WRITE) { 868 TRACE((MMS_ERR, "dm_accept_cmd: mms_writer error: %s", 869 strerror(errno))); 870 } 871 free(unacc); 872 } 873 874 /* 875 * Function name 876 * dm_resp_error(int msgid, ...) 877 * 878 * Parameters: 879 * msgid message id 880 * ... argument list, terminated by NULL. 881 * 882 * Description: 883 * send response error command 884 * 885 * Return code: 886 * none 887 * 888 * Note: 889 * 890 * 891 */ 892 893 void 894 dm_resp_error(char *task, int msgid, ...) 895 { 896 char *rep; 897 char *msgcl; 898 va_list args; 899 int rc; 900 901 /* 902 * Build a message clause 903 */ 904 va_start(args, msgid); 905 msgcl = mms_bld_msgcl(msgid, args); 906 va_end(args); 907 908 rep = mms_strnew("response task [ '%s' ] " 909 "error [ '%s' '%s' ] %s ;", 910 task, 911 mms_sym_code_to_str(dm_msg_class()), 912 mms_sym_code_to_str(dm_msg_code()), 913 msgcl); 914 free(msgcl); 915 rc = dm_writer(rep); 916 free(rep); 917 if (rc == DM_ERROR) { 918 TRACE((MMS_ERR, "dm_resp_error: mms_writer error: %s", 919 strerror(errno))); 920 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 921 "mms_writer error: %s", strerror(errno))); 922 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 923 DM_EXIT(DM_RESTART); 924 } else if (rc == DM_PARTIAL_WRITE) { 925 TRACE((MMS_ERR, "dm_resp_error: mms_writer error: %s", 926 strerror(errno))); 927 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 928 "mms_writer error: %s", strerror(errno))); 929 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 930 DM_EXIT(DM_RESTART); 931 } 932 } 933 934 935 /* 936 * Function name 937 * dm_resp_success(char *task, char *text) 938 * 939 * Parameters: 940 * task task id 941 * text content of text clause 942 * 943 * Description: 944 * send response success command 945 * 946 * Return code: 947 * none 948 * 949 * Note: 950 * 951 * 952 */ 953 954 void 955 dm_resp_success(char *task, char *text) 956 { 957 char *rep; 958 char *textcl = NULL; 959 int rc; 960 961 if (text != NULL && text[0] != '\0') { 962 textcl = mms_strnew("text [ '%s' ] ", text); 963 } 964 rep = mms_strnew("response task [ '%s' ] success %s;", 965 task, textcl == NULL ? "" : textcl); 966 rc = dm_writer(rep); 967 free(rep); 968 free(textcl); 969 if (rc == DM_ERROR) { 970 TRACE((MMS_ERR, "dm_resp_success: mms_writer error: %s", 971 strerror(errno))); 972 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 973 "mms_writer error: %s", strerror(errno))); 974 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 975 DM_EXIT(DM_RESTART); 976 } else if (rc == DM_PARTIAL_WRITE) { 977 TRACE((MMS_DEBUG, "dm_resp_success: mms_writer error: %s", 978 strerror(errno))); 979 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 980 "mms_writer error: %s", strerror(errno))); 981 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 982 DM_EXIT(DM_RESTART); 983 } 984 } 985 986 /* 987 * Function name 988 * dm_send_message(char *who, char *severity, int msgid, ...) 989 * 990 * Parameters: 991 * who who to send message to 992 * severity severity of message 993 * msgid message id 994 * ... variable list of arguments of the message ending with NULL 995 * 996 * Description: 997 * send a message to the administrator 998 * 999 * Return code: 1000 * none 1001 * 1002 * Note: 1003 * 1004 * 1005 */ 1006 1007 void 1008 dm_send_message(char *who, char *severity, int msgid, ...) 1009 { 1010 char *msg_cmd; 1011 char *task; 1012 dm_command_t *cmd; 1013 char *msgcl; 1014 va_list ap; 1015 1016 task = dm_bld_task("message"); 1017 va_start(ap, msgid); 1018 msgcl = mms_bld_msgcl(msgid, ap); 1019 va_end(ap); 1020 msg_cmd = mms_strnew("message task [ '%s' ] who [ %s ] " 1021 "severity [ %s ] %s ;", task, who, severity, msgcl); 1022 cmd = dm_send_cmd(msg_cmd, dm_cmd_response, task); 1023 free(task); 1024 free(msgcl); 1025 free(msg_cmd); 1026 if (cmd == NULL || cmd->cmd_rc != 0) { 1027 TRACE((MMS_ERR, "Unable to send message command")); 1028 if (cmd) { 1029 dm_destroy_cmd(cmd); 1030 } 1031 return; 1032 } 1033 dm_destroy_cmd(cmd); 1034 dm_msg_destroy(); /* clean up message queue */ 1035 } 1036 1037 /* 1038 * Function name 1039 * dm_send_ready(int msgid, ...) 1040 * 1041 * Parameters: 1042 * msgid message id 1043 * ... variable list of arguments ending with NULL 1044 * 1045 * Description: 1046 * send a ready command 1047 * 1048 * Return code: 1049 * 1050 * 1051 * Note: 1052 * 1053 * 1054 */ 1055 1056 int 1057 dm_send_ready(int msgid, ...) 1058 { 1059 va_list ap; 1060 int rc; 1061 1062 va_start(ap, msgid); 1063 rc = dm_send_ready_aux(NULL, msgid, ap); 1064 va_end(ap); 1065 return (rc); 1066 } 1067 1068 /* 1069 * Function name 1070 * dm_send_ready_broken(int msgid, ...) 1071 * 1072 * Parameters: 1073 * msgid message id 1074 * ... arguments for message ending with NULL 1075 * 1076 * Description: 1077 * send ready broken message 1078 * 1079 * Return code: 1080 * 0 success 1081 * -1 error 1082 * 1083 * Note: 1084 * 1085 * 1086 */ 1087 1088 int 1089 dm_send_ready_broken(int msgid, ...) 1090 { 1091 va_list ap; 1092 int rc; 1093 1094 va_start(ap, msgid); 1095 rc = dm_send_ready_aux("broken", msgid, ap); 1096 va_end(ap); 1097 return (rc); 1098 } 1099 1100 /* 1101 * Function name 1102 * dm_send_ready_disconnected(int msgid, ...) 1103 * 1104 * Parameters: 1105 * msgid message id 1106 * ... arguments for message ending with NULL 1107 * 1108 * Description: 1109 * send ready disconnected message 1110 * 1111 * Return code: 1112 * 0 success 1113 * -1 error 1114 * 1115 * Note: 1116 * 1117 * 1118 */ 1119 1120 int 1121 dm_send_ready_disconnected(int msgid, ...) 1122 { 1123 va_list ap; 1124 int rc; 1125 1126 va_start(ap, msgid); 1127 rc = dm_send_ready_aux("disconnected", msgid, ap); 1128 va_end(ap); 1129 return (rc); 1130 } 1131 1132 /* 1133 * Function name 1134 * dm_send_ready_not(int msgid, ...) 1135 * 1136 * Parameters: 1137 * msgid message id 1138 * ... arguments for message ending with NULL 1139 * 1140 * Description: 1141 * send ready not message 1142 * 1143 * Return code: 1144 * 0 success 1145 * -1 error 1146 * 1147 * Note: 1148 * 1149 * 1150 */ 1151 1152 int 1153 dm_send_ready_not(int msgid, ...) 1154 { 1155 va_list ap; 1156 int rc; 1157 1158 va_start(ap, msgid); 1159 rc = dm_send_ready_aux("not", msgid, ap); 1160 va_end(ap); 1161 return (rc); 1162 } 1163 1164 /* 1165 * Function name 1166 * dm_send_ready_aux(char *spec, int msgid, va_list args) 1167 * 1168 * Parameters: 1169 * spec specific ready type 1170 * msgid message id 1171 * args variable length arg list terminated by NULL 1172 * 1173 * Description: 1174 * construct a ready message and send it 1175 * 1176 * Return code: 1177 * 0 success 1178 * -1 error 1179 * 1180 * Note: 1181 * 1182 * 1183 */ 1184 1185 int 1186 dm_send_ready_aux(char *spec, int msgid, va_list args) 1187 { 1188 dm_command_t *cmd; 1189 char *ready_cmd; 1190 char *task; 1191 char *msgcl; 1192 1193 /* 1194 * Build a message clause 1195 */ 1196 msgcl = mms_bld_msgcl(msgid, args); 1197 1198 task = dm_bld_task("ready"); 1199 if (spec == NULL) { 1200 spec = ""; 1201 } 1202 ready_cmd = mms_strnew("ready task['%s'] %s %s;", task, spec, msgcl); 1203 cmd = dm_send_cmd(ready_cmd, dm_cmd_response, task); 1204 free(task); 1205 free(msgcl); 1206 free(ready_cmd); 1207 if (cmd == NULL || cmd->cmd_rc != 0) { 1208 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1209 "send ready command error")); 1210 if (cmd) { 1211 dm_destroy_cmd(cmd); 1212 } 1213 return (-1); 1214 } 1215 dm_destroy_cmd(cmd); 1216 return (0); 1217 } 1218 1219 /* 1220 * Function name 1221 * dm_update_capacity(void) 1222 * 1223 * Parameters: 1224 * none 1225 * 1226 * Description: 1227 * get capacity of cartridge and update the partition size in 1228 * the PARTITION object. 1229 * 1230 * Return code: 1231 * 0 success 1232 * -1 error 1233 * 1234 * Note: 1235 * 1236 * 1237 */ 1238 1239 int 1240 dm_update_capacity(void) 1241 { 1242 int rc = 0; 1243 1244 if (drv->drv_flags & DRV_LOADED) { 1245 /* 1246 * Read capacity from tape 1247 */ 1248 if (DRV_CALL(drv_get_capacity, (&drv->drv_cap)) == 0) { 1249 /* update capacity */ 1250 if (dm_send_capacity(&drv->drv_cap) != 0) { 1251 DM_MSG_ADD((MMS_INTERNAL, 1252 MMS_DM_E_INTERNAL, 1253 "update capacity error")); 1254 rc = -1; 1255 } 1256 } else { 1257 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1258 "cannot get cartridge capacity")); 1259 } 1260 } 1261 return (rc); 1262 } 1263 1264 /* 1265 * Function name 1266 * dm_send_capacity(mms_capacity_t *cap) 1267 * 1268 * Parameters: 1269 * cap addr of mms_capacity_t 1270 * 1271 * Description: 1272 * send capacity to MM to update capacity 1273 * 1274 * Return code: 1275 * o success 1276 * -1 error 1277 * 1278 * Note: 1279 * 1280 * 1281 */ 1282 1283 int 1284 dm_send_capacity(mms_capacity_t *cap) 1285 { 1286 char *attr_cmd; 1287 char *task; 1288 dm_command_t *cmd; 1289 1290 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 1291 TRACE((MMS_ERR, "No connection to MM")); 1292 return (-1); 1293 } 1294 1295 task = dm_bld_task("send-capacity"); 1296 attr_cmd = mms_strnew("attribute task['%s'] " 1297 "match[ and (streq(CARTRIDGE.'CartridgePCL' '%s') " 1298 "streq(PARTITION.'PartitionName' '%s') " 1299 "streq(DRIVE.'DriveName' '%s'))]" 1300 "set[PARTITION.'PartitionSize' '%lld'] " 1301 "set[PARTITION.'PartitionAvailable' '%lld'] " 1302 "set[PARTITION.'PartitionPercentAvailable' '%d'] " 1303 "set[CARTRIDGETYPE.'CartridgeTypeMediaLength' '%lld'] " 1304 ";", 1305 task, dca->dca_pcl, dca->dca_part_name, drv->drv_drvname, 1306 cap->mms_max, cap->mms_avail, cap->mms_pc_avail, cap->mms_max); 1307 1308 cmd = dm_send_cmd(attr_cmd, dm_cmd_response, task); 1309 free(task); 1310 free(attr_cmd); 1311 if (cmd == NULL || cmd->cmd_rc != 0) { 1312 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1313 "update capacity error")); 1314 if (cmd) { 1315 dm_destroy_cmd(cmd); 1316 } 1317 return (-1); 1318 } 1319 dm_destroy_cmd(cmd); 1320 return (0); 1321 } 1322 1323 /* 1324 * Function name 1325 * dm_send_loaded(void) 1326 * 1327 * Parameters: 1328 * none 1329 * 1330 * Description: 1331 * update DriveStateHard to loaded 1332 * 1333 * Return code: 1334 * 0 success 1335 * -1 error 1336 * 1337 * Note: 1338 * 1339 * 1340 */ 1341 1342 int 1343 dm_send_loaded(void) 1344 { 1345 char *attr_cmd; 1346 char *task; 1347 dm_command_t *cmd; 1348 1349 task = dm_bld_task("send-loaded"); 1350 attr_cmd = mms_strnew("attribute task['%s'] " 1351 "match[ streq(DRIVE.'DriveName' '%s') ] " 1352 "set[DRIVE.'DriveStateHard' 'loaded'] " 1353 "set[DRIVE.'DMName' '%s'] ;", task, DRVNAME, DMNAME); 1354 1355 cmd = dm_send_cmd(attr_cmd, dm_cmd_response, task); 1356 free(task); 1357 free(attr_cmd); 1358 if (cmd == NULL || cmd->cmd_rc != 0) { 1359 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1360 "send loaded error")); 1361 if (cmd) { 1362 dm_destroy_cmd(cmd); 1363 } 1364 return (-1); 1365 } 1366 dm_destroy_cmd(cmd); 1367 return (0); 1368 } 1369 1370 /* 1371 * Function name 1372 * dm_get_capacity(mms_par_node_t *root) 1373 * 1374 * Parameters: 1375 * root pointer to the parse tree 1376 * 1377 * Description: 1378 * get capacity from the response of a show command and save it 1379 * in drv->drv_avail. 1380 * 1381 * Return code: 1382 * 0 success 1383 * -1 error 1384 * 1385 * Note: 1386 * 1387 * 1388 */ 1389 1390 int 1391 dm_get_capacity(mms_par_node_t *root) 1392 { 1393 char *val; 1394 1395 /* 1396 * Save tape capacity 1397 */ 1398 val = dm_get_attr_value(root, "PARTITION", "PartitionSize"); 1399 if (val == NULL) { 1400 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1401 "unable to get partition size")); 1402 return (-1); 1403 } 1404 1405 sscanf(val, "%lld", (int64_t *)&drv->drv_capacity); 1406 1407 val = dm_get_attr_value(root, "PARTITION", "PartitionAvailable"); 1408 if (val == NULL) { 1409 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1410 "unable to get partition available")); 1411 return (-1); 1412 } 1413 1414 sscanf(val, "%lld", (int64_t *)&drv->drv_avail); 1415 1416 val = dm_get_attr_value(root, "PARTITION", "PartitionPercentAvailable"); 1417 if (val == NULL) { 1418 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1419 "unable to get partition % available")); 1420 return (-1); 1421 } 1422 1423 sscanf(val, "%d", (int32_t *)&drv->drv_pc_avail); 1424 return (0); 1425 } 1426 1427 /* 1428 * Function name 1429 * dm_show_mount_point(mms_par_node_t **typeroot) 1430 * 1431 * Parameters: 1432 * typeroot addr of pointer to root of response parse tree 1433 * 1434 * Description: 1435 * Show mount points of all cartridges that can be mounted on 1436 * the drive controlled by this DM. 1437 * 1438 * Return code: 1439 * 0 success - root of parse tree returned in typeroot. 1440 * -1 error 1441 * 1442 * Note: 1443 * 1444 * 1445 */ 1446 1447 int 1448 dm_show_mount_point(mms_par_node_t **typeroot) 1449 { 1450 char *show_cmd; 1451 char *task; 1452 dm_command_t *cmd; 1453 1454 /* 1455 * Show mount points of all cartridges that can be mounted on 1456 * the drive controlled by this DM. 1457 */ 1458 task = dm_bld_task("show-mount-point"); 1459 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue unique] " 1460 "match[and(streq(DM.'DMName' '%s') " 1461 "streq(CARTRIDGETYPE.'CartridgeShapeName' 'DISK'))] " 1462 "report[CARTRIDGE.'CartridgeMountPoint'] " 1463 ";", task, drv->drv_dmname); 1464 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 1465 free(task); 1466 free(show_cmd); 1467 if (cmd == NULL || cmd->cmd_rc != 0) { 1468 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1469 "show mount point error")); 1470 if (cmd) { 1471 dm_destroy_cmd(cmd); 1472 } 1473 return (-1); 1474 } 1475 1476 *typeroot = cmd->cmd_root; 1477 cmd->cmd_root = NULL; 1478 dm_destroy_cmd(cmd); 1479 return (0); 1480 } 1481 1482 /* 1483 * Function name 1484 * dm_show_virt_cart_path(void) 1485 * 1486 * Parameters: 1487 * none 1488 * 1489 * Description: 1490 * show the path to a DISK cartridge 1491 * 1492 * Return code: 1493 * pointer to path string. Caller must free after use. 1494 * NULL can't get path 1495 * 1496 * Note: 1497 * 1498 * 1499 */ 1500 1501 char * 1502 dm_show_virt_cart_path(void) 1503 { 1504 char *show_cmd; 1505 char *task; 1506 mms_par_node_t *root; 1507 dm_command_t *cmd; 1508 char *mp; 1509 char *fn; 1510 char *path; 1511 int len; 1512 1513 task = dm_bld_task("show-virt-cart-type"); 1514 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 1515 "match[streq(CARTRIDGE.'CartridgePCL' '%s') ] " 1516 "report[CARTRIDGE.'CartridgeMountPoint' CARTRIDGE.'CartridgePath' ]" 1517 ";", task, mnt->mnt_pcl); 1518 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 1519 free(task); 1520 free(show_cmd); 1521 if (cmd == NULL || cmd->cmd_rc != 0) { 1522 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1523 "show virt cart type error")); 1524 if (cmd) { 1525 dm_destroy_cmd(cmd); 1526 } 1527 return (NULL); 1528 } 1529 root = cmd->cmd_root; 1530 mp = dm_get_attr_value(root, "CARTRIDGE", "CartridgeMountPoint"); 1531 len = strlen(mp); 1532 if (mp[len - 1] == '/') { 1533 mp[len - 1] = '\0'; 1534 } 1535 fn = dm_get_attr_value(root, "CARTRIDGE", "CartridgePath"); 1536 1537 path = mms_strnew("%s/%s", mp, fn); 1538 dm_destroy_cmd(cmd); 1539 return (path); 1540 } 1541 1542 int 1543 dm_show_eof_pos(void) 1544 { 1545 char *show_cmd; 1546 char *task; 1547 mms_par_node_t *root; 1548 dm_command_t *cmd; 1549 char *val; 1550 int eof; 1551 int pmode; 1552 1553 task = dm_bld_task("show-eof-pos"); 1554 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 1555 "match[ and (streq(CARTRIDGE.'CartridgePCL' '%s') " 1556 "streq(SIDE.'SideName' '%s') " 1557 "streq(PARTITION.'PartitionName' '%s') " 1558 "streq(DRIVE.'DriveName' '%s'))]" 1559 "report[ PARTITION.'PartitionEOFPos' ]" 1560 ";", 1561 task, dca->dca_pcl, dca->dca_side_name, dca->dca_part_name, 1562 drv->drv_drvname); 1563 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 1564 free(task); 1565 free(show_cmd); 1566 if (cmd == NULL || cmd->cmd_rc != 0) { 1567 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1568 "show eof position error")); 1569 if (cmd) { 1570 dm_destroy_cmd(cmd); 1571 } 1572 return (-1); 1573 } 1574 root = cmd->cmd_root; 1575 1576 /* 1577 * Save EOF position 1578 */ 1579 val = dm_get_attr_value(root, "PARTITION", "PartitionEOFPos"); 1580 if (val == NULL) { 1581 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1582 "unable to get EOF position")); 1583 if (cmd) { 1584 dm_destroy_cmd(cmd); 1585 } 1586 return (-1); 1587 } 1588 1589 drv->drv_flags &= ~DRV_VALID_EOF_POS; /* assume no eof pos */ 1590 if (strcmp(val, "none") != 0) { 1591 /* EOF position is valid */ 1592 if (sscanf(val, "%lld %d %d %d %d %d", 1593 (int64_t *)&drv->drv_eof_pos.lgclblkno, 1594 &drv->drv_eof_pos.fileno, 1595 &drv->drv_eof_pos.blkno, 1596 &drv->drv_eof_pos.partition, 1597 &eof, &pmode) == 6) { 1598 drv->drv_eof_pos.eof = eof; 1599 drv->drv_eof_pos.pmode = pmode; 1600 1601 drv->drv_flags |= DRV_VALID_EOF_POS; 1602 } 1603 } 1604 1605 dm_destroy_cmd(cmd); 1606 return (0); 1607 } 1608 1609 int 1610 dm_send_eof_pos(void) 1611 { 1612 char *attr_cmd; 1613 char *task; 1614 dm_command_t *cmd; 1615 1616 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 1617 TRACE((MMS_ERR, "No connection to MM")); 1618 return (-1); 1619 } 1620 1621 task = dm_bld_task("update-eof-pos"); 1622 if (drv->drv_flags & DRV_VALID_EOF_POS) { 1623 attr_cmd = mms_strnew("attribute task['%s'] " 1624 "match[ and (streq(CARTRIDGE.'CartridgePCL' '%s') " 1625 "streq(SIDE.'SideName' '%s') " 1626 "streq(PARTITION.'PartitionName' '%s') " 1627 "streq(DRIVE.'DriveName' '%s'))]" 1628 "set[PARTITION.'PartitionEOFPos' '%lld %d %d %d %d %d '] " 1629 ";", 1630 task, dca->dca_pcl, dca->dca_side_name, dca->dca_part_name, 1631 drv->drv_drvname, 1632 drv->drv_eof_pos.lgclblkno, 1633 drv->drv_eof_pos.fileno, 1634 drv->drv_eof_pos.blkno, 1635 drv->drv_eof_pos.partition, 1636 drv->drv_eof_pos.eof, 1637 drv->drv_eof_pos.pmode); 1638 } else { 1639 attr_cmd = mms_strnew("attribute task['%s'] " 1640 "match[ and (streq(CARTRIDGE.'CartridgePCL' '%s') " 1641 "streq(SIDE.'SideName' '%s') " 1642 "streq(PARTITION.'PartitionName' '%s') " 1643 "streq(DRIVE.'DriveName' '%s'))]" 1644 "unset[PARTITION.'PartitionEOFPos'] " 1645 ";", 1646 task, dca->dca_pcl, dca->dca_side_name, dca->dca_part_name, 1647 drv->drv_drvname); 1648 } 1649 cmd = dm_send_cmd(attr_cmd, dm_cmd_response, task); 1650 free(task); 1651 free(attr_cmd); 1652 if (cmd == NULL || cmd->cmd_rc != 0) { 1653 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1654 "send eof position error")); 1655 if (cmd) { 1656 dm_destroy_cmd(cmd); 1657 } 1658 return (-1); 1659 } 1660 dm_destroy_cmd(cmd); 1661 return (0); 1662 } 1663 1664 int 1665 dm_send_write_protect(int wp) 1666 { 1667 char *attr_cmd; 1668 char *task; 1669 dm_command_t *cmd; 1670 1671 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 1672 TRACE((MMS_ERR, "No connection to MM")); 1673 return (-1); 1674 } 1675 1676 task = dm_bld_task("update-write-protect"); 1677 attr_cmd = mms_strnew("attribute task['%s'] " 1678 "match[ and (streq(CARTRIDGE.'CartridgePCL' '%s') " 1679 "streq(SIDE.'SideName' '%s') " 1680 "streq(PARTITION.'PartitionName' '%s') " 1681 "streq(DRIVE.'DriveName' '%s'))]" 1682 "set[CARTRIDGE.'CartridgeWriteProtected' '%s'] " 1683 ";", 1684 task, dca->dca_pcl, dca->dca_side_name, dca->dca_part_name, 1685 drv->drv_drvname, 1686 wp ? "yes" : "no"); 1687 cmd = dm_send_cmd(attr_cmd, dm_cmd_response, task); 1688 free(task); 1689 free(attr_cmd); 1690 if (cmd == NULL || cmd->cmd_rc != 0) { 1691 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1692 "send write protect error")); 1693 if (cmd) { 1694 dm_destroy_cmd(cmd); 1695 } 1696 return (-1); 1697 } 1698 dm_destroy_cmd(cmd); 1699 return (0); 1700 } 1701 1702 int 1703 dm_show_dca_info(mms_par_node_t **rt) 1704 { 1705 char *show_cmd; 1706 char *val; 1707 char *task; 1708 dm_command_t *cmd; 1709 mms_par_node_t *root; 1710 1711 memset(dca, 0, sizeof (drv_cart_access_t)); 1712 task = dm_bld_task("show-dca-info"); 1713 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 1714 "match[ and( streq(DRIVE.'DriveName' '%s') " 1715 "streq(VOLUME.'VolumeName' '%s')) ] " 1716 "report[ " 1717 "DRIVE.'DriveTimeMountedLast' " 1718 "DRIVE.'DriveShapeName' " 1719 "CARTRIDGETYPE.'CartridgeShapeName' " 1720 "CARTRIDGETYPE.'CartridgeTypeMediaType' " 1721 "CARTRIDGE.'CartridgeNumberMounts' " 1722 "PARTITION.'SideName' " 1723 "PARTITION.'PartitionName' " 1724 "PARTITION.'CartridgeID' " 1725 "PARTITION.'PartitionRWMode' " 1726 "PARTITION.'PartitionSize' " 1727 "PARTITION.'PartitionAvailable' " 1728 "PARTITION.'PartitionPercentAvailable' " 1729 "PARTITION.'PartitionEOFPos' " 1730 "] ;", task, DRVNAME, mnt->mnt_volumename); 1731 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 1732 free(task); 1733 free(show_cmd); 1734 if (cmd == NULL || cmd->cmd_rc != 0) { 1735 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1736 "send show dca info error")); 1737 goto error; 1738 } 1739 1740 root = cmd->cmd_root; 1741 val = dm_get_attr_value(root, "PARTITION", "SideName"); 1742 if (val == NULL) { 1743 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1744 "unable to get side name")); 1745 goto error; 1746 } 1747 dca->dca_side_name = strdup(val); 1748 1749 val = dm_get_attr_value(root, "PARTITION", "PartitionName"); 1750 if (val == NULL) { 1751 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1752 "unable to get partition name")); 1753 goto error; 1754 } 1755 dca->dca_part_name = strdup(val); 1756 1757 val = dm_get_attr_value(root, "CARTRIDGE", "CartridgeID"); 1758 if (val == NULL) { 1759 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1760 "unable to get cartridge ID")); 1761 goto error; 1762 } 1763 dca->dca_cart_id = strdup(val); 1764 1765 val = dm_get_attr_value(root, "DRIVE", "DriveTimeMountedLast"); 1766 if (val == NULL) { 1767 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1768 "unable to get DriveTimeMountedLast")); 1769 goto error; 1770 } 1771 dm_mms_to_db_time(val); 1772 dca->dca_mounted_last = strdup(val); 1773 1774 val = dm_get_attr_value(root, "CARTRIDGETYPE", "CartridgeShapeName"); 1775 if (val == NULL) { 1776 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1777 "unable to get CartridgeShapeName")); 1778 goto error; 1779 } 1780 dca->dca_cart_shape_name = strdup(val); 1781 1782 val = dm_get_attr_value(root, "DRIVE", "DriveShapeName"); 1783 if (val == NULL) { 1784 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1785 "unable to get DriveShapeName")); 1786 goto error; 1787 } 1788 dca->dca_drv_shape_name = strdup(val); 1789 1790 dca->dca_pcl = strdup(mnt->mnt_pcl); 1791 1792 dca->dca_flags |= DRV_DCA_VALID; 1793 *rt = cmd->cmd_root; 1794 cmd->cmd_root = NULL; 1795 dm_destroy_cmd(cmd); 1796 return (0); 1797 1798 error: 1799 dm_destroy_dca(); 1800 if (cmd != NULL) { 1801 dm_destroy_cmd(cmd); 1802 } 1803 return (-1); 1804 } 1805 1806 int 1807 dm_show_application(mms_par_node_t **rt) 1808 { 1809 char *show_cmd; 1810 char *task; 1811 dm_command_t *cmd; 1812 1813 task = dm_bld_task("show-application"); 1814 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 1815 "match[ streq(VOLUME.'VolumeName' '%s') ] " 1816 "report[ " 1817 "APPLICATION " 1818 "] ;", task, mnt->mnt_volumename); 1819 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 1820 free(task); 1821 free(show_cmd); 1822 if (cmd == NULL || cmd->cmd_rc != 0) { 1823 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1824 "send show application error")); 1825 goto error; 1826 } 1827 1828 *rt = cmd->cmd_root; 1829 cmd->cmd_root = NULL; 1830 dm_destroy_cmd(cmd); 1831 return (0); 1832 1833 error: 1834 if (cmd != NULL) { 1835 dm_destroy_cmd(cmd); 1836 } 1837 return (-1); 1838 } 1839 1840 int 1841 dm_send_error(void) 1842 { 1843 char *create_cmd; 1844 char *ts; 1845 char sense[200]; 1846 char cdb[64]; 1847 char *task; 1848 dm_command_t *cmd; 1849 1850 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 1851 TRACE((MMS_ERR, "No connection to MM")); 1852 return (-1); 1853 } 1854 1855 /* 1856 * Create DRIVECARTRIDGEERROR 1857 */ 1858 task = dm_bld_task("create-drive-cart-error"); 1859 ts = dm_timestamp(); 1860 create_cmd = mms_strnew("create task['%s'] " 1861 "type [ DRIVECARTRIDGEERROR ] " 1862 "set[DRIVECARTRIDGEERROR.'DriveName' '%s' ] " 1863 "set[DRIVECARTRIDGEERROR.'DMName' '%s' ] " 1864 "set[DRIVECARTRIDGEERROR.'CartridgeID' '%s' ] " 1865 "set[DRIVECARTRIDGEERROR.'SideName' '%s' ] " 1866 "set[DRIVECARTRIDGEERROR.'PartitionName' '%s' ] " 1867 "set[DRIVECARTRIDGEERROR.'ApplicationName' '%s' ] " 1868 "set[DRIVECARTRIDGEERROR.'CartridgePCL' '%s' ] " 1869 "set[DRIVECARTRIDGEERROR.'DriveSerialNum' '%s' ] " 1870 "set[DRIVECARTRIDGEERROR.'CartridgeShapeName' '%s' ] " 1871 "set[DRIVECARTRIDGEERROR.'DriveShapeName' '%s' ] " 1872 "set[DRIVECARTRIDGEERROR.'SCSICommand' '%s' ] " 1873 "set[DRIVECARTRIDGEERROR.'TimeStamp' '%s' ] " 1874 "set[DRIVECARTRIDGEERROR.'CDB' '%s' ] " 1875 "set[DRIVECARTRIDGEERROR.'IOStatus' '%s' ] " 1876 "set[DRIVECARTRIDGEERROR.'SenseKey' '%s' ] " 1877 "set[DRIVECARTRIDGEERROR.'AdditionalSenseCode' '%2.2x' ] " 1878 "set[DRIVECARTRIDGEERROR.'AdditionalSenseCodeQualifier' '%2.2x' ] " 1879 "set[DRIVECARTRIDGEERROR.'SenseBytes' '%s' ] " 1880 "set[DRIVECARTRIDGEERROR.'ErrorText' '%s' ] " 1881 ";", 1882 task, DRVNAME, DMNAME, 1883 dca->dca_cart_id == NULL ? "None" : dca->dca_cart_id, 1884 dca->dca_side_name == NULL ? "None" : dca->dca_side_name, 1885 dca->dca_part_name == NULL ? "None" : dca->dca_part_name, 1886 dca->dca_app_name == NULL ? "None" : dca->dca_app_name, 1887 dca->dca_pcl == NULL ? "None" : dca->dca_pcl, 1888 drv->drv_serial_num == NULL ? "None" : drv->drv_serial_num, 1889 dca->dca_cart_shape_name == 1890 NULL ? "None" : dca->dca_cart_shape_name, 1891 dca->dca_drv_shape_name == NULL ? "None" : dca->dca_drv_shape_name, 1892 mms_scsi_cmd(serr->se_cdb[0]), 1893 ts, 1894 dm_char_to_hex(serr->se_cdb, serr->se_cdblen, cdb, sizeof (cdb)), 1895 mms_scsi_status(serr->se_status), 1896 mms_scsi_sensekey(serr->se_senkey), 1897 serr->se_asc, 1898 serr->se_ascq, 1899 serr->se_senkey == KEY_NO_SENSE ? "No sense" : 1900 dm_char_to_hex(serr->se_sense, serr->se_senlen, 1901 sense, sizeof (sense)), 1902 (serr->se_err_text == NULL) ? "unknown error" : serr->se_err_text); 1903 free(ts); 1904 cmd = dm_send_cmd(create_cmd, dm_cmd_response, task); 1905 free(task); 1906 free(create_cmd); 1907 if (cmd == NULL || cmd->cmd_rc != 0) { 1908 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1909 "send drive cartridge error error")); 1910 if (cmd) { 1911 dm_destroy_cmd(cmd); 1912 } 1913 return (-1); 1914 } 1915 1916 dm_destroy_cmd(cmd); 1917 return (0); 1918 } 1919 1920 int 1921 dm_send_clean_request(void) 1922 { 1923 char *clean_cmd; 1924 char *task; 1925 dm_command_t *cmd; 1926 1927 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 1928 TRACE((MMS_ERR, "No connection to MM")); 1929 return (-1); 1930 } 1931 1932 task = dm_bld_task("cleaning-request"); 1933 clean_cmd = mms_strnew("private task['%s'] " 1934 "set[DRIVE.'DriveNeedsCleaning' 'true'] " 1935 ";", task); 1936 1937 cmd = dm_send_cmd(clean_cmd, dm_cmd_response, task); 1938 free(task); 1939 free(clean_cmd); 1940 if (cmd == NULL || cmd->cmd_rc != 0) { 1941 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 1942 "send drive needs cleaning error")); 1943 if (cmd) { 1944 dm_destroy_cmd(cmd); 1945 } 1946 return (-1); 1947 } 1948 1949 dm_destroy_cmd(cmd); 1950 return (0); 1951 } 1952 1953 int 1954 dm_send_statistics(void) 1955 { 1956 char *create_cmd; 1957 char *unmnttime; 1958 char *task; 1959 dm_command_t *cmd; 1960 1961 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 1962 TRACE((MMS_ERR, "No connection to MM")); 1963 return (-1); 1964 } 1965 1966 /* 1967 * Create DRIVECARTRIDGEACCESS 1968 */ 1969 task = dm_bld_task("create-drive-cart-access"); 1970 unmnttime = dm_timestamp(); 1971 create_cmd = mms_strnew("create task['%s'] " 1972 "type [ DRIVECARTRIDGEACCESS ] " 1973 "set[DRIVECARTRIDGEACCESS.'DriveName' '%s' ] " 1974 "set[DRIVECARTRIDGEACCESS.'DMName' '%s' ] " 1975 "set[DRIVECARTRIDGEACCESS.'CartridgeID' '%s' ] " 1976 "set[DRIVECARTRIDGEACCESS.'SideName' '%s' ] " 1977 "set[DRIVECARTRIDGEACCESS.'PartitionName' '%s' ] " 1978 "set[DRIVECARTRIDGEACCESS.'ApplicationName' '%s' ] " 1979 "set[DRIVECARTRIDGEACCESS.'CartridgePCL' '%s' ] " 1980 "set[DRIVECARTRIDGEACCESS.'DriveSerialNum' '%s' ] " 1981 "set[DRIVECARTRIDGEACCESS.'CartridgeShapeName' '%s' ] " 1982 "set[DRIVECARTRIDGEACCESS.'DriveShapeName' '%s' ] " 1983 "set[DRIVECARTRIDGEACCESS.'DriveCartridgeAccessTimeMount' '%s' ] " 1984 "set[DRIVECARTRIDGEACCESS." 1985 "'DriveCartridgeAccessTimeUnmount' '%s' ] " 1986 "set[DRIVECARTRIDGEACCESS." 1987 "'DriveCartridgeAccessByteReadCount' '%lld' ] " 1988 "set[DRIVECARTRIDGEACCESS." 1989 "'DriveCartridgeAccessMediumByteReadCount' '%lld' ] " 1990 "set[DRIVECARTRIDGEACCESS." 1991 "'DriveCartridgeAccessByteWriteCount' '%lld' ] " 1992 "set[DRIVECARTRIDGEACCESS." 1993 "'DriveCartridgeAccessMediumByteWriteCount' '%lld' ] " 1994 "set[DRIVECARTRIDGEACCESS." 1995 "'DriveCartridgeAccessHardReadErrorCount' '%d' ] " 1996 "set[DRIVECARTRIDGEACCESS." 1997 "'DriveCartridgeAccessSoftReadErrorCount' '%d' ] " 1998 "set[DRIVECARTRIDGEACCESS." 1999 "'DriveCartridgeAccessHardWriteErrorCount' '%d' ] " 2000 "set[DRIVECARTRIDGEACCESS." 2001 "'DriveCartridgeAccessSoftWriteErrorCount' '%d' ] " 2002 ";", task, DRVNAME, DMNAME, 2003 dca->dca_cart_id == NULL ? "None" : dca->dca_cart_id, 2004 dca->dca_side_name == NULL ? "None" : dca->dca_side_name, 2005 dca->dca_part_name == NULL ? "None" : dca->dca_part_name, 2006 dca->dca_app_name == NULL ? "None" : dca->dca_app_name, 2007 dca->dca_pcl == NULL ? "None" : dca->dca_pcl, 2008 drv->drv_serial_num == NULL ? "None" : drv->drv_serial_num, 2009 dca->dca_cart_shape_name == 2010 NULL ? "None" : dca->dca_cart_shape_name, 2011 dca->dca_drv_shape_name == NULL ? "None" : dca->dca_drv_shape_name, 2012 dca->dca_mounted_last, 2013 unmnttime, 2014 dca->dca_bytes_read, 2015 dca->dca_bytes_read_med, 2016 dca->dca_bytes_written, 2017 dca->dca_bytes_written_med, 2018 dca->dca_read_err, 2019 dca->dca_rcvd_read_err, 2020 dca->dca_write_err, 2021 dca->dca_rcvd_write_err); 2022 free(unmnttime); 2023 cmd = dm_send_cmd(create_cmd, dm_cmd_response, task); 2024 free(task); 2025 free(create_cmd); 2026 if (cmd == NULL || cmd->cmd_rc != 0) { 2027 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2028 "send drive cartridge access error")); 2029 if (cmd) { 2030 dm_destroy_cmd(cmd); 2031 } 2032 return (-1); 2033 } 2034 2035 dm_destroy_dca(); 2036 dm_destroy_cmd(cmd); 2037 return (0); 2038 } 2039 2040 void 2041 dm_destroy_dca(void) 2042 { 2043 if (dca->dca_side_name) 2044 free(dca->dca_side_name); 2045 if (dca->dca_part_name) 2046 free(dca->dca_part_name); 2047 if (dca->dca_app_name) 2048 free(dca->dca_app_name); 2049 if (dca->dca_cart_id) 2050 free(dca->dca_cart_id); 2051 if (dca->dca_mounted_last) 2052 free(dca->dca_mounted_last); 2053 if (dca->dca_cart_shape_name) 2054 free(dca->dca_cart_shape_name); 2055 if (dca->dca_drv_shape_name) 2056 free(dca->dca_drv_shape_name); 2057 if (dca->dca_pcl) 2058 free(dca->dca_pcl); 2059 memset(dca, 0, sizeof (drv_cart_access_t)); 2060 } 2061 2062 char * 2063 dm_timestamp(void) 2064 { 2065 struct timeval tv; 2066 struct tm *cl; 2067 char *buf; 2068 2069 gettimeofday(&tv, NULL); 2070 time(&tv.tv_sec); 2071 cl = localtime(&tv.tv_sec); 2072 buf = mms_strnew("%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d.%3.3d", 2073 cl->tm_year + 1900, 2074 cl->tm_mon + 1, 2075 cl->tm_mday, 2076 cl->tm_hour, 2077 cl->tm_min, 2078 cl->tm_sec, 2079 (int32_t)tv.tv_usec / 1000); 2080 return (buf); 2081 } 2082 2083 void 2084 dm_mms_to_db_time(char *db) 2085 { 2086 db[4] = '-'; 2087 db[7] = '-'; 2088 db[13] = ':'; 2089 db[16] = ':'; 2090 db[19] = '.'; 2091 } 2092 2093 int 2094 dm_send_drive_broken(void) 2095 { 2096 char *attr_cmd; 2097 char *task; 2098 dm_command_t *cmd; 2099 2100 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 2101 TRACE((MMS_ERR, "No connection to MM")); 2102 return (-1); 2103 } 2104 2105 task = dm_bld_task("set-drive-broken"); 2106 attr_cmd = mms_strnew("attribute task['%s'] " 2107 "match[ streq(DRIVE.'DriveName' '%s') ] " 2108 "set[DRIVE.'DriveBroken' '%s'] " 2109 ";", task, DRVNAME, "true"); 2110 cmd = dm_send_cmd(attr_cmd, dm_cmd_response, task); 2111 free(attr_cmd); 2112 free(task); 2113 if (cmd == NULL || cmd->cmd_rc != 0) { 2114 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2115 "send drive broken error")); 2116 if (cmd) { 2117 dm_destroy_cmd(cmd); 2118 } 2119 return (-1); 2120 } 2121 dm_destroy_cmd(cmd); 2122 return (0); 2123 } 2124 2125 int 2126 dm_send_cartridge_media_error(void) 2127 { 2128 char *attr_cmd; 2129 char *task; 2130 dm_command_t *cmd; 2131 2132 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 2133 TRACE((MMS_ERR, "No connection to MM")); 2134 return (-1); 2135 } 2136 2137 task = dm_bld_task("set-cart-media-error"); 2138 attr_cmd = mms_strnew("attribute task['%s'] " 2139 "match[ and (streq(CARTRIDGE.'CartridgePCL' '%s') " 2140 "streq(SIDE.'SideName' '%s') " 2141 "streq(PARTITION.'PartitionName' '%s') " 2142 "streq(DRIVE.'DriveName' '%s'))]" 2143 "set[CARTRIDGE.'CartridgeMediaError' '%s'] " 2144 ";", 2145 task, dca->dca_pcl, dca->dca_side_name, dca->dca_part_name, 2146 drv->drv_drvname, 2147 "yes"); 2148 cmd = dm_send_cmd(attr_cmd, dm_cmd_response, task); 2149 free(attr_cmd); 2150 free(task); 2151 if (cmd == NULL || cmd->cmd_rc != 0) { 2152 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2153 "send cartridge media error error")); 2154 if (cmd) { 2155 dm_destroy_cmd(cmd); 2156 } 2157 return (-1); 2158 } 2159 dm_destroy_cmd(cmd); 2160 return (0); 2161 } 2162 2163 int 2164 dm_show_drive_dmname(char **dmname) 2165 { 2166 char *show_cmd; 2167 char *task; 2168 mms_par_node_t *root; 2169 dm_command_t *cmd; 2170 char *val; 2171 2172 *dmname = NULL; 2173 task = dm_bld_task("drive-dmname"); 2174 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 2175 "match[ streq(DRIVE.'DriveName' '%s') ] " 2176 "report[DRIVE.'DMName'] ;", task, DRVNAME); 2177 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 2178 free(show_cmd); 2179 free(task); 2180 if (cmd == NULL || cmd->cmd_rc != 0) { 2181 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2182 "send show command error")); 2183 if (cmd) { 2184 dm_destroy_cmd(cmd); 2185 } 2186 return (-1); 2187 } 2188 root = cmd->cmd_root; 2189 2190 /* 2191 * Save drive dmname 2192 */ 2193 val = dm_get_attr_value(root, "DRIVE", "DMName"); 2194 if (val == NULL) { 2195 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2196 "unable to get drive DMName")); 2197 if (cmd) { 2198 dm_destroy_cmd(cmd); 2199 } 2200 return (-1); 2201 } 2202 2203 *dmname = strdup(val); 2204 2205 dm_destroy_cmd(cmd); 2206 return (0); 2207 } 2208 2209 int 2210 dm_show_system(mms_par_node_t ** root) 2211 { 2212 char *show_cmd; 2213 char *task; 2214 dm_command_t *cmd; 2215 2216 task = dm_bld_task("show-system"); 2217 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 2218 "report[SYSTEM] ;", task); 2219 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 2220 free(show_cmd); 2221 free(task); 2222 if (cmd == NULL || cmd->cmd_rc != 0) { 2223 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2224 "unable to send show SYSTEM command")); 2225 if (cmd) { 2226 dm_destroy_cmd(cmd); 2227 } 2228 return (-1); 2229 } 2230 2231 *root = cmd->cmd_root; 2232 cmd->cmd_root = NULL; 2233 dm_destroy_cmd(cmd); 2234 return (0); 2235 } 2236 2237 int 2238 dm_show_drive(mms_par_node_t ** root) 2239 { 2240 char *show_cmd; 2241 char *task; 2242 dm_command_t *cmd; 2243 2244 task = dm_bld_task("show-drive"); 2245 show_cmd = mms_strnew("show task['%s'] reportmode[namevalue] " 2246 "match[ streq(DRIVE.'DriveName' '%s') ] " 2247 "report[DRIVE] ;", 2248 task, DRVNAME); 2249 cmd = dm_send_cmd(show_cmd, dm_cmd_response, task); 2250 free(show_cmd); 2251 free(task); 2252 if (cmd == NULL || cmd->cmd_rc != 0) { 2253 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2254 "send show drive error")); 2255 if (cmd) { 2256 dm_destroy_cmd(cmd); 2257 } 2258 return (-1); 2259 } 2260 *root = cmd->cmd_root; 2261 cmd->cmd_root = NULL; 2262 dm_destroy_cmd(cmd); 2263 return (0); 2264 } 2265 2266 int 2267 dm_cmd_response(dm_command_t *cmd) 2268 { 2269 mms_par_node_t *root; 2270 mms_par_node_t *id = NULL; 2271 mms_par_node_t *man = NULL; 2272 mms_par_node_t *mod = NULL; 2273 mms_par_node_t *msgid = NULL; 2274 mms_par_node_t *work = NULL; 2275 2276 root = mms_pn_lookup(cmd->cmd_root, NULL, MMS_PN_CMD, NULL); 2277 switch (cmd->cmd_state) { 2278 case 0: 2279 /* 2280 * check for accept 2281 */ 2282 if (dm_responded_with(cmd, "accepted")) { 2283 TRACE((MMS_INFO, "Command %s accepted", 2284 mms_pn_token(root))); 2285 cmd->cmd_state++; 2286 return (DM_CONTINUE); 2287 } else if (dm_responded_with(cmd, "unacceptable")) { 2288 id = mms_pn_lookup(root, "id", MMS_PN_CLAUSE, 2289 NULL); 2290 if (id != NULL) { 2291 work = NULL; 2292 man = mms_pn_lookup(id, NULL, 2293 MMS_PN_STRING, &work); 2294 mod = mms_pn_lookup(id, NULL, 2295 MMS_PN_STRING, &work); 2296 msgid = mms_pn_lookup(id, NULL, 2297 MMS_PN_STRING, &work); 2298 } 2299 TRACE((MMS_ERR, "Command %s unacceptable, " 2300 "manufacturer '%s', model '%s', msgid '%s'", 2301 mms_pn_token(root), 2302 man == NULL ? "[none]" : mms_pn_token(man), 2303 mod == NULL ? "[none]" : mms_pn_token(mod), 2304 msgid == NULL ? "[none]" : mms_pn_token(msgid))); 2305 cmd->cmd_rc = -1; 2306 } else if (dm_responded_with(cmd, "cancelled")) { 2307 id = mms_pn_lookup(root, "id", MMS_PN_CLAUSE, 2308 NULL); 2309 if (id != NULL) { 2310 work = NULL; 2311 man = mms_pn_lookup(id, NULL, 2312 MMS_PN_STRING, &work); 2313 mod = mms_pn_lookup(id, NULL, 2314 MMS_PN_STRING, &work); 2315 msgid = mms_pn_lookup(id, NULL, 2316 MMS_PN_STRING, &work); 2317 } 2318 TRACE((MMS_ERR, "Command %s cancelled, " 2319 "manufacturer '%s', model '%s', msgid '%s'", 2320 mms_pn_token(root), 2321 man == NULL ? "[none]" : mms_pn_token(man), 2322 mod == NULL ? "[none]" : mms_pn_token(mod), 2323 msgid == NULL ? "[none]" : 2324 mms_pn_token(msgid))); 2325 cmd->cmd_rc = -1; 2326 } 2327 return (DM_COMPLETE); 2328 2329 case 1: 2330 /* 2331 * check for success 2332 */ 2333 if (dm_responded_with(cmd, "success")) { 2334 return (DM_COMPLETE); 2335 } else if (dm_responded_with(cmd, "cancelled")) { 2336 TRACE((MMS_CRIT, "Unable to config DM, " 2337 "command cancelled")); 2338 cmd->cmd_rc = -1; 2339 return (DM_COMPLETE); 2340 } else if (dm_responded_with(cmd, "error")) { 2341 TRACE((MMS_CRIT, "Unable to config DM, " 2342 "command had error")); 2343 cmd->cmd_rc = -1; 2344 return (DM_COMPLETE); 2345 } else { 2346 TRACE((MMS_CRIT, "Unexpected response from MM")); 2347 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2348 "Unexpected response from MM")); 2349 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 2350 DM_EXIT(DM_NO_RESTART); 2351 } 2352 default: 2353 /* 2354 * Should not happen 2355 */ 2356 TRACE((MMS_CRIT, "Unexpected cmd state: %d", cmd->cmd_state)); 2357 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2358 "Unexpected cmd state: %d", cmd->cmd_state)); 2359 DM_MSG_SEND((DM_ADM_ERR, DM_6526_MSG, DM_MSG_REASON)); 2360 DM_EXIT(DM_RESTART); 2361 } 2362 2363 return (DM_COMPLETE); 2364 } 2365 2366 void 2367 dm_dispatch_cmds(void) 2368 { 2369 dm_command_t *cmd; 2370 dm_command_t *next; 2371 int rc = DM_NOT_COMPLETE; /* not complete yet */ 2372 2373 pthread_mutex_lock(&wka->dm_worker_mutex); 2374 while (wka->dm_cmd_dispatchable) { 2375 wka->dm_cmd_dispatchable = 0; 2376 pthread_mutex_unlock(&wka->dm_worker_mutex); 2377 /* Dispatch commands */ 2378 pthread_mutex_lock(&wka->dm_queue_mutex); 2379 mms_list_foreach_safe(&wka->dm_cmd_queue, cmd, next) { 2380 if (cmd->cmd_flags & CMD_DISPATCHABLE) { 2381 cmd->cmd_flags &= ~CMD_DISPATCHABLE; 2382 /* 2383 * dispatch the command 2384 */ 2385 dm_msg_destroy(); /* clean up messages */ 2386 if (cmd->cmd_func != NULL) { 2387 pthread_mutex_unlock(&wka-> 2388 dm_queue_mutex); 2389 rc = (cmd->cmd_func) (cmd); 2390 pthread_mutex_lock(&wka-> 2391 dm_queue_mutex); 2392 next = mms_list_next(&wka->dm_cmd_queue, 2393 cmd); 2394 } 2395 if (rc == DM_COMPLETE) { 2396 if (cmd->cmd_flags & CMD_INCOMING) { 2397 /* Incoming command completes */ 2398 mms_list_remove(&wka-> 2399 dm_cmd_queue, cmd); 2400 dm_destroy_cmd(cmd); 2401 } 2402 } 2403 dm_msg_destroy(); /* clean up messages */ 2404 } 2405 } 2406 pthread_mutex_unlock(&wka->dm_queue_mutex); 2407 pthread_mutex_lock(&wka->dm_worker_mutex); 2408 } 2409 pthread_mutex_unlock(&wka->dm_worker_mutex); 2410 } 2411 2412 void 2413 dm_destroy_cmd(dm_command_t *cmd) 2414 { 2415 if (cmd->cmd_root) { 2416 mms_pn_destroy(cmd->cmd_root); 2417 } 2418 if (cmd->cmd_task) { 2419 free(cmd->cmd_task); 2420 } 2421 if (cmd->cmd_textcmd) { 2422 free(cmd->cmd_textcmd); 2423 } 2424 free(cmd); 2425 } 2426 2427 dm_command_t * 2428 dm_send_cmd(char *cmdbuf, int (*cmd_func) (dm_command_t *), char *task) 2429 { 2430 dm_command_t *cmd; 2431 2432 /* Build dm_command_t */ 2433 cmd = (dm_command_t *)malloc(sizeof (dm_command_t)); 2434 if (cmd == NULL) { 2435 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2436 "send command error: out of memory")); 2437 return (NULL); 2438 } 2439 memset(cmd, 0, sizeof (dm_command_t)); 2440 cmd->cmd_textcmd = strdup(cmdbuf); 2441 cmd->cmd_func = cmd_func; 2442 cmd->cmd_task = strdup(task); 2443 pthread_cond_init(&cmd->cmd_done_cv, NULL); 2444 pthread_mutex_init(&cmd->cmd_done_mutex, NULL); 2445 2446 /* Put command in cmd_queue */ 2447 pthread_mutex_lock(&wka->dm_queue_mutex); 2448 mms_list_insert_tail(&wka->dm_cmd_queue, cmd); 2449 pthread_mutex_unlock(&wka->dm_queue_mutex); 2450 /* send cmd */ 2451 if (dm_writer(cmdbuf) != 0) { 2452 pthread_mutex_lock(&wka->dm_queue_mutex); 2453 mms_list_remove(&wka->dm_cmd_queue, cmd); 2454 TRACE((MMS_DEBUG, "send cmd %p removed from dm_cmd_queue", 2455 cmd)); 2456 pthread_mutex_unlock(&wka->dm_queue_mutex); 2457 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_COMMUNICATION, 2458 "unable to send command to MM: socket write error")); 2459 dm_destroy_cmd(cmd); 2460 return (NULL); 2461 } 2462 2463 /* 2464 * Wait for command to complete 2465 */ 2466 mms_trace_flush(); 2467 pthread_mutex_lock(&cmd->cmd_done_mutex); 2468 while ((cmd->cmd_flags & CMD_COMPLETE) == 0) { 2469 pthread_cond_wait(&cmd->cmd_done_cv, &cmd->cmd_done_mutex); 2470 } 2471 pthread_mutex_unlock(&cmd->cmd_done_mutex); 2472 2473 pthread_mutex_lock(&wka->dm_queue_mutex); 2474 mms_list_remove(&wka->dm_cmd_queue, cmd); 2475 pthread_mutex_unlock(&wka->dm_queue_mutex); 2476 2477 pthread_cond_destroy(&cmd->cmd_done_cv); 2478 pthread_mutex_destroy(&cmd->cmd_done_mutex); 2479 2480 return (cmd); 2481 } 2482 2483 int 2484 dm_setup_incoming_cmd(dm_command_t *cmd) 2485 { 2486 mms_par_node_t *root; 2487 2488 mms_trace_flush(); 2489 root = mms_pn_lookup(cmd->cmd_root, NULL, MMS_PN_CMD, NULL); 2490 if (strcmp(mms_pn_token(root), "activate") == 0) { 2491 cmd->cmd_func = dm_activate_cmd; 2492 } else if (strcmp(mms_pn_token(root), "attach") == 0) { 2493 cmd->cmd_func = dm_attach_cmd; 2494 } else if (strcmp(mms_pn_token(root), "private") == 0) { 2495 cmd->cmd_func = dm_dmpm_private_cmd; 2496 } else if (strcmp(mms_pn_token(root), "load") == 0) { 2497 cmd->cmd_func = dm_load_cmd; 2498 } else if (strcmp(mms_pn_token(root), "identify") == 0) { 2499 cmd->cmd_func = dm_identify_cmd; 2500 } else if (strcmp(mms_pn_token(root), "detach") == 0) { 2501 cmd->cmd_func = dm_detach_cmd; 2502 } else if (strcmp(mms_pn_token(root), "unload") == 0) { 2503 cmd->cmd_func = dm_unload_cmd; 2504 } else if (strcmp(mms_pn_token(root), "reset") == 0) { 2505 cmd->cmd_func = (int (*)(dm_command_t *))dm_reset_cmd; 2506 } else if (strcmp(mms_pn_token(root), "exit") == 0) { 2507 cmd->cmd_func = (int (*)(dm_command_t *))dm_exit_cmd; 2508 } else { 2509 /* Unknown command */ 2510 DM_MSG_ADD((MMS_INVALID, MMS_DM_E_UNSUPPORTED, 2511 "Unsupported command %s", mms_pn_token(root))); 2512 return (-1); 2513 } 2514 return (0); 2515 } 2516 2517 int 2518 dm_send_config(void) 2519 { 2520 char *cfg_cmd; 2521 char *task; 2522 dm_command_t *cmd; 2523 2524 task = dm_bld_task("config"); 2525 cfg_cmd = dm_bld_config_cmd(task); 2526 if (cfg_cmd == NULL) { 2527 free(task); 2528 return (-1); 2529 } 2530 cmd = dm_send_cmd(cfg_cmd, dm_cmd_response, task); 2531 free(task); 2532 free(cfg_cmd); 2533 if (cmd == NULL || cmd->cmd_rc != 0) { 2534 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2535 "send config command error")); 2536 if (cmd) { 2537 dm_destroy_cmd(cmd); 2538 } 2539 return (-1); 2540 } 2541 2542 dm_destroy_cmd(cmd); 2543 return (0); 2544 } 2545 2546 int 2547 dm_activate_cmd(dm_command_t *cmd) 2548 { 2549 mms_par_node_t *node; 2550 int rc; 2551 2552 node = mms_pn_lookup(cmd->cmd_root, NULL, MMS_PN_KEYWORD, NULL); 2553 if (strcmp(mms_pn_token(node), "enable") == 0) { 2554 /* Enable DM */ 2555 rc = dm_activate_enable(cmd); 2556 } else if (strcmp(mms_pn_token(node), "disable") == 0) { 2557 /* Disable DM */ 2558 rc = dm_activate_disable(cmd); 2559 } else if (strcmp(mms_pn_token(node), "reserve") == 0) { 2560 /* Reserve Drive */ 2561 rc = dm_activate_reserve(cmd); 2562 } else if (strcmp(mms_pn_token(node), "release") == 0) { 2563 /* Release Drive */ 2564 rc = dm_activate_release(cmd); 2565 } 2566 2567 return (rc); 2568 } 2569 2570 /* 2571 * Activate DM 2572 * - send contact drive and send config 2573 */ 2574 int 2575 dm_activate_enable(dm_command_t *cmd) 2576 { 2577 if (drv->drv_flags & DRV_ENABLED) { 2578 /* Already enabled */ 2579 DM_MSG_ADD((MMS_STATE, MMS_DM_E_ENABLED, 2580 "already enabled")); 2581 goto error; 2582 } 2583 2584 /* 2585 * Have to re-open the DM device to unbind the target device 2586 * so that we may probe all the devices to find the one with 2587 * the matching serial number. 2588 */ 2589 if (dm_open_dm_device() != 0) { 2590 DM_MSG_ADD((MMS_STATE, MMS_DM_E_INTERNAL, 2591 "reopen DM device error")); 2592 goto error; 2593 } 2594 2595 /* 2596 * default size of sense data 2597 */ 2598 drv->drv_mtee_stat_len = sizeof (struct scsi_extended_sense); 2599 2600 /* 2601 * Close all the device dynamic libraries 2602 */ 2603 if (wka->dm_default_lib_hdl) { 2604 dlclose(wka->dm_default_lib_hdl); 2605 } 2606 if (wka->dm_dev_lib_hdl) { 2607 dlclose(wka->dm_dev_lib_hdl); 2608 } 2609 2610 /* 2611 * Load default device library 2612 */ 2613 if (dm_load_default_lib() != 0) { 2614 goto error1; 2615 } 2616 2617 /* 2618 * Get system options 2619 */ 2620 if (dm_get_system_options() != 0) { 2621 goto error1; 2622 } 2623 2624 /* 2625 * Get DM target path 2626 */ 2627 if (dm_get_target_base() != 0 || 2628 wka->dm_target_base == NULL) { 2629 goto error1; 2630 } 2631 2632 /* 2633 * configure device 2634 */ 2635 if (dm_stat_targ_base() != 0) { 2636 goto error1; 2637 } 2638 2639 /* 2640 * Connect to target drive 2641 */ 2642 if (dm_bind_target() != 0) { 2643 goto error1; 2644 } 2645 /* 2646 * Load the device dependent library 2647 */ 2648 if (dm_load_devlib() != 0) { 2649 goto error1; 2650 } 2651 2652 if (DRV_CALL(drv_rebind_target, ()) != 0) { 2653 goto error1; 2654 } 2655 2656 if (DRV_CALL(drv_init_dev, ())) { 2657 goto error1; 2658 } 2659 2660 /* 2661 * Get sense data size 2662 */ 2663 dm_init_sense_buf(); 2664 2665 if (dm_update_drivetype() != 0) { 2666 goto error1; 2667 } 2668 2669 /* 2670 * Make prsv key and set it in dmd. 2671 */ 2672 DRV_CALL(drv_mk_prsv_key, ()); 2673 2674 /* 2675 * Set up disallowed USCSI commands and ioctl 2676 */ 2677 DRV_CALL(drv_disallowed, ()); 2678 2679 /* 2680 * Tell driver we are ready 2681 */ 2682 ioctl(wka->dm_drm_fd, DRM_DM_READY, 1); 2683 TRACE((MMS_DEVP, "main: DM is ready")); 2684 2685 /* 2686 * Send config to MM 2687 */ 2688 if (dm_send_config() != 0) { 2689 goto error1; 2690 } 2691 2692 drv->drv_flags |= DRV_ENABLED; 2693 dm_resp_success(cmd->cmd_task, NULL); 2694 2695 return (DM_COMPLETE); 2696 2697 error1: 2698 (void) dm_send_ready_disconnected(DM_6501_MSG, "type", "enable", 2699 DM_MSG_REASON); 2700 error: 2701 dm_resp_error(cmd->cmd_task, DM_6501_MSG, "type", "enable", 2702 DM_MSG_REASON); 2703 return (DM_COMPLETE); 2704 } 2705 2706 /* 2707 * Activate DM 2708 * - reserve the drive 2709 */ 2710 int 2711 dm_activate_reserve(dm_command_t *cmd) 2712 { 2713 /* 2714 * Start timing mount time 2715 */ 2716 gettimeofday(&wka->dm_mnt_start, NULL); 2717 2718 /* 2719 * Get system options. Use what we know if error. 2720 */ 2721 if (dm_get_system_options() != 0) { 2722 goto error; 2723 } 2724 2725 /* 2726 * Check if reserve drive 2727 */ 2728 if ((wka->dm_flags & DM_RESERVE_DRIVE) == 0) { 2729 /* Don't reserve drive */ 2730 goto success; 2731 } 2732 2733 /* 2734 * Reserve target 2735 */ 2736 if (dm_reserve_target() != 0) { 2737 goto error; 2738 } 2739 success: 2740 dm_resp_success(cmd->cmd_task, NULL); 2741 return (DM_COMPLETE); 2742 2743 error: 2744 dm_resp_error(cmd->cmd_task, DM_6501_MSG, "type", "reserve", 2745 DM_MSG_REASON); 2746 return (DM_COMPLETE); 2747 } 2748 2749 int 2750 dm_activate_release(dm_command_t *cmd) 2751 { 2752 if ((wka->dm_flags & DM_RESERVE_DRIVE) == 0) { 2753 /* Didn't reserve drive */ 2754 dm_resp_success(cmd->cmd_task, NULL); 2755 return (DM_COMPLETE); 2756 } 2757 2758 if (drv->drv_flags & DRV_RESERVED) { 2759 /* 2760 * Release is always successful. 2761 * If there is any problem, let 2762 * activate reserve take care of it. 2763 */ 2764 if (drv->drv_flags & DRV_USE_PRSV) { 2765 /* Do persistent release */ 2766 if (DRV_CALL(drv_prsv_register, ()) || 2767 DRV_CALL(drv_prsv_release, ())) { 2768 goto error; 2769 } 2770 /* Do SCSI release */ 2771 } else if (DRV_CALL(drv_release, ()) != 0) { 2772 goto error; 2773 } 2774 } 2775 dm_resp_success(cmd->cmd_task, NULL); 2776 return (DM_COMPLETE); 2777 2778 error: 2779 dm_resp_error(cmd->cmd_task, DM_6501_MSG, "type", "release", 2780 DM_MSG_REASON); 2781 return (DM_COMPLETE); 2782 } 2783 2784 int 2785 dm_activate_disable(dm_command_t *cmd) 2786 { 2787 /* success */ 2788 drv->drv_flags &= ~DRV_ENABLED; 2789 dm_resp_success(cmd->cmd_task, NULL); 2790 2791 return (DM_COMPLETE); 2792 } 2793 2794 int 2795 dm_dmpm_private_cmd(dm_command_t *cmd) 2796 { 2797 int len; 2798 2799 memset(mnt, 0, sizeof (drv_mount_t)); 2800 mnt->mnt_blksize = -1; 2801 mnt->mnt_fseq = -1; /* fseq not specified */ 2802 if (dm_get_mount_options(cmd) != 0) { 2803 /* had error */ 2804 dm_resp_error(cmd->cmd_task, DM_6507_MSG, DM_MSG_REASON); 2805 return (DM_COMPLETE); 2806 } 2807 /* 2808 * If a private cmd for mounting, check to see if authorized to 2809 * use tape 2810 */ 2811 if (mnt->mnt_user) { 2812 if (dm_chk_dev_auth(mnt->mnt_user) != 0) { 2813 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2814 "User %s is not authorized to use MMS", 2815 mnt->mnt_user)); 2816 dm_resp_error(cmd->cmd_task, DM_6527_MSG, 2817 DM_MSG_REASON); 2818 return (DM_COMPLETE); 2819 } 2820 } 2821 2822 /* 2823 * Set up default options 2824 */ 2825 if (mnt->mnt_fseq == -1) { 2826 mnt->mnt_fseq = 1; 2827 } 2828 if (mnt->mnt_vid == NULL && mnt->mnt_pcl != NULL) { 2829 mnt->mnt_vid = strdup(mnt->mnt_pcl); 2830 } 2831 if (mnt->mnt_fname == NULL && mnt->mnt_volumename != NULL) { 2832 /* Filename defaults to volumename */ 2833 mnt->mnt_fname = malloc(18); 2834 if (mnt->mnt_fname == NULL) { 2835 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 2836 "out of memory")); 2837 dm_resp_error(cmd->cmd_task, DM_6506_MSG, 2838 DM_MSG_REASON); 2839 return (DM_COMPLETE); 2840 } 2841 memset(mnt->mnt_fname, ' ', 17); 2842 mnt->mnt_fname[17] = '\0'; 2843 len = strlen(mnt->mnt_volumename); 2844 if (len > 17) { 2845 strncpy(mnt->mnt_fname, 2846 mnt->mnt_volumename + (len - 17), 17); 2847 } else { 2848 strncpy(mnt->mnt_fname, mnt->mnt_volumename, len); 2849 } 2850 } 2851 if (mnt->mnt_flags & MNT_MMS) { 2852 /* In MMS mode */ 2853 if (!(mnt->mnt_flags & (MNT_BSD | MNT_NOBSD | MNT_MMS_TM))) { 2854 /* set default if no TM processing option */ 2855 mnt->mnt_flags |= MNT_MMS_TM; 2856 } 2857 } else { 2858 /* 2859 * Raw mode 2860 */ 2861 if (!(mnt->mnt_flags & (MNT_BSD | MNT_NOBSD | MNT_MMS_TM))) { 2862 /* set default if no TM processing option */ 2863 mnt->mnt_flags |= MNT_NOBSD; 2864 } 2865 } 2866 2867 dm_resp_success(cmd->cmd_task, NULL); 2868 2869 return (DM_COMPLETE); 2870 } 2871 2872 int 2873 dm_get_mount_options(dm_command_t *cmd) 2874 { 2875 mms_par_node_t *name; 2876 mms_par_node_t *val; 2877 mms_par_node_t *set; 2878 mms_par_node_t *work = NULL; 2879 char *np; 2880 char *vp; 2881 char *errtok; 2882 int len; 2883 mms_trace_sev_t sev; 2884 2885 /* 2886 * Check if mount options 2887 */ 2888 for (set = mms_pn_lookup(cmd->cmd_root, "set", 2889 MMS_PN_CLAUSE, &work); 2890 set != NULL; 2891 set = mms_pn_lookup(cmd->cmd_root, "set", 2892 MMS_PN_CLAUSE, &work)) { 2893 /* look for set cap. If found then this is mount option */ 2894 if (mms_pn_lookup(set, "cap", MMS_PN_STRING, NULL)) { 2895 /* Mount options, clean out mnttab */ 2896 dm_destroy_mnt(); 2897 } 2898 } 2899 2900 work = NULL; 2901 for (set = mms_pn_lookup(cmd->cmd_root, "set", 2902 MMS_PN_CLAUSE, &work); 2903 set != NULL; 2904 set = mms_pn_lookup(cmd->cmd_root, "set", 2905 MMS_PN_CLAUSE, &work)) { 2906 mnt->mnt_flags &= ~MNT_PRIVILEGED; 2907 mms_list_pair_foreach(&set->pn_arglist, name, val) { 2908 np = mms_pn_token(name); 2909 vp = mms_pn_token(val); 2910 if (strcmp(np, "filename") == 0) { 2911 dm_trim_tail(vp); 2912 if (strlen(vp) > DRV_LBN_LEN) { 2913 vp += (strlen(vp) - DRV_LBN_LEN); 2914 } 2915 dm_to_upper(vp); 2916 mnt->mnt_fname = malloc(18); 2917 memset(mnt->mnt_fname, ' ', 17); 2918 mnt->mnt_fname[17] = '\0'; 2919 len = strlen(vp); 2920 if (len > 17) { 2921 /* Get last 17 chars from name */ 2922 strncpy(mnt->mnt_fname, 2923 vp + (len - 17), 17); 2924 } else { 2925 strncpy(mnt->mnt_fname, vp, len); 2926 } 2927 } else if (strcmp(np, "volumeid") == 0) { 2928 /* VID must be in uppercase */ 2929 dm_to_upper(vp); 2930 mnt->mnt_vid = malloc(7); 2931 memset(mnt->mnt_vid, ' ', 6); 2932 mnt->mnt_vid[6] = '\0'; 2933 strncpy(mnt->mnt_vid, vp, strlen(vp)); 2934 } else if (strcmp(np, "CartridgePCL") == 0) { 2935 dm_to_upper(vp); 2936 mnt->mnt_pcl = strdup(vp); 2937 } else if (strcmp(np, "user") == 0) { 2938 mnt->mnt_user = strdup(vp); 2939 } else if (strcmp(np, "VolumeName") == 0) { 2940 mnt->mnt_volumename = strdup(vp); 2941 } else if (strcmp(np, "blocksize") == 0) { 2942 sscanf(vp, "%d", &mnt->mnt_blksize); 2943 } else if (strcmp(np, "defaultblocksize") == 0) { 2944 sscanf(vp, "%d", &mnt->mnt_dflt_blksize); 2945 } else if (strcmp(np, "cap") == 0) { 2946 errtok = dm_get_capabilities(vp); 2947 if (errtok != NULL) { 2948 /* Have an invalid capability */ 2949 return (-1); 2950 } 2951 } else if (strcmp(np, "DMMessageLevel") == 0) { 2952 wka->dm_msg_level = mms_msg_get_severity(vp); 2953 } else if (strcmp(np, "TraceLevel") == 0) { 2954 (void) mms_trace_str2sev(vp, &sev); 2955 (void) mms_trace_filter(sev); 2956 } else if (strcmp(np, "TraceFileSize") == 0) { 2957 (void) mms_trace_set_fsize(vp); 2958 } else if (strcmp(np, "privileged") == 0) { 2959 if (strcmp(vp, "true") == 0) { 2960 mnt->mnt_flags |= MNT_PRIVILEGED; 2961 } 2962 } else if (strcmp(np, "SystemDiskMountTimeout") == 0) { 2963 sscanf(vp, "%d", &drv->drv_disk_mount_timeout); 2964 } 2965 /* Ignore unknown attributes */ 2966 } 2967 } 2968 return (0); 2969 } 2970 2971 int 2972 dm_attach_cmd(dm_command_t *cmd) 2973 { 2974 mms_par_node_t *approot; 2975 mms_par_node_t *root; 2976 char *handle; 2977 struct passwd pwd; 2978 struct passwd *pwent; 2979 time_t t; 2980 int err; 2981 int i; 2982 char tbuf[] = "YYYYMMDDhhmmss"; 2983 uint64_t max_cap; 2984 int try = 0; 2985 char *val; 2986 2987 if (drv->drv_flags & DRV_ATTACHED) { 2988 /* Drive already attached */ 2989 DM_MSG_ADD((MMS_STATE, MMS_DM_E_INTERNAL, 2990 "already attached")); 2991 dm_resp_error(cmd->cmd_task, DM_6508_MSG, DM_MSG_REASON); 2992 /* 2993 * Something is very wrong here because MM has not done 2994 * a detach. Restart and cleanup. 2995 */ 2996 DM_MSG_SEND((DM_ADM_ERR, DM_6524_MSG, DM_MSG_REASON)); 2997 DM_EXIT(DM_RESTART); 2998 } 2999 3000 /* 3001 * Create a handle for application 3002 */ 3003 time(&t); 3004 strftime(tbuf, sizeof (tbuf), "%Y""%m""%d""%H""%M""%S", localtime(&t)); 3005 handle = mms_strnew("%s/%s.%d.%s-%s", MMS_HDL_DIR, wka->dm_hdl_prefix, 3006 wka->dm_counter++, tbuf, mnt->mnt_pcl); 3007 /* Replace blanks in handle with '-' */ 3008 for (i = 0; handle[i] != '\0'; i++) { 3009 if (handle[i] == ' ') { 3010 handle[i] = '-'; 3011 } 3012 } 3013 wka->dm_targ_hdl = handle; 3014 wka->dm_hdl_major = wka->dm_drm_major; 3015 3016 /* 3017 * Get a minor dev number for handle which must be > 255. 3018 */ 3019 wka->dm_hdl_minor = dm_hdl_minor(); 3020 TRACE((MMS_DEBUG, "Handle: %s (%d,%d)", wka->dm_targ_hdl, 3021 wka->dm_hdl_major, wka->dm_hdl_minor)); 3022 3023 if (mknod(wka->dm_targ_hdl, S_IFCHR | S_IRUSR | S_IWUSR, 3024 makedev(wka->dm_hdl_major, wka->dm_hdl_minor))) { 3025 err = errno; 3026 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_MAKEHANDLE, 3027 "make handle error: %s: %s", 3028 wka->dm_targ_hdl, strerror(err))); 3029 dm_resp_error(cmd->cmd_task, DM_6508_MSG, DM_MSG_REASON); 3030 free(wka->dm_targ_hdl); 3031 return (DM_COMPLETE); 3032 } 3033 3034 /* 3035 * Tell dmd driver about the current minor dev number 3036 */ 3037 ioctl(wka->dm_drm_fd, DRM_TARG_MINOR, wka->dm_hdl_minor); 3038 3039 if (mnt->mnt_user) { 3040 /* Change owner of handle to user */ 3041 setpwent(); /* to beginning of PW file */ 3042 pwent = getpwnam_r(mnt->mnt_user, &pwd, 3043 wka->dm_pwbuf, wka->dm_pwbuf_size); 3044 endpwent(); 3045 3046 if (pwent == NULL) { 3047 /* 3048 * Can't find user 3049 */ 3050 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_USER, 3051 "no user")); 3052 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3053 DM_MSG_REASON); 3054 free(wka->dm_targ_hdl); 3055 return (DM_COMPLETE); 3056 } 3057 3058 if (chown(wka->dm_targ_hdl, pwent->pw_uid, pwent->pw_gid)) { 3059 /* chown error */ 3060 TRACE((MMS_ERR, "Can't chown to user")); 3061 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_USER, 3062 "cannot chown handle to user")); 3063 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3064 DM_MSG_REASON); 3065 free(wka->dm_targ_hdl); 3066 return (DM_COMPLETE); 3067 } 3068 } 3069 3070 drv->drv_rdbytes = 0; 3071 drv->drv_wrbytes = 0; 3072 3073 3074 /* 3075 * Get info from databse 3076 */ 3077 if (dm_show_application(&approot) != 0) { 3078 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3079 "unable to get APPLICATION")); 3080 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3081 DM_MSG_REASON); 3082 return (DM_COMPLETE); 3083 } 3084 3085 dm_destroy_dca(); 3086 while ((dca->dca_flags & DRV_DCA_VALID) == 0 && try < 10) { 3087 if (dm_show_dca_info(&root) != 0) { 3088 dm_destroy_dca(); 3089 sleep(1); 3090 try++; 3091 continue; 3092 } 3093 dca->dca_flags |= DRV_DCA_VALID; 3094 } 3095 3096 val = dm_get_attr_value(approot, "APPLICATION", "ApplicationName"); 3097 if (val == NULL) { 3098 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3099 "unable to get application name")); 3100 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3101 DM_MSG_REASON); 3102 mms_pn_destroy(root); 3103 mms_pn_destroy(approot); 3104 return (DM_COMPLETE); 3105 } 3106 dca->dca_app_name = strdup(val); 3107 3108 if ((dca->dca_flags & DRV_DCA_VALID) == 0) { 3109 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3110 "unable to get info for DRIVECARTRIDGEACCESS")); 3111 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3112 DM_MSG_REASON); 3113 mms_pn_destroy(root); 3114 mms_pn_destroy(approot); 3115 return (DM_COMPLETE); 3116 } 3117 3118 /* 3119 * Get application options 3120 */ 3121 if (dm_get_app_options(approot) != 0 || 3122 dm_get_part_rwmode(root) != 0 || dm_update_write_protect() != 0) { 3123 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3124 "unable to get info for application/partition")); 3125 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3126 DM_MSG_REASON); 3127 mms_pn_destroy(root); 3128 mms_pn_destroy(approot); 3129 return (DM_COMPLETE); 3130 } 3131 3132 /* 3133 * Override options with mount command options 3134 */ 3135 if (mnt->mnt_flags & MNT_VALIDATE_VID) { 3136 drv->drv_flags |= DRV_VALIDATE_VID; 3137 } else if (mnt->mnt_flags & MNT_NO_VALIDATE_VID) { 3138 drv->drv_flags &= ~DRV_VALIDATE_VID; 3139 } 3140 3141 if (mnt->mnt_flags & MNT_VALIDATE_XDATE) { 3142 drv->drv_flags |= DRV_VALIDATE_XDATE; 3143 } else if (mnt->mnt_flags & MNT_NO_VALIDATE_XDATE) { 3144 drv->drv_flags &= ~DRV_VALIDATE_XDATE; 3145 } 3146 3147 if (mnt->mnt_flags & MNT_VALIDATE_FNAME) { 3148 drv->drv_flags |= DRV_VALIDATE_FNAME; 3149 } else if (mnt->mnt_flags & MNT_NO_VALIDATE_FNAME) { 3150 drv->drv_flags &= ~DRV_VALIDATE_FNAME; 3151 } 3152 3153 if (mnt->mnt_flags & MNT_PREEMPT_RSV) { 3154 wka->dm_flags &= ~DM_ASK_PREEMPT_RSV; 3155 wka->dm_flags |= DM_PREEMPT_RSV; 3156 } else if (mnt->mnt_flags & MNT_ASK_PREEMPT_RSV) { 3157 wka->dm_flags &= ~DM_PREEMPT_RSV; 3158 wka->dm_flags |= DM_ASK_PREEMPT_RSV; 3159 } else if (mnt->mnt_flags & MNT_NO_PREEMPT_RSV) { 3160 wka->dm_flags &= ~(DM_PREEMPT_RSV | DM_ASK_PREEMPT_RSV); 3161 } 3162 3163 if (mnt->mnt_flags & MNT_SWITCH_LBL) { 3164 drv->drv_flags &= ~DRV_ASK_SWITCH_LBL; 3165 drv->drv_flags |= DRV_SWITCH_LBL; 3166 } else if (mnt->mnt_flags & MNT_ASK_SWITCH_LBL) { 3167 drv->drv_flags &= ~DRV_SWITCH_LBL; 3168 drv->drv_flags |= DRV_ASK_SWITCH_LBL; 3169 } else if (mnt->mnt_flags & MNT_NO_SWITCH_LBL) { 3170 drv->drv_flags &= ~(DRV_SWITCH_LBL | DRV_ASK_SWITCH_LBL); 3171 } 3172 3173 if (mnt->mnt_flags & MNT_WRITEOVER) { 3174 drv->drv_flags &= ~DRV_ASK_WRITEOVER; 3175 drv->drv_flags |= DRV_WRITEOVER; 3176 } else if (mnt->mnt_flags & MNT_ASK_WRITEOVER) { 3177 drv->drv_flags &= ~DRV_WRITEOVER; 3178 drv->drv_flags |= DRV_ASK_WRITEOVER; 3179 } else if (mnt->mnt_flags & MNT_NO_WRITEOVER) { 3180 drv->drv_flags &= ~(DRV_WRITEOVER | DRV_ASK_WRITEOVER); 3181 } 3182 3183 /* 3184 * Tell dmd driver the operation mode - raw/mms. 3185 */ 3186 ioctl(wka->dm_drm_fd, DRM_MMS_MODE, 3187 (mnt->mnt_flags & MNT_MMS) ? 1 : 0); 3188 3189 dm_trace_drv_flags(); 3190 dm_trace_mnt_flags(); 3191 3192 /* 3193 * get tape capacity from DB 3194 */ 3195 if (dm_get_capacity(root) != 0) { 3196 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3197 "unable to get info for application/partition")); 3198 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3199 DM_MSG_REASON); 3200 mms_pn_destroy(root); 3201 mms_pn_destroy(approot); 3202 return (DM_COMPLETE); 3203 } 3204 max_cap = drv->drv_capacity; 3205 3206 /* 3207 * Update capacity 3208 */ 3209 if (drv->drv_capacity != max_cap || 3210 drv->drv_capacity == (uint64_t)(-1LL) || 3211 drv->drv_avail == (uint64_t)(-1LL) || 3212 drv->drv_pc_avail == (uint32_t)(-1)) { 3213 /* Uninitialized capacity */ 3214 if (dm_update_capacity() != 0) { 3215 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3216 "unable to update capacity")); 3217 dm_resp_error(cmd->cmd_task, DM_6508_MSG, 3218 DM_MSG_REASON); 3219 mms_pn_destroy(root); 3220 mms_pn_destroy(approot); 3221 return (DM_COMPLETE); 3222 } 3223 } 3224 3225 mms_pn_destroy(root); 3226 mms_pn_destroy(approot); 3227 3228 /* Success */ 3229 drv->drv_flags |= DRV_ATTACHED; 3230 dm_resp_success(cmd->cmd_task, wka->dm_targ_hdl); 3231 3232 return (DM_COMPLETE); 3233 } 3234 3235 int 3236 dm_get_app_options(mms_par_node_t *root) 3237 { 3238 mms_par_node_t *attr; 3239 mms_par_node_t *name; 3240 mms_par_node_t *val; 3241 3242 attr = mms_pn_lookup(root, "attrlist", MMS_PN_CLAUSE, NULL); 3243 if (attr == NULL) { 3244 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3245 "unable to get attrlist")); 3246 mms_pn_destroy(root); 3247 return (-1); 3248 } 3249 3250 mms_list_pair_foreach(&attr->pn_arglist, name, val) { 3251 if (strcmp(mms_pn_token(name), "ValidateFileName") == 0) { 3252 if (strcmp(mms_pn_token(val), "yes") == 0) { 3253 drv->drv_flags |= DRV_VALIDATE_FNAME; 3254 } else { 3255 drv->drv_flags &= ~DRV_VALIDATE_FNAME; 3256 } 3257 } else if (strcmp(mms_pn_token(name), 3258 "ValidateVolumeID") == 0) { 3259 if (strcmp(mms_pn_token(val), "yes") == 0) { 3260 drv->drv_flags |= DRV_VALIDATE_VID; 3261 } else { 3262 drv->drv_flags &= ~DRV_VALIDATE_VID; 3263 } 3264 } else if (strcmp(mms_pn_token(name), 3265 "ValidateExpirationDate") == 0) { 3266 if (strcmp(mms_pn_token(val), "yes") == 0) { 3267 drv->drv_flags |= DRV_VALIDATE_XDATE; 3268 } else { 3269 drv->drv_flags &= ~DRV_VALIDATE_XDATE; 3270 } 3271 } else if (strcmp(mms_pn_token(name), "SwitchLabel") == 0) { 3272 drv->drv_flags &= 3273 ~(DRV_SWITCH_LBL | DRV_ASK_SWITCH_LBL); 3274 if (strcmp(mms_pn_token(val), "yes") == 0) { 3275 drv->drv_flags |= DRV_SWITCH_LBL; 3276 } else if (strcmp(mms_pn_token(val), "ask") == 0) { 3277 drv->drv_flags |= DRV_ASK_SWITCH_LBL; 3278 } 3279 } else if (strcmp(mms_pn_token(name), 3280 "WriteOverExistingData") == 0) { 3281 drv->drv_flags &= 3282 ~(DRV_WRITEOVER | DRV_ASK_WRITEOVER); 3283 if (strcmp(mms_pn_token(val), "yes") == 0) { 3284 drv->drv_flags |= DRV_WRITEOVER; 3285 } else if (strcmp(mms_pn_token(val), "ask") == 0) { 3286 drv->drv_flags |= DRV_ASK_WRITEOVER; 3287 } 3288 } else if (strcmp(mms_pn_token(name), "Retention") == 0) { 3289 sscanf(mms_pn_token(val), "%d", 3290 &drv->drv_retention); 3291 } 3292 } 3293 3294 return (0); 3295 } 3296 3297 int 3298 dm_get_part_rwmode(mms_par_node_t *root) 3299 { 3300 char *val; 3301 3302 val = dm_get_attr_value(root, "PARTITION", "PartitionRWMode"); 3303 if (val == NULL) { 3304 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3305 "unable to get partition RW mode, assume readonly")); 3306 mms_pn_destroy(root); 3307 return (-1); 3308 } 3309 3310 if (strcmp(val, "readonly") == 0) { 3311 mnt->mnt_flags |= MNT_READONLY; 3312 mnt->mnt_flags &= ~MNT_READWRITE; 3313 TRACE((MMS_DEBUG, "Volume is readonly")); 3314 } 3315 3316 return (0); 3317 } 3318 3319 int 3320 dm_update_write_protect(void) 3321 { 3322 int wp; 3323 3324 /* 3325 * Read mode sense data 3326 */ 3327 if (DRV_CALL(drv_get_write_protect, (&wp))) { 3328 /* Error getting WP flag */ 3329 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3330 "unable to get WP flag")); 3331 return (-1); 3332 } 3333 if (dm_send_write_protect(wp) != 0) { 3334 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3335 "update write protect error")); 3336 return (-1); 3337 } 3338 3339 3340 if (wp == 1) { 3341 /* Cartridge is write protected */ 3342 drv->drv_flags |= DRV_WRITEPROTECTED; 3343 } 3344 3345 return (0); 3346 } 3347 3348 int 3349 dm_update_drivetype(void) 3350 { 3351 char *attr_cmd; 3352 char *task; 3353 dm_command_t *cmd; 3354 3355 if ((wka->dm_flags & DM_HAVE_SESSION) == 0) { 3356 TRACE((MMS_ERR, "No connection to MM")); 3357 return (-1); 3358 } 3359 3360 task = dm_bld_task("send-drivetype"); 3361 attr_cmd = mms_strnew("attribute task['%s'] " 3362 "match[ streq(DRIVE.'DriveName' '%s') ] " 3363 "set[DRIVE.'DriveVendorID' '%s'] " 3364 "set[DRIVE.'DriveProductID' '%s'] " 3365 "set[DRIVE.'DriveTypeName' '%s'] " 3366 "set[DM.'DMTargetPath' '%s'] " 3367 ";", task, drv->drv_drvname, 3368 drv->drv_vend, drv->drv_prod, drv->drv_typename, 3369 wka->dm_target_base); 3370 3371 cmd = dm_send_cmd(attr_cmd, dm_cmd_response, task); 3372 free(attr_cmd); 3373 free(task); 3374 if (cmd == NULL || cmd->cmd_rc != 0) { 3375 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3376 "update drivetype error")); 3377 if (cmd) { 3378 dm_destroy_cmd(cmd); 3379 } 3380 return (-1); 3381 } 3382 dm_destroy_cmd(cmd); 3383 return (0); 3384 } 3385 3386 int 3387 dm_load_cmd(dm_command_t *cmd) 3388 { 3389 TRACE((MMS_DEBUG, "Loading drive")); 3390 3391 /* 3392 * If the tape is already loaded, check to see if access mode 3393 * asks for a load command to be issued. 3394 */ 3395 if ((drv->drv_flags & DRV_LOADED) && (drv->drv_flags & DRV_UDATA)) { 3396 if (mnt->mnt_flags & MNT_NOLOAD) { 3397 /* Don't issue load command */ 3398 dm_resp_success(cmd->cmd_task, NULL); 3399 return (DM_COMPLETE); 3400 } 3401 } 3402 3403 /* 3404 * Save DRV_LOAD_FLAGS 3405 */ 3406 drv->drv_flags &= DRV_LOAD_FLAGS; 3407 3408 /* issue a load command */ 3409 if (DRV_CALL(drv_load, ()) != 0) { 3410 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_DRIVE, 3411 "load failed, drive not ready")); 3412 dm_resp_error(cmd->cmd_task, DM_6517_MSG, DM_MSG_REASON); 3413 return (DM_COMPLETE); 3414 } 3415 3416 drv->drv_flags |= (DRV_LOADED | DRV_BOM); 3417 3418 /* 3419 * Get rid of any pending attention 3420 */ 3421 while (DRV_CALL(drv_tur, ()) != 0) { 3422 ; 3423 } 3424 3425 dm_resp_success(cmd->cmd_task, NULL); 3426 return (DM_COMPLETE); 3427 } 3428 3429 3430 int 3431 dm_identify_cmd(dm_command_t *cmd) 3432 { 3433 drv_vol1_t *vol1 = &drv->drv_vol1; 3434 int rc; 3435 char *resp; 3436 3437 if ((drv->drv_flags & DRV_LOADED) == 0) { 3438 DM_MSG_ADD((MMS_STATE, MMS_DM_E_LOAD, "drive not loaded")); 3439 dm_resp_error(cmd->cmd_task, DM_6510_MSG, DM_MSG_REASON); 3440 return (DM_COMPLETE); 3441 } 3442 3443 if ((mnt->mnt_flags & MNT_MMS) == 0) { 3444 /* No MMS control */ 3445 dm_resp_success(cmd->cmd_task, "No Signature"); 3446 goto done; 3447 } 3448 3449 /* 3450 * If tape has already been identified, then return VSN. 3451 * else rewind the tape and read VOL1. 3452 */ 3453 3454 if (drv->drv_flags & DRV_IDENTIFIED) { 3455 dm_resp_success(cmd->cmd_task, drv->drv_vid); 3456 goto done; 3457 } 3458 3459 /* No VSN, must determine VSN */ 3460 if (DRV_CALL(drv_rewind, ()) != 0) { 3461 /* I/O error */ 3462 drv->drv_flags |= DRV_LOST_POS; 3463 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_IO, "rewind error")); 3464 dm_resp_error(cmd->cmd_task, DM_6510_MSG, DM_MSG_REASON); 3465 return (DM_COMPLETE); 3466 } 3467 3468 if (dm_set_label_blksize() != 0) { 3469 /* I/O error */ 3470 TRACE((MMS_DEBUG, "Can't set label blksize")); 3471 dm_resp_error(cmd->cmd_task, DM_6510_MSG, DM_MSG_REASON); 3472 return (DM_COMPLETE); 3473 } 3474 3475 drv->drv_vid[0] = '\0'; /* No VSN yet */ 3476 3477 rc = DRV_CALL(drv_read, ((char *)vol1, 80)); 3478 if (rc != 80) { 3479 /* Did not read a label */ 3480 drv->drv_lbl_type = DRV_NL; /* a non labeled tape */ 3481 } else if (strncmp(vol1->vol1_id, VOL1_ID, 4) == 0) { 3482 drv->drv_lbl_type = DRV_AL; 3483 } else { 3484 drv->drv_lbl_type = DRV_NL; 3485 } 3486 if (rc > 0 || (drv->drv_flags & DRV_TM)) { 3487 /* 3488 * Read something ot hit a tapemark. Not a blank tape anymore. 3489 */ 3490 drv->drv_flags &= ~DRV_BLANK; 3491 } 3492 if (drv->drv_flags & DRV_EOM) { 3493 /* Hit EOM, must be a blank tape */ 3494 drv->drv_flags |= DRV_BLANK; 3495 } 3496 3497 if (drv->drv_lbl_type == DRV_NL) { 3498 3499 if (DRV_CALL(drv_rewind, ()) != 0) { 3500 /* I/O error */ 3501 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_IO, 3502 "rewind error")); 3503 dm_resp_error(cmd->cmd_task, DM_6510_MSG, 3504 DM_MSG_REASON); 3505 return (DM_COMPLETE); 3506 } 3507 drv->drv_fseq = 1; /* at file seq 1 */ 3508 drv->drv_flags |= (DRV_BOF | DRV_UDATA); 3509 if (dm_get_bof_pos() != 0) { 3510 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3511 "unable to get BOF position")); 3512 dm_resp_error(cmd->cmd_task, DM_6510_MSG, 3513 DM_MSG_REASON); 3514 return (DM_COMPLETE); 3515 } 3516 resp = "No Signature"; 3517 } else { 3518 3519 drv->drv_flags |= DRV_VOL1; /* has VOL1 lable */ 3520 drv->drv_fseq = 1; /* at file seq 1 */ 3521 if (strncmp(vol1->vol1_impid, DRV_IMPID, DRV_IMPID_LEN) == 0 || 3522 strncmp(vol1->vol1_impid, DRV_IMPID2, DRV_IMPID_LEN) == 0) { 3523 /* Created by SUN mms */ 3524 drv->drv_flags |= DRV_MMS_LBL; 3525 } 3526 3527 /* Return VSN */ 3528 strncpy(drv->drv_vid, vol1->vol1_vid, 6); 3529 drv->drv_vid[6] = '\0'; 3530 3531 /* 3532 * Verify the mounted cartridge has the requested VSN 3533 */ 3534 if (drv->drv_flags & DRV_VALIDATE_VID) { 3535 if ((mnt->mnt_flags & MNT_NO_VALIDATE_VID) == 0) { 3536 if (strcmp(drv->drv_vid, mnt->mnt_vid) != 0) { 3537 /* Wrong cartridge mounted */ 3538 DM_MSG_ADD((MMS_INTERNAL, 3539 MMS_DM_E_VOLUME_ID, 3540 "incorrect volume id: " 3541 "requested %s, mounted %s", 3542 mnt->mnt_vid, drv->drv_vid)); 3543 dm_resp_error(cmd->cmd_task, 3544 DM_6510_MSG, DM_MSG_REASON); 3545 return (DM_COMPLETE); 3546 } 3547 } 3548 } 3549 resp = drv->drv_vid[0] == '\0' ? "Null VSN" : drv->drv_vid; 3550 } 3551 drv->drv_flags |= DRV_IDENTIFIED; 3552 dm_resp_success(cmd->cmd_task, resp); 3553 done: 3554 /* 3555 * Calculate mount time 3556 */ 3557 gettimeofday(&wka->dm_mnt_done, NULL); 3558 wka->dm_mnt_time.tv_sec = 3559 wka->dm_mnt_done.tv_sec - wka->dm_mnt_start.tv_sec; 3560 wka->dm_mnt_time.tv_usec = 3561 wka->dm_mnt_done.tv_usec - wka->dm_mnt_start.tv_usec; 3562 if (wka->dm_mnt_time.tv_usec < 0) { 3563 wka->dm_mnt_time.tv_usec += 1000000; 3564 wka->dm_mnt_time.tv_sec--; 3565 } 3566 TRACE((MMS_OPER, "Mount time = %ld.%l6.6d", 3567 wka->dm_mnt_time.tv_sec, wka->dm_mnt_time.tv_usec)); 3568 3569 return (DM_COMPLETE); 3570 } 3571 3572 int 3573 dm_detach_cmd(dm_command_t *cmd) 3574 { 3575 mms_par_node_t *handle; 3576 mms_par_node_t *stale; 3577 3578 TRACE((MMS_DEBUG, "Enter dm_detach_cmd")); 3579 3580 handle = 3581 mms_pn_lookup(cmd->cmd_root, "drivehandle", MMS_PN_CLAUSE, 3582 NULL); 3583 handle = mms_pn_lookup(handle, NULL, MMS_PN_STRING, NULL); 3584 3585 stale = 3586 mms_pn_lookup(cmd->cmd_root, "stale", MMS_PN_CLAUSE, NULL); 3587 stale = mms_pn_lookup(stale, NULL, MMS_PN_KEYWORD, NULL); 3588 3589 3590 if (wka->dm_targ_hdl == NULL) { 3591 DM_MSG_ADD((MMS_INVALID, MMS_DM_E_NOEXISTHANDLE, 3592 "no handle")); 3593 dm_resp_error(cmd->cmd_task, DM_6511_MSG, DM_MSG_REASON); 3594 return (DM_COMPLETE); 3595 } else if (strcmp(mms_pn_token(handle), wka->dm_targ_hdl) != 0) { 3596 /* unknown handle name */ 3597 DM_MSG_ADD((MMS_INVALID, MMS_DM_E_BADHANDLE, 3598 "unknown handle")); 3599 dm_resp_error(cmd->cmd_task, DM_6511_MSG, DM_MSG_REASON); 3600 return (DM_COMPLETE); 3601 } else if (wka->dm_app_pid != 0) { 3602 DM_MSG_ADD((MMS_INVALID, MMS_DM_E_HANDLEINUSE, 3603 "handle in use by pid %d", (int)wka->dm_app_pid)); 3604 dm_resp_error(cmd->cmd_task, DM_6511_MSG, DM_MSG_REASON); 3605 return (DM_COMPLETE); 3606 } else if ((drv->drv_flags & DRV_ATTACHED) == 0) { 3607 DM_MSG_ADD((MMS_STATE, MMS_DM_E_DEVDET, "not attached")); 3608 dm_resp_error(cmd->cmd_task, DM_6511_MSG, DM_MSG_REASON); 3609 return (DM_COMPLETE); 3610 } 3611 3612 if (strcmp(mms_pn_token(stale), "false") == 0) { 3613 /* 3614 * Not a stale handle. Must be a detach from normal 3615 * unmount processing. 3616 * Remove the handle. 3617 */ 3618 3619 ioctl(wka->dm_drm_fd, DRM_TARG_MINOR, NULL); 3620 3621 unlink(mms_pn_token(handle)); 3622 if (wka->dm_targ_hdl != NULL) { 3623 free(wka->dm_targ_hdl); 3624 wka->dm_targ_hdl = NULL; 3625 } 3626 drv->drv_flags &= ~DRV_ATTACHED; 3627 3628 /* 3629 * Clean up mnt table 3630 */ 3631 dm_destroy_mnt(); 3632 dm_destroy_dca(); 3633 drv->drv_flags &= ~DRV_VALIDATED_FNAME; 3634 3635 dm_resp_success(cmd->cmd_task, NULL); 3636 } else { 3637 /* 3638 * A stale handle 3639 */ 3640 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3641 "stale handle")); 3642 dm_resp_error(cmd->cmd_task, DM_6511_MSG, DM_MSG_REASON); 3643 } 3644 3645 return (DM_COMPLETE); 3646 } 3647 3648 int 3649 dm_unload_cmd(dm_command_t *cmd) 3650 { 3651 int release = 0; 3652 3653 if ((wka->dm_flags & (DM_DFLT_LIB_LOADED | DM_DEV_LIB_LOADED)) == 0) { 3654 /* library not loaded */ 3655 TRACE((MMS_DEBUG, 3656 "dm_unload_cmd: device libraries not loaded")); 3657 dm_resp_success(cmd->cmd_task, NULL); 3658 return (DM_COMPLETE); 3659 } 3660 3661 /* 3662 * Update capacity 3663 */ 3664 if (wka->dm_flags & DM_SEND_CAPACITY) { 3665 if (dm_send_capacity(&drv->drv_cap) != 0) { 3666 TRACE((MMS_ERR, "Can't send capacity")); 3667 } else { 3668 wka->dm_flags &= ~DM_SEND_CAPACITY; 3669 } 3670 } 3671 /* 3672 * Update EOF pos 3673 */ 3674 if (wka->dm_flags & DM_SEND_EOF_POS) { 3675 if (dm_send_eof_pos()) { 3676 TRACE((MMS_ERR, "Can't send eof pos")); 3677 } else { 3678 wka->dm_flags &= ~DM_SEND_EOF_POS; 3679 } 3680 } 3681 3682 /* 3683 * If not reserved, then reserve it to prevent st from reserving it 3684 */ 3685 if ((drv->drv_flags & DRV_RESERVED) == 0) { 3686 if (DRV_CALL(drv_prsv_register, ()) == 0 && 3687 DRV_CALL(drv_prsv_reserve, ()) == 0) { 3688 release = 1; 3689 } 3690 } 3691 3692 /* 3693 * Get drive statistics before unloading 3694 */ 3695 if (dca->dca_flags & DRV_DCA_VALID) { 3696 if (DRV_CALL(drv_get_statistics, ()) == 0) { 3697 (void) dm_send_statistics(); 3698 } 3699 dm_destroy_dca(); 3700 } 3701 3702 /* 3703 * Ignore any unload error so MM can unload the tape 3704 */ 3705 DRV_CALL(drv_unload, ()); 3706 dm_resp_success(cmd->cmd_task, NULL); 3707 3708 if (release == 1) { 3709 DRV_CALL(drv_prsv_register, ()); 3710 DRV_CALL(drv_prsv_release, ()); 3711 } 3712 3713 /* 3714 * Save DRV_ATTACH flag 3715 */ 3716 drv->drv_flags &= DRV_LOAD_FLAGS; 3717 3718 return (DM_COMPLETE); 3719 } 3720 3721 void 3722 dm_exit_cmd(dm_command_t *cmd) 3723 { 3724 dm_resp_success(cmd->cmd_task, NULL); 3725 dm_exit(DM_NO_RESTART, __FILE__, __LINE__); 3726 } 3727 3728 void 3729 dm_reset_cmd(dm_command_t *cmd) 3730 { 3731 dm_resp_success(cmd->cmd_task, NULL); 3732 dm_exit(DM_RESTART, __FILE__, __LINE__); 3733 } 3734 3735 void 3736 dm_destroy_mnt(void) 3737 { 3738 if (mnt->mnt_volumename) { 3739 free(mnt->mnt_volumename); 3740 mnt->mnt_volumename = NULL; 3741 } 3742 if (mnt->mnt_vid) { 3743 free(mnt->mnt_vid); 3744 mnt->mnt_vid = NULL; 3745 } 3746 if (mnt->mnt_pcl) { 3747 free(mnt->mnt_pcl); 3748 mnt->mnt_pcl = NULL; 3749 } 3750 if (mnt->mnt_fname) { 3751 free(mnt->mnt_fname); 3752 mnt->mnt_fname = NULL; 3753 } 3754 if (mnt->mnt_user) { 3755 free(mnt->mnt_user); 3756 mnt->mnt_user = NULL; 3757 } 3758 if (mnt->mnt_dencode) { 3759 free(mnt->mnt_dencode); 3760 mnt->mnt_dencode = NULL; 3761 } 3762 if (mnt->mnt_shape) { 3763 free(mnt->mnt_shape); 3764 mnt->mnt_shape = NULL; 3765 } 3766 } 3767 3768 char * 3769 dm_bld_config_cmd(char *task) 3770 { 3771 int kwlen; 3772 int i; 3773 char *conf = NULL; 3774 char *fmt = DRV_CONFIG; 3775 char **cp; 3776 drv_shape_density_t *sd; 3777 mms_sym_t *mms_sym; 3778 3779 /* 3780 * Now, substitute values 3781 */ 3782 for (i = 0, cp = 0; fmt[i] != '\0'; i += kwlen) { 3783 kwlen = 0; 3784 if (strncmp(fmt + i, CONF_TASK, 3785 kwlen = strlen(CONF_TASK)) == 0) { 3786 conf = mms_strapp(conf, "%s", task); 3787 } else if (strncmp(fmt + i, CONF_DMNAME, 3788 kwlen = strlen(CONF_DMNAME)) == 0) { 3789 conf = mms_strapp(conf, "%s", drv->drv_dmname); 3790 } else if (strncmp(fmt + i, CONF_DENSITY_RW, 3791 kwlen = strlen(CONF_DENSITY_RW)) == 0) { 3792 for (sd = drv->drv_shape_den; 3793 sd->drv_shape != NULL; sd++) { 3794 if (sd->drv_den != NULL && 3795 strcmp(sd->drv_bit, sd->drv_den) == 0) { 3796 conf = mms_strapp(conf, 3797 "'%s' ", sd->drv_den); 3798 } 3799 } 3800 } else if (strncmp(fmt + i, CONF_DENSITY_RO, 3801 kwlen = strlen(CONF_DENSITY_RO)) == 0) { 3802 for (sd = drv->drv_shape_den; 3803 sd->drv_shape != NULL; sd++) { 3804 if (sd->drv_den == NULL) { 3805 conf = mms_strapp(conf, 3806 "'%s' ", sd->drv_bit); 3807 } 3808 } 3809 } else if (strncmp(fmt + i, CONF_BITFORMAT, 3810 kwlen = strlen(CONF_BITFORMAT)) == 0) { 3811 for (mms_sym = drv->drv_density; 3812 mms_sym->sym_token != NULL; mms_sym++) { 3813 conf = mms_strapp(conf, 3814 "'bit_%s' ", 3815 mms_sym->sym_token); 3816 } 3817 } else if (strncmp(fmt + i, CONF_BITFORMAT_RW, 3818 kwlen = strlen(CONF_BITFORMAT_RW)) == 0) { 3819 for (sd = drv->drv_shape_den; 3820 sd->drv_shape != NULL; sd++) { 3821 if (sd->drv_den != NULL && 3822 strcmp(sd->drv_bit, sd->drv_den) == 0) { 3823 conf = mms_strapp(conf, 3824 "'bit_%s' ", 3825 sd->drv_den); 3826 } 3827 } 3828 } else if (strncmp(fmt + i, CONF_BITFORMAT_RO, 3829 kwlen = strlen(CONF_BITFORMAT_RO)) == 0) { 3830 for (sd = drv->drv_shape_den; 3831 sd->drv_shape != NULL; sd++) { 3832 if (sd->drv_den == NULL) { 3833 conf = mms_strapp(conf, 3834 "'bit_%s'", 3835 sd->drv_bit); 3836 } 3837 } 3838 } else if (strncmp(fmt + i, CONF_BITFORMAT_WO, 3839 kwlen = strlen(CONF_BITFORMAT_WO)) == 0) { 3840 for (sd = drv->drv_shape_den; 3841 sd->drv_shape != NULL; sd++) { 3842 if (sd->drv_den != NULL && 3843 strcmp(sd->drv_bit, sd->drv_den) != 0) { 3844 conf = mms_strapp(conf, 3845 "'bit_%s'", 3846 sd->drv_bit); 3847 } 3848 } 3849 } else if (strncmp(fmt + i, CONF_BIT_CLAUSE, 3850 kwlen = strlen(CONF_BIT_CLAUSE)) == 0) { 3851 for (sd = drv->drv_shape_den; 3852 sd->drv_shape != NULL; sd++) { 3853 if (dm_duplicate_bit(sd)) { 3854 continue; 3855 } 3856 conf = mms_strapp(conf, 3857 "bitformat " 3858 "['bitformat_%s' 'bit_%s'] ", 3859 sd->drv_bit, sd->drv_bit); 3860 } 3861 } else if (strncmp(fmt + i, CONF_SHAPE, 3862 kwlen = strlen(CONF_SHAPE)) == 0) { 3863 for (cp = drv->drv_shape; *cp != NULL; cp++) { 3864 conf = mms_strapp(conf, 3865 "'%s' ", *cp); 3866 } 3867 } else if (strncmp(fmt + i, CONF_SHAPE_RW, 3868 kwlen = strlen(CONF_SHAPE_RW)) == 0) { 3869 for (sd = drv->drv_shape_den; 3870 sd->drv_shape != NULL; sd++) { 3871 if (sd->drv_den == NULL || 3872 strcmp(sd->drv_bit, sd->drv_den) != 0 || 3873 dm_duplicate_shape(sd, "rw")) { 3874 continue; 3875 } 3876 conf = mms_strapp(conf, 3877 "'%s' ", sd->drv_shape); 3878 } 3879 } else if (strncmp(fmt + i, CONF_SHAPE_RO, 3880 kwlen = strlen(CONF_SHAPE_RO)) == 0) { 3881 for (sd = drv->drv_shape_den; 3882 sd->drv_shape != NULL; sd++) { 3883 if (sd->drv_den != NULL || 3884 dm_rw_shape(sd->drv_shape) || 3885 dm_duplicate_shape(sd, "ro")) { 3886 continue; 3887 } 3888 conf = mms_strapp(conf, 3889 "'%s' ", sd->drv_shape); 3890 } 3891 } else if (strncmp(fmt + i, CONF_DRIVE_SPEC, 3892 kwlen = strlen(CONF_DRIVE_SPEC)) == 0) { 3893 conf = mms_strapp(conf, 3894 "'%s' '%s' '%s' ", drv->drv_dmname, 3895 drv->drv_drvname, wka->dm_target_base); 3896 } else if (strncmp(fmt + i, CONF_DRIVE_TYPE, 3897 kwlen = strlen(CONF_DRIVE_TYPE)) == 0) { 3898 conf = mms_strapp(conf, "%s", drv->drv_drive_type); 3899 } else if (strncmp(fmt + i, CONF_CAP_DENSITY_CLAUSE, 3900 kwlen = strlen(CONF_CAP_DENSITY_CLAUSE)) == 0) { 3901 if (dm_cap_clause(&conf) != 0) { 3902 goto err; 3903 } 3904 } else { 3905 conf = mms_strnapp(conf, 1, fmt + i); 3906 kwlen = 1; 3907 } 3908 } 3909 3910 return (conf); 3911 3912 err: 3913 free(conf); 3914 return (NULL); 3915 } 3916 3917 int 3918 dm_cap_clause(char **pconf) 3919 { 3920 drv_shape_density_t *sd; 3921 char *readwrite = DRV_CAP_READWRITE; 3922 char *writeover = DRV_CAP_WRITEOVER; 3923 3924 for (sd = drv->drv_shape_den; sd->drv_shape != NULL; sd++) { 3925 if (sd->drv_den != NULL && 3926 strcmp(sd->drv_bit, sd->drv_den) == 0) { 3927 /* Readwrite density */ 3928 if (dm_cap_clause_aux(readwrite, pconf, sd) != 0) { 3929 return (-1); 3930 } 3931 } else if (sd->drv_den != NULL) { 3932 /* Writeover density */ 3933 if (dm_cap_clause_aux(writeover, pconf, sd) != 0) { 3934 return (-1); 3935 } 3936 } 3937 } 3938 return (0); 3939 } 3940 3941 int 3942 dm_cap_clause_aux(char *fmt, char **pconf, drv_shape_density_t *sd) 3943 { 3944 int i; 3945 char *conf = *pconf; 3946 int kwlen; 3947 char *buf; 3948 3949 for (i = 0; fmt[i] != '\0'; i += kwlen) { 3950 if (strncmp(fmt + i, CONF_DRIVE_SPEC, 3951 kwlen = strlen(CONF_DRIVE_SPEC)) == 0) { 3952 conf = mms_strapp(conf, 3953 "'%s' '%s' '%s' ", drv->drv_dmname, 3954 drv->drv_drvname, wka->dm_target_base); 3955 } else if (strncmp(fmt + i, CONF_DMNAME, 3956 kwlen = strlen(CONF_DMNAME)) == 0) { 3957 conf = mms_strapp(conf, "%s", drv->drv_dmname); 3958 } else if (strncmp(fmt + i, CONF_DRIVE_TYPE, 3959 kwlen = strlen(CONF_DRIVE_TYPE)) == 0) { 3960 conf = mms_strapp(conf, "%s", drv->drv_drive_type); 3961 } else if (strncmp(fmt + i, CUR_DENSITY_RW, 3962 kwlen = strlen(CUR_DENSITY_RW)) == 0) { 3963 conf = mms_strapp(conf, "%s", sd->drv_den); 3964 } else if (strncmp(fmt + i, CUR_BITFORMAT_RW, 3965 kwlen = strlen(CUR_BITFORMAT_RW)) == 0) { 3966 conf = mms_strapp(conf, 3967 "bit_%s", sd->drv_bit); 3968 } else if (strncmp(fmt + i, CUR_BITFORMAT_WO, 3969 kwlen = strlen(CUR_BITFORMAT_WO)) == 0) { 3970 conf = mms_strapp(conf, 3971 "bit_%s", sd->drv_bit); 3972 } else if (strncmp(fmt + i, CUR_SHAPE_RW, 3973 kwlen = strlen(CUR_SHAPE_RW)) == 0) { 3974 conf = mms_strapp(conf, "%s", sd->drv_shape); 3975 } else if (fmt[i] == '$') { 3976 buf = mms_strnew("%-50.50", fmt + i); 3977 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 3978 "Unknown keyword %s", buf)); 3979 free(buf); 3980 goto err; 3981 } else { 3982 conf = mms_strnapp(conf, 1, fmt + i); 3983 kwlen = 1; 3984 } 3985 } 3986 3987 *pconf = conf; 3988 return (0); 3989 err: 3990 return (-1); 3991 } 3992 3993 int 3994 dm_rw_shape(char *shape) 3995 { 3996 drv_shape_density_t *sd; 3997 3998 for (sd = drv->drv_shape_den; sd->drv_shape != NULL; sd++) { 3999 if (strcmp(sd->drv_shape, shape) == 0) { 4000 if (sd->drv_den != NULL && 4001 strcmp(sd->drv_bit, sd->drv_den) == 0) { 4002 return (1); 4003 } 4004 } 4005 } 4006 return (0); 4007 } 4008 4009 int 4010 dm_duplicate_bit(drv_shape_density_t *sd) 4011 { 4012 drv_shape_density_t *sd1; 4013 4014 for (sd1 = drv->drv_shape_den; sd1 < sd; sd1++) { 4015 if (strcmp(sd1->drv_bit, sd->drv_bit) == 0) { 4016 return (1); 4017 } 4018 } 4019 return (0); 4020 } 4021 4022 int 4023 dm_duplicate_shape(drv_shape_density_t *sd, char *type) 4024 { 4025 drv_shape_density_t *sd1; 4026 int rw; 4027 4028 rw = strcmp(type, "rw") == 0; 4029 for (sd1 = drv->drv_shape_den; sd1 < sd; sd1++) { 4030 if (rw) { 4031 /* Readwrite shape */ 4032 if (sd1->drv_den != NULL && 4033 strcmp(sd1->drv_bit, sd1->drv_den) == 0) { 4034 if (strcmp(sd1->drv_shape, sd->drv_shape) 4035 == 0) { 4036 return (1); 4037 } 4038 } 4039 } else { 4040 /* Readonly shape */ 4041 if (sd1->drv_den == NULL) { 4042 if (strcmp(sd1->drv_shape, sd->drv_shape) 4043 == 0) { 4044 return (1); 4045 } 4046 } 4047 } 4048 } 4049 return (0); 4050 } 4051 4052 /* 4053 * drv_get_capabilities - get capabilities values from string 4054 * If no error, return NULL, otherwise, return the token in error. 4055 */ 4056 4057 char * 4058 dm_get_capabilities(char *tokens) 4059 { 4060 char *cp; 4061 char *tok = tokens; 4062 mms_sym_t *mms_sym; 4063 drv_shape_density_t *sd; 4064 4065 mnt->mnt_flags = 0; 4066 for (cp = strchr(tok, ':'); 4067 tok[0] != '\0' && cp != NULL; 4068 tok = cp + 1, cp = strchr(tok, ':')) { 4069 cp[0] = '\0'; 4070 if (strcmp(tok, "*load") == 0) { 4071 mnt->mnt_flags &= ~MNT_NOLOAD; 4072 } else if (strcmp(tok, "noload") == 0) { 4073 mnt->mnt_flags |= MNT_NOLOAD; 4074 } else if (strcmp(tok, "*rewind") == 0) { 4075 mnt->mnt_flags &= ~MNT_NOREWIND; 4076 } else if (strcmp(tok, "norewind") == 0) { 4077 mnt->mnt_flags |= MNT_NOREWIND; 4078 } else if (strcmp(tok, "fixed") == 0 || 4079 strcmp(tok, "block") == 0) { 4080 mnt->mnt_flags |= MNT_FIXED; 4081 mnt->mnt_flags &= ~MNT_VARIABLE; 4082 } else if (strcmp(tok, "variable") == 0) { 4083 mnt->mnt_flags |= MNT_VARIABLE; 4084 mnt->mnt_flags &= ~MNT_FIXED; 4085 } else if (strcmp(tok, "*dflt_vldt_vid") == 0) { 4086 mnt->mnt_flags &= ~(MNT_VALIDATE_VID | 4087 MNT_NO_VALIDATE_VID); 4088 } else if (strcmp(tok, "validate_vid") == 0) { 4089 mnt->mnt_flags &= ~(MNT_VALIDATE_VID | 4090 MNT_NO_VALIDATE_VID); 4091 mnt->mnt_flags |= MNT_VALIDATE_VID; 4092 } else if (strcmp(tok, "no_validate_vid") == 0) { 4093 mnt->mnt_flags &= ~(MNT_VALIDATE_VID | 4094 MNT_NO_VALIDATE_VID); 4095 mnt->mnt_flags |= MNT_NO_VALIDATE_VID; 4096 } else if (strcmp(tok, "*dflt_vldt_xdate") == 0) { 4097 mnt->mnt_flags &= ~(MNT_VALIDATE_XDATE | 4098 MNT_NO_VALIDATE_XDATE); 4099 } else if (strcmp(tok, "validate_xdate") == 0) { 4100 mnt->mnt_flags &= ~(MNT_VALIDATE_XDATE | 4101 MNT_NO_VALIDATE_XDATE); 4102 mnt->mnt_flags |= MNT_VALIDATE_XDATE; 4103 } else if (strcmp(tok, "no_validate_xdate") == 0) { 4104 mnt->mnt_flags &= ~(MNT_VALIDATE_XDATE | 4105 MNT_NO_VALIDATE_XDATE); 4106 mnt->mnt_flags |= MNT_NO_VALIDATE_XDATE; 4107 } else if (strcmp(tok, "*dflt_vldt_filename") == 0) { 4108 mnt->mnt_flags &= ~(MNT_VALIDATE_FNAME | 4109 MNT_NO_VALIDATE_FNAME); 4110 } else if (strcmp(tok, "validate_filename") == 0) { 4111 mnt->mnt_flags &= ~(MNT_VALIDATE_FNAME | 4112 MNT_NO_VALIDATE_FNAME); 4113 mnt->mnt_flags |= MNT_VALIDATE_FNAME; 4114 } else if (strcmp(tok, "no_validate_filename") == 0) { 4115 mnt->mnt_flags &= ~(MNT_VALIDATE_FNAME | 4116 MNT_NO_VALIDATE_FNAME); 4117 mnt->mnt_flags |= MNT_NO_VALIDATE_FNAME; 4118 } else if (strcmp(tok, "*dflt_preempt_rsv") == 0) { 4119 mnt->mnt_flags &= ~(MNT_PREEMPT_RSV | 4120 MNT_ASK_PREEMPT_RSV | MNT_NO_PREEMPT_RSV); 4121 } else if (strcmp(tok, "preempt_rsv") == 0) { 4122 mnt->mnt_flags &= ~(MNT_PREEMPT_RSV | 4123 MNT_ASK_PREEMPT_RSV | MNT_NO_PREEMPT_RSV); 4124 mnt->mnt_flags |= MNT_PREEMPT_RSV; 4125 } else if (strcmp(tok, "ask_preempt_rsv") == 0) { 4126 mnt->mnt_flags &= ~(MNT_PREEMPT_RSV | 4127 MNT_ASK_PREEMPT_RSV | MNT_NO_PREEMPT_RSV); 4128 mnt->mnt_flags |= MNT_ASK_PREEMPT_RSV; 4129 } else if (strcmp(tok, "nopreempt_rsv") == 0) { 4130 mnt->mnt_flags &= ~(MNT_PREEMPT_RSV | 4131 MNT_ASK_PREEMPT_RSV | MNT_NO_PREEMPT_RSV); 4132 mnt->mnt_flags |= MNT_NO_PREEMPT_RSV; 4133 } else if (strcmp(tok, "*dflt_writeover") == 0) { 4134 mnt->mnt_flags &= ~(MNT_WRITEOVER | 4135 MNT_ASK_WRITEOVER | MNT_NO_WRITEOVER); 4136 } else if (strcmp(tok, "writeover") == 0) { 4137 mnt->mnt_flags &= ~(MNT_WRITEOVER | 4138 MNT_ASK_WRITEOVER | MNT_NO_WRITEOVER); 4139 mnt->mnt_flags |= MNT_WRITEOVER; 4140 } else if (strcmp(tok, "ask_writeover") == 0) { 4141 mnt->mnt_flags &= ~(MNT_WRITEOVER | 4142 MNT_ASK_WRITEOVER | MNT_NO_WRITEOVER); 4143 mnt->mnt_flags |= MNT_ASK_WRITEOVER; 4144 } else if (strcmp(tok, "no_writeover") == 0) { 4145 mnt->mnt_flags &= ~(MNT_WRITEOVER | 4146 MNT_ASK_WRITEOVER | MNT_NO_WRITEOVER); 4147 mnt->mnt_flags |= MNT_NO_WRITEOVER; 4148 } else if (strcmp(tok, "*dflt_switch_lbl") == 0) { 4149 mnt->mnt_flags &= ~(MNT_SWITCH_LBL | 4150 MNT_ASK_SWITCH_LBL | MNT_NO_SWITCH_LBL); 4151 } else if (strcmp(tok, "switch_lbl") == 0) { 4152 mnt->mnt_flags &= ~(MNT_SWITCH_LBL | 4153 MNT_ASK_SWITCH_LBL | MNT_NO_SWITCH_LBL); 4154 mnt->mnt_flags |= MNT_SWITCH_LBL; 4155 } else if (strcmp(tok, "ask_switch_lbl") == 0) { 4156 mnt->mnt_flags &= ~(MNT_SWITCH_LBL | 4157 MNT_ASK_SWITCH_LBL | MNT_NO_SWITCH_LBL); 4158 mnt->mnt_flags |= MNT_ASK_SWITCH_LBL; 4159 } else if (strcmp(tok, "no_switch_lbl") == 0) { 4160 mnt->mnt_flags &= ~(MNT_SWITCH_LBL | 4161 MNT_ASK_SWITCH_LBL | MNT_NO_SWITCH_LBL); 4162 mnt->mnt_flags |= MNT_NO_SWITCH_LBL; 4163 } else if (strcmp(tok, "mms") == 0) { 4164 mnt->mnt_flags |= MNT_MMS; 4165 } else if (strcmp(tok, "raw") == 0) { 4166 mnt->mnt_flags &= ~MNT_MMS; 4167 } else if (strcmp(tok, "*nocompression") == 0) { 4168 mnt->mnt_flags &= ~MNT_COMPRESSION; 4169 } else if (strcmp(tok, "compression") == 0) { 4170 mnt->mnt_flags |= MNT_COMPRESSION; 4171 mnt->mnt_flags &= 4172 ~(MNT_LOW | MNT_MEDIUM | MNT_HIGH | MNT_ULTRA); 4173 } else if (strcmp(tok, "low") == 0) { 4174 mnt->mnt_flags &= 4175 ~(MNT_LOW | MNT_MEDIUM | MNT_HIGH | MNT_ULTRA); 4176 mnt->mnt_flags |= MNT_LOW; 4177 } else if (strcmp(tok, "medium") == 0) { 4178 mnt->mnt_flags &= 4179 ~(MNT_LOW | MNT_MEDIUM | MNT_HIGH | MNT_ULTRA); 4180 mnt->mnt_flags |= MNT_MEDIUM; 4181 } else if (strcmp(tok, "high") == 0) { 4182 mnt->mnt_flags &= 4183 ~(MNT_LOW | MNT_MEDIUM | MNT_HIGH | MNT_ULTRA); 4184 mnt->mnt_flags |= MNT_HIGH; 4185 } else if (strcmp(tok, "ultra") == 0) { 4186 mnt->mnt_flags &= 4187 ~(MNT_LOW | MNT_MEDIUM | MNT_HIGH | MNT_ULTRA); 4188 mnt->mnt_flags |= MNT_ULTRA; 4189 } else if (strcmp(tok, "mms_tm") == 0) { 4190 mnt->mnt_flags &= 4191 ~(MNT_BSD | MNT_NOBSD | MNT_MMS_TM); 4192 mnt->mnt_flags |= MNT_MMS_TM; 4193 } else if (strcmp(tok, "st_bsd") == 0) { 4194 mnt->mnt_flags &= 4195 ~(MNT_BSD | MNT_NOBSD | MNT_MMS_TM); 4196 mnt->mnt_flags |= MNT_BSD; 4197 } else if (strcmp(tok, "st_nobsd") == 0) { 4198 mnt->mnt_flags &= 4199 ~(MNT_BSD | MNT_NOBSD | MNT_MMS_TM); 4200 mnt->mnt_flags |= MNT_NOBSD; 4201 } else if (strcmp(tok, "readonly") == 0) { 4202 mnt->mnt_flags |= MNT_READONLY; 4203 mnt->mnt_flags &= ~MNT_READWRITE; 4204 } else if (strcmp(tok, "readwrite") == 0) { 4205 mnt->mnt_flags &= ~MNT_READONLY; 4206 mnt->mnt_flags |= MNT_READWRITE; 4207 } else if (strcmp(tok, "*readwrite") == 0) { 4208 mnt->mnt_flags &= ~(MNT_READONLY | MNT_READWRITE); 4209 } else if (strcmp(tok, "al") == 0 || 4210 strcmp(tok, "*default_lbl") == 0) { 4211 mnt->mnt_lbl_type = DRV_AL; 4212 } else if (strcmp(tok, "sl") == 0) { 4213 mnt->mnt_lbl_type = DRV_SL; 4214 } else if (strcmp(tok, "nl") == 0) { 4215 mnt->mnt_lbl_type = DRV_NL; 4216 } else if (strcmp(tok, "blp") == 0) { 4217 mnt->mnt_lbl_type = DRV_BLP; 4218 } else if (strcmp(tok, "*oflag") == 0) { 4219 mnt->mnt_flags &= ~(MNT_CREAT | MNT_OLD); 4220 } else if (strcmp(tok, "old") == 0) { 4221 mnt->mnt_flags |= MNT_OLD; 4222 mnt->mnt_flags &= ~MNT_CREAT; 4223 } else if (strcmp(tok, "creat") == 0 || 4224 strcmp(tok, "new") == 0) { 4225 mnt->mnt_flags &= ~MNT_OLD; 4226 mnt->mnt_flags |= MNT_CREAT; 4227 } else if (strcmp(tok, "*auto_density") == 0) { 4228 mnt->mnt_flags |= MNT_AUTO_DEN; 4229 } else if (strcmp(tok, "*auto_drive") && 4230 strcmp(tok, "*bit_unknown") && 4231 strcmp(tok, DMNAME) && 4232 strcmp(tok, DRVNAME) && 4233 strcmp(tok, "*default_tm") && 4234 strcmp(tok, wka->dm_target_base)) { 4235 /* 4236 * Look for drive type name 4237 */ 4238 if (strcmp(tok, drv->drv_drive_type) == 0) { 4239 /* Matching drive type name */ 4240 continue; 4241 } 4242 /* 4243 * Look for read/write supported density 4244 */ 4245 if (mms_sym = dm_sym_in(drv->drv_density, tok)) { 4246 for (sd = drv->drv_shape_den; 4247 sd->drv_shape != NULL; sd++) { 4248 if (sd->drv_den != NULL && 4249 strcmp(sd->drv_bit, 4250 sd->drv_den) != 0 && 4251 strcmp(sd->drv_den, tok) != 0) { 4252 break; 4253 } 4254 } 4255 if (sd->drv_shape != NULL) { 4256 /* Found a matching R/W density */ 4257 mnt->mnt_density = mms_sym; 4258 continue; 4259 } 4260 } 4261 /* 4262 * Look for bitformat 4263 */ 4264 /* skip "bit_" to get density */ 4265 if (mms_sym = dm_sym_in(drv->drv_density, tok + 4)) { 4266 /* Found matching bitformat */ 4267 mnt->mnt_bitformat = mms_sym; 4268 continue; 4269 } 4270 /* 4271 * Look for matching shape 4272 */ 4273 for (sd = drv->drv_shape_den; 4274 sd->drv_shape != NULL; sd++) { 4275 if (strcmp(sd->drv_shape, tok) == 0) { 4276 /* found a matching shape */ 4277 break; 4278 } 4279 } 4280 if (sd->drv_shape == NULL) { 4281 /* Unknown token, error */ 4282 DM_MSG_ADD((MMS_INVALID, MMS_DM_E_BADVAL, 4283 "unsupported capability: %s", tok)); 4284 return (tok); 4285 } 4286 } 4287 } 4288 4289 return (NULL); 4290 } 4291 4292 int 4293 dm_drv_assigned(void) 4294 { 4295 char *dmname; 4296 4297 if (dm_show_drive_dmname(&dmname) != 0) { 4298 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 4299 "Can't read DRIVE.'DMName'")); 4300 return (-1); 4301 } 4302 if (dmname != NULL && strcmp(dmname, "none") == 0) { 4303 /* drive not assigned */ 4304 TRACE((MMS_DEBUG, "Drive not assigned")); 4305 free(dmname); 4306 return (-1); 4307 } 4308 4309 /* Drive assigned */ 4310 TRACE((MMS_DEBUG, "Drive assigned to %s", dmname)); 4311 free(dmname); 4312 return (0); 4313 } 4314 4315 int 4316 dm_get_system_options(void) 4317 { 4318 mms_par_node_t *root; 4319 char *val; 4320 4321 if (dm_show_system(&root) != 0) { 4322 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 4323 "cannot get SYSTEM attributes")); 4324 return (-1); 4325 } 4326 4327 /* 4328 * Save system options 4329 */ 4330 4331 val = dm_get_attr_value(root, "SYSTEM", "PreemptReservation"); 4332 if (val == NULL) { 4333 mms_pn_destroy(root); 4334 return (-1); 4335 } 4336 4337 wka->dm_flags &= ~(DM_PREEMPT_RSV | DM_ASK_PREEMPT_RSV); 4338 if (strcmp(val, "yes") == 0) { 4339 wka->dm_flags |= DM_PREEMPT_RSV; 4340 } else if (strcmp(val, "ask") == 0) { 4341 wka->dm_flags &= ~DM_ASK_PREEMPT_RSV; 4342 } 4343 4344 val = dm_get_attr_value(root, "SYSTEM", "DefaultBlocksize"); 4345 if (val == NULL) { 4346 mms_pn_destroy(root); 4347 return (-1); 4348 } 4349 4350 sscanf(val, "%d", &drv->drv_dflt_blksize); 4351 mms_pn_destroy(root); 4352 4353 /* 4354 * Get attributes from drive 4355 */ 4356 if (dm_show_drive(&root) != 0) { 4357 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 4358 "cannot get DRIVE attributes")); 4359 return (-1); 4360 } 4361 4362 /* 4363 * Save drive options 4364 */ 4365 4366 val = dm_get_attr_value(root, "DRIVE", "ReserveDrive"); 4367 if (val == NULL) { 4368 mms_pn_destroy(root); 4369 return (-1); 4370 } 4371 if (strcmp(val, "yes") == 0) { 4372 wka->dm_flags |= DM_RESERVE_DRIVE; 4373 } else { 4374 wka->dm_flags &= ~DM_RESERVE_DRIVE; 4375 } 4376 4377 val = dm_get_attr_value(root, "DRIVE", "DriveSerialNum"); 4378 if (val == NULL) { 4379 mms_pn_destroy(root); 4380 return (-1); 4381 } 4382 memset(drv->drv_serial_num, 0, sizeof (drv->drv_serial_num)); 4383 strncpy(drv->drv_serial_num, val, sizeof (drv->drv_serial_num) - 1); 4384 mms_pn_destroy(root); 4385 return (0); 4386 } 4387 4388 void 4389 dm_send_request(char **reply, int msgid, ...) 4390 { 4391 char *req_cmd; 4392 char *task; 4393 mms_par_node_t *root; 4394 dm_command_t *cmd; 4395 mms_par_node_t *text; 4396 mms_par_node_t *val; 4397 mms_par_node_t *work = NULL; 4398 char *msgcl; 4399 va_list args; 4400 4401 *reply = NULL; 4402 task = dm_bld_task("request"); 4403 va_start(args, msgid); 4404 msgcl = mms_bld_msgcl(msgid, args); 4405 va_end(args); 4406 req_cmd = mms_strnew("request task ['%s'] type[DM] " 4407 "priority ['1000'] %s ;", task, msgcl); 4408 cmd = dm_send_cmd(req_cmd, dm_cmd_response, task); 4409 free(req_cmd); 4410 free(task); 4411 free(msgcl); 4412 if (cmd == NULL || cmd->cmd_rc != 0) { 4413 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 4414 "unable to send request")); 4415 if (cmd) { 4416 dm_destroy_cmd(cmd); 4417 } 4418 return; 4419 } 4420 root = cmd->cmd_root; 4421 4422 /* 4423 * Get reply 4424 */ 4425 text = mms_pn_lookup(root, "text", MMS_PN_CLAUSE, NULL); 4426 /* Skip down to the replied value */ 4427 val = mms_pn_lookup(text, NULL, MMS_PN_STRING, &work); 4428 val = mms_pn_lookup(text, NULL, MMS_PN_STRING, &work); 4429 val = mms_pn_lookup(text, NULL, MMS_PN_STRING, &work); 4430 *reply = val->pn_string; 4431 val->pn_string = NULL; 4432 4433 dm_destroy_cmd(cmd); 4434 } 4435 4436 char * 4437 dm_get_attr_value(mms_par_node_t *root, char *obj, char *attr) 4438 { 4439 mms_par_node_t *name; 4440 mms_par_node_t *val; 4441 mms_par_node_t *work = NULL; 4442 4443 name = mms_pn_lookup(root, attr, MMS_PN_STRING, &work); 4444 if (name == NULL) { 4445 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 4446 "%s.'%s' not found", obj, attr)); 4447 return (NULL); 4448 } 4449 4450 val = mms_pn_lookup(root, "", MMS_PN_STRING, &work); 4451 if (val == NULL) { 4452 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_INTERNAL, 4453 "%s.'%s' has no value", obj, attr)); 4454 return (NULL); 4455 } 4456 TRACE((MMS_DEBUG, "'%s' '%s'", attr, mms_pn_token(val))); 4457 return (mms_pn_token(val)); 4458 } 4459 4460 int 4461 dm_update_bitformat(void) 4462 { 4463 int den; 4464 mms_sym_t *mms_sym; 4465 char *cmdbuf; 4466 char *task; 4467 dm_command_t *cmd; 4468 4469 /* 4470 * Get current density 4471 */ 4472 if (DRV_CALL(drv_get_density, (&den, NULL)) != 0) { 4473 return (-1); 4474 } 4475 4476 /* 4477 * If current density matches density of requested bitformat density, 4478 * then no need to update. 4479 */ 4480 if (mnt->mnt_bitformat != NULL) { 4481 if (den == (mnt->mnt_bitformat->sym_code & 0xff)) { 4482 return (0); 4483 } 4484 } 4485 4486 /* 4487 * Lookup density name 4488 */ 4489 for (mms_sym = drv->drv_density; mms_sym->sym_token != NULL; 4490 mms_sym++) { 4491 if (mms_sym->sym_code == den) { 4492 break; 4493 } 4494 } 4495 if (mms_sym->sym_token == NULL) { 4496 DM_MSG_ADD((MMS_INTERNAL, MMS_DM_E_DENSITY, 4497 "Unsupported density 0x%x", den)); 4498 return (-1); 4499 } 4500 mnt->mnt_bitformat = mms_sym; 4501 4502 /* 4503 * Update bitformat 4504 */ 4505 task = dm_bld_task("update-bitformat"); 4506 cmdbuf = mms_strnew("attribute task['%s'] " 4507 "match[ and (streq(CARTRIDGE.'CartridgePCL' '%s') " 4508 "streq(SIDE.'SideName' '%s') " 4509 "streq(PARTITION.'PartitionName' '%s') " 4510 "streq(DRIVE.'DriveName' '%s'))]" 4511 "set [ PARTITION.'PartitionBitFormat' 'bitformat_%s' ] ;", 4512 task, dca->dca_pcl, dca->dca_side_name, dca->dca_part_name, 4513 drv->drv_drvname, 4514 mms_sym->sym_token); 4515 cmd = dm_send_cmd(cmdbuf, dm_cmd_response, task); 4516 free(cmdbuf); 4517 free(task); 4518 if (cmd == NULL || cmd->cmd_rc != 0) { 4519 TRACE((MMS_ERR, "Unable to update bitformat")); 4520 if (cmd) { 4521 dm_destroy_cmd(cmd); 4522 } 4523 return (-1); 4524 } 4525 4526 dm_destroy_cmd(cmd); 4527 return (0); 4528 } 4529 4530 mms_sym_t * 4531 dm_sym_in(mms_sym_t *arr, char *token) 4532 { 4533 mms_sym_t *mms_sym; 4534 4535 for (mms_sym = arr; mms_sym->sym_token != NULL; mms_sym++) { 4536 if (strcmp(mms_sym->sym_token, token) == 0) { 4537 /* mms_sym in arr */ 4538 return (mms_sym); 4539 } 4540 } 4541 /* 4542 * Symbol not in array 4543 */ 4544 return (NULL); 4545 } 4546 4547 void 4548 dm_trace_drv_flags(void) 4549 { 4550 char on[] = "on"; 4551 char off[] = "off"; 4552 char *buf = NULL; 4553 4554 #define DM_DRV_FLAGS(f) \ 4555 buf = mms_strapp(buf, "\n" #f " - %s", \ 4556 (drv->drv_flags & f) ? on : off); 4557 4558 buf = mms_strapp(buf, "drv_flags =\n"); 4559 4560 DM_DRV_FLAGS(DRV_LOADED); 4561 DM_DRV_FLAGS(DRV_IDENTIFIED); 4562 DM_DRV_FLAGS(DRV_MMS_LBL); 4563 DM_DRV_FLAGS(DRV_VALIDATED_FNAME); 4564 DM_DRV_FLAGS(DRV_VOL1); 4565 DM_DRV_FLAGS(DRV_HDR1); 4566 DM_DRV_FLAGS(DRV_HDR2); 4567 DM_DRV_FLAGS(DRV_TERM_FILE); 4568 DM_DRV_FLAGS(DRV_OPENED); 4569 DM_DRV_FLAGS(DRV_UDATA); 4570 DM_DRV_FLAGS(DRV_FATAL); 4571 DM_DRV_FLAGS(DRV_ENABLED); 4572 DM_DRV_FLAGS(DRV_BOF); 4573 DM_DRV_FLAGS(DRV_EOF); 4574 DM_DRV_FLAGS(DRV_TM); 4575 DM_DRV_FLAGS(DRV_BLANK); 4576 DM_DRV_FLAGS(DRV_ATTACHED); 4577 DM_DRV_FLAGS(DRV_BOM); 4578 DM_DRV_FLAGS(DRV_EOM); 4579 DM_DRV_FLAGS(DRV_FIXED); 4580 DM_DRV_FLAGS(DRV_VARIABLE); 4581 DM_DRV_FLAGS(DRV_EOF1); 4582 DM_DRV_FLAGS(DRV_EOF2); 4583 DM_DRV_FLAGS(DRV_VALID_BOF_POS); 4584 DM_DRV_FLAGS(DRV_LOST_POS); 4585 DM_DRV_FLAGS(DRV_VALID_STAT); 4586 DM_DRV_FLAGS(DRV_VALID_EOF_POS); 4587 DM_DRV_FLAGS(DRV_UPDATE_EOF_POS); 4588 DM_DRV_FLAGS(DRV_UPDATE_CAPACITY); 4589 DM_DRV_FLAGS(DRV_READONLY); 4590 DM_DRV_FLAGS(DRV_RESERVED); 4591 DM_DRV_FLAGS(DRV_WRITEOVER); 4592 DM_DRV_FLAGS(DRV_ASK_WRITEOVER); 4593 DM_DRV_FLAGS(DRV_SWITCH_LBL); 4594 DM_DRV_FLAGS(DRV_ASK_SWITCH_LBL); 4595 DM_DRV_FLAGS(DRV_VALIDATE_FNAME); 4596 DM_DRV_FLAGS(DRV_VALIDATE_VID); 4597 DM_DRV_FLAGS(DRV_VALIDATE_XDATE); 4598 DM_DRV_FLAGS(DRV_WRITEPROTECTED); 4599 DM_DRV_FLAGS(DRV_CREAT); 4600 DM_DRV_FLAGS(DRV_APPEND); 4601 DM_DRV_FLAGS(DRV_USE_PRSV); 4602 4603 TRACE((MMS_DEBUG, buf)); 4604 free(buf); 4605 } 4606 4607 void 4608 dm_trace_mnt_flags(void) 4609 { 4610 char on[] = "on"; 4611 char off[] = "off"; 4612 char *buf = NULL; 4613 4614 #define DM_MNT_FLAGS(f) \ 4615 buf = mms_strapp(buf, "\n" #f " - %s", \ 4616 (mnt->mnt_flags & f) ? on : off); 4617 4618 buf = mms_strapp(buf, "mnt_flags =\n"); 4619 4620 DM_MNT_FLAGS(MNT_FIXED); 4621 DM_MNT_FLAGS(MNT_VARIABLE); 4622 DM_MNT_FLAGS(MNT_MMS); 4623 DM_MNT_FLAGS(MNT_NOT_USED); 4624 DM_MNT_FLAGS(MNT_NOREWIND); 4625 DM_MNT_FLAGS(MNT_AVAIL_0); 4626 DM_MNT_FLAGS(MNT_COMPRESSION); 4627 DM_MNT_FLAGS(MNT_AVAIL_1); 4628 DM_MNT_FLAGS(MNT_LOW); 4629 DM_MNT_FLAGS(MNT_MEDIUM); 4630 DM_MNT_FLAGS(MNT_HIGH); 4631 DM_MNT_FLAGS(MNT_ULTRA); 4632 DM_MNT_FLAGS(MNT_AUTO_DEN); 4633 DM_MNT_FLAGS(MNT_BSD); 4634 DM_MNT_FLAGS(MNT_NOBSD); 4635 DM_MNT_FLAGS(MNT_MMS_TM); 4636 DM_MNT_FLAGS(MNT_NOLOAD); 4637 DM_MNT_FLAGS(MNT_PRIVILEGED); 4638 DM_MNT_FLAGS(MNT_VALIDATE_VID); 4639 DM_MNT_FLAGS(MNT_NO_VALIDATE_VID); 4640 DM_MNT_FLAGS(MNT_VALIDATE_XDATE); 4641 DM_MNT_FLAGS(MNT_NO_VALIDATE_XDATE); 4642 DM_MNT_FLAGS(MNT_VALIDATE_FNAME); 4643 DM_MNT_FLAGS(MNT_NO_VALIDATE_FNAME); 4644 DM_MNT_FLAGS(MNT_PREEMPT_RSV); 4645 DM_MNT_FLAGS(MNT_ASK_PREEMPT_RSV); 4646 DM_MNT_FLAGS(MNT_NO_PREEMPT_RSV); 4647 DM_MNT_FLAGS(MNT_SWITCH_LBL); 4648 DM_MNT_FLAGS(MNT_ASK_SWITCH_LBL); 4649 DM_MNT_FLAGS(MNT_NO_SWITCH_LBL); 4650 DM_MNT_FLAGS(MNT_WRITEOVER); 4651 DM_MNT_FLAGS(MNT_ASK_WRITEOVER); 4652 DM_MNT_FLAGS(MNT_NO_WRITEOVER); 4653 DM_MNT_FLAGS(MNT_READONLY); 4654 DM_MNT_FLAGS(MNT_READWRITE); 4655 DM_MNT_FLAGS(MNT_OLD); 4656 DM_MNT_FLAGS(MNT_CREAT); 4657 4658 TRACE((MMS_DEBUG, buf)); 4659 free(buf); 4660 } 4661