Blame iscsiuio/src/unix/main.c

Packit eace71
/*
Packit eace71
 * Copyright (c) 2001, Adam Dunkels.
Packit eace71
 * All rights reserved.
Packit eace71
 *
Packit eace71
 * Redistribution and use in source and binary forms, with or without
Packit eace71
 * modification, are permitted provided that the following conditions
Packit eace71
 * are met:
Packit eace71
 * 1. Redistributions of source code must retain the above copyright
Packit eace71
 *    notice, this list of conditions and the following disclaimer.
Packit eace71
 * 2. Redistributions in binary form must reproduce the above copyright
Packit eace71
 *    notice, this list of conditions and the following disclaimer in the
Packit eace71
 *    documentation and/or other materials provided with the distribution.
Packit eace71
 * 3. All advertising materials mentioning features or use of this software
Packit eace71
 *    must display the following acknowledgement:
Packit eace71
 *      This product includes software developed by Adam Dunkels.
Packit eace71
 * 4. The name of the author may not be used to endorse or promote
Packit eace71
 *    products derived from this software without specific prior
Packit eace71
 *    written permission.
Packit eace71
 *
Packit eace71
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
Packit eace71
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Packit eace71
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit eace71
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
Packit eace71
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit eace71
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
Packit eace71
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit eace71
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
Packit eace71
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
Packit eace71
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit eace71
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit eace71
 *
Packit eace71
 * This file is part of the uIP TCP/IP stack.
Packit eace71
 *
Packit eace71
 *
Packit eace71
 */
Packit eace71
Packit eace71
#include <dlfcn.h>
Packit eace71
#include <errno.h>
Packit eace71
#include <fcntl.h>
Packit eace71
#include <string.h>
Packit eace71
#include <signal.h>
Packit eace71
#include <stdlib.h>
Packit eace71
#include <getopt.h>
Packit eace71
#include <unistd.h>
Packit eace71
#include <sys/types.h>
Packit eace71
#include <sys/stat.h>
Packit eace71
#include <sys/utsname.h>
Packit eace71
#include <net/ethernet.h>
Packit eace71
#include <arpa/inet.h>
Packit eace71
#include <sys/mman.h>
Packit eace71
#ifndef	NO_SYSTEMD
Packit eace71
#include <systemd/sd-daemon.h>
Packit eace71
#endif
Packit eace71
Packit eace71
#include "uip.h"
Packit eace71
#include "uip_arp.h"
Packit eace71
#include "uip_eth.h"
Packit eace71
Packit eace71
#include "timer.h"
Packit eace71
Packit eace71
#include "build_date.h"
Packit eace71
#include "config.h"
Packit eace71
#include "iscsid_ipc.h"
Packit eace71
#include "logger.h"
Packit eace71
#include "nic.h"
Packit eace71
#include "nic_id.h"
Packit eace71
#include "nic_nl.h"
Packit eace71
#include "nic_utils.h"
Packit eace71
#include "options.h"
Packit eace71
#include "packet.h"
Packit eace71
Packit eace71
#include "dhcpc.h"
Packit eace71
Packit eace71
#include "iscsid_ipc.h"
Packit eace71
#include "brcm_iscsi.h"
Packit eace71
Packit eace71
/*******************************************************************************
Packit eace71
 *  Constants
Packit eace71
 ******************************************************************************/
Packit eace71
#define PFX "main "
Packit eace71
Packit eace71
static const char default_pid_filepath[] = "/run/iscsiuio.pid";
Packit eace71
Packit eace71
/*******************************************************************************
Packit eace71
 *  Global Variables
Packit eace71
 ******************************************************************************/
Packit eace71
static const struct option long_options[] = {
Packit eace71
	{"foreground", no_argument, NULL, 'f'},
Packit eace71
	{"debug", required_argument, NULL, 'd'},
Packit eace71
	{"pid", required_argument, NULL, 'p'},
Packit eace71
	{"version", no_argument, NULL, 'v'},
Packit eace71
	{"help", no_argument, NULL, 'h'},
Packit eace71
	{NULL, no_argument, NULL, 0}
Packit eace71
};
Packit eace71
Packit eace71
struct options opt = {
Packit eace71
	.debug = DEBUG_OFF,
Packit eace71
};
Packit eace71
Packit eace71
int event_loop_stop;
Packit eace71
extern nic_t *nic_list;
Packit eace71
Packit eace71
struct utsname cur_utsname;
Packit eace71
Packit eace71
/**
Packit eace71
 *  cleanup() - This function is called when this program is to be closed
Packit eace71
 *              This function will clean up all the cnic uio interfaces and
Packit eace71
 *              flush/close the logger
Packit eace71
 */
