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