1 /*        $NetBSD: toolcontext.c,v 1.8 2014/11/15 01:24:38 joerg Exp $          */
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "lib.h"
19 #include "toolcontext.h"
20 #include "metadata.h"
21 #include "defaults.h"
22 #include "lvm-string.h"
23 #include "activate.h"
24 #include "filter.h"
25 #include "filter-composite.h"
26 #include "filter-md.h"
27 #include "filter-persistent.h"
28 #include "filter-regex.h"
29 #include "filter-sysfs.h"
30 #include "label.h"
31 #include "lvm-file.h"
32 #include "format-text.h"
33 #include "display.h"
34 #include "memlock.h"
35 #include "str_list.h"
36 #include "segtype.h"
37 #include "lvmcache.h"
38 #include "dev-cache.h"
39 #include "archiver.h"
40 
41 #ifdef HAVE_LIBDL
42 #include "sharedlib.h"
43 #endif
44 
45 #ifdef LVM1_INTERNAL
46 #include "format1.h"
47 #endif
48 
49 #ifdef POOL_INTERNAL
50 #include "format_pool.h"
51 #endif
52 
53 #include <locale.h>
54 #include <sys/stat.h>
55 #include <sys/utsname.h>
56 #include <syslog.h>
57 #include <time.h>
58 
59 #ifdef linux
60 #  include <malloc.h>
61 #endif
62 
_get_env_vars(struct cmd_context * cmd)63 static int _get_env_vars(struct cmd_context *cmd)
64 {
65           const char *e;
66 
67           /* Set to "" to avoid using any system directory */
68           if ((e = getenv("LVM_SYSTEM_DIR"))) {
69                     if (dm_snprintf(cmd->system_dir, sizeof(cmd->system_dir),
70                                          "%s", e) < 0) {
71                               log_error("LVM_SYSTEM_DIR environment variable "
72                                           "is too long.");
73                               return 0;
74                     }
75           }
76 
77           return 1;
78 }
79 
_get_sysfs_dir(struct cmd_context * cmd)80 static void _get_sysfs_dir(struct cmd_context *cmd)
81 {
82           static char proc_mounts[PATH_MAX];
83           static char *split[4], buffer[PATH_MAX + 16];
84           FILE *fp;
85           char *sys_mnt = NULL;
86 
87           cmd->sysfs_dir[0] = '\0';
88           if (!*cmd->proc_dir) {
89                     log_debug("No proc filesystem found: skipping sysfs detection");
90                     return;
91           }
92 
93           if (dm_snprintf(proc_mounts, sizeof(proc_mounts),
94                                "%s/mounts", cmd->proc_dir) < 0) {
95                     log_error("Failed to create /proc/mounts string for sysfs detection");
96                     return;
97           }
98 
99           if (!(fp = fopen(proc_mounts, "r"))) {
100                     log_sys_error("_get_sysfs_dir: fopen %s", proc_mounts);
101                     return;
102           }
103 
104           while (fgets(buffer, sizeof(buffer), fp)) {
105                     if (dm_split_words(buffer, 4, 0, split) == 4 &&
106                         !strcmp(split[2], "sysfs")) {
107                               sys_mnt = split[1];
108                               break;
109                     }
110           }
111 
112           if (fclose(fp))
113                     log_sys_error("fclose", proc_mounts);
114 
115           if (!sys_mnt) {
116                     log_error("Failed to find sysfs mount point");
117                     return;
118           }
119 
120           strncpy(cmd->sysfs_dir, sys_mnt, sizeof(cmd->sysfs_dir));
121 }
122 
_init_logging(struct cmd_context * cmd)123 static void _init_logging(struct cmd_context *cmd)
124 {
125           int append = 1;
126           time_t t;
127 
128           const char *log_file;
129           char timebuf[26];
130 
131           /* Syslog */
132           cmd->default_settings.syslog =
133               find_config_tree_int(cmd, "log/syslog", DEFAULT_SYSLOG);
134           if (cmd->default_settings.syslog != 1)
135                     fin_syslog();
136 
137           if (cmd->default_settings.syslog > 1)
138                     init_syslog(cmd->default_settings.syslog);
139 
140           /* Debug level for log file output */
141           cmd->default_settings.debug =
142               find_config_tree_int(cmd, "log/level", DEFAULT_LOGLEVEL);
143           init_debug(cmd->default_settings.debug);
144 
145           /* Verbose level for tty output */
146           cmd->default_settings.verbose =
147               find_config_tree_int(cmd, "log/verbose", DEFAULT_VERBOSE);
148           init_verbose(cmd->default_settings.verbose + VERBOSE_BASE_LEVEL);
149 
150           /* Log message formatting */
151           init_indent(find_config_tree_int(cmd, "log/indent",
152                                             DEFAULT_INDENT));
153 
154           cmd->default_settings.msg_prefix = find_config_tree_str(cmd,
155                                                                          "log/prefix",
156                                                                          DEFAULT_MSG_PREFIX);
157           init_msg_prefix(cmd->default_settings.msg_prefix);
158 
159           cmd->default_settings.cmd_name = find_config_tree_int(cmd,
160                                                                        "log/command_names",
161                                                                        DEFAULT_CMD_NAME);
162           init_cmd_name(cmd->default_settings.cmd_name);
163 
164           /* Test mode */
165           cmd->default_settings.test =
166               find_config_tree_int(cmd, "global/test", 0);
167           init_test(cmd->default_settings.test);
168 
169           /* Settings for logging to file */
170           if (find_config_tree_int(cmd, "log/overwrite", DEFAULT_OVERWRITE))
171                     append = 0;
172 
173           log_file = find_config_tree_str(cmd, "log/file", 0);
174 
175           if (log_file) {
176                     release_log_memory();
177                     fin_log();
178                     init_log_file(log_file, append);
179           }
180 
181           log_file = find_config_tree_str(cmd, "log/activate_file", 0);
182           if (log_file)
183                     init_log_direct(log_file, append);
184 
185           init_log_while_suspended(find_config_tree_int(cmd,
186                                                              "log/activation", 0));
187 
188           t = time(NULL);
189           ctime_r(&t, &timebuf[0]);
190           timebuf[24] = '\0';
191           log_verbose("Logging initialised at %s", timebuf);
192 
193           /* Tell device-mapper about our logging */
194 #ifdef DEVMAPPER_SUPPORT
195           dm_log_with_errno_init(print_log);
196 #endif
197 }
198 
_process_config(struct cmd_context * cmd)199 static int _process_config(struct cmd_context *cmd)
200 {
201           mode_t old_umask;
202           const char *read_ahead;
203           struct stat st;
204 
205           /* umask */
206           cmd->default_settings.umask = find_config_tree_int(cmd,
207                                                                   "global/umask",
208                                                                   DEFAULT_UMASK);
209 
210           if ((old_umask = umask((mode_t) cmd->default_settings.umask)) !=
211               (mode_t) cmd->default_settings.umask)
212                     log_verbose("Set umask to %04o", cmd->default_settings.umask);
213 
214           /* dev dir */
215           if (dm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
216                                find_config_tree_str(cmd, "devices/dir",
217                                                    DEFAULT_DEV_DIR)) < 0) {
218                     log_error("Device directory given in config file too long");
219                     return 0;
220           }
221 #ifdef DEVMAPPER_SUPPORT
222           dm_set_dev_dir(cmd->dev_dir);
223 #endif
224 #ifndef __NetBSD__
225           /* proc dir */
226           if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
227                                find_config_tree_str(cmd, "global/proc",
228                                                    DEFAULT_PROC_DIR)) < 0) {
229                     log_error("Device directory given in config file too long");
230                     return 0;
231           }
232 #endif
233           if (*cmd->proc_dir && !dir_exists(cmd->proc_dir)) {
234                     log_error("WARNING: proc dir %s not found - some checks will be bypassed",
235                                 cmd->proc_dir);
236                     *cmd->proc_dir = '\0';
237           }
238 
239           _get_sysfs_dir(cmd);
240 
241           /* activation? */
242           cmd->default_settings.activation = find_config_tree_int(cmd,
243                                                                          "global/activation",
244                                                                          DEFAULT_ACTIVATION);
245           set_activation(cmd->default_settings.activation);
246 
247           cmd->default_settings.suffix = find_config_tree_int(cmd,
248                                                                    "global/suffix",
249                                                                    DEFAULT_SUFFIX);
250 
251           if (!(cmd->default_settings.unit_factor =
252                 units_to_bytes(find_config_tree_str(cmd,
253                                                        "global/units",
254                                                        DEFAULT_UNITS),
255                                    &cmd->default_settings.unit_type))) {
256                     log_error("Invalid units specification");
257                     return 0;
258           }
259 
260           read_ahead = find_config_tree_str(cmd, "activation/readahead", DEFAULT_READ_AHEAD);
261           if (!strcasecmp(read_ahead, "auto"))
262                     cmd->default_settings.read_ahead = DM_READ_AHEAD_AUTO;
263           else if (!strcasecmp(read_ahead, "none"))
264                     cmd->default_settings.read_ahead = DM_READ_AHEAD_NONE;
265           else {
266                     log_error("Invalid readahead specification");
267                     return 0;
268           }
269 
270           cmd->default_settings.udev_sync = find_config_tree_int(cmd,
271                                                                                 "activation/udev_sync",
272                                                                                 DEFAULT_UDEV_SYNC);
273 
274           cmd->stripe_filler = find_config_tree_str(cmd,
275                                                               "activation/missing_stripe_filler",
276                                                               DEFAULT_STRIPE_FILLER);
277 
278           /* FIXME Missing error code checks from the stats, not log_warn?, notify if setting overridden, delay message/check till it is actually used (eg consider if lvm shell - file could appear later after this check)? */
279           if (!strcmp(cmd->stripe_filler, "/dev/ioerror") &&
280               stat(cmd->stripe_filler, &st))
281                     cmd->stripe_filler = "error";
282 
283           if (strcmp(cmd->stripe_filler, "error")) {
284                     if (stat(cmd->stripe_filler, &st)) {
285                               log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
286                                          "is invalid,", cmd->stripe_filler);
287                               log_warn("         stat failed: %s", strerror(errno));
288                               log_warn("Falling back to \"error\" missing_stripe_filler.");
289                               cmd->stripe_filler = "error";
290                     } else if (!S_ISBLK(st.st_mode)) {
291                               log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
292                                          "is not a block device.", cmd->stripe_filler);
293                               log_warn("Falling back to \"error\" missing_stripe_filler.");
294                               cmd->stripe_filler = "error";
295                     }
296           }
297 
298           cmd->si_unit_consistency = find_config_tree_int(cmd,
299                                                               "global/si_unit_consistency",
300                                                               DEFAULT_SI_UNIT_CONSISTENCY);
301 
302           return 1;
303 }
304 
_set_tag(struct cmd_context * cmd,const char * tag)305 static int _set_tag(struct cmd_context *cmd, const char *tag)
306 {
307           log_very_verbose("Setting host tag: %s", dm_pool_strdup(cmd->libmem, tag));
308 
309           if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
310                     log_error("_set_tag: str_list_add %s failed", tag);
311                     return 0;
312           }
313 
314           return 1;
315 }
316 
_check_host_filters(struct cmd_context * cmd,struct config_node * hn,int * passes)317 static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
318                                      int *passes)
319 {
320           struct config_node *cn;
321           struct config_value *cv;
322 
323           *passes = 1;
324 
325           for (cn = hn; cn; cn = cn->sib) {
326                     if (!cn->v)
327                               continue;
328                     if (!strcmp(cn->key, "host_list")) {
329                               *passes = 0;
330                               if (cn->v->type == CFG_EMPTY_ARRAY)
331                                         continue;
332                               for (cv = cn->v; cv; cv = cv->next) {
333                                         if (cv->type != CFG_STRING) {
334                                                   log_error("Invalid hostname string "
335                                                               "for tag %s", cn->key);
336                                                   return 0;
337                                         }
338                                         if (!strcmp(cv->v.str, cmd->hostname)) {
339                                                   *passes = 1;
340                                                   return 1;
341                                         }
342                               }
343                     }
344                     if (!strcmp(cn->key, "host_filter")) {
345                               log_error("host_filter not supported yet");
346                               return 0;
347                     }
348           }
349 
350           return 1;
351 }
352 
_init_tags(struct cmd_context * cmd,struct config_tree * cft)353 static int _init_tags(struct cmd_context *cmd, struct config_tree *cft)
354 {
355           const struct config_node *tn, *cn;
356           const char *tag;
357           int passes;
358 
359           if (!(tn = find_config_node(cft->root, "tags")) || !tn->child)
360                     return 1;
361 
362           /* NB hosttags 0 when already 1 intentionally does not delete the tag */
363           if (!cmd->hosttags && find_config_int(cft->root, "tags/hosttags",
364                                                         DEFAULT_HOSTTAGS)) {
365                     /* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
366                     if (!_set_tag(cmd, cmd->hostname))
367                               return_0;
368                     cmd->hosttags = 1;
369           }
370 
371           for (cn = tn->child; cn; cn = cn->sib) {
372                     if (cn->v)
373                               continue;
374                     tag = cn->key;
375                     if (*tag == '@')
376                               tag++;
377                     if (!validate_name(tag)) {
378                               log_error("Invalid tag in config file: %s", cn->key);
379                               return 0;
380                     }
381                     if (cn->child) {
382                               passes = 0;
383                               if (!_check_host_filters(cmd, cn->child, &passes))
384                                         return_0;
385                               if (!passes)
386                                         continue;
387                     }
388                     if (!_set_tag(cmd, tag))
389                               return_0;
390           }
391 
392           return 1;
393 }
394 
_load_config_file(struct cmd_context * cmd,const char * tag)395 static int _load_config_file(struct cmd_context *cmd, const char *tag)
396 {
397           char config_file[PATH_MAX] = "";
398           const char *filler = "";
399           struct stat info;
400           struct config_tree_list *cfl;
401 
402           if (*tag)
403                     filler = "_";
404 
405           if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
406                                cmd->system_dir, filler, tag) < 0) {
407                     log_error("LVM_SYSTEM_DIR or tag was too long");
408                     return 0;
409           }
410 
411           if (!(cfl = dm_pool_alloc(cmd->libmem, sizeof(*cfl)))) {
412                     log_error("config_tree_list allocation failed");
413                     return 0;
414           }
415 
416           if (!(cfl->cft = create_config_tree(config_file, 0))) {
417                     log_error("config_tree allocation failed");
418                     return 0;
419           }
420 
421           /* Is there a config file? */
422           if (stat(config_file, &info) == -1) {
423                     if (errno == ENOENT) {
424                               dm_list_add(&cmd->config_files, &cfl->list);
425                               goto out;
426                     }
427                     log_sys_error("stat", config_file);
428                     destroy_config_tree(cfl->cft);
429                     return 0;
430           }
431 
432           log_very_verbose("Loading config file: %s", config_file);
433           if (!read_config_file(cfl->cft)) {
434                     log_error("Failed to load config file %s", config_file);
435                     destroy_config_tree(cfl->cft);
436                     return 0;
437           }
438 
439           dm_list_add(&cmd->config_files, &cfl->list);
440 
441       out:
442           if (*tag)
443                     _init_tags(cmd, cfl->cft);
444           else
445                     /* Use temporary copy of lvm.conf while loading other files */
446                     cmd->cft = cfl->cft;
447 
448           return 1;
449 }
450 
451 /* Find and read first config file */
_init_lvm_conf(struct cmd_context * cmd)452 static int _init_lvm_conf(struct cmd_context *cmd)
453 {
454           /* No config file if LVM_SYSTEM_DIR is empty */
455           if (!*cmd->system_dir) {
456                     if (!(cmd->cft = create_config_tree(NULL, 0))) {
457                               log_error("Failed to create config tree");
458                               return 0;
459                     }
460                     return 1;
461           }
462 
463           if (!_load_config_file(cmd, ""))
464                     return_0;
465 
466           return 1;
467 }
468 
469 /* Read any additional config files */
_init_tag_configs(struct cmd_context * cmd)470 static int _init_tag_configs(struct cmd_context *cmd)
471 {
472           struct str_list *sl;
473 
474           /* Tag list may grow while inside this loop */
475           dm_list_iterate_items(sl, &cmd->tags) {
476                     if (!_load_config_file(cmd, sl->str))
477                               return_0;
478           }
479 
480           return 1;
481 }
482 
_merge_config_files(struct cmd_context * cmd)483 static int _merge_config_files(struct cmd_context *cmd)
484 {
485           struct config_tree_list *cfl;
486 
487           /* Replace temporary duplicate copy of lvm.conf */
488           if (cmd->cft->root) {
489                     if (!(cmd->cft = create_config_tree(NULL, 0))) {
490                               log_error("Failed to create config tree");
491                               return 0;
492                     }
493           }
494 
495           dm_list_iterate_items(cfl, &cmd->config_files) {
496                     /* Merge all config trees into cmd->cft using merge/tag rules */
497                     if (!merge_config_tree(cmd, cmd->cft, cfl->cft))
498                               return_0;
499           }
500 
501           return 1;
502 }
503 
_destroy_tags(struct cmd_context * cmd)504 static void _destroy_tags(struct cmd_context *cmd)
505 {
506           struct dm_list *slh, *slht;
507 
508           dm_list_iterate_safe(slh, slht, &cmd->tags) {
509                     dm_list_del(slh);
510           }
511 }
512 
config_files_changed(struct cmd_context * cmd)513 int config_files_changed(struct cmd_context *cmd)
514 {
515           struct config_tree_list *cfl;
516 
517           dm_list_iterate_items(cfl, &cmd->config_files) {
518                     if (config_file_changed(cfl->cft))
519                               return 1;
520           }
521 
522           return 0;
523 }
524 
_destroy_tag_configs(struct cmd_context * cmd)525 static void _destroy_tag_configs(struct cmd_context *cmd)
526 {
527           struct config_tree_list *cfl;
528 
529           dm_list_iterate_items(cfl, &cmd->config_files) {
530                     if (cfl->cft == cmd->cft)
531                               cmd->cft = NULL;
532                     destroy_config_tree(cfl->cft);
533           }
534 
535           if (cmd->cft) {
536                     destroy_config_tree(cmd->cft);
537                     cmd->cft = NULL;
538           }
539 
540           dm_list_init(&cmd->config_files);
541 }
542 
_init_dev_cache(struct cmd_context * cmd)543 static int _init_dev_cache(struct cmd_context *cmd)
544 {
545           const struct config_node *cn;
546           struct config_value *cv;
547 
548           if (!dev_cache_init(cmd))
549                     return_0;
550 
551           if (!(cn = find_config_tree_node(cmd, "devices/scan"))) {
552                     if (!dev_cache_add_dir("/dev")) {
553                               log_error("Failed to add /dev to internal "
554                                           "device cache");
555                               return 0;
556                     }
557                     log_verbose("device/scan not in config file: "
558                                   "Defaulting to /dev");
559                     return 1;
560           }
561 
562           for (cv = cn->v; cv; cv = cv->next) {
563                     if (cv->type != CFG_STRING) {
564                               log_error("Invalid string in config file: "
565                                           "devices/scan");
566                               return 0;
567                     }
568 
569                     if (!dev_cache_add_dir(cv->v.str)) {
570                               log_error("Failed to add %s to internal device cache",
571                                           cv->v.str);
572                               return 0;
573                     }
574           }
575 
576           if (!(cn = find_config_tree_node(cmd, "devices/loopfiles")))
577                     return 1;
578 
579           for (cv = cn->v; cv; cv = cv->next) {
580                     if (cv->type != CFG_STRING) {
581                               log_error("Invalid string in config file: "
582                                           "devices/loopfiles");
583                               return 0;
584                     }
585 
586                     if (!dev_cache_add_loopfile(cv->v.str)) {
587                               log_error("Failed to add loopfile %s to internal "
588                                           "device cache", cv->v.str);
589                               return 0;
590                     }
591           }
592 
593 
594           return 1;
595 }
596 
597 #define MAX_FILTERS 4
598 
_init_filter_components(struct cmd_context * cmd)599 static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
600 {
601           unsigned nr_filt = 0;
602           const struct config_node *cn;
603           struct dev_filter *filters[MAX_FILTERS];
604 
605           memset(filters, 0, sizeof(filters));
606 
607           /*
608            * Filters listed in order: top one gets applied first.
609            * Failure to initialise some filters is not fatal.
610            * Update MAX_FILTERS definition above when adding new filters.
611            */
612 
613           /*
614            * sysfs filter. Only available on 2.6 kernels.  Non-critical.
615            * Listed first because it's very efficient at eliminating
616            * unavailable devices.
617            */
618           if (find_config_tree_bool(cmd, "devices/sysfs_scan",
619                                    DEFAULT_SYSFS_SCAN)) {
620                     if ((filters[nr_filt] = sysfs_filter_create(cmd->sysfs_dir)))
621                               nr_filt++;
622           }
623 
624           /* regex filter. Optional. */
625           if (!(cn = find_config_tree_node(cmd, "devices/filter")))
626                     log_very_verbose("devices/filter not found in config file: "
627                                          "no regex filter installed");
628 
629           else if (!(filters[nr_filt++] = regex_filter_create(cn->v))) {
630                     log_error("Failed to create regex device filter");
631                     return NULL;
632           }
633 
634           /* device type filter. Required. */
635           cn = find_config_tree_node(cmd, "devices/types");
636           if (!(filters[nr_filt++] = lvm_type_filter_create(cmd->proc_dir, cn))) {
637                     log_error("Failed to create lvm type filter");
638                     return NULL;
639           }
640 
641           /* md component filter. Optional, non-critical. */
642           if (find_config_tree_bool(cmd, "devices/md_component_detection",
643                                    DEFAULT_MD_COMPONENT_DETECTION)) {
644                     init_md_filtering(1);
645                     if ((filters[nr_filt] = md_filter_create()))
646                               nr_filt++;
647           }
648 
649           /* Only build a composite filter if we really need it. */
650           return (nr_filt == 1) ?
651               filters[0] : composite_filter_create(nr_filt, filters);
652 }
653 
_init_filters(struct cmd_context * cmd,unsigned load_persistent_cache)654 static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
655 {
656           const char *dev_cache = NULL, *cache_dir, *cache_file_prefix;
657           struct dev_filter *f3, *f4;
658           struct stat st;
659           char cache_file[PATH_MAX];
660 
661           cmd->dump_filter = 0;
662 
663           if (!(f3 = _init_filter_components(cmd)))
664                     return 0;
665 
666           init_ignore_suspended_devices(find_config_tree_int(cmd,
667               "devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
668 
669           /*
670            * If 'cache_dir' or 'cache_file_prefix' is set, ignore 'cache'.
671            */
672           cache_dir = find_config_tree_str(cmd, "devices/cache_dir", NULL);
673           cache_file_prefix = find_config_tree_str(cmd, "devices/cache_file_prefix", NULL);
674 
675           if (cache_dir || cache_file_prefix) {
676                     if (dm_snprintf(cache_file, sizeof(cache_file),
677                         "%s%s%s/%s.cache",
678                         cache_dir ? "" : cmd->system_dir,
679                         cache_dir ? "" : "/",
680                         cache_dir ? : DEFAULT_CACHE_SUBDIR,
681                         cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
682                               log_error("Persistent cache filename too long.");
683                               return 0;
684                     }
685           } else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
686                        (dm_snprintf(cache_file, sizeof(cache_file),
687                                         "%s/%s/%s.cache",
688                                         cmd->system_dir, DEFAULT_CACHE_SUBDIR,
689                                         DEFAULT_CACHE_FILE_PREFIX) < 0)) {
690                     log_error("Persistent cache filename too long.");
691                     return 0;
692           }
693 
694           if (!dev_cache)
695                     dev_cache = cache_file;
696 
697           if (!(f4 = persistent_filter_create(f3, dev_cache))) {
698                     log_error("Failed to create persistent device filter");
699                     return 0;
700           }
701 
702           /* Should we ever dump persistent filter state? */
703           if (find_config_tree_int(cmd, "devices/write_cache_state", 1))
704                     cmd->dump_filter = 1;
705 
706           if (!*cmd->system_dir)
707                     cmd->dump_filter = 0;
708 
709           /*
710            * Only load persistent filter device cache on startup if it is newer
711            * than the config file and this is not a long-lived process.
712            */
713           if (load_persistent_cache && !cmd->is_long_lived &&
714               !stat(dev_cache, &st) &&
715               (st.st_ctime > config_file_timestamp(cmd->cft)) &&
716               !persistent_filter_load(f4, NULL))
717                     log_verbose("Failed to load existing device cache from %s",
718                                   dev_cache);
719 
720           cmd->filter = f4;
721 
722           return 1;
723 }
724 
_init_formats(struct cmd_context * cmd)725 static int _init_formats(struct cmd_context *cmd)
726 {
727           const char *format;
728 
729           struct format_type *fmt;
730 
731 #ifdef HAVE_LIBDL
732           const struct config_node *cn;
733 #endif
734 
735           label_init();
736 
737 #ifdef LVM1_INTERNAL
738           if (!(fmt = init_lvm1_format(cmd)))
739                     return 0;
740           fmt->library = NULL;
741           dm_list_add(&cmd->formats, &fmt->list);
742 #endif
743 
744 #ifdef POOL_INTERNAL
745           if (!(fmt = init_pool_format(cmd)))
746                     return 0;
747           fmt->library = NULL;
748           dm_list_add(&cmd->formats, &fmt->list);
749 #endif
750 
751 #ifdef HAVE_LIBDL
752           /* Load any formats in shared libs if not static */
753           if (!is_static() &&
754               (cn = find_config_tree_node(cmd, "global/format_libraries"))) {
755 
756                     struct config_value *cv;
757                     struct format_type *(*init_format_fn) (struct cmd_context *);
758                     void *lib;
759 
760                     for (cv = cn->v; cv; cv = cv->next) {
761                               if (cv->type != CFG_STRING) {
762                                         log_error("Invalid string in config file: "
763                                                     "global/format_libraries");
764                                         return 0;
765                               }
766                               if (!(lib = load_shared_library(cmd, cv->v.str,
767                                                                       "format", 0)))
768                                         return_0;
769 
770                               if (!(init_format_fn = dlsym(lib, "init_format"))) {
771                                         log_error("Shared library %s does not contain "
772                                                     "format functions", cv->v.str);
773                                         dlclose(lib);
774                                         return 0;
775                               }
776 
777                               if (!(fmt = init_format_fn(cmd)))
778                                         return 0;
779                               fmt->library = lib;
780                               dm_list_add(&cmd->formats, &fmt->list);
781                     }
782           }
783 #endif
784 
785           if (!(fmt = create_text_format(cmd)))
786                     return 0;
787           fmt->library = NULL;
788           dm_list_add(&cmd->formats, &fmt->list);
789 
790           cmd->fmt_backup = fmt;
791 
792           format = find_config_tree_str(cmd, "global/format",
793                                          DEFAULT_FORMAT);
794 
795           dm_list_iterate_items(fmt, &cmd->formats) {
796                     if (!strcasecmp(fmt->name, format) ||
797                         (fmt->alias && !strcasecmp(fmt->alias, format))) {
798                               cmd->default_settings.fmt = fmt;
799                               cmd->fmt = cmd->default_settings.fmt;
800                               return 1;
801                     }
802           }
803 
804           log_error("_init_formats: Default format (%s) not found", format);
805           return 0;
806 }
807 
init_lvmcache_orphans(struct cmd_context * cmd)808 int init_lvmcache_orphans(struct cmd_context *cmd)
809 {
810           struct format_type *fmt;
811 
812           dm_list_iterate_items(fmt, &cmd->formats)
813                     if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt))
814                               return_0;
815 
816           return 1;
817 }
818 
819 struct segtype_library {
820           struct cmd_context *cmd;
821           void *lib;
822           const char *libname;
823 };
824 
lvm_register_segtype(struct segtype_library * seglib,struct segment_type * segtype)825 int lvm_register_segtype(struct segtype_library *seglib,
826                                struct segment_type *segtype)
827 {
828           struct segment_type *segtype2;
829 
830           segtype->library = seglib->lib;
831           segtype->cmd = seglib->cmd;
832 
833           dm_list_iterate_items(segtype2, &seglib->cmd->segtypes) {
834                     if (strcmp(segtype2->name, segtype->name))
835                               continue;
836                     log_error("Duplicate segment type %s: "
837                                 "unloading shared library %s",
838                                 segtype->name, seglib->libname);
839                     segtype->ops->destroy(segtype);
840                     return 0;
841           }
842 
843           dm_list_add(&seglib->cmd->segtypes, &segtype->list);
844 
845           return 1;
846 }
847 
848 #ifdef __NetBSD__
849 #include <dlfcn.h>
850 #endif
851 
_init_single_segtype(struct cmd_context * cmd,struct segtype_library * seglib)852 static int _init_single_segtype(struct cmd_context *cmd,
853                                         struct segtype_library *seglib)
854 {
855           struct segment_type *(*init_segtype_fn) (struct cmd_context *);
856           struct segment_type *segtype;
857 
858           if (!(init_segtype_fn = dlsym(seglib->lib, "init_segtype"))) {
859                     log_error("Shared library %s does not contain segment type "
860                                 "functions", seglib->libname);
861                     return 0;
862           }
863 
864           if (!(segtype = init_segtype_fn(seglib->cmd)))
865                     return_0;
866 
867           return lvm_register_segtype(seglib, segtype);
868 }
869 
_init_segtypes(struct cmd_context * cmd)870 static int _init_segtypes(struct cmd_context *cmd)
871 {
872           struct segment_type *segtype;
873           struct segtype_library seglib = { .cmd = cmd };
874 
875 #ifdef HAVE_LIBDL
876           const struct config_node *cn;
877 #endif
878 
879           if (!(segtype = init_striped_segtype(cmd)))
880                     return 0;
881           segtype->library = NULL;
882           dm_list_add(&cmd->segtypes, &segtype->list);
883 
884           if (!(segtype = init_zero_segtype(cmd)))
885                     return 0;
886           segtype->library = NULL;
887           dm_list_add(&cmd->segtypes, &segtype->list);
888 
889           if (!(segtype = init_error_segtype(cmd)))
890                     return 0;
891           segtype->library = NULL;
892           dm_list_add(&cmd->segtypes, &segtype->list);
893 
894           if (!(segtype = init_free_segtype(cmd)))
895                     return 0;
896           segtype->library = NULL;
897           dm_list_add(&cmd->segtypes, &segtype->list);
898 
899 #ifdef SNAPSHOT_INTERNAL
900           if (!(segtype = init_snapshot_segtype(cmd)))
901                     return 0;
902           segtype->library = NULL;
903           dm_list_add(&cmd->segtypes, &segtype->list);
904 #endif
905 
906 #ifdef MIRRORED_INTERNAL
907           if (!(segtype = init_mirrored_segtype(cmd)))
908                     return 0;
909           segtype->library = NULL;
910           dm_list_add(&cmd->segtypes, &segtype->list);
911 #endif
912 
913 #ifdef HAVE_LIBDL
914           /* Load any formats in shared libs unless static */
915           if (!is_static() &&
916               (cn = find_config_tree_node(cmd, "global/segment_libraries"))) {
917 
918                     struct config_value *cv;
919                     int (*init_multiple_segtypes_fn) (struct cmd_context *,
920                                                               struct segtype_library *);
921 
922                     for (cv = cn->v; cv; cv = cv->next) {
923                               if (cv->type != CFG_STRING) {
924                                         log_error("Invalid string in config file: "
925                                                     "global/segment_libraries");
926                                         return 0;
927                               }
928                               seglib.libname = cv->v.str;
929                               if (!(seglib.lib = load_shared_library(cmd,
930                                                                       seglib.libname,
931                                                                       "segment type", 0)))
932                                         return_0;
933 
934                               if ((init_multiple_segtypes_fn =
935                                   dlsym(seglib.lib, "init_multiple_segtypes"))) {
936                                         if (dlsym(seglib.lib, "init_segtype"))
937                                                   log_warn("WARNING: Shared lib %s has "
938                                                              "conflicting init fns.  Using"
939                                                              " init_multiple_segtypes().",
940                                                              seglib.libname);
941                               } else
942                                         init_multiple_segtypes_fn =
943                                             _init_single_segtype;
944 
945                               if (!init_multiple_segtypes_fn(cmd, &seglib)) {
946                                         struct dm_list *sgtl, *tmp;
947                                         log_error("init_multiple_segtypes() failed: "
948                                                     "Unloading shared library %s",
949                                                     seglib.libname);
950                                         dm_list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
951                                                   segtype = dm_list_item(sgtl, struct segment_type);
952                                                   if (segtype->library == seglib.lib) {
953                                                             dm_list_del(&segtype->list);
954                                                             segtype->ops->destroy(segtype);
955                                                   }
956                                         }
957                                         dlclose(seglib.lib);
958                                         return_0;
959                               }
960                     }
961           }
962 #endif
963 
964           return 1;
965 }
966 
_init_hostname(struct cmd_context * cmd)967 static int _init_hostname(struct cmd_context *cmd)
968 {
969           struct utsname uts;
970 
971           if (uname(&uts)) {
972                     log_sys_error("uname", "_init_hostname");
973                     return 0;
974           }
975 
976           if (!(cmd->hostname = dm_pool_strdup(cmd->libmem, uts.nodename))) {
977                     log_error("_init_hostname: dm_pool_strdup failed");
978                     return 0;
979           }
980 
981           if (!(cmd->kernel_vsn = dm_pool_strdup(cmd->libmem, uts.release))) {
982                     log_error("_init_hostname: dm_pool_strdup kernel_vsn failed");
983                     return 0;
984           }
985 
986           return 1;
987 }
988 
_init_backup(struct cmd_context * cmd)989 static int _init_backup(struct cmd_context *cmd)
990 {
991           uint32_t days, min;
992           char default_dir[PATH_MAX];
993           const char *dir;
994 
995 #if 0
996           if (!cmd->system_dir) {
997                     log_warn("WARNING: Metadata changes will NOT be backed up");
998                     backup_init(cmd, "", 0);
999                     archive_init(cmd, "", 0, 0, 0);
1000                     return 1;
1001           }
1002 #endif
1003 
1004           /* set up archiving */
1005           cmd->default_settings.archive =
1006               find_config_tree_bool(cmd, "backup/archive",
1007                                    DEFAULT_ARCHIVE_ENABLED);
1008 
1009           days = (uint32_t) find_config_tree_int(cmd, "backup/retain_days",
1010                                                     DEFAULT_ARCHIVE_DAYS);
1011 
1012           min = (uint32_t) find_config_tree_int(cmd, "backup/retain_min",
1013                                                    DEFAULT_ARCHIVE_NUMBER);
1014 
1015           if (dm_snprintf
1016               (default_dir, sizeof(default_dir), "%s/%s", cmd->system_dir,
1017                DEFAULT_ARCHIVE_SUBDIR) == -1) {
1018                     log_error("Couldn't create default archive path '%s/%s'.",
1019                                 cmd->system_dir, DEFAULT_ARCHIVE_SUBDIR);
1020                     return 0;
1021           }
1022 
1023           dir = find_config_tree_str(cmd, "backup/archive_dir",
1024                                     default_dir);
1025 
1026           if (!archive_init(cmd, dir, days, min,
1027                                 cmd->default_settings.archive)) {
1028                     log_debug("archive_init failed.");
1029                     return 0;
1030           }
1031 
1032           /* set up the backup */
1033           cmd->default_settings.backup =
1034               find_config_tree_bool(cmd, "backup/backup",
1035                                    DEFAULT_BACKUP_ENABLED);
1036 
1037           if (dm_snprintf
1038               (default_dir, sizeof(default_dir), "%s/%s", cmd->system_dir,
1039                DEFAULT_BACKUP_SUBDIR) == -1) {
1040                     log_error("Couldn't create default backup path '%s/%s'.",
1041                                 cmd->system_dir, DEFAULT_BACKUP_SUBDIR);
1042                     return 0;
1043           }
1044 
1045           dir = find_config_tree_str(cmd, "backup/backup_dir", default_dir);
1046 
1047           if (!backup_init(cmd, dir, cmd->default_settings.backup)) {
1048                     log_debug("backup_init failed.");
1049                     return 0;
1050           }
1051 
1052           return 1;
1053 }
1054 
_init_rand(struct cmd_context * cmd)1055 static void _init_rand(struct cmd_context *cmd)
1056 {
1057           if (read_urandom(&cmd->rand_seed, sizeof(cmd->rand_seed)))
1058                     return;
1059 
1060           cmd->rand_seed = (unsigned) time(NULL) + (unsigned) getpid();
1061 }
1062 
_init_globals(struct cmd_context * cmd)1063 static void _init_globals(struct cmd_context *cmd)
1064 {
1065           init_full_scan_done(0);
1066           init_mirror_in_sync(0);
1067 
1068 }
1069 
1070 /* Entry point */
create_toolcontext(unsigned is_long_lived,const char * system_dir)1071 struct cmd_context *create_toolcontext(unsigned is_long_lived,
1072                                                const char *system_dir)
1073 {
1074           struct cmd_context *cmd;
1075 
1076 #ifdef M_MMAP_MAX
1077           mallopt(M_MMAP_MAX, 0);
1078 #endif
1079 
1080           if (!setlocale(LC_ALL, ""))
1081                     log_very_verbose("setlocale failed");
1082 
1083 #ifdef INTL_PACKAGE
1084           bindtextdomain(INTL_PACKAGE, LOCALEDIR);
1085 #endif
1086 
1087           init_syslog(DEFAULT_LOG_FACILITY);
1088 
1089           if (!(cmd = dm_malloc(sizeof(*cmd)))) {
1090                     log_error("Failed to allocate command context");
1091                     return NULL;
1092           }
1093           memset(cmd, 0, sizeof(*cmd));
1094           cmd->is_long_lived = is_long_lived;
1095           cmd->handles_missing_pvs = 0;
1096           cmd->handles_unknown_segments = 0;
1097           cmd->hosttags = 0;
1098           dm_list_init(&cmd->formats);
1099           dm_list_init(&cmd->segtypes);
1100           dm_list_init(&cmd->tags);
1101           dm_list_init(&cmd->config_files);
1102 
1103           /* FIXME Make this configurable? */
1104           reset_lvm_errno(1);
1105 
1106           /*
1107            * Environment variable LVM_SYSTEM_DIR overrides this below.
1108            */
1109         if (system_dir)
1110                     strncpy(cmd->system_dir, system_dir, sizeof(cmd->system_dir) - 1);
1111           else
1112                     strcpy(cmd->system_dir, DEFAULT_SYS_DIR);
1113 
1114           if (!_get_env_vars(cmd))
1115                     goto_out;
1116 
1117           /* Create system directory if it doesn't already exist */
1118           if (*cmd->system_dir && !dm_create_dir(cmd->system_dir)) {
1119                     log_error("Failed to create LVM2 system dir for metadata backups, config "
1120                                 "files and internal cache.");
1121                     log_error("Set environment variable LVM_SYSTEM_DIR to alternative location "
1122                                 "or empty string.");
1123                     goto out;
1124           }
1125 
1126           if (!(cmd->libmem = dm_pool_create("library", 4 * 1024))) {
1127                     log_error("Library memory pool creation failed");
1128                     goto out;
1129           }
1130 
1131           if (!_init_lvm_conf(cmd))
1132                     goto_out;
1133 
1134           _init_logging(cmd);
1135 
1136           if (!_init_hostname(cmd))
1137                     goto_out;
1138 
1139           if (!_init_tags(cmd, cmd->cft))
1140                     goto_out;
1141 
1142           if (!_init_tag_configs(cmd))
1143                     goto_out;
1144 
1145           if (!_merge_config_files(cmd))
1146                     goto_out;
1147 
1148           if (!_process_config(cmd))
1149                     goto_out;
1150 
1151           if (!_init_dev_cache(cmd))
1152                     goto_out;
1153 
1154           if (!_init_filters(cmd, 1))
1155                     goto_out;
1156 
1157           if (!(cmd->mem = dm_pool_create("command", 4 * 1024))) {
1158                     log_error("Command memory pool creation failed");
1159                     goto out;
1160           }
1161 
1162           memlock_init(cmd);
1163 
1164           if (!_init_formats(cmd))
1165                     goto_out;
1166 
1167           if (!init_lvmcache_orphans(cmd))
1168                     goto_out;
1169 
1170           if (!_init_segtypes(cmd))
1171                     goto_out;
1172 
1173           if (!_init_backup(cmd))
1174                     goto_out;
1175 
1176           _init_rand(cmd);
1177 
1178           _init_globals(cmd);
1179 
1180           cmd->default_settings.cache_vgmetadata = 1;
1181           cmd->current_settings = cmd->default_settings;
1182 
1183           cmd->config_valid = 1;
1184 out:
1185           return cmd;
1186 }
1187 
_destroy_formats(struct dm_list * formats)1188 static void _destroy_formats(struct dm_list *formats)
1189 {
1190           struct dm_list *fmtl, *tmp;
1191           struct format_type *fmt;
1192           void *lib;
1193 
1194           dm_list_iterate_safe(fmtl, tmp, formats) {
1195                     fmt = dm_list_item(fmtl, struct format_type);
1196                     dm_list_del(&fmt->list);
1197                     lib = fmt->library;
1198                     fmt->ops->destroy(fmt);
1199 #ifdef HAVE_LIBDL
1200                     if (lib)
1201                               dlclose(lib);
1202 #endif
1203           }
1204 }
1205 
_destroy_segtypes(struct dm_list * segtypes)1206 static void _destroy_segtypes(struct dm_list *segtypes)
1207 {
1208           struct dm_list *sgtl, *tmp;
1209           struct segment_type *segtype;
1210           void *lib;
1211 
1212           dm_list_iterate_safe(sgtl, tmp, segtypes) {
1213                     segtype = dm_list_item(sgtl, struct segment_type);
1214                     dm_list_del(&segtype->list);
1215                     lib = segtype->library;
1216                     segtype->ops->destroy(segtype);
1217 #ifdef HAVE_LIBDL
1218                     /*
1219                      * If no segtypes remain from this library, close it.
1220                      */
1221                     if (lib) {
1222                               struct segment_type *segtype2;
1223                               dm_list_iterate_items(segtype2, segtypes)
1224                                         if (segtype2->library == lib)
1225                                                   goto skip_dlclose;
1226                               dlclose(lib);
1227 skip_dlclose:
1228                               ;
1229                     }
1230 #endif
1231           }
1232 }
1233 
refresh_filters(struct cmd_context * cmd)1234 int refresh_filters(struct cmd_context *cmd)
1235 {
1236           if (cmd->filter) {
1237                     cmd->filter->destroy(cmd->filter);
1238                     cmd->filter = NULL;
1239           }
1240 
1241           return _init_filters(cmd, 0);
1242 }
1243 
refresh_toolcontext(struct cmd_context * cmd)1244 int refresh_toolcontext(struct cmd_context *cmd)
1245 {
1246           log_verbose("Reloading config files");
1247 
1248           /*
1249            * Don't update the persistent filter cache as we will
1250            * perform a full rescan.
1251            */
1252 
1253           activation_release();
1254           lvmcache_destroy(cmd, 0);
1255           label_exit();
1256           _destroy_segtypes(&cmd->segtypes);
1257           _destroy_formats(&cmd->formats);
1258           if (cmd->filter) {
1259                     cmd->filter->destroy(cmd->filter);
1260                     cmd->filter = NULL;
1261           }
1262           dev_cache_exit();
1263           _destroy_tags(cmd);
1264           _destroy_tag_configs(cmd);
1265 
1266           cmd->config_valid = 0;
1267 
1268           cmd->hosttags = 0;
1269 
1270           if (!_init_lvm_conf(cmd))
1271                     return 0;
1272 
1273           _init_logging(cmd);
1274 
1275           if (!_init_tags(cmd, cmd->cft))
1276                     return 0;
1277 
1278           if (!_init_tag_configs(cmd))
1279                     return 0;
1280 
1281           if (!_merge_config_files(cmd))
1282                     return 0;
1283 
1284           if (!_process_config(cmd))
1285                     return 0;
1286 
1287           if (!_init_dev_cache(cmd))
1288                     return 0;
1289 
1290           if (!_init_filters(cmd, 0))
1291                     return 0;
1292 
1293           if (!_init_formats(cmd))
1294                     return 0;
1295 
1296           if (!init_lvmcache_orphans(cmd))
1297                     return 0;
1298 
1299           if (!_init_segtypes(cmd))
1300                     return 0;
1301 
1302           cmd->config_valid = 1;
1303 
1304           reset_lvm_errno(1);
1305           return 1;
1306 }
1307 
destroy_toolcontext(struct cmd_context * cmd)1308 void destroy_toolcontext(struct cmd_context *cmd)
1309 {
1310           if (cmd->dump_filter)
1311                     persistent_filter_dump(cmd->filter);
1312 
1313           archive_exit(cmd);
1314           backup_exit(cmd);
1315           lvmcache_destroy(cmd, 0);
1316           label_exit();
1317           _destroy_segtypes(&cmd->segtypes);
1318           _destroy_formats(&cmd->formats);
1319           if (cmd->filter)
1320                     cmd->filter->destroy(cmd->filter);
1321           if (cmd->mem)
1322                     dm_pool_destroy(cmd->mem);
1323           dev_cache_exit();
1324           _destroy_tags(cmd);
1325           _destroy_tag_configs(cmd);
1326           if (cmd->libmem)
1327                     dm_pool_destroy(cmd->libmem);
1328           dm_free(cmd);
1329 
1330           release_log_memory();
1331           activation_exit();
1332           fin_log();
1333           fin_syslog();
1334           reset_lvm_errno(0);
1335 }
1336