|
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 |
}
|