Exemple #1
0
static int stats_file_setup(struct stats_file *file)
{
	struct stats_file_header *hdr;
	struct stat st;
	size_t size = 0;
	int err;

	DBG("file %p fd %d name %s", file, file->fd, file->name);

	err = fstat(file->fd, &st);
	if (err < 0) {
		connman_error("fstat error %s for %s\n",
			strerror(errno), file->name);

		TFR(close(file->fd));
		g_free(file->name);
		file->name = NULL;

		return -errno;
	}

	size = (size_t)st.st_size;
	file->max_len = STATS_MAX_FILE_SIZE;

	if (size < (size_t)sysconf(_SC_PAGESIZE))
		size = sysconf(_SC_PAGESIZE);

	err = stats_file_remap(file, size);
	if (err < 0) {
		TFR(close(file->fd));
		g_free(file->name);
		file->name = NULL;

		return err;
	}

	hdr = get_hdr(file);

	if (hdr->magic != MAGIC ||
			hdr->begin < sizeof(struct stats_file_header) ||
			hdr->end < sizeof(struct stats_file_header) ||
			hdr->home < sizeof(struct stats_file_header) ||
			hdr->roaming < sizeof(struct stats_file_header) ||
			hdr->begin > file->len ||
			hdr->end > file->len) {
		hdr->magic = MAGIC;
		hdr->begin = sizeof(struct stats_file_header);
		hdr->end = sizeof(struct stats_file_header);
		hdr->home = UINT_MAX;
		hdr->roaming = UINT_MAX;

		stats_file_update_cache(file);
	}

	return 0;
}
Exemple #2
0
static int stats_file_remap(struct stats_file *file, size_t size)
{
	size_t page_size, new_size;
	void *addr;
	int err;

	DBG("file %p size %zu addr %p len %zu", file, size, file->addr,
		file->len);

	page_size = sysconf(_SC_PAGESIZE);
	new_size = (size + page_size - 1) & ~(page_size - 1);

	err = ftruncate(file->fd, new_size);
	if (err < 0) {
		connman_error("ftrunctate error %s for %s",
				strerror(errno), file->name);
		return -errno;
	}

	if (!file->addr) {
		/*
		 * Though the buffer is not shared between processes, we still
		 * have to take MAP_SHARED because MAP_PRIVATE does not
		 * guarantee that writes will hit the file without an explicit
		 * call to munmap or msync. For more details please read the
		 * mmap man pages.
		 */
		addr = mmap(NULL, new_size, PROT_READ | PROT_WRITE,
				MAP_SHARED, file->fd, 0);
	} else {
		addr = mremap(file->addr, file->len, new_size, MREMAP_MAYMOVE);
	}

	if (addr == MAP_FAILED) {
		connman_error("mmap error %s for %s",
				strerror(errno), file->name);
		if (errno == EINVAL) {
			connman_error("%s might be on a file system, such as "
					"JFFS2, that does not allow shared "
					"writable mappings.", file->name);
		}
		return -errno;
	}

	file->addr = addr;
	file->len = new_size;

	if (get_hdr(file)->magic == MAGIC32)
		stats_file_update_cache32(file);
	else
		stats_file_update_cache(file);

	return 0;
}
Exemple #3
0
static int append_record(struct stats_file *file,
				struct stats_record *rec)
{
	struct stats_record *cur, *next;
	int err;

	if (file->last == get_end(file)) {
		err = stats_file_remap(file, file->len +
					sysconf(_SC_PAGESIZE));
		if (err < 0)
			return err;

		stats_file_update_cache(file);
	}

	cur = get_end(file);
	next = get_next(file, cur);

	memcpy(next, rec, sizeof(struct stats_record));

	set_end(file, next);

	return 0;
}
Exemple #4
0
int main(int argc, char *argv[])
{
	GOptionContext *context;
	GError *error = NULL;

	struct stats_file_header *hdr;
	struct stats_file data, *data_file;
	struct stats_record *rec;
	time_t start_ts;
	int err;

	rec = NULL;

	data_file = &data;

	putenv("TZ=GMT0");

	context = g_option_context_new(NULL);
	g_option_context_add_main_entries(context, options, NULL);

	if (!g_option_context_parse(context, &argc, &argv, &error)) {
		if (error) {
			g_printerr("%s\n", error->message);
			g_error_free(error);
		} else
			g_printerr("An unknown error occurred\n");
		exit(1);
	}

	g_option_context_free(context);

	if (argc < 2) {
		printf("Usage: %s [FILENAME]\n", argv[0]);
		exit(0);
	}

	err = stats_open(data_file, argv[1]);
	if (err < 0) {
		fprintf(stderr, "failed open file %s\n", argv[1]);
		exit(1);
	}

	if (option_last_file_name) {
		struct stats_file last;
		if (stats_open(&last, option_last_file_name) < 0) {
			fprintf(stderr, "failed open file %s\n",
				option_last_file_name);
			exit(1);
		}

		rec = get_end(&last);
	}

	if (option_start_ts == -1)
		start_ts = time(NULL);
	else
		start_ts = option_start_ts;

	if (option_create > 0)
		stats_create(data_file, option_create, option_interval,
				start_ts, rec);

	hdr = get_hdr(data_file);
	if (hdr->magic != MAGIC) {
		fprintf(stderr, "header file magic test failed\n");
		goto err;
	}

	stats_file_update_cache(data_file);

	stats_hdr_info(data_file);

	if (option_dump)
		stats_print_entries(data_file);

	if (option_summary)
		stats_print_diff(data_file);

	if (option_info_file_name)
		history_file_update(data_file, option_info_file_name);

err:
	stats_close(data_file);

	return 0;
}
Exemple #5
0
static int stats_create(struct stats_file *file, unsigned int nr,
			unsigned int interval, time_t start_ts,
			struct stats_record *start)
{
	unsigned int i;
	int err;
	struct stats_record *cur, *next;
	struct stats_file_header *hdr;
	unsigned int pkt;
	unsigned int step_ts;
	unsigned int roaming = FALSE;

