Exemplo n.º 1
0
switchlink_db_status_t
switchlink_db_route_add(switchlink_db_route_info_t *route_info) {
    switchlink_db_route_obj_t * obj =
        switchlink_malloc(sizeof(switchlink_db_route_obj_t), 1);
    memcpy(&(obj->route_info), route_info, sizeof(switchlink_db_route_info_t));
    tommy_list_insert_tail(&switchlink_db_route_obj_list, &obj->list_node, obj);
    return SWITCHLINK_DB_STATUS_SUCCESS;
}
Exemplo n.º 2
0
void tommy_hashtable_insert(tommy_hashtable* hashtable, tommy_hashtable_node* node, void* data, tommy_hash_t hash)
{
	unsigned pos = hash & hashtable->bucket_mask;

	tommy_list_insert_tail(&hashtable->bucket[pos], node, data);

	node->key = hash;

	++hashtable->count;
}
Exemplo n.º 3
0
switchlink_db_status_t
switchlink_db_ecmp_add(switchlink_db_ecmp_info_t *ecmp_info) {
    assert(ecmp_info->num_nhops < SWITCHLINK_ECMP_NUM_MEMBERS_MAX);
    switchlink_db_ecmp_obj_t * obj =
        switchlink_malloc(sizeof(switchlink_db_ecmp_obj_t), 1);
    memcpy(&(obj->ecmp_info), ecmp_info, sizeof(switchlink_db_ecmp_info_t));
    obj->ref_count = 0;
    tommy_list_insert_tail(&switchlink_db_ecmp_obj_list, &obj->list_node, obj);
    tommy_trie_inplace_insert(&switchlink_db_handle_obj_map,
                              &obj->handle_node, obj, obj->ecmp_info.ecmp_h);
    return SWITCHLINK_DB_STATUS_SUCCESS;
}
Exemplo n.º 4
0
void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash)
{
	unsigned pos = hash & hashdyn->bucket_mask;

	tommy_list_insert_tail(&hashdyn->bucket[pos], node, data);

	node->key = hash;

	++hashdyn->count;

	hashdyn_grow_step(hashdyn);
}
Exemplo n.º 5
0
switchlink_db_status_t
switchlink_db_oifl_add(switchlink_db_oifl_info_t *oifl_info) {
    static switchlink_handle_t s_oifl_h = 1;
    assert(oifl_info->num_intfs < SWITCHLINK_OIFL_NUM_MEMBERS_MAX);
    switchlink_db_oifl_obj_t * obj =
        switchlink_malloc(sizeof(switchlink_db_oifl_obj_t), 1);
    oifl_info->oifl_h = (s_oifl_h++ & ~SWITCHLINK_HANDLE_TYPE_OIFL) |
        SWITCHLINK_HANDLE_TYPE_OIFL;
    memcpy(&(obj->oifl_info), oifl_info, sizeof(switchlink_db_oifl_info_t));
    obj->ref_count = 0;
    tommy_list_insert_tail(&switchlink_db_oifl_obj_list, &obj->list_node, obj);
    tommy_trie_inplace_insert(&switchlink_db_handle_obj_map,
                              &obj->handle_node, obj, obj->oifl_info.oifl_h);
    return SWITCHLINK_DB_STATUS_SUCCESS;
}
Exemplo n.º 6
0
switchlink_db_status_t switchlink_db_mac_add(switchlink_mac_addr_t mac_addr,
                                             switchlink_handle_t bridge_h,
                                             switchlink_handle_t intf_h) {
  switchlink_db_mac_obj_t *obj =
      switchlink_malloc(sizeof(switchlink_db_mac_obj_t), 1);
  memcpy(obj->addr, mac_addr, sizeof(switchlink_mac_addr_t));
  obj->bridge_h = bridge_h;
  obj->intf_h = intf_h;

  uint32_t hash;
  uint8_t key[SWITCHLINK_MAC_KEY_LEN];
  switchlink_db_mac_key_hash(mac_addr, bridge_h, key, &hash);
  tommy_hashlin_insert(&switchlink_db_mac_obj_hash, &obj->hash_node, obj, hash);
  tommy_list_insert_tail(&switchlink_db_mac_obj_list, &obj->list_node, obj);
  return SWITCHLINK_DB_STATUS_SUCCESS;
}
Exemplo n.º 7
0
Arquivo: hash.c Projeto: tnako/pureble
void pcore_hash_insert(phash_pool pool, const puint32 value, void* const data)
{
    if (!pool) {
        plog_error("%s(): Нет phash_pool!", __PRETTY_FUNCTION__);
        return;
    }

    plog_dbg("%s(): Вставка ресурсов со значением '%d'", __PRETTY_FUNCTION__, value);

    phash_object object = pcore_hash_newObject(value, data);

    tommy_list_insert_tail(pool->list, &object->list_node, object);

    switch (pool->type) {
    case PHASH_FAST_SEARCH:
        tommy_hashdyn_insert((tommy_hashdyn *)pool->hash_struct, &object->hash_node, object, tommy_inthash_u32(object->value));
        break;
    case PHASH_FAST_INSERT:
    default:
        tommy_hashtable_insert((tommy_hashtable *)pool->hash_struct, &object->hash_node, object, tommy_inthash_u32(object->value));
        break;
    }
}
Exemplo n.º 8
0
static switch_status_t switch_l3_insert_into_vrf_list(
    switch_l3_hash_t *hash_entry) {
  switch_vrf_route_list_t *vrf_route_list = NULL;
  void *temp = NULL;
  switch_ip_addr_t ip_addr;
  switch_handle_t vrf_handle = 0;

  memset(&ip_addr, 0, sizeof(switch_ip_addr_t));
  switch_l3_hash_key_decode(hash_entry, &vrf_handle, &ip_addr);
  if (ip_addr.type == SWITCH_API_IP_ADDR_V4) {
    JLG(temp, switch_vrf_v4_routes, vrf_handle);
  } else {
    JLG(temp, switch_vrf_v6_routes, vrf_handle);
  }

  if (!temp) {
    vrf_route_list = switch_malloc(sizeof(switch_vrf_route_list_t), 1);
    if (!vrf_route_list) {
      SWITCH_API_ERROR("%s:%d: No memory!", __FUNCTION__, __LINE__);
      return SWITCH_STATUS_NO_MEMORY;
    }
    tommy_list_init(&(vrf_route_list->routes));
    vrf_route_list->num_entries = 0;
    if (ip_addr.type == SWITCH_API_IP_ADDR_V4) {
      JLI(temp, switch_vrf_v4_routes, vrf_handle);
    } else {
      JLI(temp, switch_vrf_v6_routes, vrf_handle);
    }
    *(unsigned long *)temp = (unsigned long)(vrf_route_list);
  }
  vrf_route_list = (switch_vrf_route_list_t *)(*(unsigned long *)temp);
  tommy_list_insert_tail(
      &(vrf_route_list->routes), &(hash_entry->vrf_route_node), hash_entry);
  vrf_route_list->num_entries++;
  return SWITCH_STATUS_SUCCESS;
}
Exemplo n.º 9
0
void state_device(struct snapraid_state* state, int operation, tommy_list* filterlist_disk)
{
	tommy_node* i;
	unsigned j;
	tommy_list high;
	tommy_list low;
	int ret;

	switch (operation) {
	case DEVICE_UP : msg_progress("Spinup...\n"); break;
	case DEVICE_DOWN : msg_progress("Spindown...\n"); break;
	}

	tommy_list_init(&high);
	tommy_list_init(&low);

	/* for all disks */
	for (i = state->disklist; i != 0; i = i->next) {
		struct snapraid_disk* disk = i->data;
		devinfo_t* entry;

		if (filterlist_disk != 0 && filter_path(filterlist_disk, 0, disk->name, 0) != 0)
			continue;

		entry = calloc_nofail(1, sizeof(devinfo_t));

		entry->device = disk->device;
		pathcpy(entry->name, sizeof(entry->name), disk->name);
		pathcpy(entry->mount, sizeof(entry->mount), disk->dir);
		pathcpy(entry->smartctl, sizeof(entry->smartctl), disk->smartctl);

		tommy_list_insert_tail(&high, &entry->node, entry);
	}

	/* for all parities */
	for (j = 0; j < state->level; ++j) {
		devinfo_t* entry;

		if (filterlist_disk != 0 && filter_path(filterlist_disk, 0, lev_config_name(j), 0) != 0)
			continue;

		entry = calloc_nofail(1, sizeof(devinfo_t));

		entry->device = state->parity[j].device;
		pathcpy(entry->name, sizeof(entry->name), lev_config_name(j));
		pathcpy(entry->mount, sizeof(entry->mount), state->parity[j].path);
		pathcpy(entry->smartctl, sizeof(entry->smartctl), state->parity[j].smartctl);
		pathcut(entry->mount); /* remove the parity file */

		tommy_list_insert_tail(&high, &entry->node, entry);
	}

	if (state->opt.fake_device) {
		ret = devtest(&low, operation);
	} else {
		int others = operation == DEVICE_SMART;

		ret = devquery(&high, &low, operation, others);
	}

	/* if the list is empty, it's not supported in this platform */
	if (ret == 0 && tommy_list_empty(&low))
		ret = -1;

	if (ret != 0) {
		const char* ope = 0;
		switch (operation) {
		case DEVICE_UP : ope = "Spinup"; break;
		case DEVICE_DOWN : ope = "Spindown"; break;
		case DEVICE_LIST : ope = "Device listing"; break;
		case DEVICE_SMART : ope = "Smart"; break;
		}
		log_fatal("%s is unsupported in this platform.\n", ope);
	} else {
		if (operation == DEVICE_LIST) {
			for (i = tommy_list_head(&low); i != 0; i = i->next) {
				devinfo_t* devinfo = i->data;
				devinfo_t* parent = devinfo->parent;
#ifdef _WIN32
				printf("%" PRIu64 "\t%s\t%08" PRIx64 "\t%s\t%s\n", devinfo->device, devinfo->wfile, parent->device, parent->wfile, parent->name);
#else
				printf("%u:%u\t%s\t%u:%u\t%s\t%s\n", major(devinfo->device), minor(devinfo->device), devinfo->file, major(parent->device), minor(parent->device), parent->file, parent->name);
#endif
			}
		}

		if (operation == DEVICE_SMART)
			state_smart(state->level + tommy_list_count(&state->disklist), &low);
	}

	tommy_list_foreach(&high, free);
	tommy_list_foreach(&low, free);
}
Exemplo n.º 10
0
/**
 * Fill with fake data the device list.
 */
