[libmultipath] move get_refwwid() to libmultipath/configure.c
[platform/upstream/multipath-tools.git] / 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:      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  * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
19  * Copyright (c) 2005 Benjamin Marzinski, Redhat
20  * Copyright (c) 2005 Kiyoshi Ueda, NEC
21  * Copyright (c) 2005 Patrick Caulfield, Redhat
22  * Copyright (c) 2005 Edward Goggin, EMC
23  */
24
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <sysfs/libsysfs.h>
29
30 #include <vector.h>
31 #include <memory.h>
32 #include <libdevmapper.h>
33 #include <devmapper.h>
34 #include <path_state.h>
35 #include <blacklist.h>
36 #include <util.h>
37 #include <defaults.h>
38 #include <structs.h>
39 #include <structs_vec.h>
40 #include <dmparser.h>
41 #include <cache.h>
42 #include <config.h>
43 #include <discovery.h>
44 #include <debug.h>
45 #include <switchgroup.h>
46 #include <print.h>
47 #include <alias.h>
48 #include <configure.h>
49 #include <pgpolicies.h>
50
51 #include "main.h"
52
53 static int
54 filter_pathvec (vector pathvec, char * refwwid)
55 {
56         int i;
57         struct path * pp;
58
59         if (!refwwid || !strlen(refwwid))
60                 return 0;
61
62         vector_foreach_slot (pathvec, pp, i) {
63                 if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
64                         condlog(3, "skip path %s : out of scope", pp->dev);
65                         free_path(pp);
66                         vector_del_slot(pathvec, i);
67                         i--;
68                 }
69         }
70         return 0;
71 }
72
73 static void
74 usage (char * progname)
75 {
76         fprintf (stderr, VERSION_STRING);
77         fprintf (stderr, "Usage: %s\t[-v level] [-d] [-l|-ll|-f|-F]\n",
78                 progname);
79         fprintf (stderr,
80                 "\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
81                 "\t\t\t[device]\n" \
82                 "\n" \
83                 "\t-v level\tverbosity level\n" \
84                 "\t   0\t\t\tno output\n" \
85                 "\t   1\t\t\tprint created devmap names only\n" \
86                 "\t   2\t\t\tdefault verbosity\n" \
87                 "\t   3\t\t\tprint debug information\n" \
88                 "\t-b file\t\tbindings file location\n" \
89                 "\t-d\t\tdry run, do not create or update devmaps\n" \
90                 "\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
91                 "\t-ll\t\tshow multipath topology (maximum info)\n" \
92                 "\t-f\t\tflush a multipath device map\n" \
93                 "\t-F\t\tflush all multipath device maps\n" \
94                 "\t-p policy\tforce all maps to specified policy :\n" \
95                 "\t   failover\t\t1 path per priority group\n" \
96                 "\t   multibus\t\tall paths in 1 priority group\n" \
97                 "\t   group_by_serial\t1 priority group per serial\n" \
98                 "\t   group_by_prio\t1 priority group per priority lvl\n" \
99                 "\t   group_by_node_name\t1 priority group per target node\n" \
100                 "\n" \
101                 "\tdevice\t\tlimit scope to the device's multipath\n" \
102                 "\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
103                 "\t\t\tor major:minor or a device map name)\n" \
104                 );
105
106         exit(1);
107 }
108
109 static int
110 update_paths (struct multipath * mpp)
111 {
112         int i, j;
113         struct pathgroup * pgp;
114         struct path * pp;
115
116         if (!mpp->pg)
117                 return 0;
118
119         vector_foreach_slot (mpp->pg, pgp, i) {
120                 if (!pgp->paths)
121                         continue;
122
123                 vector_foreach_slot (pgp->paths, pp, j) {
124                         if (!strlen(pp->dev)) {
125                                 if (devt2devname(pp->dev, pp->dev_t)) {
126                                         /*
127                                          * path is not in sysfs anymore
128                                          */
129                                         pp->state = PATH_DOWN;
130                                         continue;
131                                 }
132                                 pathinfo(pp, conf->hwtable, DI_ALL);
133                                 continue;
134                         }
135                         if (pp->state == PATH_UNCHECKED)
136                                 pathinfo(pp, conf->hwtable, DI_CHECKER);
137
138                         if (!pp->priority)
139                                 pathinfo(pp, conf->hwtable, DI_PRIO);
140                 }
141         }
142         return 0;
143 }
144
145 static int
146 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
147 {
148         int i;
149         struct multipath * mpp;
150
151         if (dm_get_maps(curmp, DEFAULT_TARGET))
152                 return 1;
153
154         vector_foreach_slot (curmp, mpp, i) {
155                 /*
156                  * discard out of scope maps
157                  */
158                 if (mpp->wwid && refwwid &&
159                     strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
160                         condlog(3, "skip map %s: out of scope", mpp->alias);
161                         free_multipath(mpp, KEEP_PATHS);
162                         vector_del_slot(curmp, i);
163                         i--;
164                         continue;
165                 }
166
167                 condlog(3, "params = %s", mpp->params);
168                 condlog(3, "status = %s", mpp->status);
169
170                 disassemble_map(pathvec, mpp->params, mpp);
171
172                 /*
173                  * disassemble_map() can add new paths to pathvec.
174                  * If not in "fast list mode", we need to fetch information
175                  * about them
176                  */
177                 if (conf->list != 1)
178                         update_paths(mpp);
179
180                 if (conf->list > 1)
181                         mpp->bestpg = select_path_group(mpp);
182
183                 disassemble_status(mpp->status, mpp);
184
185                 if (conf->list)
186                         print_mp(mpp, conf->verbosity);
187
188                 if (!conf->dry_run)
189                         reinstate_paths(mpp);
190         }
191         return 0;
192 }
193
194
195 /*
196  * Return value:
197  *  -1: Retry
198  *   0: Success
199  *   1: Failure
200  */
201 static int
202 configure (void)
203 {
204         vector curmp = NULL;
205         vector pathvec = NULL;
206         struct vectors vecs;
207         int r = 1;
208         int di_flag = 0;
209         char * refwwid = NULL;
210         char * dev = NULL;
211
212         /*
213          * allocate core vectors to store paths and multipaths
214          */
215         curmp = vector_alloc();
216         pathvec = vector_alloc();
217
218         if (!curmp || !pathvec) {
219                 condlog(0, "can not allocate memory");
220                 goto out;
221         }
222         vecs.pathvec = pathvec;
223         vecs.mpvec = curmp;
224
225         /*
226          * if we have a blacklisted device parameter, exit early
227          */
228         if (conf->dev) {
229                 if (!strncmp(conf->dev, "/dev/", 5) &&
230                     strlen(conf->dev) > 5)
231                         dev = conf->dev + 5;
232                 else
233                         dev = conf->dev;
234         }
235         
236         if (dev && blacklist(conf->blist, dev))
237                 goto out;
238         
239         condlog(3, "load path identifiers cache");
240         cache_load(pathvec);
241
242         if (conf->verbosity > 2)
243                 print_all_paths(pathvec, 1);
244
245         /*
246          * scope limiting must be translated into a wwid
247          * failing the translation is fatal (by policy)
248          */
249         if (conf->dev) {
250                 refwwid = get_refwwid(conf->dev, conf->dev_type, pathvec);
251
252                 if (!refwwid) {
253                         condlog(3, "scope is nul");
254                         goto out;
255                 }
256                 condlog(3, "scope limited to %s", refwwid);
257         }
258
259         /*
260          * get a path list
261          */
262         if (conf->dev)
263                 di_flag = DI_WWID;
264
265         if (conf->list > 1)
266                 /* extended path info '-ll' */
267                 di_flag |= DI_SYSFS | DI_CHECKER;
268         else if (conf->list)
269                 /* minimum path info '-l' */
270                 di_flag |= DI_SYSFS;
271         else
272                 /* maximum info */
273                 di_flag = DI_ALL;
274
275         if (path_discovery(pathvec, conf, di_flag))
276                 goto out;
277
278         if (conf->verbosity > 2)
279                 print_all_paths(pathvec, 1);
280
281         get_path_layout(pathvec);
282
283         if (get_dm_mpvec(curmp, pathvec, refwwid))
284                 goto out;
285
286         filter_pathvec(pathvec, refwwid);
287
288         if (conf->list)
289                 goto out;
290
291         /*
292          * core logic entry point
293          */
294         r = coalesce_paths(&vecs, NULL);
295
296 out:
297         if (refwwid)
298                 FREE(refwwid);
299
300         free_multipathvec(curmp, KEEP_PATHS);
301         free_pathvec(pathvec, FREE_PATHS);
302
303         return r;
304 }
305
306 int
307 main (int argc, char *argv[])
308 {
309         int arg;
310         extern char *optarg;
311         extern int optind;
312         int i, r;
313
314         if (getuid() != 0) {
315                 fprintf(stderr, "need to be root\n");
316                 exit(1);
317         }
318
319         if (dm_prereq(DEFAULT_TARGET, 1, 0, 3))
320                 exit(1);
321
322         if (sysfs_get_mnt_path(sysfs_path, FILE_NAME_SIZE)) {
323                 condlog(0, "multipath tools need sysfs mounted");
324                 exit(1);
325         }
326         if (load_config(DEFAULT_CONFIGFILE))
327                 exit(1);
328
329         while ((arg = getopt(argc, argv, ":qdl::Ffi:M:v:p:b:")) != EOF ) {
330                 switch(arg) {
331                 case 1: printf("optarg : %s\n",optarg);
332                         break;
333                 case 'v':
334                         if (sizeof(optarg) > sizeof(char *) ||
335                             !isdigit(optarg[0]))
336                                 usage (argv[0]);
337
338                         conf->verbosity = atoi(optarg);
339                         break;
340                 case 'b':
341                         conf->bindings_file = optarg;
342                         break;
343                 case 'd':
344                         conf->dry_run = 1;
345                         break;
346                 case 'f':
347                         conf->remove = FLUSH_ONE;
348                         break;
349                 case 'F':
350                         conf->remove = FLUSH_ALL;
351                         break;
352                 case 'l':
353                         conf->list = 1;
354                         conf->dry_run = 1;
355
356                         if (optarg && !strncmp(optarg, "l", 1))
357                                 conf->list++;
358
359                         break;
360                 case 'M':
361 #if _DEBUG_
362                         debug = atoi(optarg);
363 #endif
364                         break;
365                 case 'p':
366                         conf->pgpolicy_flag = get_pgpolicy_id(optarg);
367                         if (conf->pgpolicy_flag == -1) {
368                                 printf("'%s' is not a valid policy\n", optarg);
369                                 usage(argv[0]);
370                         }                
371                         break;
372                 case ':':
373                         fprintf(stderr, "Missing option arguement\n");
374                         usage(argv[0]);        
375                 case '?':
376                         fprintf(stderr, "Unknown switch: %s\n", optarg);
377                         usage(argv[0]);
378                 default:
379                         usage(argv[0]);
380                 }
381         }        
382         if (optind < argc) {
383                 conf->dev = MALLOC(FILE_NAME_SIZE);
384
385                 if (!conf->dev)
386                         goto out;
387
388                 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
389
390                 if (filepresent(conf->dev))
391                         conf->dev_type = DEV_DEVNODE;
392                 else if (sscanf(conf->dev, "%d:%d", &i, &i) == 2)
393                         conf->dev_type = DEV_DEVT;
394                 else
395                         conf->dev_type = DEV_DEVMAP;
396
397         }
398
399         if (conf->remove == FLUSH_ONE) {
400                 if (conf->dev_type == DEV_DEVMAP)
401                         dm_flush_map(conf->dev, DEFAULT_TARGET);
402                 else
403                         condlog(0, "must provide a map name to remove");
404
405                 goto out;
406         }
407         else if (conf->remove == FLUSH_ALL) {
408                 dm_flush_maps(DEFAULT_TARGET);
409                 goto out;
410         }
411         while ((r = configure()) < 0)
412                 condlog(3, "restart multipath configuration process");
413         
414 out:
415         free_config(conf);
416         dm_lib_release();
417         dm_lib_exit();
418 #ifdef _DEBUG_
419         dbg_free_final(NULL);
420 #endif
421         return r;
422 }