	hdr = get_hdr(file);

	hdr->magic = MAGIC;
	hdr->begin = sizeof(struct stats_file_header);
	hdr->end = sizeof(struct stats_file_header);
	hdr->home = UINT_MAX;
	hdr->roaming = UINT_MAX;

	stats_file_update_cache(file);

	if (start) {
		struct stats_record *rec;

		rec = get_end(file);
		memcpy(rec, start, sizeof(struct stats_record));
	} else {
		get_end(file)->ts = start_ts;
	}

	for (i = 0; i < nr; i++) {
		if (file->last == get_end(file)) {
			err = stats_file_remap(file, file->len +
						sysconf(_SC_PAGESIZE));
			if (err < 0)
				return err;

			stats_file_update_cache(file);
		}
		cur = get_end(file);
		next = get_next(file, cur);

		step_ts = (rand() % interval);
		if (step_ts == 0)
			step_ts = 1;

		next->ts = cur->ts + step_ts;
		next->roaming = roaming;
		next->data.time = cur->data.time + step_ts;

		next->data.rx_packets = cur->data.rx_packets;
		next->data.rx_bytes = cur->data.rx_bytes;

		if (rand() % 3 == 0) {
			pkt = rand() % 5;
			next->data.rx_packets += pkt;
			next->data.rx_bytes += pkt * (rand() % 1500);
		}

		next->data.tx_packets = cur->data.tx_packets;
		next->data.tx_bytes = cur->data.tx_bytes;

		if (rand() % 3 == 0) {
			pkt = rand() % 5;
			next->data.tx_packets += pkt;
			next->data.tx_bytes += pkt * (rand() % 1500);
		}

		set_end(file, next);

		if ((rand() % 50) == 0)
			roaming = roaming ? FALSE : TRUE;

	}

