libmultipath: remove unused "stdout helpers"
[multipath-tools/.git] / mpathpersist / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include "checkers.h"
7 #include "vector.h"
8 #include "config.h"
9 #include "structs.h"
10 #include <getopt.h>
11 #include <libudev.h>
12 #include "mpath_persist.h"
13 #include "main.h"
14 #include <pthread.h>
15 #include <ctype.h>
16 #include <string.h>
17
18 static const char * pr_type_strs[] = {
19         "obsolete [0]",
20         "Write Exclusive",
21         "obsolete [2]",
22         "Exclusive Access",
23         "obsolete [4]",
24         "Write Exclusive, registrants only",
25         "Exclusive Access, registrants only",
26         "Write Exclusive, all registrants",
27         "Exclusive Access, all registrants",
28         "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
29         "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
30 };
31
32 int get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids);
33 void mpath_print_buf_readcap(struct prin_resp *pr_buff);
34 void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
35 void mpath_print_buf_readresv(struct prin_resp *pr_buff);
36 void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
37 void dumpHex(const char* str, int len, int no_ascii);
38 void * mpath_alloc_prin_response(int prin_sa);
39 void mpath_print_transport_id(struct prin_fulldescr *fdesc);
40 int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
41
42 int logsink;
43 struct config *multipath_conf;
44
45 struct config *get_multipath_config(void)
46 {
47         return multipath_conf;
48 }
49
50 void put_multipath_config(struct config *conf)
51 {
52         /* Noop for now */
53 }
54
55 void rcu_register_thread_memb(void) {}
56
57 void rcu_unregister_thread_memb(void) {}
58
59 struct udev *udev;
60
61 int main (int argc, char * argv[])
62 {
63         int fd, c, res;
64         const char *device_name = NULL;
65         int num_prin_sa = 0;
66         int num_prout_sa = 0;
67         int num_prout_param = 0;
68         int prin_flag = 0;
69         int prout_flag = 0;
70         int ret = 0;
71         int hex = 0;
72         uint64_t param_sark = 0;
73         unsigned int prout_type = 0;
74         int param_alltgpt = 0;
75         int param_aptpl = 0;
76         uint64_t param_rk = 0;
77         unsigned int param_rtp = 0;
78         int num_transportids = 0;
79         struct transportid transportids[MPATH_MX_TIDS];
80         int prout = 1;
81         int prin = 1;
82         int prin_sa = -1;
83         int prout_sa = -1;
84         int verbose = 0;
85         int loglevel = 0;
86         int noisy = 0;
87         int num_transport =0;
88         void *resp = NULL;
89         struct transportid * tmp;
90         struct config *conf;
91
92         if (optind == argc)
93         {
94
95                 fprintf (stderr, "No parameter used\n");
96                 usage ();
97                 exit (1);
98         }
99
100         if (getuid () != 0)
101         {
102                 fprintf (stderr, "need to be root\n");
103                 exit (1);
104         }
105
106         udev = udev_new();
107         conf = mpath_lib_init();
108         if(!conf) {
109                 udev_unref(udev);
110                 exit(1);
111         }
112
113         memset(transportids, 0, MPATH_MX_TIDS * sizeof(struct transportid));
114         multipath_conf = conf;
115
116         while (1)
117         {
118                 int option_index = 0;
119
120                 c = getopt_long (argc, argv, "v:Cd:hHioZK:S:PAT:skrGILcRX:l:",
121                                 long_options, &option_index);
122                 if (c == -1)
123                         break;
124
125                 switch (c)
126                 {
127                         case 'v':
128                                 if (1 != sscanf (optarg, "%d", &loglevel))
129                                 {
130                                         fprintf (stderr, "bad argument to '--verbose'\n");
131                                         return MPATH_PR_SYNTAX_ERROR;
132                                 }
133                                 break;
134
135                         case 'C':
136                                 prout_sa = MPATH_PROUT_CLEAR_SA;
137                                 ++num_prout_sa;
138                                 break;
139
140                         case 'd':
141                                 device_name = optarg;
142                                 break;
143
144                         case 'h':
145                                 usage ();
146                                 return 0;
147
148                         case 'H':
149                                 hex=1;
150                                 break;
151
152                         case 'i':
153                                 prin_flag = 1;
154                                 break;
155
156                         case 'o':
157                                 prout_flag = 1;
158                                 break;
159
160                         case 'Z':
161                                 param_aptpl = 1;
162                                 ++num_prout_param;
163                                 break;
164                         case 'K':
165                                 if (1 != sscanf (optarg, "%" SCNx64 "", &param_rk))
166                                 {
167                                         fprintf (stderr, "bad argument to '--param-rk'\n");
168                                         return MPATH_PR_SYNTAX_ERROR;
169                                 }
170                                 ++num_prout_param;
171                                 break;
172
173                         case 'S':
174                                 if (1 != sscanf (optarg, "%" SCNx64 "", &param_sark))
175                                 {
176                                         fprintf (stderr, "bad argument to '--param-sark'\n");
177                                         return MPATH_PR_SYNTAX_ERROR;
178                                 }
179                                 ++num_prout_param;
180                                 break;
181
182                         case 'P':
183                                 prout_sa = MPATH_PROUT_PREE_SA;
184                                 ++num_prout_sa;
185                                 break;
186
187                         case 'A':
188                                 prout_sa = MPATH_PROUT_PREE_AB_SA;
189                                 ++num_prout_sa;
190                                 break;
191
192                         case 'T':
193                                 if (1 != sscanf (optarg, "%x", &prout_type))
194                                 {
195                                         fprintf (stderr, "bad argument to '--prout-type'\n");
196                                         return MPATH_PR_SYNTAX_ERROR;
197                                 }
198                                 ++num_prout_param;
199                                 break;
200
201                         case 's':
202                                 prin_sa = MPATH_PRIN_RFSTAT_SA;
203                                 ++num_prin_sa;
204                                 break;
205
206                         case 'k':
207                                 prin_sa = MPATH_PRIN_RKEY_SA;
208                                 ++num_prin_sa;
209                                 break;
210
211                         case 'r':
212                                 prin_sa = MPATH_PRIN_RRES_SA;
213                                 ++num_prin_sa;
214                                 break;
215
216                         case 'G':
217                                 prout_sa = MPATH_PROUT_REG_SA;
218                                 ++num_prout_sa;
219                                 break;
220
221                         case 'I':
222                                 prout_sa = MPATH_PROUT_REG_IGN_SA;
223                                 ++num_prout_sa;
224                                 break;
225
226                         case 'L':
227                                 prout_sa = MPATH_PROUT_REL_SA;
228                                 ++num_prout_sa;
229                                 break;
230
231                         case 'c':
232                                 prin_sa = MPATH_PRIN_RCAP_SA;
233                                 ++num_prin_sa;
234                                 break;
235
236                         case 'R':
237                                 prout_sa = MPATH_PROUT_RES_SA;
238                                 ++num_prout_sa;
239                                 break;
240
241                         case 'X':
242                                 if (0 != construct_transportid(optarg, transportids, num_transport)) {
243                                         fprintf(stderr, "bad argument to '--transport-id'\n");
244                                         return MPATH_PR_SYNTAX_ERROR;
245                                 }
246
247                                 ++num_transport;
248                                 break;
249
250                         case 'l':
251                                 if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) {
252                                         fprintf(stderr, "bad argument to '--alloc-length'\n");
253                                         return MPATH_PR_SYNTAX_ERROR;
254                                 } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) {
255                                         fprintf(stderr, "'--alloc-length' argument exceeds maximum"
256                                                         " limit(%d)\n", MPATH_MAX_PARAM_LEN);
257                                         return MPATH_PR_SYNTAX_ERROR;
258                                 }
259                                 break;
260
261                         default:
262                                 fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c);
263                                 usage ();
264                                 ret = MPATH_PR_SYNTAX_ERROR;
265                                 goto out;
266                 }
267         }
268
269         if (optind < argc)
270         {
271
272                 if (NULL == device_name)
273                 {
274                         device_name = argv[optind];
275                         ++optind;
276                 }
277                 if (optind < argc)
278                 {
279                         for (; optind < argc; ++optind)
280                                 fprintf (stderr, "Unexpected extra argument: %s\n", argv[optind]);
281                         usage ();
282                         ret = MPATH_PR_SYNTAX_ERROR;
283                         goto out;
284                 }
285         }
286
287         /* set verbosity */
288         noisy = (loglevel >= 3) ? 1 : hex;
289         verbose = (loglevel >= 3)? 3: loglevel;
290
291         if ((prout_flag + prin_flag) == 0)
292         {
293                 fprintf (stderr, "choose either '--in' or '--out' \n");
294                 usage ();
295                 ret = MPATH_PR_SYNTAX_ERROR;
296                 goto out;
297         }
298         if ((prout_flag + prin_flag) > 1)
299         {
300                 fprintf (stderr, "choose either '--in' or '--out' \n");
301                 usage ();
302                 ret = MPATH_PR_SYNTAX_ERROR;
303                 goto out;
304         }
305         else if (prout_flag)
306         {                               /* syntax check on PROUT arguments */
307                 prin = 0;
308                 if ((1 != num_prout_sa) || (0 != num_prin_sa))
309                 {
310                         fprintf (stderr, " For Persistent Reserve Out only one "
311                                         "appropriate\n service action must be "
312                                         "chosen \n");
313                         ret = MPATH_PR_SYNTAX_ERROR;
314                         goto out;
315                 }
316         }
317         else if (prin_flag)
318         {                               /* syntax check on PRIN arguments */
319                 prout = 0;
320                 if (num_prout_sa > 0)
321                 {
322                         fprintf (stderr, " When a service action for Persistent "
323                                         "Reserve Out is chosen the\n"
324                                         " '--out' option must be given \n");
325                         ret = MPATH_PR_SYNTAX_ERROR;
326                         goto out;
327                 }
328                 if (0 == num_prin_sa)
329                 {
330                         fprintf (stderr,
331                                         " No service action given for Persistent Reserve IN\n");
332                         usage();
333                         ret = MPATH_PR_SYNTAX_ERROR;
334                 }
335                 else if (num_prin_sa > 1)
336                 {
337                         fprintf (stderr, " Too many service actions given; choose "
338                                         "one only\n");
339                         usage();
340                         ret = MPATH_PR_SYNTAX_ERROR;
341                 }
342         }
343         else
344         {
345                 usage ();
346                 ret = MPATH_PR_SYNTAX_ERROR;
347                 goto out;
348         }
349
350         if ((param_rtp) && (MPATH_PROUT_REG_MOV_SA != prout_sa))
351         {
352                 fprintf (stderr, " --relative-target-port"
353                                 " only useful with --register-move\n");
354                 usage ();
355                 ret = MPATH_PR_SYNTAX_ERROR;
356                 goto out;
357         }
358
359         if (((MPATH_PROUT_RES_SA == prout_sa) ||
360                                 (MPATH_PROUT_REL_SA == prout_sa) ||
361                                 (MPATH_PROUT_PREE_SA == prout_sa) ||
362                                 (MPATH_PROUT_PREE_AB_SA == prout_sa)) &&
363                         (0 == prout_type)) {
364                 fprintf(stderr, "Warning: --prout-type probably needs to be "
365                                 "given\n");
366         }
367         if ((verbose > 2) && num_transportids)
368         {
369                 fprintf (stderr, "number of tranport-ids decoded from "
370                                 "command line : %d\n", num_transportids);
371         }
372
373         if (device_name == NULL)
374         {
375                 fprintf (stderr, "No device name given \n");
376                 usage ();
377                 ret = MPATH_PR_SYNTAX_ERROR;
378                 goto out;
379         }
380
381         /* open device */
382         if ((fd = open (device_name, O_WRONLY)) < 0)
383         {
384                 fprintf (stderr, "%s: error opening file (rw) fd=%d\n",
385                                 device_name, fd);
386                 ret = MPATH_PR_FILE_ERROR;
387                 goto out;
388         }
389
390
391         if (prin)
392         {
393                 resp = mpath_alloc_prin_response(prin_sa);
394                 if (!resp)
395                 {
396                         fprintf (stderr, "failed to allocate PRIN response buffer\n");
397                         ret = MPATH_PR_OTHER;
398                         goto out;
399                 }
400
401                 ret = mpath_persistent_reserve_in (fd, prin_sa, resp, noisy, verbose);
402                 if (ret != MPATH_PR_SUCCESS )
403                 {
404                         fprintf (stderr, "Persistent Reserve IN command failed\n");
405                         goto out;
406                 }
407
408                 switch(prin_sa)
409                 {
410                         case MPATH_PRIN_RKEY_SA:
411                                 mpath_print_buf_readkeys(resp);
412                                 break;
413                         case MPATH_PRIN_RRES_SA:
414                                 mpath_print_buf_readresv(resp);
415                                 break;
416                         case MPATH_PRIN_RCAP_SA:
417                                 mpath_print_buf_readcap(resp);
418                                 break;
419                         case MPATH_PRIN_RFSTAT_SA:
420                                 mpath_print_buf_readfullstat(resp);
421                                 break;
422                 }
423                 free(resp);
424         }
425         else if (prout)
426         {
427                 int j;
428                 struct prout_param_descriptor *paramp;
429
430                 paramp= malloc(sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS )));
431
432                 memset(paramp, 0, sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS)));
433
434                 for (j = 7; j >= 0; --j) {
435                         paramp->key[j] = (param_rk & 0xff);
436                         param_rk >>= 8;
437                 }
438
439                 for (j = 7; j >= 0; --j) {
440                         paramp->sa_key[j] = (param_sark & 0xff);
441                         param_sark >>= 8;
442                 }
443
444                 if (param_alltgpt)
445                         paramp->sa_flags |= 0x4;
446                 if (param_aptpl)
447                         paramp->sa_flags |= 0x1;
448
449                 if (num_transport)
450                 {
451                         paramp->sa_flags |= MPATH_F_SPEC_I_PT_MASK;
452                         paramp->num_transportid = num_transport;
453                         for (j = 0 ; j < num_transport; j++)
454                         {
455                                 paramp->trnptid_list[j] = (struct transportid *)malloc(sizeof(struct transportid));
456                                 memcpy(paramp->trnptid_list[j], &transportids[j],sizeof(struct transportid));
457                         }
458                 }
459
460                 /* PROUT commands other than 'register and move' */
461                 ret = mpath_persistent_reserve_out (fd, prout_sa, 0, prout_type,
462                                 paramp, noisy, verbose);
463                 for (j = 0 ; j < num_transport; j++)
464                 {
465                         tmp = paramp->trnptid_list[j];
466                         free(tmp);
467                 }
468                 free(paramp);
469         }
470
471         if (ret != MPATH_PR_SUCCESS)
472         {
473                 switch(ret)
474                 {
475                         case MPATH_PR_SENSE_UNIT_ATTENTION:
476                                 printf("persistent reserve out: scsi status: Unit Attention\n");
477                                 break;
478                         case MPATH_PR_RESERV_CONFLICT:
479                                 printf("persistent reserve out: scsi status: Reservation Conflict\n");
480                                 break;
481                 }
482                 printf("PR out: command failed\n");
483         }
484
485         res = close (fd);
486         if (res < 0)
487         {
488                 mpath_lib_exit(conf);
489                 udev_unref(udev);
490                 return MPATH_PR_FILE_ERROR;
491         }
492
493 out :
494         mpath_lib_exit(conf);
495         udev_unref(udev);
496         return (ret >= 0) ? ret : MPATH_PR_OTHER;
497 }
498
499 int
500 get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids)
501 {
502         int compact_len = 0;
503         unsigned char * ucp = transportid_arr;
504         int k, off, protocol_id, len;
505         for (k = 0, off = 0; ((k < num_transportids) && (k < max_transportid));
506                         ++k, off += MPATH_MX_TID_LEN) {
507                 protocol_id = ucp[off] & 0xf;
508                 if (5 == protocol_id) {
509                         len = (ucp[off + 2] << 8) + ucp[off + 3] + 4;
510                         if (len < 24)
511                                 len = 24;
512                         if (off > compact_len)
513                                 memmove(ucp + compact_len, ucp + off, len);
514                         compact_len += len;
515
516                 } else {
517                         if (off > compact_len)
518                                 memmove(ucp + compact_len, ucp + off, 24);
519                         compact_len += 24;
520                 }
521         }
522
523         return compact_len;
524 }
525
526 void mpath_print_buf_readkeys( struct prin_resp *pr_buff)
527 {
528         int i,j,k, num;
529         unsigned char *keyp;
530         uint64_t prkey;
531         printf("  PR generation=0x%x, ", pr_buff->prin_descriptor.prin_readkeys.prgeneration);
532
533         num = pr_buff->prin_descriptor.prin_readkeys.additional_length / 8;
534         if (0 == num) {
535                 printf("        0 registered reservation key.\n");
536                 return;
537         }
538         else if (1 == num)
539                 printf("        1 registered reservation key follows:\n");
540         else
541                 printf("        %d registered reservation keys follow:\n", num);
542
543
544         keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
545         for (i = 0; i < num ; i++)
546         {
547                 prkey = 0;
548                 for (j = 0; j < 8; ++j) {
549
550                         if (j > 0)
551                                 prkey <<= 8;
552                         prkey |= keyp[j];
553                 }
554                 printf("    0x%" PRIx64 "\n", prkey);
555                 k=8*i+j;
556                 keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[k];
557         }
558 }
559
560 void mpath_print_buf_readresv( struct prin_resp *pr_buff)
561 {
562         int j, num, scope=0, type=0;
563         unsigned char *keyp;
564         uint64_t prkey;
565
566         num = pr_buff->prin_descriptor.prin_readresv.additional_length / 8;
567         if (0 == num)
568         {
569                 printf("  PR generation=0x%x, there is NO reservation held \n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
570                 return ;
571         }
572         else
573                 printf("  PR generation=0x%x, Reservation follows:\n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
574         keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
575         prkey = 0;
576         for (j = 0; j < 8; ++j) {
577                 if (j > 0)
578                         prkey <<= 8;
579                 prkey |= keyp[j];
580         }
581
582         printf("   Key = 0x%" PRIx64 "\n", prkey);
583
584         scope = (pr_buff->prin_descriptor.prin_readresv.scope_type >> 4) &  0x0f;
585         type = pr_buff->prin_descriptor.prin_readresv.scope_type & 0x0f;
586
587         if (scope == 0)
588                 printf("  scope = LU_SCOPE, type = %s", pr_type_strs[type]);
589         else
590                 printf("  scope = %d, type = %s", scope, pr_type_strs[type]);
591
592         printf("\n");
593
594 }
595
596 void mpath_print_buf_readcap( struct prin_resp *pr_buff)
597 {
598         if ( pr_buff->prin_descriptor.prin_readcap.length <= 2 ) {
599                 fprintf(stderr, "Unexpected response for PRIN Report "
600                                 "Capabilities\n");
601                 return; //MALFORMED;
602         }
603
604         printf("Report capabilities response:\n");
605
606         printf("  Compatible Reservation Handling(CRH): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10));
607         printf("  Specify Initiator Ports Capable(SIP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8));
608         printf("  All Target Ports Capable(ATP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4 ));
609         printf("  Persist Through Power Loss Capable(PTPL_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0]));
610         printf("  Type Mask Valid(TMV): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80));
611         printf("  Allow Commands: %d\n", !!(( pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7));
612         printf("  Persist Through Power Loss Active(PTPL_A): %d\n",
613                         !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1));
614
615         if(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)
616         {
617                 printf("    Support indicated in Type mask:\n");
618
619                 printf("      %s: %d\n", pr_type_strs[7], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x80);
620                 printf("      %s: %d\n", pr_type_strs[6], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x40);
621                 printf("      %s: %d\n", pr_type_strs[5], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x20);
622                 printf("      %s: %d\n", pr_type_strs[3], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x8);
623                 printf("      %s: %d\n", pr_type_strs[1], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x2);
624                 printf("      %s: %d\n", pr_type_strs[8], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x100);
625         }
626 }
627
628 void mpath_print_buf_readfullstat( struct prin_resp *pr_buff)
629 {
630
631         int i,j, num;
632         uint64_t  prkey;
633         uint16_t  rel_pt_addr;
634         unsigned char * keyp;
635
636         num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
637         if (0 == num)
638         {
639                 printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
640                 return ;
641         }
642         else
643                 printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
644
645         for (i = 0 ; i < num; i++)
646         {
647                 keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key;
648
649                 prkey = 0;
650                 for (j = 0; j < 8; ++j) {
651                         if (j > 0)
652                                 prkey <<= 8;
653                         prkey |= *keyp;
654                         ++keyp;
655                 }
656                 printf("   Key = 0x%" PRIx64 "\n", prkey);
657
658                 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x02)
659                         printf("      All target ports bit set\n");
660                 else {
661                         printf("      All target ports bit clear\n");
662
663                         rel_pt_addr = pr_buff->prin_descriptor.prin_readfd.descriptors[i]->rtpi;
664                         printf("      Relative port address: 0x%x\n",
665                                         rel_pt_addr);
666                 }
667
668                 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x1) {
669                         printf("      << Reservation holder >>\n");
670                         j = ((pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type >> 4) & 0xf);
671                         if (0 == j)
672                                 printf("      scope: LU_SCOPE, ");
673                         else
674                                 printf("      scope: %d ", j);
675                         j = (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type & 0xf);
676                         printf(" type: %s\n", pr_type_strs[j]);
677                 } else
678                         printf("      not reservation holder\n");
679                 mpath_print_transport_id(pr_buff->prin_descriptor.prin_readfd.descriptors[i]);
680         }
681 }
682
683 static void usage(void)
684 {
685         fprintf(stderr,
686                         "Usage: mpathpersist [OPTIONS] [DEVICE]\n"
687                         " Options:\n"
688                         "    --verbose|-v level         verbosity level\n"
689                         "                   0           Critical messages\n"
690                         "                   1           Error messages\n"
691                         "                   2           Warning messages\n"
692                         "                   3           Informational messages\n"
693                         "                   4           Informational messages with trace enabled\n"
694                         "    --clear|-C                 PR Out: Clear\n"
695                         "    --device=DEVICE|-d DEVICE  query or change DEVICE\n"
696                         "    --help|-h                  output this usage message\n"
697                         "    --hex|-H                   output response in hex\n"
698                         "    --in|-i                    request PR In command \n"
699                         "    --out|-o                   request PR Out command\n"
700                         "    --param-aptpl|-Z           PR Out parameter 'APTPL'\n"
701                         "    --read-keys|-k             PR In: Read Keys\n"
702                         "    --param-sark=SARK|-S SARK  PR Out parameter service "
703                         "action\n"
704                         "                               reservation key (SARK is in "
705                         "hex)\n"
706                         "    --preempt|-P               PR Out: Preempt\n"
707                         "    --preempt-abort|-A         PR Out: Preempt and Abort\n"
708                         "    --prout-type=TYPE|-T TYPE  PR Out command type\n"
709                         "    --read-full-status|-s      PR In: Read Full Status\n"
710                         "    --read-keys|-k             PR In: Read Keys\n"
711                         "    --read-reservation|-r      PR In: Read Reservation\n"
712                         "    --register|-G              PR Out: Register\n"
713                         "    --register-ignore|-I       PR Out: Register and Ignore\n"
714                         "    --release|-L               PR Out: Release\n"
715                         "    --report-capabilities|-c   PR In: Report Capabilities\n"
716                         "    --reserve|-R               PR Out: Reserve\n"
717                         "    --transport-id=TIDS|-X TIDS  TransportIDs can be mentioned \n"
718                         "                               in several forms\n"
719                         " Examples:\n"
720                         "     mpathpersist --out --register --param-sark=123abc --prout-type=5 /dev/mapper/mpath9\n"
721                         "     mpathpersist -i -k /dev/mapper/mpath9\n"  );
722 }
723
724 void
725 mpath_print_transport_id(struct prin_fulldescr *fdesc)
726 {
727         switch (fdesc->trnptid.protocol_id) {
728         case MPATH_PROTOCOL_ID_FC:
729                 printf("   FCP-2 ");
730                 if (0 != fdesc->trnptid.format_code)
731                         printf(" [Unexpected format code: %d]\n",
732                                         fdesc->trnptid.format_code);
733                 dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
734                 break;
735         case MPATH_PROTOCOL_ID_ISCSI:
736                 printf("   iSCSI ");
737                 if (0 == fdesc->trnptid.format_code) {
738                         printf("name: %.*s\n", (int)sizeof(fdesc->trnptid.iscsi_name),
739                                 fdesc->trnptid.iscsi_name);
740                 }else if (1 == fdesc->trnptid.format_code){
741                         printf("world wide unique port id: %.*s\n",
742                                         (int)sizeof(fdesc->trnptid.iscsi_name),
743                                         fdesc->trnptid.iscsi_name);
744                 }else {
745                         printf("  [Unexpected format code: %d]\n", fdesc->trnptid.format_code);
746                         dumpHex((const char *)fdesc->trnptid.iscsi_name,
747                                  (int)sizeof(fdesc->trnptid.iscsi_name), 0);
748                 }
749                 break;
750         case MPATH_PROTOCOL_ID_SAS:
751                 printf("   SAS ");
752                 if (0 != fdesc->trnptid.format_code)
753                         printf(" [Unexpected format code: %d]\n",
754                                         fdesc->trnptid.format_code);
755                 dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
756                 break;
757         default:
758                 return;
759         }
760 }
761
762 int
763 construct_transportid(const char * lcp, struct transportid transid[], int num_transportids)
764 {
765         int k = 0;
766         int j, n, b, c, len, alen;
767         const char * ecp;
768         const char * isip;
769
770         if ((0 == memcmp("fcp,", lcp, 4)) ||
771                         (0 == memcmp("FCP,", lcp, 4))) {
772                 lcp += 4;
773                 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
774
775                 len = strlen(lcp);
776                 if (len != k) {
777                         fprintf(stderr, "badly formed symbolic FCP TransportID: %s\n",
778                                         lcp);
779                         return 1;
780                 }
781                 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_FC;
782                 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
783                 for (k = 0, j = 0, b = 0; k < 16; ++k) {
784                         c = lcp[k];
785                         if (isdigit(c))
786                                 n = c - 0x30;
787                         else if (isupper(c))
788                                 n = c - 0x37;
789                         else
790                                 n = c - 0x57;
791                         if (k & 1) {
792                                 transid[num_transportids].n_port_name[j] = b | n;
793                                 ++j;
794                         } else
795                                 b = n << 4;
796                 }
797                 goto my_cont_b;
798         }
799         if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) {
800                 lcp += 4;
801                 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
802                 len =strlen(lcp);
803                 if (len != k) {
804                         fprintf(stderr, "badly formed symbolic SAS TransportID: %s\n",
805                                         lcp);
806                         return 1;
807                 }
808                 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_SAS;
809                 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
810                 memcpy(&transid[num_transportids].sas_address, lcp, 8);
811
812                 goto my_cont_b;
813         }
814         if (0 == memcmp("iqn.", lcp, 4)) {
815                 ecp = strpbrk(lcp, " \t");
816                 isip = strstr(lcp, ",i,0x");
817                 if (ecp && (isip > ecp))
818                         isip = NULL;
819                 len = ecp ? (ecp - lcp) : (int)strlen(lcp);
820                 transid[num_transportids].format_code = (isip ? MPATH_WWUI_PORT_IDENTIFIER:MPATH_WWUI_DEVICE_NAME);
821                 transid[num_transportids].protocol_id = MPATH_PROTOCOL_ID_ISCSI;
822                 alen = len + 1; /* at least one trailing null */
823                 if (alen < 20)
824                         alen = 20;
825                 else if (0 != (alen % 4))
826                         alen = ((alen / 4) + 1) * 4;
827                 if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */
828                         fprintf(stderr, "iSCSI name too long, alen=%d\n", alen);
829                         return 0;
830                 }
831                 transid[num_transportids].iscsi_name[1] = alen & 0xff;
832                 memcpy(&transid[num_transportids].iscsi_name[2], lcp, len);
833                 goto my_cont_b;
834         }
835 my_cont_b:
836         if (k >= MPATH_MAX_PARAM_LEN) {
837                 fprintf(stderr, "build_transportid: array length exceeded\n");
838                 return 1;
839         }
840         return 0;
841 }