Packit eace71
static void cleanup()
Packit eace71
{
Packit eace71
	iscsid_cleanup();
Packit eace71
Packit eace71
	nic_remove_all();
Packit eace71
Packit eace71
	unload_all_nic_libraries();
Packit eace71
Packit eace71
	LOG_INFO("Done waiting for cnic's/stacks to gracefully close");
Packit eace71
Packit eace71
	fini_logger(SHUTDOWN_LOGGER);
Packit eace71
}
Packit eace71
Packit eace71
/**
Packit eace71
 *  signal_handle_thread() - This is the signal handling thread of this program
Packit eace71
 *                           This is the only thread which will handle signals.
Packit eace71
 *                           All signals are routed here and handled here to
Packit eace71
 *                           provide consistant handling.
Packit eace71
 */
Packit eace71
static pthread_t signal_thread;
Packit eace71
static void *signal_handle_thread(void *arg)
Packit eace71
{
Packit eace71
	sigset_t set;
Packit eace71
	int rc;
Packit eace71
	int signal;
Packit eace71
Packit eace71
	sigfillset(&set);
Packit eace71
Packit eace71
	LOG_INFO("signal handling thread ready");
Packit eace71
Packit eace71
signal_wait:
Packit eace71
	rc = sigwait(&set, &signal);
Packit eace71
Packit eace71
	switch (signal) {
Packit eace71
	case SIGINT:
Packit eace71
		LOG_INFO("Caught SIGINT signal");
Packit eace71
		break;
Packit eace71
	case SIGUSR1:
Packit eace71
		LOG_INFO("Caught SIGUSR1 signal, rotate log");
Packit eace71
		fini_logger(SHUTDOWN_LOGGER);
Packit eace71
		rc = init_logger(main_log.log_file);
Packit eace71
		if (rc != 0)
Packit eace71
			fprintf(stderr, "WARN: Could not initialize the logger in "
Packit eace71
			       "signal!\n");
Packit eace71
		goto signal_wait;
Packit eace71
	default:
Packit eace71
		break;
Packit eace71
	}
Packit eace71
	event_loop_stop = 1;
Packit eace71
Packit eace71
	LOG_INFO("terminating...");
Packit eace71
Packit eace71
	cleanup();
Packit eace71
	exit(EXIT_SUCCESS);
Packit eace71
}
Packit eace71
Packit eace71
static void show_version()
Packit eace71
{
Packit eace71
	printf("%s: Version '%s', Build Date: '%s'\n",
Packit eace71
	       APP_NAME, PACKAGE_VERSION, build_date);
Packit eace71
}
Packit eace71
Packit eace71
static void main_usage()
Packit eace71
{
Packit eace71
	show_version();
Packit eace71
Packit eace71
	printf("\nUsage: %s [OPTION]\n", APP_NAME);
Packit eace71
	printf("iscsiuio daemon.\n"
Packit eace71
	       "-f, --foreground        make the program run in the foreground\n"
Packit eace71
	       "-d, --debug debuglevel  print debugging information\n"
Packit eace71
	       "-p, --pid pidfile       use pid file (default  %s).\n"
Packit eace71
	       "-h, --help              display this help and exit\n"
Packit eace71
	       "-v, --version           display version and exit\n",
Packit eace71
	       default_pid_filepath);
Packit eace71
}
Packit eace71
Packit eace71
static void daemon_init()
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
	dup2(fd, 0);
Packit eace71
	dup2(fd, 1);
Packit eace71
	dup2(fd, 2);
Packit eace71
	setsid();
Packit eace71
	chdir("/");
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
	if (nice(-10) < 0)
