chiark / gitweb /
[PATCH] update volume_id
[elogind.git] / extras / multipath-tools / multipath / main.c
1 /*
2  * Soft:        multipath device mapper target autoconfig
3  *
4  * Version:     $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
5  *
6  * Author:      Copyright (C) 2003 Christophe Varoqui
7  *
8  *              This program is distributed in the hope that it will be useful,
9  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *              See the GNU General Public License for more details.
12  *
13  *              This program is free software; you can redistribute it and/or
14  *              modify it under the terms of the GNU General Public License
15  *              as published by the Free Software Foundation; either version
16  *              2 of the License, or (at your option) any later version.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <linux/kdev_t.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <sys/ioctl.h>
29 #include <dlist.h>
30 #include <sysfs/libsysfs.h>
31 #include "../libdevmapper/libdevmapper.h"
32 #include "main.h"
33 #include "devinfo.h"
34
35 /* White list switch */
36 static int
37 get_unique_id(struct path * mypath)
38 {
39         int i;
40         static struct {
41                 char * vendor;
42                 char * product;
43                 int iopolicy;
44                 int (*getuid) (char *, char *);
45         } wlist[] = {
46                 {"COMPAQ  ", "HSV110 (C)COMPAQ", GROUP_BY_TUR, &get_evpd_wwid},
47                 {"COMPAQ  ", "MSA1000         ", GROUP_BY_TUR, &get_evpd_wwid},
48                 {"COMPAQ  ", "MSA1000 VOLUME  ", GROUP_BY_TUR, &get_evpd_wwid},
49                 {"DEC     ", "HSG80           ", GROUP_BY_TUR, &get_evpd_wwid},
50                 {"HP      ", "HSV100          ", GROUP_BY_TUR, &get_evpd_wwid},
51                 {"HP      ", "A6189A          ", MULTIBUS, &get_evpd_wwid},
52                 {"HP      ", "OPEN-           ", MULTIBUS, &get_evpd_wwid},
53                 {"DDN     ", "SAN DataDirector", MULTIBUS, &get_evpd_wwid},
54                 {"FSC     ", "CentricStor     ", MULTIBUS, &get_evpd_wwid},
55                 {"HITACHI ", "DF400           ", MULTIBUS, &get_evpd_wwid},
56                 {"HITACHI ", "DF500           ", MULTIBUS, &get_evpd_wwid},
57                 {"HITACHI ", "DF600           ", MULTIBUS, &get_evpd_wwid},
58                 {"IBM     ", "ProFibre 4000R  ", MULTIBUS, &get_evpd_wwid},
59                 {"SGI     ", "TP9100          ", MULTIBUS, &get_evpd_wwid},
60                 {"SGI     ", "TP9300          ", MULTIBUS, &get_evpd_wwid},
61                 {"SGI     ", "TP9400          ", MULTIBUS, &get_evpd_wwid},
62                 {"SGI     ", "TP9500          ", MULTIBUS, &get_evpd_wwid},
63                 {NULL, NULL, 0, NULL},
64         };
65
66         for (i = 0; wlist[i].vendor; i++) {
67                 if (strncmp(mypath->vendor_id, wlist[i].vendor, 8) == 0 &&
68                     strncmp(mypath->product_id, wlist[i].product, 16) == 0) {
69                         mypath->iopolicy = wlist[i].iopolicy;
70                         if (!wlist[i].getuid(mypath->sg_dev, mypath->wwid))
71                                 return 0;
72                 }
73         }
74         return 1;
75 }
76
77 static int
78 sysfsdevice2devname (char *devname, char *device)
79 {
80         char sysfs_path[FILE_NAME_SIZE];
81         char block_path[FILE_NAME_SIZE];
82         char link_path[FILE_NAME_SIZE];
83         int r;
84
85         if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
86                 fprintf(stderr, "[device] feature available with sysfs only\n");
87                 exit (1);
88         }
89         
90         sprintf(link_path, "%s%s/block", sysfs_path, device);
91         
92         r = sysfs_get_link(link_path, block_path, FILE_NAME_SIZE);
93
94         if (r != 0)
95                 return 1;
96
97         sysfs_get_name_from_path(block_path, devname, FILE_NAME_SIZE);
98
99         return 0;
100 }
101
102         
103 static int
104 devt2devname (char *devname, int major, int minor)
105 {
106         struct sysfs_directory * sdir;
107         struct sysfs_directory * devp;
108         char sysfs_path[FILE_NAME_SIZE];
109         char block_path[FILE_NAME_SIZE];
110         char attr_path[FILE_NAME_SIZE];
111         char attr_value[16];
112         char attr_ref_value[16];
113
114         if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
115                 fprintf(stderr, "-D feature available with sysfs only\n");
116                 exit (1);
117         }
118                 
119         sprintf(attr_ref_value, "%i:%i\n", major, minor);
120         sprintf(block_path, "%s/block", sysfs_path);
121         sdir = sysfs_open_directory(block_path);
122         sysfs_read_directory(sdir);
123
124         dlist_for_each_data(sdir->subdirs, devp, struct sysfs_directory) {
125                 sprintf(attr_path, "%s/%s/dev", block_path, devp->name);
126                 sysfs_read_attribute_value(attr_path, attr_value, 16);
127
128                 if (!strcmp(attr_value, attr_ref_value)) {
129                         sprintf(attr_path, "%s/%s", block_path, devp->name);
130                         sysfs_get_name_from_path(attr_path, devname, FILE_NAME_SIZE);
131                         break;
132                 }
133         }
134
135         sysfs_close_directory(sdir);
136         
137         return 0;
138 }
139
140 static int
141 blacklist (char * dev) {
142         int i;
143         static struct {
144                 char * headstr;
145                 int lengh;
146         } blist[] = {
147                 {"cciss", 5},
148                 {"hd", 2},
149                 {"md", 2},
150                 {"dm", 2},
151                 {"sr", 2},
152                 {"scd", 3},
153                 {"ram", 3},
154                 {"raw", 3},
155                 {NULL, 0},
156         };
157
158         for (i = 0; blist[i].lengh; i++) {
159                 if (strncmp(dev, blist[i].headstr, blist[i].lengh) == 0)
160                         return 1;
161         }
162         return 0;
163 }
164
165 static int
166 devinfo (struct path *curpath)
167 {
168         get_lun_strings(curpath->vendor_id,
169                         curpath->product_id,
170                         curpath->rev,
171                         curpath->sg_dev);
172         get_serial(curpath->serial, curpath->sg_dev);
173         curpath->tur = do_tur(curpath->sg_dev);
174         if (!get_unique_id(curpath))
175                 return 1;
176
177         return 0;
178 }
179
180
181 static int
182 get_all_paths_sysfs(struct env * conf, struct path * all_paths)
183 {
184         int k=0;
185         struct sysfs_directory * sdir;
186         struct sysfs_directory * devp;
187         struct sysfs_link * linkp;
188         char refwwid[WWID_SIZE];
189         char empty_buff[WWID_SIZE];
190         char buff[FILE_NAME_SIZE];
191         char path[FILE_NAME_SIZE];
192         struct path curpath;
193
194         memset(empty_buff, 0, WWID_SIZE);
195         memset(refwwid, 0, WWID_SIZE);
196
197         /* if called from hotplug, only consider the paths that relate
198            to the device pointed by conf.hotplugdev */
199
200         if (strncmp("/devices", conf->hotplugdev, 8) == 0) {
201                 if (sysfsdevice2devname (buff, conf->hotplugdev))
202                         return 0;
203
204                 sprintf(curpath.sg_dev, "/dev/%s", buff);
205
206                 if (devinfo(&curpath))
207                         return 0;
208
209                 strcpy(refwwid, curpath.wwid);
210                 memset(&curpath, 0, sizeof(path));
211         }
212
213         /* if major/minor specified on the cmd line,
214            only consider affiliated paths */
215
216         if (conf->major >= 0 && conf->minor >= 0) {
217                 if (devt2devname(buff, conf->major, conf->minor))
218                         return 0;
219                 
220                 sprintf(curpath.sg_dev, "/dev/%s", buff);
221
222                 if (devinfo(&curpath))
223                         return 0;
224
225                 strcpy(refwwid, curpath.wwid);
226                 memset(&curpath, 0, sizeof(path));
227         }
228                 
229
230         sprintf(path, "%s/block", conf->sysfs_path);
231         sdir = sysfs_open_directory(path);
232         sysfs_read_directory(sdir);
233
234         dlist_for_each_data(sdir->subdirs, devp, struct sysfs_directory) {
235                 if (blacklist(devp->name))
236                         continue;
237
238                 sysfs_read_directory(devp);
239
240                 if(devp->links == NULL)
241                         continue;
242
243                 dlist_for_each_data(devp->links, linkp, struct sysfs_link) {
244                         if (!strncmp(linkp->name, "device", 6))
245                                 break;
246                 }
247
248                 if (linkp == NULL) {
249                         continue;
250                 }
251
252                 basename(devp->path, buff);
253                 sprintf(curpath.sg_dev, "/dev/%s", buff);
254
255                 if(devinfo(&curpath)) {
256                         memset(&curpath, 0, sizeof(path));
257                         continue;
258                 }
259
260                 if (memcmp(empty_buff, refwwid, WWID_SIZE) != 0 && 
261                     strncmp(curpath.wwid, refwwid, WWID_SIZE) != 0) {
262                         memset(&curpath, 0, sizeof(path));
263                         continue;
264                 }
265
266                 strcpy(all_paths[k].sg_dev, curpath.sg_dev);
267                 strcpy(all_paths[k].dev, curpath.sg_dev);
268                 strcpy(all_paths[k].wwid, curpath.wwid);
269                 strcpy(all_paths[k].vendor_id, curpath.vendor_id);
270                 strcpy(all_paths[k].product_id, curpath.product_id);
271                 all_paths[k].iopolicy = curpath.iopolicy;
272                 all_paths[k].tur = curpath.tur;
273
274                 /* done with curpath, zero for reuse */
275                 memset(&curpath, 0, sizeof(path));
276
277                 basename(linkp->target, buff);
278                 sscanf(buff, "%i:%i:%i:%i",
279                         &all_paths[k].sg_id.host_no,
280                         &all_paths[k].sg_id.channel,
281                         &all_paths[k].sg_id.scsi_id,
282                         &all_paths[k].sg_id.lun);
283                 k++;
284         }
285         sysfs_close_directory(sdir);
286         return 0;
287 }
288
289 static int
290 get_all_paths_nosysfs(struct env * conf, struct path * all_paths,
291                       struct scsi_dev * all_scsi_ids)
292 {
293         int k, i, fd;
294         char buff[FILE_NAME_SIZE];
295         char file_name[FILE_NAME_SIZE];
296
297         for (k = 0; k < conf->max_devs; k++) {
298                 strcpy(file_name, "/dev/sg");
299                 sprintf(buff, "%d", k);
300                 strncat(file_name, buff, FILE_NAME_SIZE);
301                 strcpy(all_paths[k].sg_dev, file_name);
302
303                 get_lun_strings(all_paths[k].vendor_id,
304                                 all_paths[k].product_id,
305                                 all_paths[k].rev,
306                                 all_paths[k].sg_dev);
307                 get_serial(all_paths[k].serial, all_paths[k].sg_dev);
308                 if (!get_unique_id(&all_paths[k]))
309                         continue;
310
311                 if ((fd = open(all_paths[k].sg_dev, O_RDONLY)) < 0)
312                         return 0;
313
314                 if (0 > ioctl(fd, SG_GET_SCSI_ID, &(all_paths[k].sg_id)))
315                         printf("device %s failed on sg ioctl, skip\n",
316                                file_name);
317
318                 close(fd);
319
320                 for (i = 0; i < conf->max_devs; i++) {
321                         if ((all_paths[k].sg_id.host_no ==
322                              all_scsi_ids[i].host_no)
323                             && (all_paths[k].sg_id.scsi_id ==
324                                 (all_scsi_ids[i].scsi_id.dev_id & 0xff))
325                             && (all_paths[k].sg_id.lun ==
326                                 ((all_scsi_ids[i].scsi_id.dev_id >> 8) & 0xff))
327                             && (all_paths[k].sg_id.channel ==
328                                 ((all_scsi_ids[i].scsi_id.
329                                   dev_id >> 16) & 0xff))) {
330                                 strcpy(all_paths[k].dev, all_scsi_ids[i].dev);
331                                 break;
332                         }
333                 }
334         }
335         return 0;
336 }
337
338 static int
339 get_all_scsi_ids(struct env * conf, struct scsi_dev * all_scsi_ids)
340 {
341         int k, big, little, res, host_no, fd;
342         char buff[64];
343         char fname[FILE_NAME_SIZE];
344         struct scsi_idlun my_scsi_id;
345
346         for (k = 0; k < conf->max_devs; k++) {
347                 strcpy(fname, "/dev/sd");
348                 if (k < 26) {
349                         buff[0] = 'a' + (char) k;
350                         buff[1] = '\0';
351                         strcat(fname, buff);
352                 } else if (k <= 255) {
353                         /* assumes sequence goes x,y,z,aa,ab,ac etc */
354                         big = k / 26;
355                         little = k - (26 * big);
356                         big = big - 1;
357
358                         buff[0] = 'a' + (char) big;
359                         buff[1] = 'a' + (char) little;
360                         buff[2] = '\0';
361                         strcat(fname, buff);
362                 } else
363                         strcat(fname, "xxxx");
364
365                 if ((fd = open(fname, O_RDONLY)) < 0) {
366                         if (conf->verbose)
367                                 fprintf(stderr, "can't open %s. mknod ?",
368                                         fname); 
369                         continue;
370                 }
371
372                 res = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &my_scsi_id);
373                 if (res < 0) {
374                         close(fd);
375                         printf("Could not get scsi idlun\n");
376                         continue;
377                 }
378
379                 res = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no);
380                 if (res < 0) {
381                         close(fd);
382                         printf("Could not get host_no\n");
383                         continue;
384                 }
385
386                 close(fd);
387
388                 strcpy(all_scsi_ids[k].dev, fname);
389                 all_scsi_ids[k].scsi_id = my_scsi_id;
390                 all_scsi_ids[k].host_no = host_no;
391         }
392         return 0;
393 }
394
395 /* print_path style */
396 #define ALL     0
397 #define NOWWID  1
398
399 static void
400 print_path(struct path * all_paths, int k, int style)
401 {
402         if (style != NOWWID)
403                 printf("%s ", all_paths[k].wwid);
404         else
405                 printf(" \\_");
406         printf("(%i %i %i %i) ",
407                all_paths[k].sg_id.host_no,
408                all_paths[k].sg_id.channel,
409                all_paths[k].sg_id.scsi_id, all_paths[k].sg_id.lun);
410         if(0 != strcmp(all_paths[k].sg_dev, all_paths[k].dev))
411                 printf("%s ", all_paths[k].sg_dev);
412         printf("%s ", all_paths[k].dev);
413         printf("[%.16s]\n", all_paths[k].product_id);
414 }
415
416 static void
417 print_all_path(struct env * conf, struct path * all_paths)
418 {
419         int k;
420         char empty_buff[WWID_SIZE];
421
422         memset(empty_buff, 0, WWID_SIZE);
423         for (k = 0; k < conf->max_devs; k++) {
424                 if (memcmp(empty_buff, all_paths[k].wwid, WWID_SIZE) == 0)
425                         continue;
426                 print_path(all_paths, k, ALL);
427         }
428 }
429
430 static void
431 print_all_mp(struct path * all_paths, struct multipath * mp, int nmp)
432 {
433         int k, i;
434
435         for (k = 0; k <= nmp; k++) {
436                 printf("%s\n", mp[k].wwid);
437                 for (i = 0; i <= mp[k].npaths; i++)
438                         print_path(all_paths, PINDEX(k,i), NOWWID);
439         }
440 }
441
442 static int
443 coalesce_paths(struct env * conf, struct multipath * mp,
444                struct path * all_paths)
445 {
446         int k, i, nmp, np, already_done;
447         char empty_buff[WWID_SIZE];
448
449         nmp = -1;
450         already_done = 0;
451         memset(empty_buff, 0, WWID_SIZE);
452
453         for (k = 0; k < conf->max_devs - 1; k++) {
454                 /* skip this path for some reason */
455
456                 /* 1. if path has no unique id */
457                 if (memcmp(empty_buff, all_paths[k].wwid, WWID_SIZE) == 0)
458                         continue;
459
460                 /* 2. if mp with this uid already instanciated */
461                 for (i = 0; i <= nmp; i++) {
462                         if (0 == strcmp(mp[i].wwid, all_paths[k].wwid))
463                                 already_done = 1;
464                 }
465                 if (already_done) {
466                         already_done = 0;
467                         continue;
468                 }
469
470                 /* at this point, we know we really got a new mp */
471                 np = 0;
472                 nmp++;
473                 strcpy(mp[nmp].wwid, all_paths[k].wwid);
474                 PINDEX(nmp,np) = k;
475
476                 if (mp[nmp].size == 0)
477                         mp[nmp].size = get_disk_size(all_paths[k].dev);
478
479                 for (i = k + 1; i < conf->max_devs; i++) {
480                         if (0 == strcmp(all_paths[k].wwid, all_paths[i].wwid)) {
481                                 np++;
482                                 PINDEX(nmp,np) = i;
483                                 mp[nmp].npaths = np;
484                         }
485                 }
486         }
487         return nmp;
488 }
489
490 static void
491 group_by_tur(struct multipath * mp, struct path * all_paths, char * str) {
492         int left_path_count = 0;
493         int right_path_count = 0;
494         int i;
495         char left_path_buff[FILE_NAME_SIZE], right_path_buff[FILE_NAME_SIZE];
496         char * left_path_buff_p = &left_path_buff[0];
497         char * right_path_buff_p = &right_path_buff[0];
498
499         for (i = 0; i <= mp->npaths; i++) {
500                 if (all_paths[mp->pindex[i]].tur) {
501                         left_path_buff_p += sprintf(left_path_buff_p, " %s", all_paths[mp->pindex[i]].dev);
502                         left_path_count++;
503                 } else {
504                         right_path_buff_p += sprintf(right_path_buff_p, " %s", all_paths[mp->pindex[i]].dev);
505                         right_path_count++;
506                 }
507         }
508         if (!left_path_count)
509                 sprintf(str, " 1 round-robin %i 0 %s", right_path_count, right_path_buff);
510         else if (!right_path_count)
511                 sprintf(str, " 1 round-robin %i 0 %s", left_path_count, left_path_buff);
512         else
513                 sprintf(str, " 2 round-robin %i 0 %s round-robin %i 0 %s",
514                         left_path_count, left_path_buff,
515                         right_path_count, right_path_buff);
516 }
517
518 static void
519 group_by_serial(struct multipath * mp, struct path * all_paths, char * str) {
520         int path_count, pg_count = 0;
521         int i, k;
522         int * bitmap;
523         char path_buff[FILE_NAME_SIZE];
524         char pg_buff[FILE_NAME_SIZE];
525         char * path_buff_p = &path_buff[0];
526         char * pg_buff_p = &pg_buff[0];
527
528         /* init the bitmap */
529         bitmap = malloc((mp->npaths + 1) * sizeof(int));
530         memset(bitmap, 0, (mp->npaths + 1) * sizeof(int));
531
532         for (i = 0; i <= mp->npaths; i++) {
533                 if (bitmap[i])
534                         continue;
535
536                 /* here, we really got a new pg */
537                 pg_count++;
538                 path_count = 1;
539                 memset(&path_buff, 0, FILE_NAME_SIZE * sizeof(char));
540                 path_buff_p = &path_buff[0];
541
542                 path_buff_p += sprintf(path_buff_p, " %s", all_paths[mp->pindex[i]].dev);
543                 bitmap[i] = 1;
544
545                 for (k = i + 1; k <= mp->npaths; k++) {
546                         if (bitmap[k])
547                                 continue;
548                         if (0 == strcmp(all_paths[mp->pindex[i]].serial,
549                                         all_paths[mp->pindex[k]].serial)) {
550                                 path_buff_p += sprintf(path_buff_p, " %s", all_paths[mp->pindex[k]].dev);
551                                 bitmap[k] = 1;
552                                 path_count++;
553                         }
554                 }
555                 pg_buff_p += sprintf(pg_buff_p, " round-robin %i 0%s",
556                                      path_count, path_buff);
557         }
558         sprintf(str, " %i%s", pg_count, pg_buff);
559         free(bitmap);
560 }
561
562 static int
563 dm_simplecmd(int task, const char *name) {
564         int r = 0;
565         struct dm_task *dmt;
566
567         if (!(dmt = dm_task_create(task)))
568                 return 0;
569
570         if (!dm_task_set_name(dmt, name))
571                 goto out;
572
573         r = dm_task_run(dmt);
574
575         out:
576                 dm_task_destroy(dmt);
577                 return r;
578 }
579
580 static int
581 dm_addmap(int task, const char *name, const char *params, long size) {
582         struct dm_task *dmt;
583
584         if (!(dmt = dm_task_create(task)))
585                 return 0;
586
587         if (!dm_task_set_name(dmt, name))
588                 goto addout;
589
590         if (!dm_task_add_target(dmt, 0, size, DM_TARGET, params))
591                 goto addout;
592
593         if (!dm_task_run(dmt))
594                 goto addout;
595
596         addout:
597         dm_task_destroy(dmt);
598         return 1;
599 }
600
601 static int
602 setup_map(struct env * conf, struct path * all_paths,
603         struct multipath * mp, int index, int op)
604 {
605         char params[255];
606         char * params_p;
607         int i, np;
608
609         /* defaults for multipath target */
610         char * dm_ps_name           = "round-robin";
611         int dm_ps_nr_args           = 0;
612
613         params_p = &params[0];
614
615         np = 0;
616         for (i=0; i<=mp[index].npaths; i++) {
617                 if (0 == all_paths[PINDEX(index,i)].sg_id.scsi_type)
618                         np++;
619         }
620
621         if (np < 1)
622                 return 0;
623
624         if ((all_paths[PINDEX(index,0)].iopolicy == MULTIBUS &&
625             conf->iopolicy == -1) || conf->iopolicy == MULTIBUS) {
626                 params_p += sprintf(params_p, " 1 %s %i %i",
627                                     dm_ps_name, np, dm_ps_nr_args);
628                 
629                 for (i=0; i<=mp[index].npaths; i++) {
630                         if (0 != all_paths[PINDEX(index,i)].sg_id.scsi_type)
631                                 continue;
632                         params_p += sprintf(params_p, " %s",
633                                             all_paths[PINDEX(index,i)].dev);
634                 }
635         }
636
637         if ((all_paths[PINDEX(index,0)].iopolicy == FAILOVER &&
638              conf->iopolicy == -1) || conf->iopolicy == FAILOVER) {
639                 params_p += sprintf(params_p, " %i", mp[index].npaths + 1);
640                 for (i=0; i<=mp[index].npaths; i++) {
641                         if (0 != all_paths[PINDEX(index,i)].sg_id.scsi_type)
642                                 continue;
643                         params_p += sprintf(params_p, " %s ",
644                                             dm_ps_name);
645                         params_p += sprintf(params_p, "1 %i",
646                                             dm_ps_nr_args);
647                         params_p += sprintf(params_p, " %s",
648                                             all_paths[PINDEX(index,i)].dev);
649                 }
650         }
651
652         if ((all_paths[PINDEX(index,0)].iopolicy == GROUP_BY_SERIAL &&
653              conf->iopolicy == -1) || conf->iopolicy == GROUP_BY_SERIAL) {
654                 group_by_serial(&mp[index], all_paths, params_p);
655         }
656
657         if ((all_paths[PINDEX(index,0)].iopolicy == GROUP_BY_TUR &&
658              conf->iopolicy == -1) || conf->iopolicy == GROUP_BY_TUR) {
659                 group_by_tur(&mp[index], all_paths, params_p);
660         }
661
662         if (mp[index].size < 0)
663                 return 0;
664
665         if (!conf->quiet) {
666                 if (op == DM_DEVICE_RELOAD)
667                         printf("U:");
668                 if (op == DM_DEVICE_CREATE)
669                         printf("N:");
670                 printf("%s:0 %li %s %s\n",
671                         mp[index].wwid, mp[index].size, DM_TARGET, params);
672         }
673
674         if (op == DM_DEVICE_RELOAD)
675                 dm_simplecmd(DM_DEVICE_SUSPEND, mp[index].wwid);
676
677         dm_addmap(op, mp[index].wwid, params, mp[index].size);
678
679         if (op == DM_DEVICE_RELOAD)
680                 dm_simplecmd(DM_DEVICE_RESUME, mp[index].wwid);
681
682         return 1;
683 }
684
685 static int
686 map_present(char * str)
687 {
688         int r = 0;
689         struct dm_task *dmt;
690         struct dm_names *names;
691         unsigned next = 0;
692
693         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
694                 return 0;
695
696         if (!dm_task_run(dmt))
697                 goto out;
698
699         if (!(names = dm_task_get_names(dmt)))
700                 goto out;
701
702         if (!names->dev) {
703                 goto out;
704         }
705
706         do {
707                 if (0 == strcmp(names->name, str))
708                         r = 1;
709                 next = names->next;
710                 names = (void *) names + next;
711         } while (next);
712
713         out:
714         dm_task_destroy(dmt);
715         return r;
716 }
717
718 static void
719 signal_daemon (void)
720 {
721         FILE *file;
722         pid_t pid;
723         char *buf;
724
725         buf = malloc (8);
726
727         file = fopen (PIDFILE, "r");
728
729         if (!file) {
730                 fprintf(stderr, "cannot signal daemon, pidfile not found\n");
731                 return;
732         }
733
734         buf = fgets (buf, 8, file);
735         fclose (file);
736
737         pid = (pid_t) atol (buf);
738         free (buf);
739
740         kill(pid, SIGHUP);
741 }
742
743 static int
744 filepresent(char * run) {
745         struct stat buf;
746
747         if(!stat(run, &buf))
748                 return 1;
749         return 0;
750 }
751
752 static void
753 usage(char * progname)
754 {
755         fprintf(stderr, VERSION_STRING);
756         fprintf(stderr, "Usage: %s [-v|-q] [-d] [-m max_devs]\n",
757                 progname);
758         fprintf(stderr, "                   [-p failover|multibus|group_by_serial]\n" \
759                         "                   [device]\n" \
760                         "\n" \
761                         "\t-v\t\tverbose, print all paths and multipaths\n" \
762                         "\t-q\t\tquiet, no output at all\n" \
763                         "\t-d\t\tdry run, do not create or update devmaps\n" \
764                         "\t-m max_devs\tscan {max_devs} devices at most\n" \
765                         "\n" \
766                         "\t-p policy\tforce maps to specified policy :\n" \
767                         "\t   failover\t\t- 1 path per priority group\n" \
768                         "\t   multibus\t\t- all paths in 1 priority group\n" \
769                         "\t   group_by_serial\t- 1 priority group per serial\n" \
770                         "\t   group_by_tur\t\t- 1 priority group per TUR state\n" \
771                         "\n" \
772                         "\t-D maj min\tlimit scope to the device's multipath\n" \
773                         "\t\t\t(major minor device reference)\n"
774                         "\tdevice\t\tlimit scope to the device's multipath\n" \
775                         "\t\t\t(hotplug-style $DEVPATH reference)\n"
776                 );
777         exit(1);
778 }
779
780 int
781 main(int argc, char *argv[])
782 {
783         struct multipath * mp;
784         struct path * all_paths;
785         struct scsi_dev * all_scsi_ids;
786         struct env conf;
787         int i, k, nmp;
788         int try = 0;
789
790         /* Don't run in parallel */
791         while (filepresent(RUN) && try++ < MAXTRY)
792                 usleep(100000);
793
794         if (filepresent(RUN)) {
795                 fprintf(stderr, "waited for to long. exiting\n");
796                 exit (1);
797         }
798         
799         /* Our turn */
800         if (!open(RUN, O_CREAT)) {
801                 fprintf(stderr, "can't create runfile\n");
802                 exit (1);
803         }
804                 
805         /* Default behaviour */
806         conf.max_devs = MAX_DEVS;
807         conf.dry_run = 0;       /* 1 == Do not Create/Update devmaps */
808         conf.verbose = 0;       /* 1 == Print all_paths and mp */
809         conf.quiet = 0;         /* 1 == Do not even print devmaps */
810         conf.iopolicy = -1;     /* Apply the defaults in get_unique_id() */
811         conf.major = -1;
812         conf.minor = -1;
813
814         for (i = 1; i < argc; ++i) {
815                 if (0 == strcmp("-v", argv[i])) {
816                         if (conf.quiet == 1)
817                                 usage(argv[0]);
818                         conf.verbose = 1;
819                 } else if (0 == strcmp("-m", argv[i])) {
820                         conf.max_devs = atoi(argv[++i]);
821                         if (conf.max_devs < 2)
822                                 usage(argv[0]);
823                 } else if (0 == strcmp("-D", argv[i])) {
824                         conf.major = atoi(argv[++i]);
825                         conf.minor = atoi(argv[++i]);
826                 } else if (0 == strcmp("-q", argv[i])) {
827                         if (conf.verbose == 1)
828                                 usage(argv[0]);
829                         conf.quiet = 1;
830                 } else if (0 == strcmp("-d", argv[i]))
831                         conf.dry_run = 1;
832                 else if (0 == strcmp("-p", argv[i])) {
833                         i++;
834                         if (!strcmp(argv[i], "failover"))
835                                 conf.iopolicy = FAILOVER;
836                         if (!strcmp(argv[i], "multibus"))
837                                 conf.iopolicy = MULTIBUS;
838                         if (!strcmp(argv[i], "group_by_serial"))
839                                 conf.iopolicy = GROUP_BY_SERIAL;
840                         if (!strcmp(argv[i], "group_by_tur"))
841                                 conf.iopolicy = GROUP_BY_TUR;
842                 } else if (*argv[i] == '-') {
843                         fprintf(stderr, "Unknown switch: %s\n", argv[i]);
844                         usage(argv[0]);
845                 } else
846                         strncpy(conf.hotplugdev, argv[i], FILE_NAME_SIZE);
847         }
848
849         /* dynamic allocations */
850         mp = malloc(conf.max_devs * sizeof(struct multipath));
851         all_paths = malloc(conf.max_devs * sizeof(struct path));
852         all_scsi_ids = malloc(conf.max_devs * sizeof(struct scsi_dev));
853         if (mp == NULL || all_paths == NULL || all_scsi_ids == NULL)
854                 exit(1);
855
856         if (sysfs_get_mnt_path(conf.sysfs_path, FILE_NAME_SIZE)) {
857                 get_all_scsi_ids(&conf, all_scsi_ids);
858                 get_all_paths_nosysfs(&conf, all_paths, all_scsi_ids);
859         } else {
860                 get_all_paths_sysfs(&conf, all_paths);
861         }
862
863         nmp = coalesce_paths(&conf, mp, all_paths);
864
865         if (conf.verbose) {
866                 print_all_path(&conf, all_paths);
867                 fprintf(stdout, "\n");
868                 print_all_mp(all_paths, mp, nmp);
869                 fprintf(stdout, "\n");
870         }
871
872         if (conf.dry_run)
873                 exit(0);
874
875         for (k=0; k<=nmp; k++) {
876                 if (map_present(mp[k].wwid)) {
877                         setup_map(&conf, all_paths, mp, k, DM_DEVICE_RELOAD);
878                 } else {
879                         setup_map(&conf, all_paths, mp, k, DM_DEVICE_CREATE);
880                 }
881         }
882
883         /* signal multipathd that new devmaps may have come up */
884         signal_daemon();
885         
886         /* free allocs */
887         free(mp);
888         free(all_paths);
889         free(all_scsi_ids);
890
891         /* release runfile */
892         unlink(RUN);
893
894         exit(0);
895 }