Blame usr/iscsi_util.c

Packit eace71
/*
Packit eace71
 * Misc helpers
Packit eace71
 *
Packit eace71
 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
Packit eace71
 * Copyright (C) 2006 - 2010 Mike Christie
Packit eace71
 * Copyright (C) 2006 - 2010 Red Hat, Inc. All rights reserved.
Packit eace71
 * maintained by open-iscsi@googlegroups.com
Packit eace71
 *
Packit eace71
 * This program is free software; you can redistribute it and/or modify
Packit eace71
 * it under the terms of the GNU General Public License as published
Packit eace71
 * by the Free Software Foundation; either version 2 of the License, or
Packit eace71
 * (at your option) any later version.
Packit eace71
 *
Packit eace71
 * This program is distributed in the hope that it will be useful, but
Packit eace71
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit eace71
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit eace71
 * General Public License for more details.
Packit eace71
 *
Packit eace71
 * See the file COPYING included with this distribution for more details.
Packit eace71
 */
Packit eace71
#include <fcntl.h>
Packit eace71
#include <unistd.h>
Packit eace71
#include <stdlib.h>
Packit eace71
#include <stdio.h>
Packit eace71
#include <string.h>
Packit eace71
#include <errno.h>
Packit eace71
#include <ctype.h>
Packit eace71
#include <sys/socket.h>
Packit eace71
#include <sys/un.h>
Packit eace71
#include <sys/types.h>
Packit eace71
#include <sys/stat.h>
Packit eace71
#include <sys/resource.h>
Packit eace71
Packit eace71
#include "sysdeps.h"
Packit eace71
#include "log.h"
Packit eace71
#include "iscsi_settings.h"
Packit eace71
#include "iface.h"
Packit eace71
#include "session_info.h"
Packit eace71
#include "iscsi_util.h"
Packit eace71
Packit eace71
int setup_abstract_addr(struct sockaddr_un *addr, char *unix_sock_name)
Packit eace71
{
Packit eace71
	memset(addr, 0, sizeof(*addr));
Packit eace71
	addr->sun_family = AF_LOCAL;
Packit eace71
	strlcpy(addr->sun_path + 1, unix_sock_name, sizeof(addr->sun_path) - 1);
Packit eace71
	return offsetof(struct sockaddr_un, sun_path) +
Packit eace71
		strlen(addr->sun_path + 1) + 1;
Packit eace71
}
Packit eace71
Packit eace71
void daemon_init(void)
Packit eace71
{
Packit eace71
	int fd;
Packit eace71
Packit eace71
	fd = open("/dev/null", O_RDWR);
Packit eace71
	if (fd == -1) {
Packit eace71
		exit(-1);
Packit eace71
	}
Packit eace71
Packit eace71
	dup2(fd, 0);
Packit eace71
	dup2(fd, 1);
Packit eace71
	dup2(fd, 2);
Packit eace71
	setsid();
Packit eace71
	if (chdir("/") < 0)
Packit eace71
		log_debug(1, "Could not chdir to /: %s", strerror(errno));
Packit eace71
	close(fd);
Packit eace71
}
Packit eace71
Packit eace71
#define ISCSI_OOM_PATH_LEN 48
Packit eace71
Packit eace71
int oom_adjust(void)
Packit eace71
{
Packit eace71
	int fd;
Packit eace71
	char path[ISCSI_OOM_PATH_LEN];
Packit eace71
	struct stat statb;
Packit eace71
Packit eace71
	errno = 0;
Packit eace71
	if (nice(-10) == -1 && errno != 0)
Packit eace71
		log_debug(1, "Could not increase process priority: %s",
Packit eace71
			  strerror(errno));
Packit eace71
Packit eace71
	snprintf(path, ISCSI_OOM_PATH_LEN, "/proc/%d/oom_score_adj", getpid());
Packit eace71
	if (stat(path, &statb)) {
Packit eace71
		/* older kernel so use old oom_adj file */
Packit eace71
		snprintf(path, ISCSI_OOM_PATH_LEN, "/proc/%d/oom_adj",
Packit eace71
			 getpid());
Packit eace71
	}
Packit eace71
	fd = open(path, O_WRONLY);
Packit eace71
	if (fd < 0)
Packit eace71
		return -1;
Packit eace71
	if (write(fd, "-16", 3) < 0) /* for 2.6.11 */
Packit eace71
		log_debug(1, "Could not set oom score to -16: %s",
Packit eace71
			  strerror(errno));
Packit eace71
	if (write(fd, "-17", 3) < 0) /* for Andrea's patch */
Packit eace71
		log_debug(1, "Could not set oom score to -17: %s",
Packit eace71
			  strerror(errno));
Packit eace71
	close(fd);
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
char*
Packit eace71
str_to_ipport(char *str, int *port, int *tpgt)
Packit eace71
{
Packit eace71
	char *stpgt, *sport = str, *ip = str;
Packit eace71
Packit eace71
	if (!strchr(ip, '.')) {
Packit eace71
		if (*ip == '[') {
Packit eace71
			/* IPv6 with [] */
Packit eace71
			if (!(sport = strchr(ip, ']')))
Packit eace71
				return NULL;
Packit eace71
			*sport++ = '\0';
Packit eace71
			ip++;
Packit eace71
			str = sport;
Packit eace71
		} else {
Packit eace71
			/* hostname or ipv6 */
Packit eace71
			sport = strchr(ip, ':');
Packit eace71
			if (sport) {
Packit eace71
				if (strchr(sport + 1, ':'))
Packit eace71
					/* ipv6 */
Packit eace71
					sport = NULL;
Packit eace71
				else
Packit eace71
					/* hostname:port */
Packit eace71
					str = sport;
Packit eace71
			}
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (sport && (sport = strchr(str, ':'))) {
Packit eace71
		*sport++ = '\0';
Packit eace71
		*port = strtoul(sport, NULL, 10);
Packit eace71
		str = sport;
Packit eace71
	}
Packit eace71
Packit eace71
	if ((stpgt = strchr(str, ','))) {
Packit eace71
		*stpgt++ = '\0';
Packit eace71
		*tpgt = strtoul(stpgt, NULL, 10);
Packit eace71
	} else
Packit eace71
		*tpgt = PORTAL_GROUP_TAG_UNKNOWN;
Packit eace71
Packit eace71
	log_debug(2, "ip %s, port %d, tgpt %d", ip, *port, *tpgt);
Packit eace71
	return ip;
Packit eace71
}
Packit eace71
Packit eace71
#define ISCSI_MAX_FILES 16384
Packit eace71
Packit eace71
int increase_max_files(void)
Packit eace71
{
Packit eace71
	struct rlimit rl;
Packit eace71
	int err;
Packit eace71
Packit eace71
	err = getrlimit(RLIMIT_NOFILE, &rl);
Packit eace71
	if (err) {
Packit eace71
		log_debug(1, "Could not get file limit (err %d)", errno);
Packit eace71
		return errno;
Packit eace71
	}
Packit eace71
	log_debug(1, "Max file limits %lu %lu", rl.rlim_cur, rl.rlim_max);
Packit eace71
Packit eace71
	if (rl.rlim_cur < ISCSI_MAX_FILES)
Packit eace71
		rl.rlim_cur = ISCSI_MAX_FILES;
Packit eace71
	if (rl.rlim_max < ISCSI_MAX_FILES)
Packit eace71
		rl.rlim_max = ISCSI_MAX_FILES;
Packit eace71
Packit eace71
	err = setrlimit(RLIMIT_NOFILE, &rl);
Packit eace71
	if (err) {
Packit eace71
		log_debug(1, "Could not set file limit to %lu/%lu (err %d)",
Packit eace71
			  rl.rlim_cur, rl.rlim_max, errno);
Packit eace71
		return errno;
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
/*
Packit eace71
 * from linux kernel
Packit eace71
 */
Packit eace71
char *strstrip(char *s)
Packit eace71
{
Packit eace71
	size_t size;
Packit eace71
	char *end;
Packit eace71
Packit eace71
	size = strlen(s);
Packit eace71
	if (!size)
Packit eace71
		return s;
Packit eace71
Packit eace71
	end = s + size - 1;
Packit eace71
	while (end >= s && isspace(*end))
Packit eace71
		end--;
Packit eace71
	*(end + 1) = '\0';
Packit eace71
Packit eace71
	while (*s && isspace(*s))
Packit eace71
		s++;
Packit eace71
Packit eace71
	return s;
Packit eace71
}
Packit eace71
Packit eace71
/**
Packit eace71
 * cfg_get_string_param - return param value
Packit eace71
 * @pathname: pathname and filename of config file
Packit eace71
 * @key: param name
Packit eace71
 *
Packit eace71
 * Assumes the delim is a "=". "#" comments a line, but if
Packit eace71
 * the "#" is after the key= then it is a valid value.
Packit eace71
*/
Packit eace71
char *cfg_get_string_param(char *pathname, const char *key)
Packit eace71
{
Packit eace71
	FILE *f = NULL;
Packit eace71
	char *line, buffer[1024];
Packit eace71
	char *value = NULL, *param, *comment;
Packit eace71
Packit eace71
	if (!pathname) {
Packit eace71
		log_error("No pathname to load %s from", key);
Packit eace71
		return NULL;
Packit eace71
	}
Packit eace71
Packit eace71
	if ((f = fopen(pathname, "r"))) {
Packit eace71
		while ((line = fgets(buffer, sizeof (buffer), f))) {
Packit eace71
			param = strstr(line, key);
Packit eace71
			if (!param)
Packit eace71
				continue;
Packit eace71
Packit eace71
			/* make sure it is not commented out */
Packit eace71
			comment = strchr(line, '#');
Packit eace71
			if (comment) {
Packit eace71
				if (comment < param)
Packit eace71
					continue;
Packit eace71
			}
Packit eace71
Packit eace71
			param = strchr(param, '=');
Packit eace71
			if (!param) {
Packit eace71
				log_error("Invalid config line for %s. "
Packit eace71
					  "Missing '='.", key);
Packit eace71
				continue;
Packit eace71
			}
Packit eace71
Packit eace71
			param++;
Packit eace71
			if (!strlen(param)) {
Packit eace71
				log_error("Invalid config line for %s. "
Packit eace71
					  "Missing value", key);
Packit eace71
				continue;
Packit eace71
			}
Packit eace71
Packit eace71
			param = strstrip(param);
Packit eace71
			if (!strlen(param)) {
Packit eace71
				log_error("Invalid config line for %s. "
Packit eace71
					  "Missing value", key);
Packit eace71
				continue;
Packit eace71
			}
Packit eace71
Packit eace71
			value = strdup(param);
Packit eace71
			break;
Packit eace71
		}
Packit eace71
		fclose(f);
Packit eace71
		if (value)
Packit eace71
			log_debug(5, "%s=%s", key, value);
Packit eace71
	} else
Packit eace71
		log_error("can't open %s configuration file %s", key, pathname);
Packit eace71
Packit eace71
	return value;
Packit eace71
}
Packit eace71
Packit eace71
/**
Packit eace71
 * iscsi_addr_match - check if the addrs are to the same ip
Packit eace71
 * @address1: pattern
Packit eace71
 * @address2: address to check
Packit eace71
 *
Packit eace71
 * If address1 is blank then it matches any string passed in.
Packit eace71
 */
Packit eace71
static int iscsi_addr_match(char *address1, char *address2)
Packit eace71
{
Packit eace71
	struct addrinfo hints1, hints2, *res1, *res2;
Packit eace71
	int rc;
Packit eace71
Packit eace71
	if (!strlen(address1))
Packit eace71
		return 1;
Packit eace71
Packit eace71
	if (!strcmp(address1, address2))
Packit eace71
		return 1;
Packit eace71
Packit eace71
	memset(&hints1, 0, sizeof(struct addrinfo));
Packit eace71
	hints1.ai_family = AF_UNSPEC;
Packit eace71
	hints1.ai_socktype = SOCK_STREAM;
Packit eace71
Packit eace71
	memset(&hints2, 0, sizeof(struct addrinfo));
Packit eace71
	hints2.ai_family = AF_UNSPEC;
Packit eace71
	hints2.ai_socktype = SOCK_STREAM;
Packit eace71
Packit eace71
	/*
Packit eace71
	 * didn't match so we have to resolve to see if one is a dnsname
Packit eace71
	 * that matches an ip address.
Packit eace71
	 */
Packit eace71
	rc = getaddrinfo(address1, NULL, &hints1, &res1);
Packit eace71
	if (rc) {
Packit eace71
		log_debug(1, "Match error. Could not resolve %s: %s", address1,
Packit eace71
			  gai_strerror(rc));
Packit eace71
		return 0;
Packit eace71
Packit eace71
	}
Packit eace71
Packit eace71
	rc = getaddrinfo(address2, NULL, &hints2, &res2);
Packit eace71
	if (rc) {
Packit eace71
		log_debug(1, "Match error. Could not resolve %s: %s", address2,
Packit eace71
			  gai_strerror(rc));
Packit eace71
		rc = 0;
Packit eace71
		goto free_res1;
Packit eace71
	}
Packit eace71
Packit eace71
	if ((res1->ai_addrlen != res2->ai_addrlen) ||
Packit eace71
	    memcmp(res1->ai_addr, res2->ai_addr, res2->ai_addrlen))
Packit eace71
		rc = 0;
Packit eace71
	else
Packit eace71
		rc = 1;
Packit eace71
Packit eace71
	freeaddrinfo(res2);
Packit eace71
free_res1:
Packit eace71
	freeaddrinfo(res1);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
int __iscsi_match_session(node_rec_t *rec, char *targetname,
Packit eace71
			  char *address, int port, struct iface_rec *iface,
Packit eace71
			  unsigned sid)
Packit eace71
{
Packit eace71
	if (!rec) {
Packit eace71
		log_debug(6, "no rec info to match");
Packit eace71
		return 1;
Packit eace71
	}
Packit eace71
Packit eace71
	log_debug(6, "match session [%s,%s,%d][%s %s,%s,%s]:%u",
Packit eace71
		  rec->name, rec->conn[0].address, rec->conn[0].port,
Packit eace71
		  rec->iface.name, rec->iface.transport_name,
Packit eace71
		  rec->iface.hwaddress, rec->iface.ipaddress,
Packit eace71
		  rec->session.sid);
Packit eace71
Packit eace71
	if (iface)
Packit eace71
		log_debug(6, "to [%s,%s,%d][%s %s,%s,%s]:%u",
Packit eace71
			  targetname, address, port, iface->name,
Packit eace71
			  iface->transport_name, iface->hwaddress,
Packit eace71
			  iface->ipaddress, sid);
Packit eace71
Packit eace71
	if (rec->session.sid && sid && rec->session.sid != sid)
Packit eace71
		return 0;
Packit eace71
Packit eace71
	if (strlen(rec->name) && strcmp(rec->name, targetname))
Packit eace71
		return 0;
Packit eace71
Packit eace71
	if (!iscsi_addr_match(rec->conn[0].address, address))
Packit eace71
		return 0;
Packit eace71
Packit eace71
	if (rec->conn[0].port != -1 && port != rec->conn[0].port)
Packit eace71
		return 0;
Packit eace71
Packit eace71
	if (!iface_match(&rec->iface, iface))
Packit eace71
		return 0;
Packit eace71
Packit eace71
	return 1;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_match_session(void *data, struct session_info *info)
Packit eace71
{
Packit eace71
	return __iscsi_match_session(data, info->targetname,
Packit eace71
				     info->persistent_address,
Packit eace71
				     info->persistent_port, &info->iface,
Packit eace71
				     info->sid);
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_match_session_count(void *data, struct session_info *info)
Packit eace71
{
Packit eace71
	/*
Packit eace71
	 * iscsi_sysfs_for_each_session expects:
Packit eace71
	 *   0==match -1==nomatch >0==error
Packit eace71
	 * but iscsi_match_session returns:
Packit eace71
	 *   1==match 0==nomatch
Packit eace71
	 */
Packit eace71
	if (iscsi_match_session(data, info))
Packit eace71
		return 0;
Packit eace71
	return -1;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_match_target(void *data, struct session_info *info)
Packit eace71
{
Packit eace71
	return __iscsi_match_session(data, info->targetname,
Packit eace71
				     info->persistent_address,
Packit eace71
				     info->persistent_port, NULL,
Packit eace71
				     MATCH_ANY_SID);
Packit eace71
}