"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "mapscsi-0.0.11/mapscsi.c" of archive mapscsi-0.0.11.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  *  mapscsi - program for creating consistent scsi device mappings
    3  *
    4  *  Author: Michael Clark <michael@metaparadigm.com>
    5  *  Copyright Metaparadigm Pte. Ltd. 2001
    6  *
    7  *  This program is free software; you can redistribute it and/or modify
    8  *  it under the terms of the GNU General Public License version 2 as
    9  *  published by the Free Software Foundation.
   10  *
   11  */
   12 
   13 #include <stdio.h>
   14 #include <stdlib.h>
   15 #include <sys/types.h>
   16 #include <sys/stat.h>
   17 #include <unistd.h>
   18 #include <string.h>
   19 #include <fcntl.h>
   20 #include <errno.h>
   21 #include <limits.h>
   22 #include <libgen.h>
   23 #include <signal.h>
   24 #include <syslog.h>
   25 
   26 #include "qlogic_api.h"
   27 #include "scsi_api.h"
   28 #include "mapscsi.h"
   29 
   30 /* #define DEBUG 1 */
   31 
   32 
   33 /* file locations */
   34 static char* rules_file = "/etc/mapscsi.rules";
   35 static char* devicemap_file = "/var/state/mapscsi/devicemap";
   36 
   37 
   38 /* string globals */
   39 static const char* device_tmpl = "/dev/%D/c%hb%ct%tu%l";
   40 static const char* partition_tmpl = "/dev/%D/c%hb%ct%tu%lp%p";
   41 
   42 
   43 /* command line flags */
   44 static int silent_flag = 0;     /* don't show mappings on stdout */
   45 static int execute_flag = 0;    /* process rules and make links */
   46 static int bkgnd_flag = 0;      /* run in the background */
   47 static int print_flag = 0;      /* print device scan information */
   48 static int rm_links_flag = 1;   /* remove links in state file */
   49 static int save_state_flag = 1; /* save created links to state file */
   50 static int sg_numeric = 1;      /* use numeric sg device names */
   51 
   52 
   53 /* daemon mode exit signal variable */
   54 static volatile int running;
   55 
   56 /* linked list globals */
   57 static scsi_map_rule_t *rules_head = NULL;
   58 static scsi_map_t *devmap_head = NULL;
   59 static scsi_map_t *devmap_last;
   60 
   61 
   62 static int subst_device(char *dest, int dest_size,
   63 			scsi_device_t *scsidev,
   64 			const char *template)
   65 {
   66     const char *r = template;
   67     char *w = dest;
   68     int len = dest_size;
   69 
   70     while(*r) {
   71 	char c;
   72 	int l;
   73 
   74 	if(*r == '%') {
   75 	    scsi_device_param_t *param = params;
   76 	    r++;
   77 	    c = *r++;
   78 	    while(param->substchar) {
   79 		if(param->substchar == c) break;
   80 		param++;
   81 	    }
   82 	    if(param->enc) {
   83 		l = param->enc(w, ((void*)scsidev)+param->offset, len);
   84 	    } else {
   85 		fprintf(stderr, "subst_device: invalid subsitution "
   86 			"symbol '%c'\n", *r);
   87 		return -1;
   88 	    }
   89 
   90 	    if(l == -1) {
   91 		fprintf(stderr, "subst_device: buffer overun\n");
   92 		return -1;
   93 	    }
   94 	    len -= l;
   95 	    w += l;
   96 	} else {
   97 	    *w++ = *r++;
   98 	    len--;
   99 	    if(len <= 0) {
  100 		fprintf(stderr, "subst_device: buffer overun\n");
  101 		return -1;
  102 	    }
  103 	}
  104     }
  105     *w = '\0';
  106     return 0;
  107 }
  108 
  109 
  110 static int make_link(const char *linkname, const char* device)
  111 {
  112     char pathtemp[PATH_MAX+1];
  113     struct stat s;
  114     int rc, nc;
  115 
  116     /* make needed directories */
  117     do {
  118 	nc = 0;
  119 	strcpy(pathtemp, linkname);
  120 	while(dirname(pathtemp) && strcmp(pathtemp, ".") != 0
  121 	      && strcmp(pathtemp, "/") != 0) {
  122 	    if((rc = stat(pathtemp, &s)) < 0 && errno == ENOENT) {
  123 		if((rc = mkdir(pathtemp, 0777)) < 0 && errno != ENOENT) {
  124 		    return -1;
  125 		} else {
  126 		    nc++;
  127 		}
  128 	    } else if (rc < 0) {
  129 		return -1;
  130 	    }
  131 	}
  132     } while (nc > 0);
  133 
  134     /* make the link */
  135 #ifdef DEBUG
  136     printf("symlink %s %s\n", device, linkname);
  137 #endif
  138     if(symlink(device, linkname) < 0) {
  139 	return -1;
  140     }
  141 
  142     return 0;
  143 }
  144 
  145 
  146 static unsigned int hash_partitions()
  147 {
  148     FILE *parts;
  149     char data[256];
  150 
  151     unsigned int hash = 12345;
  152 
  153     if((parts = fopen("/proc/partitions", "r")) == NULL) {
  154 	perror("hash_partitions: fopen");
  155 	exit(1);
  156     }
  157 
  158     while(fgets(data, 255, parts) != NULL) {
  159 
  160 	char *part_dev, *p;
  161 
  162 	/* 4th field is device name */
  163 	if(!(part_dev = strtok(data, " "))) continue;
  164 	if(!(part_dev = strtok(NULL, " "))) continue;
  165 	if(!(part_dev = strtok(NULL, " "))) continue;
  166 	if(!(part_dev = strtok(NULL, " "))) continue;
  167 
  168 	p = part_dev;
  169 	while(*p) hash = hash*129 + (unsigned int)(*p++) + 987654321L;
  170     }
  171 
  172     fclose(parts);
  173 
  174     return hash;
  175 }
  176 
  177 static unsigned int hash_scsi()
  178 {
  179     FILE *parts;
  180     char data[256];
  181 
  182     unsigned int hash = 12345;
  183 
  184     if((parts = fopen("/proc/scsi/scsi", "r")) == NULL) {
  185 	perror("hash_scsi: fopen");
  186 	exit(1);
  187     }
  188 
  189     while(fgets(data, 255, parts) != NULL) {
  190 
  191 	char *p;
  192 
  193 	p = data;
  194 	while(*p) hash = hash*129 + (unsigned int)(*p++) + 987654321L;
  195     }
  196 
  197     fclose(parts);
  198 
  199     return hash;
  200 }
  201 
  202 
  203 static void count_partitions()
  204 {
  205     scsi_device_t *scsidev = NULL;
  206     FILE *parts;
  207     char data[256];
  208 
  209     if((parts = fopen("/proc/partitions", "r")) == NULL) {
  210 	perror("count_partitions: fopen");
  211 	exit(1);
  212     }
  213 
  214     while(fgets(data, 255, parts) != NULL) {
  215 
  216 	char *part_dev, *p;
  217 	int part_num;
  218 
  219 	/* 4th field is device name */
  220 	if(!(part_dev = strtok(data, " "))) continue;
  221 	if(!(part_dev = strtok(NULL, " "))) continue;
  222 	if(!(part_dev = strtok(NULL, " "))) continue;
  223 	if(!(part_dev = strtok(NULL, " "))) continue;
  224 
  225 	/* split the field into device name and part no */
  226 	p = part_dev;
  227 	part_num = 0;
  228 	while(*p) {
  229 	    if(isdigit(*p) && sscanf(p, "%d", &part_num) == 1) {
  230 		*p = '\0';
  231 		/* set the number of partitions on this device */
  232 		if(scsidev = find_dev_by_name(part_dev)) {
  233 		    if(part_num > scsidev->num_parts)
  234 			scsidev->num_parts = part_num;
  235 		}
  236 		break;
  237 	    }
  238 	    p++;
  239 	}
  240 
  241     }
  242 
  243     fclose(parts);
  244 }
  245 
  246 
  247 static scsi_map_t* read_devicemap(const char *filename)
  248 {
  249     char buf[1024];
  250     FILE *devicemap;
  251     char *device, *link, *t;
  252     scsi_map_t *devmap, *c_devmap;
  253 
  254     devmap = c_devmap = calloc(1, sizeof(scsi_map_t));
  255 
  256     if((devicemap = fopen(filename, "r")) == NULL) {
  257 	fprintf(stderr, "read_devicemap: cant open '%s': ", devicemap_file);
  258 	perror("");
  259 	return devmap;
  260     }
  261 
  262     while(fgets(buf, 1023, devicemap) != NULL) {
  263 	/* Remove trailing \n, if present. */
  264 	t = buf + strlen(buf) - 1;
  265 	if(*t == '\n') *t = '\0';
  266 	if((device = strtok(buf, "\t")) &&
  267 	   (link = strtok(NULL, "\t"))) {
  268 #ifdef DEBUG
  269 	    printf("read %s %s\n", device, link);
  270 #endif
  271 	    c_devmap->device = strdup(device);
  272 	    c_devmap->link = strdup(link);
  273 	    c_devmap->next = calloc(1, sizeof(scsi_map_t));
  274 	    c_devmap = c_devmap->next;
  275 	} else {
  276 	    fprintf(stderr, "read_devicemap: invalid format\n");
  277 	    exit(1);
  278 	}
  279     }
  280 
  281     fclose(devicemap);
  282 
  283     return devmap;
  284 }
  285 
  286 
  287 static int write_devicemap(scsi_map_t *devmap, const char *filename)
  288 {
  289     FILE *devicemap;
  290 
  291     scsi_map_t *c_devmap = devmap;
  292 
  293     if((devicemap = fopen(filename, "w+")) == NULL) {
  294 	fprintf(stderr, "write_devicemap: cant open '%s': ", filename);
  295 	perror("");
  296 	return -1;
  297     }
  298 
  299     while(c_devmap->next) {
  300 	fprintf(devicemap, "%s\t%s\n", c_devmap->device, c_devmap->link);
  301 	c_devmap = c_devmap->next;
  302     }
  303 
  304     fclose(devicemap);
  305 }
  306 
  307 
  308 static int link_devicemap(scsi_map_t *devmap)
  309 {
  310     scsi_map_t *c_devmap = devmap;
  311 
  312     while(c_devmap->next) {
  313 	if(make_link(c_devmap->link, c_devmap->device)) return -1;
  314 	c_devmap = c_devmap->next;
  315     }
  316     return 0;
  317 }
  318 
  319 
  320 static int free_devicemap(scsi_map_t *devmap)
  321 {
  322     scsi_map_t *c_devmap = devmap;
  323 
  324     while(c_devmap->next) {
  325 	scsi_map_t *t = c_devmap;
  326 	c_devmap = c_devmap->next;
  327 	if(t->link) free(t->link);
  328 	if(t->device) free(t->device);
  329 	free(t);
  330     }
  331     return 0;
  332 }
  333 
  334 
  335 static int unlink_devicemap(scsi_map_t *devmap)
  336 {
  337     scsi_map_t *c_devmap = devmap;
  338     char pathtemp[PATH_MAX+1];
  339 
  340     while(c_devmap->next) {
  341 #ifdef DEBUG
  342 	printf("unlink %s\n", c_devmap->link);
  343 #endif
  344 	if(unlink(c_devmap->link) < 0) {
  345 	    perror("unlink_devices");
  346 	    return -1;
  347 	}
  348 	strcpy(pathtemp, c_devmap->link);
  349 	/* remove empty parent directories */
  350 	while(dirname(pathtemp) && strcmp(pathtemp, ".") != 0
  351 	      && strcmp(pathtemp, "/") != 0) unlink(pathtemp);
  352 
  353 	c_devmap = c_devmap->next;
  354     }
  355     return 0;
  356 }
  357 
  358 
  359 static int parse_rule(char *buf, int *line, scsi_map_rule_t **c_rule)
  360 {
  361     char *k, *v, *t, q;
  362     scsi_map_rule_t *c_constraint;
  363 
  364     *line++;
  365 
  366     /* Remove trailing \n, if present. */
  367     t = buf + strlen(buf) - 1;
  368     if(*t == '\n') *t = '\0';
  369 
  370     k = buf;
  371     if(*k == '#') return 0;
  372 
  373     if((*c_rule)->next_constraint) {
  374 	(*c_rule)->next_rule = calloc(1, sizeof(scsi_map_rule_t));
  375 	(*c_rule)->next_rule->rule_num = (*c_rule)->rule_num + 1;
  376 	(*c_rule) = (*c_rule)->next_rule;
  377     }
  378     c_constraint = (*c_rule);
  379 
  380     while(*k) {
  381 
  382 	/* eat whitespace */
  383 	while(*k && isspace(*k)) k++;
  384 
  385 	/* find value after = */
  386 	v = k;
  387 	while (*v != '=' && *v != '\0') {
  388 	    if(!isalnum(*v)) {
  389 		fprintf(stderr, "read_rules: invalid paramater "
  390 			"character '%c', line %d\n", *v, *line);
  391 		return -1;
  392 	    }
  393 	    v++;
  394 	}
  395 	if( *v == '\0' ) break;
  396 	*v++ = '\0';
  397 
  398 	if(*v == '"' || *v == '\'') {
  399 	    q = *v;
  400 	    v++;
  401 	} else q = '\0';
  402 
  403 	/* terminate value */
  404 	t = v;
  405 	while(*t && ((q && *t != q) ||
  406 		     (!q && *t != ' ' && *t != '\t'))) t++;
  407 	if(q && *t != q) {
  408 	    fprintf(stderr, "read_rules: unterminated quotes on "
  409 		    "parameter '%s', line %d\n", k, *line);
  410 	    return -1;
  411 	}
  412 	if(*t) *t++ = '\0';
  413 
  414 	c_constraint->key = strdup(k);
  415 	c_constraint->value = strdup(v);
  416 	c_constraint->next_constraint = calloc(1, sizeof(scsi_map_rule_t));
  417 	c_constraint = c_constraint->next_constraint;
  418 
  419 	k = t;
  420     }
  421     return 0;
  422 }
  423 
  424 
  425 static int read_rules()
  426 {
  427     char buf[1024];
  428     FILE *conf;
  429     int line;
  430     scsi_map_rule_t *c_rule;
  431 
  432     if((conf = fopen(rules_file, "r")) == NULL) return -1;
  433 
  434     c_rule = rules_head = calloc(1, sizeof(scsi_map_rule_t));
  435     c_rule->rule_num = 1;
  436 
  437     while(fgets(buf, 1023, conf) != NULL) {
  438 	if(parse_rule(buf, &line, &c_rule)) exit(1);
  439     }
  440 
  441     if(c_rule->next_constraint) {
  442 	c_rule->next_rule = calloc(1, sizeof(scsi_map_rule_t));
  443 	c_rule->next_rule->rule_num = c_rule->rule_num + 1;
  444     }
  445 
  446     fclose(conf);
  447 
  448     return 0;
  449 }
  450 
  451 
  452 static int default_rules()
  453 {
  454     rules_head = calloc(1, sizeof(scsi_map_rule_t));
  455     rules_head->next_rule = calloc(1, sizeof(scsi_map_rule_t));
  456     rules_head->next_constraint = calloc(1, sizeof(scsi_map_rule_t));
  457     rules_head->rule_num = 1;
  458     rules_head->key = strdup("map");
  459     rules_head->value = strdup(device_tmpl);
  460 }
  461 
  462 
  463 static void str_path(char *p)
  464 {
  465     char *t, *r, *w = p;
  466 
  467     t = r = strdup(p);
  468     while(*r) {
  469 	if(*r != ' ') *w++ = *r++;
  470 	else r++;
  471     }
  472     *w = '\0';
  473     free(t);
  474     while(*p) {
  475 	if(!isalnum(*p) && *p != '/') *p = '-';
  476 	p++;
  477     }
  478 }
  479 
  480 
  481 static int create_links(scsi_device_t *scsidev,
  482 			const char* map, const char* partmap)
  483 {
  484     char dev[PATH_MAX+1];
  485     char link[PATH_MAX+1];
  486     int p;
  487 
  488     if(map) {
  489 	if(subst_device(link, PATH_MAX, scsidev, map) == 0) {
  490 	    str_path(link);
  491 	    if(!silent_flag) printf("%s -> %s\n", link, scsidev->device);
  492 	    devmap_last->link = strdup(link);
  493 	    devmap_last->device = strdup(scsidev->device);;
  494 	    devmap_last->next = calloc(1, sizeof(scsi_map_t));
  495 	    devmap_last = devmap_last->next;
  496 	} else {
  497 	    exit(1);
  498 	}
  499     }
  500 
  501     if(partmap) {
  502 	for(p=1; p <= scsidev->num_parts; p++) {
  503 	    scsidev->part = p;
  504 	    if(subst_device(link, PATH_MAX, scsidev, partmap) == 0) {
  505 		str_path(link);
  506 		sprintf(dev, "%s%d", scsidev->device, p);
  507 		if(!silent_flag) printf("%s -> %s\n", link, dev);
  508 		devmap_last->link = strdup(link);
  509 		devmap_last->device = strdup(dev);;
  510 		devmap_last->next = calloc(1, sizeof(scsi_map_t));
  511 		devmap_last = devmap_last->next;
  512 	    } else {
  513 		exit(1);
  514 	    }
  515 	}
  516     }
  517 }
  518 
  519 
  520 int match_rules(scsi_device_t *scsidev)
  521 {
  522     char buf[256];
  523     scsi_map_rule_t *c_rule = rules_head;
  524 
  525     /* loop through the rules */
  526     while(c_rule->next_rule) {
  527 	scsi_map_rule_t *c_constraint = c_rule;
  528 	int rules = 0, matches = 0;
  529 	char *map = NULL, *partmap = NULL;
  530 
  531 	/* see if we can match this rule */
  532 	while(c_constraint->next_constraint) {
  533 
  534 	    if(strcmp(c_constraint->key, "map") == 0) {
  535 		map = c_constraint->value;
  536 	    } else if(strcmp(c_constraint->key, "partmap") == 0) {
  537 		partmap = c_constraint->value;
  538 	    } else {
  539 		scsi_device_param_t *param = params;
  540 		while(param->substchar) {
  541 		    if(strcmp(param->name, c_constraint->key) == 0) break;
  542 		    param++;
  543 		}
  544 		/* okay found param, see if values match */
  545 		if(param->substchar) {
  546 		    rules++;
  547 		    if(param->enc(buf, ((void*)scsidev)+param->offset, 255) >= 0 && strcmp(buf, c_constraint->value) == 0) {
  548 			matches++;
  549 		    }
  550 		}
  551 	    }
  552 	    c_constraint = c_constraint->next_constraint;
  553 	}
  554 
  555 	if(rules == matches) {
  556 	    if(map && !partmap) {
  557 		partmap = (char*)malloc(strlen(map)+4);
  558 		strcpy(partmap, map);
  559 		strcat(partmap, "p%p");
  560 		create_links(scsidev, map, partmap);
  561 		free(partmap);
  562 	    } else if(!map && !partmap) {
  563 		create_links(scsidev, device_tmpl, partition_tmpl);
  564 	    } else {
  565 		create_links(scsidev, map, partmap);
  566 	    }
  567 	}
  568 
  569 	c_rule = c_rule->next_rule;
  570     }
  571 }
  572 
  573 
  574 static void do_mapscsi()
  575 {
  576     if(scsidev_head) free_scsidev(scsidev_head);
  577     scsidev_head = calloc(1, sizeof(scsi_device_t));
  578     if(devmap_head) free_devicemap(devmap_head);
  579     devmap_head = devmap_last = calloc(1, sizeof(scsi_map_t));
  580     scan_scsi_devices(sg_numeric);
  581     map_sg_devices(TYPE_DISK, "sd", 0);
  582     map_sg_devices(TYPE_MOD, "sd", 0);        /* this can block ?? */
  583     map_sg_devices(TYPE_TAPE, "st", 1);
  584     map_sg_devices(TYPE_WORM, "scd", 1);
  585     map_sg_devices(TYPE_ROM, "scd", 1);
  586     map_sg_devices(TYPE_SCANNER, "sg", 1);    /* need to optimize */
  587     map_sg_devices(TYPE_PROCESSOR, "sg", 1);  /* need to optimize */
  588     qlogic_map_wwn_to_sd();
  589     qlogic_free();
  590     count_partitions();
  591 }
  592 
  593 
  594 static void parse_command_line(int argc, char *argv[])
  595 {
  596     int c;
  597     int error_flag = 0, help_flag = 0;
  598 
  599     while ((c = getopt(argc, argv, "hpanxbsRSc:d:")) != EOF)
  600 	switch (c)
  601 	{
  602 	case 'p':
  603 	    print_flag++;
  604 	    break;
  605 	case 'h':
  606 	    help_flag++;
  607 	    break;
  608 	case 'a':
  609 	    sg_numeric = 0;
  610 	    break;
  611 	case 'n':
  612 	    sg_numeric = 1;
  613 	    break;
  614 	case 'x':
  615 	    execute_flag = 1;
  616 	    break;
  617 	case 'b':
  618 	    bkgnd_flag = 1;
  619 	    silent_flag = 1;
  620 	    break;
  621 	case 's':
  622 	    silent_flag = 1;
  623 	    break;
  624 	case 'c':
  625 	    rules_file = optarg;
  626 	    break;
  627 	case 'd':
  628 	    devicemap_file = optarg;
  629 	    break;
  630 	case 'R':
  631 	    rm_links_flag = 0;
  632 	    break;
  633 	case 'S':
  634 	    save_state_flag = 0;
  635 	    break;
  636 	case '?':
  637 	    error_flag++;
  638 	}
  639 
  640     /* read rules from the command line */
  641     if (argc - optind > 0) {
  642 	int k, line=0;
  643 	scsi_map_rule_t *c_rule;
  644 
  645 	c_rule = rules_head = calloc(1, sizeof(scsi_map_rule_t));
  646 	c_rule->rule_num = 1;
  647 	for(k=optind; k < argc; k++) {
  648 	    if(parse_rule(argv[k], &line, &c_rule)) exit(1);
  649 	}
  650 	if(c_rule->next_constraint) {
  651 	    c_rule->next_rule = calloc(1, sizeof(scsi_map_rule_t));
  652 	    c_rule->next_rule->rule_num = c_rule->rule_num + 1;
  653 	}
  654     }
  655 
  656     if(print_flag + execute_flag + bkgnd_flag > 1) {
  657 	fprintf(stderr, "must choose only one of -x -b or -p\n");
  658 	error_flag++;
  659     }
  660 
  661     if (error_flag || help_flag)
  662     {
  663 	scsi_device_param_t *param = params;
  664 
  665 	fprintf(stderr, "usage:\t%s [-h] [-x] [-s] [-n] [-a] [-R] [-S]\\\n"
  666 		"\t[-c <config file>] [-d <devicemap file>] \\\n"
  667 		"\t[attrib=value [attrib=value]...]\n\n", argv[0]);
  668 	fprintf(stderr,
  669 		"-h     show this help message\n"
  670 		"-p     print - print device scan information\n"
  671 		"-x     execute - actually make the links\n"
  672 		"-b     background - poll for changes in the background\n"
  673 		"-s     silent - don't show mappings on stdout\n"
  674 		"-n     numeric sg device names eg. /dev/sg0 (default)\n"
  675 		"-a     alpha sg device names eg. /dev/sga\n"
  676 		"-R     don't remove previous links\n"
  677 		"-S     don't save state in /var/state/mapscsi/devicemap\n"
  678 		"-c <f> mapscsi rules file (default /etc/mapscsi.rules)\n"
  679 		"-d <f> mapscsi state file (default /var/state/mapscsi/devicemap)\n\n"
  680 		"example /etc/mapscsi.rules\n\n");
  681 	fprintf(stderr, "type=disk map='%s' partmap='%s'\n",
  682 		device_tmpl, partition_tmpl);
  683 	fprintf(stderr, "type=cdrom map='%s'\n", "/dev/scsi/cdrom-%V-%P");
  684 	fprintf(stderr, "%s", "\nTemplate codes:\n");
  685 	while(param->substchar) {
  686 	    fprintf(stderr, "%c\t%s\n", param->substchar, param->description);
  687 	    param++;
  688 	}
  689 	exit(1);
  690     }
  691 }
  692 
  693 
  694 static void sighandler(int signal)
  695 {
  696   switch(signal) {
  697   case SIGQUIT:
  698   case SIGTERM:
  699     syslog(LOG_INFO, "exiting on SIGTERM");
  700     running = 0;
  701     break;
  702   default:
  703     break;
  704   }
  705 }
  706 
  707 
  708 int main(int argc, char **argv)
  709 {
  710     int k;
  711     scsi_device_t *scsidev;
  712     scsi_map_t *devmap_old = NULL;
  713 
  714     parse_command_line(argc, argv);
  715 
  716     if(bkgnd_flag) {
  717 	unsigned int last_part_hash = 0, last_scsi_hash = 0;
  718 	int pid;
  719 
  720 	if ((pid = fork()) == -1)
  721 	{
  722 	    perror("Unable to fork:");
  723 	    exit(1);
  724 	}
  725 
  726 	if (pid) exit(0);
  727 	close(0);
  728 	close(1);
  729 	close(2);
  730 	open("/dev/null", O_RDONLY);
  731 	open("/dev/null", O_WRONLY);
  732 	open("/dev/null", O_WRONLY);
  733 	chdir("/");
  734 	setsid();
  735 	signal(SIGTERM, &sighandler);
  736 	running = 1;
  737 
  738 	openlog("mapscsi", LOG_PID, LOG_DAEMON);
  739 	if(!rules_head && read_rules()) {
  740 	    syslog(LOG_ERR, "%s reading rules file %s\n"
  741 		   "Using default rules", strerror(errno), rules_file);
  742 	    default_rules();
  743 	}
  744 
  745 	while(running) {
  746 	    unsigned int part_hash, scsi_hash;
  747 
  748 	    part_hash = hash_partitions();
  749 	    scsi_hash = hash_scsi();
  750 
  751 	    if(part_hash != last_part_hash ||
  752 	       scsi_hash != last_scsi_hash) {
  753 
  754 		if(part_hash && last_part_hash)
  755 		    syslog(LOG_INFO, "device change detected. rescanning...");
  756 		do_mapscsi();
  757 		scsidev = scsidev_head;
  758 		while(scsidev->next) {
  759 		    if(scsidev->device) match_rules(scsidev);
  760 		    scsidev = scsidev->next;
  761 		}
  762 		if(rm_links_flag) {
  763 		    if(!devmap_old)
  764 			devmap_old = read_devicemap(devicemap_file);
  765 		    if(unlink_devicemap(devmap_old)) {
  766 			syslog(LOG_ERR, "error unlinking old devices");
  767 		    }
  768 		    free_devicemap(devmap_old);
  769 		}
  770 		if(link_devicemap(devmap_head)) {
  771 		    syslog(LOG_ERR, "error linking new devices");
  772 		    exit(1);
  773 		}
  774 		if(save_state_flag &&
  775 		   write_devicemap(devmap_head, devicemap_file)) {
  776 		    syslog(LOG_ERR, "error writing device map");
  777 		    exit(1);
  778 		}
  779 		devmap_old = devmap_head;
  780 		devmap_head = NULL; /* prevent freeing of devmap */
  781 	    }
  782 
  783 	    last_part_hash = part_hash;
  784 	    last_scsi_hash = scsi_hash;
  785 	    if(running) sleep(5);
  786 	}
  787 	closelog();
  788 
  789     }
  790 
  791     do_mapscsi();
  792 
  793     if(print_flag) {
  794 	scsidev = scsidev_head;
  795 	while(scsidev->next) {
  796 	    if(scsidev->device) print_scsi_dev_info(scsidev);
  797 	    scsidev = scsidev->next;
  798 	}
  799     } else {
  800 	if(!rules_head && read_rules()) {
  801 	    if(!silent_flag)
  802 		fprintf(stderr, "%s reading rules file %s:"
  803 			" using default rules\n",
  804 			strerror(errno), rules_file);
  805 	    default_rules();
  806 	}
  807 	scsidev = scsidev_head;
  808 	while(scsidev->next) {
  809 	    if(scsidev->device) match_rules(scsidev);
  810 	    scsidev = scsidev->next;
  811 	}
  812 	if(execute_flag) {
  813 	    if(rm_links_flag) {
  814 		devmap_old = read_devicemap(devicemap_file);
  815 		if(unlink_devicemap(devmap_old)) {
  816 		    fprintf(stderr,"error unlinking old devices\n");
  817 		}
  818 		free_devicemap(devmap_old);
  819 	    }
  820 	    if(link_devicemap(devmap_head)) {
  821 		fprintf(stderr,"error linking new devices\n");
  822 		exit(1);
  823 	    }
  824 	    if(save_state_flag &&
  825 	       write_devicemap(devmap_head, devicemap_file)) {
  826 		fprintf(stderr,"error writing device map\n");
  827 		exit(1);
  828 	    }
  829 	}
  830     }
  831 
  832     return 0;
  833 }
  834