Packit eace71
		LOG_DEBUG("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("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("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
Packit eace71
/*******************************************************************************
Packit eace71
 * Main routine
Packit eace71
 ******************************************************************************/
Packit eace71
int main(int argc, char *argv[])
Packit eace71
{
Packit eace71
	int rc;
Packit eace71
	sigset_t set;
Packit eace71
	const char *pid_file = default_pid_filepath;
Packit eace71
	int fd;
Packit eace71
	int foreground = 0;
Packit eace71
	pid_t pid;
Packit eace71
	pthread_attr_t attr;
Packit eace71
	int pipefds[2];
Packit eace71
Packit eace71
	/*  Record the start time for the user space daemon */
Packit eace71
	opt.start_time = time(NULL);
Packit eace71
Packit eace71
	/*  parse the parameters */
Packit eace71
	while (1) {
Packit eace71
		int c, option_index;
Packit eace71
Packit eace71
		c = getopt_long(argc, argv, "fd:p:vh",
Packit eace71
				long_options, &option_index);
Packit eace71
Packit eace71
		if (c == -1)
Packit eace71
			break;
Packit eace71
Packit eace71
		switch (c) {
Packit eace71
Packit eace71
		case 'f':
Packit eace71
			foreground = 1;
Packit eace71
			break;
Packit eace71
Packit eace71
			/* Enable debugging mode */
Packit eace71
		case 'd':
Packit eace71
			main_log.level = atoi(optarg);
Packit eace71
			opt.debug = DEBUG_ON;
Packit eace71
			break;
Packit eace71
		case 'p':
Packit eace71
			pid_file = optarg;
Packit eace71
			break;
Packit eace71
		case 'v':
Packit eace71
			show_version();
Packit eace71
			exit(EXIT_SUCCESS);
Packit eace71
		case 'h':
Packit eace71
		default:
Packit eace71
			main_usage();
Packit eace71
			exit(EXIT_SUCCESS);
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (main_log.enabled == LOGGER_ENABLED) {
Packit eace71
		/*  initialize the logger */
Packit eace71
		rc = init_logger(main_log.log_file);
Packit eace71
		if (rc != 0 && opt.debug == DEBUG_ON)
Packit eace71
			fprintf(stderr, "WARN: Could not initialize the logger\n");
Packit eace71
	}
Packit eace71
Packit eace71
	LOG_INFO("Started iSCSI uio stack: Ver " PACKAGE_VERSION);
Packit eace71
	LOG_INFO("Build date: %s", build_date);
Packit eace71
Packit eace71
	if (opt.debug == DEBUG_ON)
Packit eace71
		LOG_INFO("Debug mode enabled");
Packit eace71
Packit eace71
	event_loop_stop = 0;
Packit eace71
	nic_list = NULL;
Packit eace71
Packit eace71
	/*  Determine the current kernel version */
Packit eace71
	memset(&cur_utsname, 0, sizeof(cur_utsname));
Packit eace71
Packit eace71
	rc = uname(&cur_utsname);
Packit eace71
	if (rc == 0) {
Packit eace71
		LOG_INFO("Running on sysname: '%s', release: '%s', "
Packit eace71
			 "version '%s' machine: '%s'",
Packit eace71
			 cur_utsname.sysname, cur_utsname.release,
Packit eace71
			 cur_utsname.version, cur_utsname.machine);
Packit eace71
	} else
Packit eace71
		LOG_WARN("Could not determine kernel version");
Packit eace71
Packit eace71
	/*  Initialze the iscsid listener */
Packit eace71
	rc = iscsid_init();
Packit eace71
	if (rc != 0)
Packit eace71
		goto error;
Packit eace71
Packit eace71
	if (!foreground) {
Packit eace71
		char buf[64];
Packit eace71
		ssize_t written_bytes;
Packit eace71
Packit eace71
		fd = open(pid_file, O_WRONLY | O_CREAT, 0644);
Packit eace71
		if (fd < 0) {
Packit eace71
			fprintf(stderr, "ERR: Unable to create pid file: %s\n",
Packit eace71
				pid_file);
Packit eace71
			exit(1);
Packit eace71
		}
Packit eace71
Packit eace71
		if (pipe(pipefds) < 0) {
Packit eace71
			fprintf(stderr, "ERR: Unable to create a PIPE: %s\n",
Packit eace71
				strerror(errno));
Packit eace71
			exit(1);
Packit eace71
		}
Packit eace71
Packit eace71
		pid = fork();
Packit eace71
		if (pid < 0) {
Packit eace71
			fprintf(stderr, "ERR: Starting daemon failed\n");
Packit eace71
			exit(1);
Packit eace71
		} else if (pid) {
Packit eace71
			char msgbuf[4];
Packit eace71
Packit eace71
			/* parent: wait for child msg then exit */
Packit eace71
			close(pipefds[1]);
Packit Service 83beb6
			read(pipefds[0], msgbuf, sizeof(msgbuf));
Packit eace71
			exit(0);
Packit eace71
		}
Packit eace71
Packit eace71
		/* the child */
Packit eace71
		rc = chdir("/");
Packit eace71
		if (rc == -1)
Packit eace71
			fprintf(stderr, "WARN: Unable to chdir(\") [%s]\n", strerror(errno));
Packit eace71
Packit eace71
		if (lockf(fd, F_TLOCK, 0) < 0) {
Packit eace71
			fprintf(stderr, "ERR: Unable to lock pid file: %s [%s]\n",
Packit eace71
			       pid_file, strerror(errno));
Packit eace71
			exit(1);
Packit eace71
		}
Packit eace71
Packit eace71
		rc = ftruncate(fd, 0);
Packit eace71
		if (rc == -1)
Packit eace71
			fprintf(stderr, "WARN: ftruncate(%d, 0) failed [%s]\n",
Packit eace71
			       fd, strerror(errno));
Packit eace71
Packit eace71
		sprintf(buf, "%d\n", getpid());
Packit eace71
		written_bytes = write(fd, buf, strlen(buf));
Packit eace71
		if (written_bytes == -1) {
Packit eace71
			fprintf(stderr, "ERR: Could not write pid file [%s]\n",
Packit eace71
			       strerror(errno));
Packit eace71
			exit(1);
Packit eace71
		}
Packit eace71
		close(fd);
Packit eace71
Packit eace71
		daemon_init();
Packit eace71
	}
Packit eace71
Packit eace71
	/*  Load the NIC libraries */
Packit eace71
	rc = load_all_nic_libraries();
Packit eace71
	if (rc != 0)
Packit eace71
		goto error;
Packit eace71
Packit eace71
	brcm_iscsi_init();
Packit eace71
Packit eace71
	/*  ensure we don't see any signals */
Packit eace71
	sigemptyset(&set);
Packit eace71
	sigaddset(&set, SIGINT);
Packit eace71
	sigaddset(&set, SIGQUIT);
Packit eace71
	sigaddset(&set, SIGTERM);
Packit eace71
	sigaddset(&set, SIGUSR1);
Packit eace71
	rc = pthread_sigmask(SIG_SETMASK, &set, NULL);
Packit eace71
Packit eace71
	/*  Spin off the signal handling thread */
Packit eace71
	pthread_attr_init(&attr);
Packit eace71
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
Packit eace71
	rc = pthread_create(&signal_thread, &attr, signal_handle_thread, NULL);
Packit eace71
	if (rc != 0)
Packit eace71
		LOG_ERR("Could not create signal handling thread");
Packit eace71
Packit eace71
	/* Using sysfs to discover iSCSI hosts */
Packit eace71
	nic_discover_iscsi_hosts();
Packit eace71
Packit eace71
	/* oom-killer will not kill us at the night... */
Packit eace71
	if (oom_adjust())
Packit eace71
		LOG_DEBUG("Can not adjust oom-killer's pardon");
Packit eace71
Packit eace71
	/* we don't want our active sessions to be paged out... */
Packit eace71
	if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
Packit eace71
		LOG_ERR("failed to mlockall, exiting...");
Packit eace71
		goto error;
Packit eace71
	}
Packit eace71
Packit eace71
	/*  Start the iscsid listener */
Packit eace71
	rc = iscsid_start();
Packit eace71
	if (rc != 0)
Packit eace71
		goto error;
Packit eace71
Packit eace71
	if (!foreground) {
Packit eace71
		/* signal parent they can go away now */
Packit eace71
		close(pipefds[0]);
Packit Service 83beb6
		write(pipefds[1], "ok\n", 3);
Packit eace71
		close(pipefds[1]);
Packit eace71
	}
Packit eace71
Packit eace71
#ifndef	NO_SYSTEMD
Packit eace71
	sd_notify(0, "READY=1\n"
Packit eace71
		     "STATUS=Ready to process requests\n");
Packit eace71
#endif
Packit eace71
Packit eace71
	/*  NetLink connection to listen to NETLINK_ISCSI private messages */
Packit eace71
	if (nic_nl_open() != 0)
Packit eace71
		goto error;
Packit eace71
Packit eace71
error:
Packit eace71
	cleanup();
Packit eace71
	exit(EXIT_FAILURE);
Packit eace71
}