fix lintian issues
[debian/mtx] / nsmhack.c
1 /* Copyright 2001 DISC Inc. 
2  * Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
3  * Released under terms of the GNU General Public License as required
4  * by the license on the file "mtxl.c". See file "LICENSE" for details.
5  */
6
7 #define DEBUG_NSM 1
8
9 /* This is a hack to make the NSM modular series jukeboxes stick out
10  * their tongue, then retract tongue, so we can import media. They
11  * automatically stick out their tongue when exporting media, but
12  * importing media is not working, you try to do a MOVE_MEDIUM and
13  * it says "What medium?" before even sticking out its tongue. 
14  * My manager has turned in a change request to NSM engineering to direct 
15  * their firmware guys to add EEPOS support to the NSM modular jukeboxes so 
16  * that we have tongue firmware that's compatible with Exabyte, Sony, Breece
17  *  Hill, etc., but until that new firmware is here, this hack will work.
18  */
19
20 /* Note: Perhaps "hack" is an overstatement, since this will also
21  * eventually add pack management and other things of that nature
22  * that are extremely loader dependent.
23  */
24
25 /* Commands:
26    -f <devicenode>
27    tongue_out <sourceslot>
28    tongue_in
29    tongue_button_wait
30    tongue_button_enable
31    tongue_button_disable
32 */
33    
34
35 #include "mtxl.h"  /* get the SCSI routines out of the main file */
36
37 /****************************************************************/
38 /* Variables:  */
39 /****************************************************************/   
40
41 /* the device handle we're operating upon, sigh. */
42 static char *device;  /* the text of the device thingy. */
43 static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1;
44 char *argv0;
45 int arg[4]; /* arguments for the command. */
46 #define arg1 (arg[0])  /* for backward compatibility, sigh */
47 static SCSI_Flags_T SCSI_Flags = { 0, 0, 0,0 };
48
49 static ElementStatus_T *ElementStatus = NULL;
50
51 /* Okay, now let's do the main routine: */
52
53 void Usage(void) {
54   FatalError("Usage: nsmhack -f <generic-device> <command> where <command> is:\n [tongue_out] | [tongue_in] | [tongue_button_wait] | [tongue_button_enable]\n    | tongue_button_disable. \n");
55 }
56
57 static int S_tongue_out(void);
58 static int S_tongue_in(void);
59 static int S_slotinfo(void);
60 static int S_jukeinfo(void);
61
62 struct command_table_struct {
63   int num_args;
64   char *name;
65   int (*command)(void);
66 } command_table[] = {
67   { 1, "tongue_out", S_tongue_out },
68   { 0, "tongue_in", S_tongue_in },
69   { 0, "slotinfo", S_slotinfo },
70   { 0, "jukeinfo", S_jukeinfo },
71   { 0, NULL, NULL }
72 };
73
74
75 /* open_device() -- set the 'fh' variable.... */
76 void open_device(void) {
77
78   if (MediumChangerFD != -1) {
79     SCSI_CloseDevice("Unknown",MediumChangerFD);  /* close it, sigh...  new device now! */
80   }
81
82   MediumChangerFD = SCSI_OpenDevice(device);
83
84 }
85
86 static int get_arg(char *arg) {
87   int retval=-1;
88
89   if (*arg < '0' || *arg > '9') {
90     return -1;  /* sorry! */
91   }
92
93   retval=atoi(arg);
94   return retval;
95 }
96
97 /* we see if we've got a file open. If not, we open one :-(. Then
98  * we execute the actual command. Or not :-(. 
99  */ 
100 int execute_command(struct command_table_struct *command) {
101
102   /* if the device is not already open, then open it from the 
103    * environment.
104    */
105   if (MediumChangerFD == -1) {
106     /* try to get it from STAPE or TAPE environment variable... */
107     device=getenv("STAPE");
108     if (device==NULL) {
109       device=getenv("TAPE");
110       if (device==NULL) {
111         Usage();
112       }
113     }
114     open_device();
115   }
116
117
118   /* okay, now to execute the command... */
119   return command->command();
120 }
121
122 /* parse_args():
123  *   Basically, we are parsing argv/argc. We can have multiple commands
124  * on a line now, such as "unload 3 0 load 4 0" to unload one tape and
125  * load in another tape into drive 0, and we execute these commands one
126  * at a time as we come to them. If we don't have a -f at the start, we
127  * barf. If we leave out a drive #, we default to drive 0 (the first drive
128  * in the cabinet). 
129  */ 
130
131 int parse_args(int argc,char **argv) {
132   int i,cmd_tbl_idx,retval,arg_idx;
133   struct command_table_struct *command;
134
135   i=1;
136   arg_idx=0;
137   while (i<argc) {
138     if (strcmp(argv[i],"-f") == 0) {
139       i++;
140       if (i>=argc) {
141         Usage();
142       }
143       device=argv[i++];
144       open_device(); /* open the device and do a status scan on it... */
145     } else {
146       cmd_tbl_idx=0;
147       command=&command_table[0]; /* default to the first command... */
148       command=&command_table[cmd_tbl_idx];
149       while (command->name) {
150         if (!strcmp(command->name,argv[i])) {
151           /* we have a match... */
152           break;
153         }
154         /* otherwise we don't have a match... */
155         cmd_tbl_idx++;
156         command=&command_table[cmd_tbl_idx];
157       }
158       /* if it's not a command, exit.... */
159       if (!command->name) {
160         Usage();
161       }
162       i++;  /* go to the next argument, if possible... */
163       /* see if we need to gather arguments, though! */
164       arg1=-1; /* default it to something */
165       for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) {
166         if (i < argc) {
167           arg[arg_idx]=get_arg(argv[i]);
168           if (arg[arg_idx] !=  -1) {
169             i++; /* increment i over the next cmd. */
170           }
171         } else {
172           arg[arg_idx]=0; /* default to 0 setmarks or whatever */
173         } 
174       }
175       retval=execute_command(command);  /* execute_command handles 'stuff' */
176       exit(retval);
177     }
178   }
179   return 0; /* should never get here */
180 }
181
182 static void init_param(NSM_Param_T *param, char *command, int paramlen, int resultlen) {
183   int i;
184
185   /* zero it out first: */
186   memset((char *)param,0,sizeof(NSM_Param_T));
187
188   resultlen=resultlen+sizeof(NSM_Result_T)-0xffff;
189
190   
191   param->page_code=0x80;
192   param->reserved=0;
193   param->page_len_msb=((paramlen+8)>>8) & 0xff;
194   param->page_len_lsb=(paramlen+8) & 0xff;
195   param->allocation_msb=((resultlen + 10) >> 8) & 0xff;
196   param->allocation_lsb= (resultlen+10) & 0xff;
197   param->reserved2[0]=0;
198   param->reserved2[1]=0;
199
200   for (i=0;i<4;i++) {
201     param->command_code[i]=command[i];
202   }
203
204 }
205
206 static NSM_Result_T *SendRecHack(NSM_Param_T *param,int param_len, 
207                                  int read_len) {
208   NSM_Result_T *result;
209   /* send the command: */
210   if (SendNSMHack(MediumChangerFD,param,param_len,0)) {
211     PrintRequestSense(&scsi_error_sense);                   
212     FatalError("SendNSMHack failed.\n");    
213   }
214
215   /* Now read the result: */
216   result=RecNSMHack(MediumChangerFD,read_len,0);
217   if (!result) {
218     PrintRequestSense(&scsi_error_sense);                   
219     FatalError("RecNSMHack failed.\n");    
220   }  
221
222   return result;
223 }
224
225
226 /* Print some info about the NSM jukebox. */
227 static int S_jukeinfo(void) {
228   NSM_Result_T *result;
229   NSM_Param_T param;
230
231   if (!device)
232     Usage();
233
234   /* okay, we have a device: Let's get vendor ID: */
235   init_param(&param,"1010",0,8);
236   result=SendRecHack(&param,0,8);
237   /* Okay, we got our result, print out the vendor ID: */
238   result->return_data[8]=0;
239   printf("Vendor ID: %s\n",result->return_data);
240   free(result);
241   
242   /* Get our product ID: */
243   init_param(&param,"1011",0,16);
244   result=SendRecHack(&param,0,16);
245   result->return_data[16]=0;
246   printf("Product ID: %s\n",result->return_data);
247   free(result);
248
249   init_param(&param,"1012",0,4);
250   result=SendRecHack(&param,0,4);
251   result->return_data[4]=0;
252   printf("Product Revision: %s\n",result->return_data);
253   free(result);
254
255   init_param(&param,"1013",0,8);
256   result=SendRecHack(&param,0,8);
257   result->return_data[8]=0;
258   printf("Production Date: %s\n",result->return_data);
259   free(result);
260
261   init_param(&param,"1014",0,8);
262   result=SendRecHack(&param,0,8);
263   result->return_data[8]=0;
264   printf("Part Number: %s\n",result->return_data);
265   free(result);
266
267   init_param(&param,"1015",0,12);
268   result=SendRecHack(&param,0,12);
269   result->return_data[12]=0;
270   printf("Serial Number: %s\n",result->return_data);
271   free(result);
272
273   init_param(&param,"1016",0,4);
274   result=SendRecHack(&param,0,4);
275   result->return_data[4]=0;
276   printf("Firmware Release: %s\n",result->return_data);
277   free(result);
278
279   init_param(&param,"1017",0,8);
280   result=SendRecHack(&param,0,8);
281   result->return_data[8]=0;
282   printf("Firmware Date: %s\n",result->return_data);
283   free(result);
284
285   return 0;
286 }
287
288 static int S_slotinfo(void) {
289   NSM_Result_T *result;
290   NSM_Param_T param;
291
292   if (!device)
293     Usage();
294
295   /* Okay, let's see what I can get from slotinfo: */
296   init_param(&param,"1020",0,6);
297   result=SendRecHack(&param,0,6);
298   result->return_data[6]=0;
299   printf("Layout: %s\n",result->return_data);
300   free(result);
301   
302   return 0;
303 }
304
305 static int S_tongue_in(void) {
306   return 0;
307 }
308
309 /* okay, stick our tongue out. We need a slot ID to grab a caddy from. */
310 static int S_tongue_out(void) {
311   int slotnum=arg1;
312   Inquiry_T *inquiry_info;  /* needed by MoveMedium etc... */
313   RequestSense_T RequestSense;
314
315   /* see if we have element status: */
316   if (ElementStatus==NULL) {
317     inquiry_info=RequestInquiry(MediumChangerFD,&RequestSense);
318     if (!inquiry_info) {
319       PrintRequestSense(&RequestSense);                   
320       FatalError("INQUIRY Command Failed\n"); 
321     }
322     ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags);
323     if (!ElementStatus) {
324       PrintRequestSense(&RequestSense);                   
325       FatalError("READ ELEMENT STATUS Command Failed\n"); 
326     }
327   }
328   
329   /* Okay, we have element status, so now let's assume that */
330   return 0;
331 }
332
333 /* See parse_args for the scoop. parse_args does all. */
334 int main(int argc, char **argv) {
335   argv0=argv[0];
336   parse_args(argc,argv);
337
338   if (device) 
339     SCSI_CloseDevice(device,MediumChangerFD);
340
341   exit(0);
342 }