	return 0;
}
Exemple #6
0
static int stats_open(struct stats_file *file, const char *name)
{
	struct stats_file_header *hdr;
	struct stat tm;
	int err;
	size_t size = 0;

	bzero(file, sizeof(struct stats_file));

	if (name) {
		file->name = g_strdup(name);

		file->fd = TFR(open(file->name,
					O_RDWR | O_CREAT | O_CLOEXEC, 0644));
		if (file->fd == -1) {
			fprintf(stderr, "open error %s for %s\n",
				strerror(errno), file->name);
			return -errno;
		}

		err = fstat(file->fd, &tm);
		if (err < 0) {
			fprintf(stderr, "fstat error %s for %s\n",
				strerror(errno), file->name);
			return err;
		}

		size = (size_t)tm.st_size;
	} else {
		file->name = g_strdup("stats.XXXXXX.tmp");
		file->fd = g_mkstemp_full(file->name, O_RDWR | O_CREAT, 0644);
		if (file->fd == -1) {
			fprintf(stderr, "creating tmp failed\n");
			return -1;
		}
	}

	if (size == 0)
		size = sysconf(_SC_PAGESIZE);

	err = stats_file_remap(file, size);
	if (err < 0) {
		fprintf(stderr, "remap failed\n");
		return err;
	}

	/* Initialize new file */
	hdr = get_hdr(file);
	if (hdr->magic != MAGIC ||
			hdr->begin < sizeof(struct stats_file_header) ||
			hdr->end < sizeof(struct stats_file_header) ||
			hdr->home < sizeof(struct stats_file_header) ||
			hdr->roaming < sizeof(struct stats_file_header) ||
			hdr->begin > file->len ||
			hdr->end > file->len) {
		hdr->magic = MAGIC;
		hdr->begin = sizeof(struct stats_file_header);
		hdr->end = sizeof(struct stats_file_header);
		hdr->home = UINT_MAX;
		hdr->roaming = UINT_MAX;

	}
	stats_file_update_cache(file);

	return 0;
}
Exemple #7
0
static void stats_convert(struct stats_file *file)
{
	struct stats_file temp_file;
	int err;

	DBG("converting data file %s", file->name);

	stats_file_update_cache32(file);

	bzero(&temp_file, sizeof(struct stats_file));

	err = stats_open_temp(&temp_file);
	if (err < 0) {
		connman_error("failed to open temporary file during data conversion");
		return;
	}
	stats_file_setup(&temp_file);

	struct stats_iter32 data_iter;
	struct stats_record32 *record;

	data_iter.file = file;
	data_iter.begin = get_iterator_begin32(data_iter.file);
	data_iter.end = get_iterator_end32(data_iter.file);
	data_iter.it = data_iter.begin;

	record = get_next_record32(&data_iter);
	while (record) {
		struct stats_record *next;

		if (temp_file.last == get_end(&temp_file)) {
			err = stats_file_remap(&temp_file, temp_file.len + sysconf(_SC_PAGESIZE));
			if (err < 0) {
				connman_error("failed to extend file %s", temp_file.name);
				unlink(temp_file.name);
				stats_file_unmap(&temp_file);
				TFR(close(temp_file.fd));
				stats_file_cleanup(&temp_file);
				return;
			}

			stats_file_update_cache(&temp_file);
		}

		next = get_next(&temp_file, get_end(&temp_file));
		if (next == get_begin(&temp_file)) {
			connman_error("ring buffer is full");
			unlink(temp_file.name);
            stats_file_unmap(&temp_file);
			TFR(close(temp_file.fd));
			stats_file_cleanup(&temp_file);
			return;
		}

		next->ts = record->ts;
		next->roaming = record->roaming;
		next->data.rx_packets = record->data.rx_packets;
		next->data.tx_packets = record->data.tx_packets;
		next->data.rx_bytes = record->data.rx_bytes;
		next->data.tx_bytes = record->data.tx_bytes;
		next->data.rx_errors = record->data.rx_errors;
		next->data.tx_errors = record->data.tx_errors;
		next->data.rx_dropped = record->data.rx_dropped;
		next->data.tx_dropped = record->data.tx_dropped;
		next->data.time = record->data.time;

		if (next->roaming)
			set_roaming(&temp_file, next);
		else
			set_home(&temp_file, next);

		set_end(&temp_file, next);

		record = get_next_record32(&data_iter);
	}

	// close and swap
	stats_file_unmap(file);
	TFR(close(file->fd));
	err = rename(temp_file.name, file->name);
	if (err < 0)
		connman_error("failed to rename converted data file %s to %s", temp_file.name, file->name);

	g_free(temp_file.name);
	temp_file.name = file->name;

	memcpy(file, &temp_file, sizeof(struct stats_file));
}
Exemple #8
0
static int stats_file_setup(struct stats_file *file)
{
	struct stats_file_header *hdr;
	struct stat st;
	size_t size = 0;
	int err;

	DBG("file %p fd %d name %s", file, file->fd, file->name);

	err = fstat(file->fd, &st);
	if (err < 0) {
		connman_error("fstat error %s for %s\n",
			strerror(errno), file->name);

		TFR(close(file->fd));
		g_free(file->name);
		file->name = NULL;

		return -errno;
	}

	size = (size_t)st.st_size;
	file->max_len = STATS_MAX_FILE_SIZE;

	if (size < (size_t)sysconf(_SC_PAGESIZE))
		size = sysconf(_SC_PAGESIZE);

	err = stats_file_remap(file, size);
	if (err < 0) {
		TFR(close(file->fd));
		g_free(file->name);
		file->name = NULL;

		return err;
	}

	hdr = get_hdr(file);

	/* Check if data file is in old format and convert */
	if (hdr->magic == MAGIC32 &&
			hdr->begin >= sizeof(struct stats_file_header) &&
			hdr->end >= sizeof(struct stats_file_header) &&
			hdr->home >= sizeof(struct stats_file_header) &&
			hdr->roaming >= sizeof(struct stats_file_header) &&
			hdr->begin <= file->len &&
			hdr->end <= file->len) {
			stats_convert(file);
			/* conversion changes the mapped address */
			hdr = get_hdr(file);
	}

	if (hdr->magic != MAGIC64 ||
			hdr->begin < sizeof(struct stats_file_header) ||
			hdr->end < sizeof(struct stats_file_header) ||
			hdr->home < sizeof(struct stats_file_header) ||
			hdr->roaming < sizeof(struct stats_file_header) ||
			hdr->begin > file->len ||
			hdr->end > file->len) {
		hdr->magic = MAGIC64;
		hdr->begin = sizeof(struct stats_file_header);
		hdr->end = sizeof(struct stats_file_header);
		hdr->home = UINT_MAX;
		hdr->roaming = UINT_MAX;

		stats_file_update_cache(file);
	}

	return 0;
}