/* * tape390_display - Display messages on the display unit of a tape drive * * Copyright IBM Corp. 2002, 2017 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include "lib/zt_common.h" #include "tape390_common.h" #define TAPE390_DISPLAY _IOW('d', 1, struct display_struct) /* * The TAPE390_DISPLAY belongs to linux-2.5/include/asm-s390/tape390.h * * The TAPE390_DISPLAY ioctl calls the Load Display command * which transfers 17 bytes of data from the channel to the subsystem: * - 1 format control byte, and * - two 8-byte messages * * Format control byte: * 0-2: New Message Overlay * 3: Alternate Messages * 4: Blink Message * 5: Display Low/High Message * 6: Reserved * 7: Automatic Load Request * */ #define TAPE_MSGTYPE_STANDARD 0 #define TAPE_MSGTYPE_UNLOAD 1 #define TAPE_MSGTYPE_LOAD 2 #define TAPE_MSGTYPE_NOOP 3 #define TAPE_MSGTYPE_UNLOAD_LOAD 7 typedef struct display_struct { struct { unsigned char type :3; unsigned char alternate :1; unsigned char blink :1; unsigned char use_second :1; unsigned char reserved :1; unsigned char load_request :1; } cntrl; char message1[8]; char message2[8]; } __attribute__ ((packed)) display_struct; /* definitions */ static char *help_text = "tape390_display: display one or two 8-byte messages on the display" "unit of a tape drive\n" "\n" "Usage: tape390_display \"\" [\"\"] " "" "\n\n" "where are:\n" "\t-b | --blink\n" "\t\twill cause a single message to blink every 2 seconds\n" "\t\t(this option has only effect with a single message)\n" "\t-h | --help\n" "\t\tprint this text\n" "\t-v | --version\n" "\t\toutput version information and exit\n" "\t-l | --load\n" "\t\twill try to load the next tape if the loader is in system mode\n" "\t-q | --quiet\n" "\t\twill suppress all warning messages\n" "\t-t | --type \"standard|load|unload|noop|reload\"\n" "\t\tcontrols how the message is displayed:\n" "\t\t\tstandard = until the next tape movement (default)\n" "\t\t\tload = until a tape is loaded\n" "\t\t\tunload = until a tape is unloaded\n" "\t\t\tnoop = not at all (test purposes)\n" "\t\t\treload = message1 until tape is unloaded and message2\n" "\t\t\t when the next tape is loaded\n" "\n" "Note: Characters to be displayed include capital letters (A-Z), " "numerics (0-9)\n" "and special characters within single quotes. However not all " "characters\n" "might be displayed on all tape devices. Special characters that " "are supported\n" "for 3490 are '@$#,./()*&+-=%|:_<>?;'.\n"; static int quiet; /* end of definitions */ static int typename2int(char *name) { char *typenames[] = { "standard", "unload", "load", "noop", NULL, NULL, NULL, "reload" }; int i; for(i = 0; i < 8; i++) { if(typenames[i] == NULL) continue; if(strcmp(typenames[i], name) == 0) { return i; } } fprintf(stderr, "Invalid message type <%s>\n", name); return -1; } static void strchkcpy(char *tgt, const char *src) { static char *nowarn = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" "@$#,./'()*&+-=%:_<>?; "; char c; char warned; warned = 0; for(c=0; c<8 && *(src+c); c++) { *(tgt+c) = toupper(*(src+c)); if (index(nowarn, *(tgt+c)) == NULL && !quiet && !warned) { fprintf( stderr, "WARNING: Some special characters may not " "display on all device types.\n" ); warned = 1; } } } int main(int argc, char *argv[]) { char *options = "hblqt:v"; struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "blink", no_argument, NULL, 'b' }, { "load", no_argument, NULL, 'l' }, { "quiet", no_argument, NULL, 'q' }, { "type", required_argument, NULL, 't' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; char *pathname; int c; int fd, ret = 0; struct display_struct ds; /* set name of program */ set_prog_name(basename(argv[0])); memset(&ds, 0, sizeof(ds)); ds.cntrl.type = TAPE_MSGTYPE_STANDARD; while( (c = getopt_long(argc, argv, options, long_options, NULL)) != EOF ) { switch(c) { case 'h': fprintf(stdout, "%s", help_text); exit(0); case 'b': ds.cntrl.blink = 1; break; case 'l': ds.cntrl.load_request = 1; break; case 'q': quiet = 1; break; case 't': { int type = typename2int(optarg); if(type < 0) exit(1); ds.cntrl.type = type; break; } case 'v': { printf("tape390_display: zSeries tape " "display control program version %s\n", RELEASE_STRING); printf("Copyright IBM Corp. 2002, 2017\n"); exit(0); } default: fprintf(stderr, "Try '%s --help' for more" " information.\n",prog_name); exit(1); } } if(optind + 2 < argc ) { if( ds.cntrl.type == TAPE_MSGTYPE_LOAD && ds.cntrl.load_request ) { if(!quiet) { fprintf( stderr, "WARNING: " "A message with the " "--load option will only " "display the first" "\nmessage.\n" ); } } else if( ds.cntrl.type == TAPE_MSGTYPE_UNLOAD_LOAD && ds.cntrl.load_request ) { if(!quiet) { fprintf( stderr, "WARNING: " "A message with the " "--load option will only " "display the second" "\nmessage.\n" ); } } else { ds.cntrl.alternate = 1; if(ds.cntrl.blink) { ds.cntrl.blink = 0; if(!quiet) { fprintf( stderr, "Alternate messages " "override blinking\n" ); } } } strchkcpy(ds.message1, argv[optind]); strchkcpy(ds.message2, argv[optind+1]); pathname = argv[optind+2]; } else if(optind + 1 < argc) { if(ds.cntrl.type == TAPE_MSGTYPE_UNLOAD_LOAD) { fprintf(stderr, "Reload message type requires " "two messages.\n"); exit(1); } else if(ds.cntrl.type == TAPE_MSGTYPE_LOAD) { strchkcpy(ds.message2, argv[optind]); } strchkcpy(ds.message1, argv[optind]); pathname = argv[optind+1]; } else { fprintf(stderr, "%s", help_text); exit(1); } /* check whether specified device node is tape */ if (is_not_tape(pathname)) exit(EXIT_MISUSE); /* open device */ fd = open_tape(pathname); ret = ioctl(fd, TAPE390_DISPLAY, &ds); if (ret != 0) fprintf(stderr, "TAPE390_DISPLAY failed\n"); close(fd); return ret; }