static int devtest(tommy_list* low, int operation)
{
	unsigned c;

	if (operation != DEVICE_SMART)
		return -1;

	/* add some fake data */
	for (c = 0; c < 16; ++c) {
		devinfo_t* entry;
		int j;

		entry = calloc_nofail(1, sizeof(devinfo_t));

		entry->device = c;

		tommy_list_insert_tail(low, &entry->node, entry);

		for (j = 0; j < 256; ++j) {
			switch (c) {
			case 0 : entry->smart[j] = 0; break;
			case 1 : entry->smart[j] = SMART_UNASSIGNED; break;
			default:
				if (j == 193)
					entry->smart[j] = c - 2;
				else
					entry->smart[j] = 0;
				break;
			}
		}

		if (c == 0) {
			entry->smart_serial[0] = 0;
			entry->file[0] = 0;
			entry->name[0] = 0;
			entry->smart[SMART_SIZE] = SMART_UNASSIGNED;
			entry->smart[SMART_ROTATION_RATE] = 0;
		} else {
			snprintf(entry->smart_serial, sizeof(entry->smart_serial), "%u", c);
			pathcpy(entry->file, sizeof(entry->name), "file");
			pathcpy(entry->name, sizeof(entry->name), "name");
			entry->smart[SMART_SIZE] = c * TERA;
			entry->smart[SMART_ROTATION_RATE] = 7200;
		}

		entry->smart[SMART_ERROR] = 0;
		entry->smart[SMART_FLAGS] = SMART_UNASSIGNED;

		switch (c) {
		case 3 : entry->smart[SMART_ERROR] = 1; break;
		case 4 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_UNSUPPORTED; break;
		case 5 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_COMMAND; break;
		case 6 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_OPEN; break;
		case 7 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_FAIL; break;
		case 8 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_PREFAIL; break;
		case 9 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_PREFAIL_LOGGED; break;
		case 10 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_ERROR; break;
		case 11 : entry->smart[SMART_FLAGS] = SMARTCTL_FLAG_ERROR_LOGGED; break;
		}
	}

	return 0;
}
Exemplo n.º 11
0
void add_hash_table(void *ht, void *ht_node, void *ll, void *ll_node, void *obj, void *key, int key_len)
{
	tommy_hashlin_insert(ht, ht_node, obj, tommy_hash_u32(0, key, key_len));
	tommy_list_insert_tail(ll, ll_node, obj);
}
Exemplo n.º 12
0
switch_status_t switch_api_sflow_session_attach(
    switch_device_t device,
    switch_handle_t sflow_hdl,
    switch_direction_t direction,
    unsigned int priority,
    unsigned int
        sample_rate, /* != 0 can override sampling rate of the session */
    unsigned int key_value_count,
    switch_sflow_match_key_value_pair_t *kvp,
    switch_handle_t *entry_hdl) {
#ifdef P4_SFLOW_ENABLE
  switch_sflow_match_key_t match_key;
  switch_sflow_match_entry_t *match_entry = NULL;
  switch_status_t status = SWITCH_STATUS_FAILURE;
  switch_sflow_info_t *sflow_info;

  sflow_info = switch_sflow_info_get(sflow_hdl);
  if (!sflow_info) {
    return SWITCH_STATUS_INVALID_HANDLE;
  }
  // key-value pairs are used to specify the match-criteria for enabling sflow
  // For ingress sflow, ternary match on ingress port, sip, dip are supported
  // TBD - check if the match_spec is already used - callers responsibilty for
  // now

  if (!kvp || key_value_count > SWITCH_SFLOW_MATCH_FIELD_MAX) {
    return SWITCH_STATUS_INVALID_PARAMETER;
  }

  memset(&match_key, 0, sizeof(switch_sflow_match_key_t));
  match_key.port = SWITCH_API_INVALID_HANDLE;

  status = switch_sflow_match_key_from_tlv(key_value_count, kvp, &match_key);
  if (status != SWITCH_STATUS_SUCCESS) {
    goto error_return;
  }

  // create handle for match entry
  *entry_hdl = switch_sflow_ace_handle_create();
  match_entry = switch_sflow_ace_entry_get(*entry_hdl);
  match_entry->sflow_ace_hdl = *entry_hdl;

  if (direction == SWITCH_API_DIRECTION_INGRESS) {
    status = switch_pd_sflow_ingress_table_add(
        device, &match_key, priority, sample_rate, sflow_info, match_entry);
    if (status != SWITCH_STATUS_SUCCESS) {
      goto error_return;
    }
    // add the match entry to the list
    tommy_list_insert_tail(
        &sflow_info->match_list, &match_entry->node, match_entry);

  } else if (direction == SWITCH_API_DIRECTION_EGRESS) {
    status = SWITCH_STATUS_NOT_SUPPORTED;
    goto error_return;
  } else {
    status = SWITCH_STATUS_INVALID_PARAMETER;
    goto error_return;
  }
  return SWITCH_STATUS_SUCCESS;

error_return:
  *entry_hdl = SWITCH_API_INVALID_HANDLE;
  return status;

#else
  (void)device;
  (void)sflow_hdl;
  (void)direction;
  (void)priority;
  (void)key_value_count;
  (void)kvp;
  (void)entry_hdl;
  return SWITCH_STATUS_FAILURE;
#endif  // P4_SFLOW_ENABLE
}
Exemplo n.º 13
0
int main(int argc, char* argv[])
{
	int c;
	struct snapraid_option opt;
	char conf[PATH_MAX];
	struct snapraid_state state;
	int operation;
	block_off_t blockstart;
	block_off_t blockcount;
	int ret;
	tommy_list filterlist_file;
	tommy_list filterlist_disk;
	int filter_missing;
	int filter_error;
	int plan;
	int olderthan;
	char* e;
	const char* command;
	const char* import_timestamp;
	const char* import_content;
	const char* log_file;
	int lock;
	const char* gen_conf;
	const char* run;
	int speedtest;
	int period;
	time_t t;
	struct tm* tm;
	int i;

	/* defaults */
	config(conf, sizeof(conf), argv[0]);
	memset(&opt, 0, sizeof(opt));
	opt.io_error_limit = 100;
	blockstart = 0;
	blockcount = 0;
	tommy_list_init(&filterlist_file);
	tommy_list_init(&filterlist_disk);
	period = 1000;
	filter_missing = 0;
	filter_error = 0;
	plan = SCRUB_AUTO;
	olderthan = SCRUB_AUTO;
	import_timestamp = 0;
	import_content = 0;
	log_file = 0;
	lock = 0;
	gen_conf = 0;
	speedtest = 0;
	run = 0;

	opterr = 0;
	while ((c =
#if HAVE_GETOPT_LONG
		getopt_long(argc, argv, OPTIONS, long_options, 0))
#else
		getopt(argc, argv, OPTIONS))
#endif
		!= EOF) {
		switch (c) {
		case 'c' :
			pathimport(conf, sizeof(conf), optarg);
			break;
		case 'f' : {
			struct snapraid_filter* filter = filter_alloc_file(1, optarg);
			if (!filter) {
				/* LCOV_EXCL_START */
				log_fatal("Invalid filter specification '%s'\n", optarg);
				log_fatal("Filters using relative paths are not supported. Ensure to add an initial slash\n");
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			tommy_list_insert_tail(&filterlist_file, &filter->node, filter);
		} break;
		case 'd' : {
			struct snapraid_filter* filter = filter_alloc_disk(1, optarg);
			if (!filter) {
				/* LCOV_EXCL_START */
				log_fatal("Invalid filter specification '%s'\n", optarg);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			tommy_list_insert_tail(&filterlist_disk, &filter->node, filter);
		} break;
		case 'm' :
			filter_missing = 1;
			opt.expected_missing = 1;
			break;
		case 'e' :
			/* when processing only error, we filter both files and blocks */
			/* and we apply fixes only to synced ones */
			filter_error = 1;
			opt.badonly = 1;
			opt.syncedonly = 1;
			break;
		case 'p' :
			if (strcmp(optarg, "bad") == 0) {
				plan = SCRUB_BAD;
			} else if (strcmp(optarg, "new") == 0) {
				plan = SCRUB_NEW;
			} else if (strcmp(optarg, "full") == 0) {
				plan = SCRUB_FULL;
			} else {
				plan = strtoul(optarg, &e, 10);
				if (!e || *e || plan > 100) {
					/* LCOV_EXCL_START */
					log_fatal("Invalid plan/percentage '%s'\n", optarg);
					exit(EXIT_FAILURE);
					/* LCOV_EXCL_STOP */
				}
			}
			break;
		case 'o' :
			olderthan = strtoul(optarg, &e, 10);
			if (!e || *e || olderthan > 1000) {
				/* LCOV_EXCL_START */
				log_fatal("Invalid number of days '%s'\n", optarg);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			break;
		case 'S' :
			blockstart = strtoul(optarg, &e, 0);
			if (!e || *e) {
				/* LCOV_EXCL_START */
				log_fatal("Invalid start position '%s'\n", optarg);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			break;
		case 'B' :
			blockcount = strtoul(optarg, &e, 0);
			if (!e || *e) {
				/* LCOV_EXCL_START */
				log_fatal("Invalid count number '%s'\n", optarg);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			break;
		case 'L' :
			opt.io_error_limit = strtoul(optarg, &e, 0);
			if (!e || *e) {
				/* LCOV_EXCL_START */
				log_fatal("Invalid error limit number '%s'\n", optarg);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			break;
		case 'i' :
			if (import_timestamp) {
				/* LCOV_EXCL_START */
				log_fatal("Import directory '%s' already specified as '%s'\n", optarg, import_timestamp);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			import_timestamp = optarg;
			break;
		case OPT_TEST_IMPORT_CONTENT :
			if (import_content) {
				/* LCOV_EXCL_START */
				log_fatal("Import directory '%s' already specified as '%s'\n", optarg, import_content);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			import_content = optarg;
			break;
		case 'l' :
			if (log_file) {
				/* LCOV_EXCL_START */
				log_fatal("Log file '%s' already specified as '%s'\n", optarg, log_file);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
			log_file = optarg;
			break;
		case 'Z' :
			opt.force_zero = 1;
			break;
		case 'E' :
			opt.force_empty = 1;
			break;
		case 'U' :
			opt.force_uuid = 1;
			break;
		case 'D' :
			opt.force_device = 1;
			break;
		case 'N' :
			opt.force_nocopy = 1;
			break;
		case 'F' :
			opt.force_full = 1;
			break;
		case 'a' :
			opt.auditonly = 1;
			break;
		case 'h' :
			opt.prehash = 1;
			break;
		case 'v' :
			++msg_level;
			break;
		case 'q' :
			--msg_level;
			break;
		case 'G' :
			opt.gui = 1;
			break;
		case 'H' :
			usage();
			exit(EXIT_SUCCESS);
		case 'V' :
			version();
			exit(EXIT_SUCCESS);
		case 'T' :
			speedtest = 1;
			break;
		case 'C' :
			gen_conf = optarg;
			break;
		case OPT_TEST_KILL_AFTER_SYNC :
			opt.kill_after_sync = 1;
			break;
		case OPT_TEST_EXPECT_UNRECOVERABLE :
			opt.expect_unrecoverable = 1;
			break;
		case OPT_TEST_EXPECT_RECOVERABLE :
			opt.expect_recoverable = 1;
			break;
		case OPT_TEST_SKIP_SELF :
			opt.skip_self = 1;
			break;
		case OPT_TEST_SKIP_SIGN :
			opt.skip_sign = 1;
			break;
		case OPT_TEST_SKIP_FALLOCATE :
			opt.skip_fallocate = 1;
			break;
		case OPT_TEST_SKIP_SEQUENTIAL :
			opt.skip_sequential = 1;
			break;
		case OPT_TEST_SKIP_DEVICE :
			opt.skip_device = 1;
			period = 50; /* reduce period of the speed test */
			break;
		case OPT_TEST_SKIP_CONTENT_CHECK :
			opt.skip_content_check = 1;
			break;
		case OPT_TEST_SKIP_PARITY_ACCESS :
			opt.skip_parity_access = 1;
			break;
		case OPT_TEST_SKIP_DISK_ACCESS :
			opt.skip_disk_access = 1;
			break;
		case OPT_TEST_FORCE_MURMUR3 :
			opt.force_murmur3 = 1;
			break;
		case OPT_TEST_FORCE_SPOOKY2 :
			opt.force_spooky2 = 1;
			break;
		case OPT_TEST_SKIP_LOCK :
			opt.skip_lock = 1;
			break;
		case OPT_TEST_FORCE_ORDER_PHYSICAL :
			opt.force_order = SORT_PHYSICAL;
			break;
		case OPT_TEST_FORCE_ORDER_INODE :
			opt.force_order = SORT_INODE;
			break;
		case OPT_TEST_FORCE_ORDER_ALPHA :
			opt.force_order = SORT_ALPHA;
			break;
		case OPT_TEST_FORCE_ORDER_DIR :
			opt.force_order = SORT_DIR;
			break;
		case OPT_TEST_FORCE_SCRUB_AT :
			opt.force_scrub_at = atoi(optarg);
			break;
		case OPT_TEST_FORCE_SCRUB_EVEN :
			opt.force_scrub_even = 1;
			break;
		case OPT_TEST_FORCE_CONTENT_WRITE :
			opt.force_content_write = 1;
			break;
		case OPT_TEST_EXPECT_FAILURE :
			/* invert the exit codes */
			exit_success = 1;
			exit_failure = 0;
			break;
		case OPT_TEST_EXPECT_NEED_SYNC :
			/* invert the exit codes */
			exit_success = 1;
			exit_sync_needed = 0;
			break;
		case OPT_TEST_RUN :
			run = optarg;
			break;
		case OPT_TEST_FORCE_SCAN_WINFIND :
			opt.force_scan_winfind = 1;
			break;
		case OPT_TEST_FORCE_PROGRESS :
			opt.force_progress = 1;
			break;
		case OPT_TEST_FORCE_AUTOSAVE_AT :
			opt.force_autosave_at = atoi(optarg);
			break;
		case OPT_TEST_FAKE_DEVICE :
			opt.fake_device = 1;
			break;
		case OPT_NO_WARNINGS :
			opt.no_warnings = 1;
			break;
		default :
			/* LCOV_EXCL_START */
			log_fatal("Unknown option '%c'\n", (char)c);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	os_init(opt.force_scan_winfind);
	raid_init();
	crc32c_init();

	if (speedtest != 0) {
		speed(period);
		os_done();
		exit(EXIT_SUCCESS);
	}

	if (gen_conf != 0) {
		generate_configuration(gen_conf);
		os_done();
		exit(EXIT_SUCCESS);
	}

	if (optind + 1 != argc) {
		/* LCOV_EXCL_START */
		usage();
		exit(EXIT_FAILURE);
		/* LCOV_EXCL_STOP */
	}

	command = argv[optind];
	if (strcmp(command, "diff") == 0) {
		operation = OPERATION_DIFF;
	} else if (strcmp(argv[optind], "sync") == 0) {
		operation = OPERATION_SYNC;
	} else if (strcmp(argv[optind], "check") == 0) {
		operation = OPERATION_CHECK;
	} else if (strcmp(argv[optind], "fix") == 0) {
		operation = OPERATION_FIX;
	} else if (strcmp(argv[optind], "test-dry") == 0) {
		operation = OPERATION_DRY;
	} else if (strcmp(argv[optind], "dup") == 0) {
		operation = OPERATION_DUP;
	} else if (strcmp(argv[optind], "list") == 0) {
		operation = OPERATION_LIST;
	} else if (strcmp(argv[optind], "pool") == 0) {
		operation = OPERATION_POOL;
	} else if (strcmp(argv[optind], "rehash") == 0) {
		operation = OPERATION_REHASH;
	} else if (strcmp(argv[optind], "scrub") == 0) {
		operation = OPERATION_SCRUB;
	} else if (strcmp(argv[optind], "status") == 0) {
		operation = OPERATION_STATUS;
	} else if (strcmp(argv[optind], "test-rewrite") == 0) {
		operation = OPERATION_REWRITE;
	} else if (strcmp(argv[optind], "test-read") == 0) {
		operation = OPERATION_READ;
	} else if (strcmp(argv[optind], "test-nano") == 0) {
		operation = OPERATION_NANO;
	} else if (strcmp(argv[optind], "up") == 0) {
		operation = OPERATION_SPINUP;
	} else if (strcmp(argv[optind], "down") == 0) {
		operation = OPERATION_SPINDOWN;
	} else if (strcmp(argv[optind], "devices") == 0) {
		operation = OPERATION_DEVICES;
	} else if (strcmp(argv[optind], "smart") == 0) {
		operation = OPERATION_SMART;
	} else {
		/* LCOV_EXCL_START */
		log_fatal("Unknown command '%s'\n", argv[optind]);
		exit(EXIT_FAILURE);
		/* LCOV_EXCL_STOP */
	}

	/* check options compatibility */
	switch (operation) {
	case OPERATION_CHECK :
		break;
	default :
		if (opt.auditonly) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -a, --audit-only with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	switch (operation) {
	case OPERATION_FIX :
		break;
	default :
		if (opt.force_device) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -D, --force-device with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	switch (operation) {
	case OPERATION_SYNC :
	case OPERATION_CHECK :
	case OPERATION_FIX :
		break;
	default :
		if (opt.force_nocopy) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -N, --force-nocopy with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	switch (operation) {
	case OPERATION_SYNC :
		break;
	default :
		if (opt.prehash) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -h, --pre-hash with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}

		if (opt.force_full) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -F, --force-full with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	if (opt.force_full && opt.force_nocopy) {
		/* LCOV_EXCL_START */
		log_fatal("You cannot use the -F, --force-full and -N, --force-nocopy options at the same time\n");
		exit(EXIT_FAILURE);
		/* LCOV_EXCL_STOP */
	}

	if (opt.prehash && opt.force_nocopy) {
		/* LCOV_EXCL_START */
		log_fatal("You cannot use the -h, --pre-hash and -N, --force-nocopy options at the same time\n");
		exit(EXIT_FAILURE);
		/* LCOV_EXCL_STOP */
	}

	switch (operation) {
	case OPERATION_CHECK :
	case OPERATION_FIX :
	case OPERATION_DRY :
		break;
	default :
		if (!tommy_list_empty(&filterlist_file)) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -f, --filter with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
		if (!tommy_list_empty(&filterlist_disk)) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -d, --filter-disk with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
		if (filter_missing != 0) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -m, --filter-missing with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
		if (filter_error != 0) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot use -e, --filter-error with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	/* errors must be always fixed on all disks */
	/* becasue we don't keep the information on what disk is the error */
	if (filter_error != 0 && !tommy_list_empty(&filterlist_disk)) {
		/* LCOV_EXCL_START */
		log_fatal("You cannot use -e, --filter-error and -d, --filter-disk at the same time\n");
		exit(EXIT_FAILURE);
		/* LCOV_EXCL_STOP */
	}

	switch (operation) {
	case OPERATION_CHECK :
	case OPERATION_FIX :
		break;
	default :
		if (import_timestamp != 0 || import_content != 0) {
			/* LCOV_EXCL_START */
			log_fatal("You cannot import with the '%s' command\n", command);
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	switch (operation) {
	case OPERATION_LIST :
	case OPERATION_DUP :
	case OPERATION_STATUS :
	case OPERATION_REWRITE :
	case OPERATION_READ :
	case OPERATION_REHASH :
	case OPERATION_SPINUP : /* we want to do it in different threads to avoid blocking */
		/* avoid to check and access data disks if not needed */
		opt.skip_disk_access = 1;
		break;
	}

	switch (operation) {
	case OPERATION_DIFF :
	case OPERATION_LIST :
	case OPERATION_DUP :
	case OPERATION_POOL :
	case OPERATION_STATUS :
	case OPERATION_REWRITE :
	case OPERATION_READ :
	case OPERATION_REHASH :
	case OPERATION_NANO :
	case OPERATION_SPINUP : /* we want to do it in different threads to avoid blocking */
		/* avoid to check and access parity disks if not needed */
		opt.skip_parity_access = 1;
		break;
	}

	switch (operation) {
	case OPERATION_FIX :
	case OPERATION_CHECK :
		/* avoid to stop processing if a content file is not accessible */
		opt.skip_content_access = 1;
		break;
	}

	switch (operation) {
	case OPERATION_DIFF :
	case OPERATION_LIST :
	case OPERATION_DUP :
	case OPERATION_POOL :
	case OPERATION_NANO :
	case OPERATION_SPINUP :
	case OPERATION_SPINDOWN :
	case OPERATION_DEVICES :
	case OPERATION_SMART :
		opt.skip_self = 1;
		break;
	}

	switch (operation) {
	case OPERATION_DEVICES :
	case OPERATION_SMART :
		/* we may need to use these commands during operations */
		opt.skip_lock = 1;
		break;
	}

	/* open the log file */
	log_open(log_file);

	/* print generic info into the log */
	t = time(0);
	tm = localtime(&t);
	log_tag("version:%s\n", PACKAGE_VERSION);
	log_tag("unixtime:%" PRIi64 "\n", (int64_t)t);
	if (tm) {
		char datetime[64];
		strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", tm);
		log_tag("time:%s\n", datetime);
	}
	log_tag("command:%s\n", command);
	for (i = 0; i < argc; ++i)
		log_tag("argv:%u:%s\n", i, argv[i]);
	log_flush();

	if (!opt.skip_self)
		selftest();

	state_init(&state);

	/* read the configuration file */
	state_config(&state, conf, command, &opt, &filterlist_disk);

	/* set the raid mode */
	raid_mode(state.raid_mode);

#if HAVE_LOCKFILE
	/* create the lock file */
	if (!opt.skip_lock && state.lockfile[0]) {
		lock = lock_lock(state.lockfile);
		if (lock == -1) {
			/* LCOV_EXCL_START */
			if (errno != EWOULDBLOCK) {
				log_fatal("Error creating the lock file '%s'. %s.\n", state.lockfile, strerror(errno));
			} else {
				log_fatal("The lock file '%s' is already locked!\n", state.lockfile);
				log_fatal("SnapRAID is already in use!\n");
			}
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}
#else
	(void)lock;
#endif

	if (operation == OPERATION_DIFF) {
		state_read(&state);

		ret = state_diff(&state);

		/* abort if sync needed */
		if (ret > 0)
			exit(EXIT_SYNC_NEEDED);
	} else if (operation == OPERATION_SYNC) {

		/* in the next state read ensures to clear all the past hashes in case */
		/* we are reading from an incomplete sync */
		/* The undeterminated hash are only for CHG/DELETED blocks for which we don't */
		/* know if the previous interrupted sync was able to update or not the parity. */
		/* The sync process instead needs to trust this information because it's used */
		/* to avoid to recompute the parity if all the input are equals as before. */

		/* In these cases we don't know if the old state is still the one */
		/* stored inside the parity, because after an aborted sync, the parity */
		/* may be or may be not have been updated with the data that may be now */
		/* deleted. Then we reset the hash to a bogus value. */

		/* An example for CHG blocks is: */
		/* - One file is added creating a CHG block with ZERO state */
		/* - Sync aborted after updating the parity to the new state, */
		/*   but without saving the content file representing this new BLK state. */
		/* - File is now deleted after the aborted sync */
		/* - Sync again, deleting the blocks overt the CHG ones */
		/*   with the hash of CHG blocks not represeting the real parity state */

		/* An example for DELETED blocks is: */
		/* - One file is deleted creating DELETED blocks */
		/* - Sync aborted after, updating the parity to the new state, */
		/*   but without saving the content file representing this new EMPTY state. */
		/* - Another file is added again over the DELETE ones */
		/*   with the hash of DELETED blocks not represeting the real parity state */
		state.clear_past_hash = 1;

		state_read(&state);

		state_scan(&state);

		/* refresh the size info before the content write */
		state_refresh(&state);

		memory();

		/* intercept signals while operating */
		signal_init();

		/* save the new state before the sync */
		/* this allow to recover the case of the changes in the array after an aborted sync. */

		/* for example, think at this case: */
		/* - add some files at the array */
		/* - run a sync command, it will recompute the parity adding the new files */
		/* - abort the sync command before it stores the new content file */
		/* - delete the not yet synced files from the array */
		/* - run a new sync command */

		/* the new sync command has now way to know that the parity file was modified */
		/* because the files triggering these changes are now deleted */
		/* and they aren't listed in the content file */

		if (state.need_write)
			state_write(&state);

		/* run a test command if required */
		if (run != 0) {
			ret = system(run); /* ignore error */
			if (ret != 0) {
				/* LCOV_EXCL_START */
				log_fatal("Error in running command '%s'.\n", run);
				exit(EXIT_FAILURE);
				/* LCOV_EXCL_STOP */
			}
		}

		/* waits some time to ensure that any concurrent modification done at the files, */
		/* using the same mtime read by the scan process, will be read by sync. */
		/* Note that any later modification done, potentially not read by sync, will have */
		/* a different mtime, and it will be syncronized at the next sync. */
		/* The worst case is the FAT filesystem with a two seconds resolution for mtime. */
		/* If you don't use FAT, the wait is not needed, because most filesystems have now */
		/* at least microseconds resolution, but better to be safe. */
		if (!opt.skip_self)
			sleep(2);

		ret = state_sync(&state, blockstart, blockcount);

		/* save the new state if required */
		if (!opt.kill_after_sync && (state.need_write || state.opt.force_content_write))
			state_write(&state);

		/* abort if required */
		if (ret != 0) {
			/* LCOV_EXCL_START */
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	} else if (operation == OPERATION_DRY) {
		state_read(&state);

		/* filter */
		state_skip(&state);
		state_filter(&state, &filterlist_file, &filterlist_disk, filter_missing, filter_error);

		memory();

		/* intercept signals while operating */
		signal_init();

		state_dry(&state, blockstart, blockcount);
	} else if (operation == OPERATION_REHASH) {
		state_read(&state);

		/* intercept signals while operating */
		signal_init();

		state_rehash(&state);

		/* save the new state if required */
		if (state.need_write)
			state_write(&state);
	} else if (operation == OPERATION_SCRUB) {
		state_read(&state);

		memory();

		/* intercept signals while operating */
		signal_init();

		ret = state_scrub(&state, plan, olderthan);

		/* save the new state if required */
		if (state.need_write || state.opt.force_content_write)
			state_write(&state);

		/* abort if required */
		if (ret != 0) {
			/* LCOV_EXCL_START */
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	} else if (operation == OPERATION_REWRITE) {
		state_read(&state);

		/* intercept signals while operating */
		signal_init();

		state_write(&state);

		memory();
	} else if (operation == OPERATION_READ) {
		state_read(&state);

		memory();
	} else if (operation == OPERATION_NANO) {
		state_read(&state);

		state_nano(&state);

		/* intercept signals while operating */
		signal_init();

		state_write(&state);

		memory();
	} else if (operation == OPERATION_SPINUP) {
		state_device(&state, DEVICE_UP);
	} else if (operation == OPERATION_SPINDOWN) {
		state_device(&state, DEVICE_DOWN);
	} else if (operation == OPERATION_DEVICES) {
		state_device(&state, DEVICE_LIST);
	} else if (operation == OPERATION_SMART) {
		state_device(&state, DEVICE_SMART);
	} else if (operation == OPERATION_STATUS) {
		state_read(&state);

		memory();

		state_status(&state);
	} else if (operation == OPERATION_DUP) {
		state_read(&state);

		state_dup(&state);
	} else if (operation == OPERATION_LIST) {
		state_read(&state);

		state_list(&state);
	} else if (operation == OPERATION_POOL) {
		state_read(&state);

		state_pool(&state);
	} else {
		state_read(&state);

		/* if we are also trying to recover */
		if (!state.opt.auditonly) {
			/* import the user specified dirs */
			if (import_timestamp != 0)
				state_search(&state, import_timestamp);
			if (import_content != 0)
				state_import(&state, import_content);

			/* import from all the array */
			if (!state.opt.force_nocopy)
				state_search_array(&state);
		}

		/* filter */
		state_skip(&state);
		state_filter(&state, &filterlist_file, &filterlist_disk, filter_missing, filter_error);

		memory();

		/* intercept signals while operating */
		signal_init();

		if (operation == OPERATION_CHECK) {
			ret = state_check(&state, 0, blockstart, blockcount);
		} else { /* it's fix */
			ret = state_check(&state, 1, blockstart, blockcount);
		}

		/* abort if required */
		if (ret != 0) {
			/* LCOV_EXCL_START */
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}

	/* close log file */
	log_close(log_file);

#if HAVE_LOCKFILE
	if (!opt.skip_lock && state.lockfile[0]) {
		if (lock_unlock(lock) == -1) {
			/* LCOV_EXCL_START */
			log_fatal("Error closing the lock file '%s'. %s.\n", state.lockfile, strerror(errno));
			exit(EXIT_FAILURE);
			/* LCOV_EXCL_STOP */
		}
	}
#endif

	state_done(&state);
	tommy_list_foreach(&filterlist_file, (tommy_foreach_func*)filter_free);
	tommy_list_foreach(&filterlist_disk, (tommy_foreach_func*)filter_free);

	os_done();

	return EXIT_SUCCESS;
}
Exemplo n.º 14
0
void test_list(void)
{
	struct object* LIST;
	struct object_vector* VECTOR;
	tommy_node* list;
	unsigned i;

	LIST = malloc(MAX * sizeof(struct object));
	VECTOR = malloc(MAX * sizeof(struct object_vector));

	for(i=0;i<MAX;++i) {
		VECTOR[i].value = LIST[i].value = 0;
	}

	list = 0;
	for(i=0;i<MAX;++i) {
		VECTOR[i].value = LIST[i].value = rnd(MAX);
		tommy_list_insert_tail(&list, &LIST[i].node, &LIST[i]);
	}

	START("sort random");
	tommy_list_sort(&list, compare);
	STOP();

	START("C qsort random");
	qsort(VECTOR, MAX, sizeof(VECTOR[0]), compare_vector);
	STOP();

	test_list_order(list);

	/* forward order with some (1%) random values */
	list = 0;
	for(i=0;i<MAX;++i) {
		VECTOR[i].value = LIST[i].value = i;
		if (rnd(100) == 0)
			VECTOR[i].value = LIST[i].value = rnd(MAX);
		tommy_list_insert_tail(&list, &LIST[i].node, &LIST[i]);
	}

	START("sort partially ordered");
	tommy_list_sort(&list, compare);
	STOP();

	START("C qsort partially ordered");
	qsort(VECTOR, MAX, sizeof(VECTOR[0]), compare_vector);
	STOP();

	test_list_order(list);

	/* forward order */
	list = 0;
	for(i=0;i<MAX;++i) {
		VECTOR[i].value = LIST[i].value = i;
		tommy_list_insert_tail(&list, &LIST[i].node, &LIST[i]);
	}

	START("sort forward");
	tommy_list_sort(&list, compare);
	STOP();

	START("C qsort forward");
	qsort(VECTOR, MAX, sizeof(VECTOR[0]), compare_vector);
	STOP();

	test_list_order(list);

	/* backward order */
	list = 0;
	for(i=0;i<MAX;++i) {
		VECTOR[i].value = LIST[i].value = MAX - 1 - i;
		tommy_list_insert_tail(&list, &LIST[i].node, &LIST[i]);
	}

	START("sort backward");
	tommy_list_sort(&list, compare);
	STOP();

	START("C qsort backward");
	qsort(VECTOR, MAX, sizeof(VECTOR[0]), compare_vector);
	STOP();

	test_list_order(list);

	/* use a small range of random value to insert a lot of duplicates */
	list = 0;
	for(i=0;i<MAX;++i) {
		VECTOR[i].value = LIST[i].value = rnd(MAX / 1000 + 2);
		tommy_list_insert_tail(&list, &LIST[i].node, &LIST[i]);
	}

	START("sort random duplicate");
	tommy_list_sort(&list, compare);
	STOP();

	START("C qsort random duplicate");
	qsort(VECTOR, MAX, sizeof(VECTOR[0]), compare_vector);
	STOP();

	test_list_order(list);

	free(LIST);
	free(VECTOR);
}