예제 #1
0
파일: swclock.c 프로젝트: Like-all/openrc
int main(int argc, char **argv)
{
	int opt, sflag = 0, wflag = 0;
	const char *file = RC_SHUTDOWNTIME;
	struct stat sb;
	struct timeval tv;

	applet = basename_c(argv[0]);
	while ((opt = getopt_long(argc, argv, getoptstring,
		    longopts, (int *) 0)) != -1)
	{
		switch (opt) {
		case 's':
			sflag = 1;
			break;
		case 'w':
			wflag = 1;
			break;
		case_RC_COMMON_GETOPT
		}
	}

	if (optind < argc)
		file = argv[optind++];

	if (sflag) {
		if (stat(file, &sb) == -1) {
			opt = open(file, O_WRONLY | O_CREAT, 0644);
			if (opt == -1)
				eerrorx("swclock: open: %s", strerror(errno));
			close(opt);
		} else
			if (utime(file, NULL) == -1)
				eerrorx("swclock: utime: %s", strerror(errno));
		return 0;
	}

	if (stat(file, &sb) == -1) {
		if (wflag != 0 && errno == ENOENT)
			ewarn("swclock: `%s': %s", file, strerror(errno));
		else
			eerrorx("swclock: `%s': %s", file, strerror(errno));
		return 0;
	}

	tv.tv_sec = sb.st_mtime;
	tv.tv_usec = 0;

	if (settimeofday(&tv, NULL) == -1)
		eerrorx("swclock: settimeofday: %s", strerror(errno));

	return 0;
}
예제 #2
0
int daemond_pid_lock(daemond_pid * pid) {
	struct stat sb;
	int r,err;
	pid_t oldpid;
	FILE *f;
	daemond_say(pid->d, "lock %s", pid->pidfile);
	if( stat(pid->pidfile, &sb) == -1 ) {
		err = errno;
		ewarn("no pid");
		switch(err) {
			case ENOENT:
				r = daemond_pid_openlocked( pid, 0 );
				break;
			default:
				warn("shit!");
		}
	} else {
		//debug("have pid");
		f = fopen(pid->pidfile,"r");
		if (!f) {
			die("Can't open old pidfile `%s' for reading: %s",pid->pidfile, ERR);
		}
		if( fscanf(f,"%d",&oldpid) > 0 ) {
			//debug("got old pid: %d",oldpid);
			if( kill(oldpid,0) == 0 ) {
				//warn("old process %d still alive",oldpid);
				pid->oldpid = oldpid;
				return 0;
			} else {
				//daemond_say(pid->d, "<y>stalled pidfile old pid %d is invalid", oldpid);
			}
		} else {
			daemond_say(pid->d, "<r>can't read pidfile contents");
		}
		r = daemond_pid_openlocked( pid, 0 );
	}
	if (pid->locked) {
		//if (pid->verbose)
			//debug( "pidfile `%s' was locked", pid->pidfile );
		if( flock(pid->fd, LOCK_EX|LOCK_NB) == -1) {
			die("Relock pidfile `%s' failed: %s",pid->pidfile, strerror(errno));
		}
		daemond_pid_write(pid);
		return 1;
	}
	return 0;
}
예제 #3
0
int main(int argc, char **argv)
{
	int devnull_fd = -1;
#ifdef TIOCNOTTY
	int tty_fd = -1;
#endif

#ifdef HAVE_PAM
	pam_handle_t *pamh = NULL;
	int pamr;
	const char *const *pamenv = NULL;
#endif

	int opt;
	bool start = false;
	bool stop = false;
	bool oknodo = false;
	bool test = false;
	char *exec = NULL;
	char *startas = NULL;
	char *name = NULL;
	char *pidfile = NULL;
	char *retry = NULL;
	int sig = -1;
	int nicelevel = 0, ionicec = -1, ioniced = 0;
	bool background = false;
	bool makepidfile = false;
	bool interpreted = false;
	bool progress = false;
	uid_t uid = 0;
	gid_t gid = 0;
	char *home = NULL;
	int tid = 0;
	char *redirect_stderr = NULL;
	char *redirect_stdout = NULL;
	int stdin_fd;
	int stdout_fd;
	int stderr_fd;
	pid_t pid, spid;
	int i;
	char *svcname = getenv("RC_SVCNAME");
	RC_STRINGLIST *env_list;
	RC_STRING *env;
	char *tmp, *newpath, *np;
	char *p;
	char *token;
	char exec_file[PATH_MAX];
	struct passwd *pw;
	struct group *gr;
	char line[130];
	FILE *fp;
	size_t len;
	mode_t numask = 022;
	char **margv;
	unsigned int start_wait = 0;

	applet = basename_c(argv[0]);
	TAILQ_INIT(&schedule);
#ifdef DEBUG_MEMORY
	atexit(cleanup);
#endif

	signal_setup(SIGINT, handle_signal);
	signal_setup(SIGQUIT, handle_signal);
	signal_setup(SIGTERM, handle_signal);

	if ((tmp = getenv("SSD_NICELEVEL")))
		if (sscanf(tmp, "%d", &nicelevel) != 1)
			eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
			    applet, tmp);

	/* Get our user name and initial dir */
	p = getenv("USER");
	home = getenv("HOME");
	if (home == NULL || p == NULL) {
		pw = getpwuid(getuid());
		if (pw != NULL) {
			if (p == NULL)
				setenv("USER", pw->pw_name, 1);
			if (home == NULL) {
				setenv("HOME", pw->pw_dir, 1);
				home = pw->pw_dir;
			}
		}
	}

	while ((opt = getopt_long(argc, argv, getoptstring, longopts,
		    (int *) 0)) != -1)
		switch (opt) {
		case 'I': /* --ionice */
			if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0)
				eerrorx("%s: invalid ionice `%s'",
				    applet, optarg);
			if (ionicec == 0)
				ioniced = 0;
			else if (ionicec == 3)
				ioniced = 7;
			ionicec <<= 13; /* class shift */
			break;

		case 'K':  /* --stop */
			stop = true;
			break;

		case 'N':  /* --nice */
			if (sscanf(optarg, "%d", &nicelevel) != 1)
				eerrorx("%s: invalid nice level `%s'",
				    applet, optarg);
			break;

		case 'P':  /* --progress */
			progress = true;
			break;

		case 'R':  /* --retry <schedule>|<timeout> */
			retry = optarg;
			break;

		case 'S':  /* --start */
			start = true;
			break;

		case 'b':  /* --background */
			background = true;
			break;

		case 'c':  /* --chuid <username>|<uid> */
			/* DEPRECATED */
			ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead");
		case 'u':  /* --user <username>|<uid> */
		{
			p = optarg;
			tmp = strsep(&p, ":");
			changeuser = xstrdup(tmp);
			if (sscanf(tmp, "%d", &tid) != 1)
				pw = getpwnam(tmp);
			else
				pw = getpwuid((uid_t)tid);

			if (pw == NULL)
				eerrorx("%s: user `%s' not found",
				    applet, tmp);
			uid = pw->pw_uid;
			home = pw->pw_dir;
			unsetenv("HOME");
			if (pw->pw_dir)
				setenv("HOME", pw->pw_dir, 1);
			unsetenv("USER");
			if (pw->pw_name)
				setenv("USER", pw->pw_name, 1);
			if (gid == 0)
				gid = pw->pw_gid;

			if (p) {
				tmp = strsep (&p, ":");
				if (sscanf(tmp, "%d", &tid) != 1)
					gr = getgrnam(tmp);
				else
					gr = getgrgid((gid_t) tid);

				if (gr == NULL)
					eerrorx("%s: group `%s'"
					    " not found",
					    applet, tmp);
				gid = gr->gr_gid;
			}
		}
		break;

		case 'd':  /* --chdir /new/dir */
			ch_dir = optarg;
			break;

		case 'e': /* --env */
			putenv(optarg);
			break;

		case 'g':  /* --group <group>|<gid> */
			if (sscanf(optarg, "%d", &tid) != 1)
				gr = getgrnam(optarg);
			else
				gr = getgrgid((gid_t)tid);
			if (gr == NULL)
				eerrorx("%s: group `%s' not found",
				    applet, optarg);
			gid = gr->gr_gid;
			break;

		case 'i': /* --interpreted */
			interpreted = true;
			break;

		case 'k':
			if (parse_mode(&numask, optarg))
				eerrorx("%s: invalid mode `%s'",
				    applet, optarg);
			break;

		case 'm':  /* --make-pidfile */
			makepidfile = true;
			break;

		case 'n':  /* --name <process-name> */
			name = optarg;
			break;

		case 'o':  /* --oknodo */
			/* DEPRECATED */
			ewarn("WARNING: -o/--oknodo is deprecated and will be removed in the future");
			oknodo = true;
			break;

		case 'p':  /* --pidfile <pid-file> */
			pidfile = optarg;
			break;

		case 's':  /* --signal <signal> */
			sig = parse_signal(optarg);
			break;

		case 't':  /* --test */
			test = true;
			break;

		case 'r':  /* --chroot /new/root */
			ch_root = optarg;
			break;

		case 'a': /* --startas <name> */
			/* DEPRECATED */
			ewarn("WARNING: -a/--startas is deprecated and will be removed in the future, please use -x/--exec or -n/--name instead");
			startas = optarg;
			break;
		case 'w':
			if (sscanf(optarg, "%d", &start_wait) != 1)
				eerrorx("%s: `%s' not a number",
				    applet, optarg);
			break;
		case 'x':  /* --exec <executable> */
			exec = optarg;
			break;

		case '1':   /* --stdout /path/to/stdout.lgfile */
			redirect_stdout = optarg;
			break;

		case '2':  /* --stderr /path/to/stderr.logfile */
			redirect_stderr = optarg;
			break;

		case_RC_COMMON_GETOPT
		}

	endpwent();
	argc -= optind;
	argv += optind;

	/* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq
	 * instead of forcing --stop --oknodo as well */
	if (!start &&
	    !stop &&
	    sig != SIGINT &&
	    sig != SIGTERM &&
	    sig != SIGQUIT &&
	    sig != SIGKILL)
		oknodo = true;

	if (!exec)
		exec = startas;
	else if (!name)
		name = startas;

	if (!exec) {
		exec = *argv;
		if (!exec)
			exec = name;
		if (name && start)
			*argv = name;
	} else if (name) {
		*--argv = name;
		++argc;
    } else if (exec) {
		*--argv = exec;
		++argc;
	};

	if (stop || sig != -1) {
		if (sig == -1)
			sig = SIGTERM;
		if (!*argv && !pidfile && !name && !uid)
			eerrorx("%s: --stop needs --exec, --pidfile,"
			    " --name or --user", applet);
		if (background)
			eerrorx("%s: --background is only relevant with"
			    " --start", applet);
		if (makepidfile)
			eerrorx("%s: --make-pidfile is only relevant with"
			    " --start", applet);
		if (redirect_stdout || redirect_stderr)
			eerrorx("%s: --stdout and --stderr are only relevant"
			    " with --start", applet);
	} else {
		if (!exec)
			eerrorx("%s: nothing to start", applet);
		if (makepidfile && !pidfile)
			eerrorx("%s: --make-pidfile is only relevant with"
			    " --pidfile", applet);
		if ((redirect_stdout || redirect_stderr) && !background)
			eerrorx("%s: --stdout and --stderr are only relevant"
			    " with --background", applet);
	}

	/* Expand ~ */
	if (ch_dir && *ch_dir == '~')
		ch_dir = expand_home(home, ch_dir);
	if (ch_root && *ch_root == '~')
		ch_root = expand_home(home, ch_root);
	if (exec) {
		if (*exec == '~')
			exec = expand_home(home, exec);

		/* Validate that the binary exists if we are starting */
		if (*exec == '/' || *exec == '.') {
			/* Full or relative path */
			if (ch_root)
				snprintf(exec_file, sizeof(exec_file),
				    "%s/%s", ch_root, exec);
			else
				snprintf(exec_file, sizeof(exec_file),
				    "%s", exec);
		} else {
			/* Something in $PATH */
			p = tmp = xstrdup(getenv("PATH"));
			*exec_file = '\0';
			while ((token = strsep(&p, ":"))) {
				if (ch_root)
					snprintf(exec_file, sizeof(exec_file),
					    "%s/%s/%s",
					    ch_root, token, exec);
				else
					snprintf(exec_file, sizeof(exec_file),
					    "%s/%s", token, exec);
				if (exists(exec_file))
					break;
				*exec_file = '\0';
			}
			free(tmp);
		}
	}
	if (start && !exists(exec_file)) {
		eerror("%s: %s does not exist", applet,
		    *exec_file ? exec_file : exec);
		exit(EXIT_FAILURE);
	}

	/* If we don't have a pidfile we should check if it's interpreted
	 * or not. If it we, we need to pass the interpreter through
	 * to our daemon calls to find it correctly. */
	if (interpreted && !pidfile) {
		fp = fopen(exec_file, "r");
		if (fp) {
			p = fgets(line, sizeof(line), fp);
			fclose(fp);
			if (p != NULL && line[0] == '#' && line[1] == '!') {
				p = line + 2;
				/* Strip leading spaces */
				while (*p == ' ' || *p == '\t')
					p++;
				/* Remove the trailing newline */
				len = strlen(p) - 1;
				if (p[len] == '\n')
					p[len] = '\0';
				token = strsep(&p, " ");
				strncpy(exec_file, token, sizeof(exec_file));
				opt = 0;
				for (nav = argv; *nav; nav++)
					opt++;
				nav = xmalloc(sizeof(char *) * (opt + 3));
				nav[0] = exec_file;
				len = 1;
				if (p)
					nav[len++] = p;
				for (i = 0; i < opt; i++)
					nav[i + len] = argv[i];
				nav[i + len] = '\0';
			}
		}
	}
	margv = nav ? nav : argv;

	if (stop || sig != -1) {
		if (sig == -1)
			sig = SIGTERM;
		if (!stop)
			oknodo = true;
		if (retry)
			parse_schedule(retry, sig);
		else if (test || oknodo)
			parse_schedule("0", sig);
		else
			parse_schedule(NULL, sig);
		i = run_stop_schedule(exec, (const char *const *)margv,
		    pidfile, uid, test, progress);

		if (i < 0)
			/* We failed to stop something */
			exit(EXIT_FAILURE);
		if (test || oknodo)
			return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE;

		/* Even if we have not actually killed anything, we should
		 * remove information about it as it may have unexpectedly
		 * crashed out. We should also return success as the end
		 * result would be the same. */
		if (pidfile && exists(pidfile))
			unlink(pidfile);
		if (svcname)
			rc_service_daemon_set(svcname, exec,
			    (const char *const *)argv,
			    pidfile, false);
		exit(EXIT_SUCCESS);
	}

	if (pidfile)
		pid = get_pid(pidfile);
	else
		pid = 0;

	if (do_stop(exec, (const char * const *)margv, pid, uid,
		0, test) > 0)
		eerrorx("%s: %s is already running", applet, exec);

	if (test) {
		if (rc_yesno(getenv("EINFO_QUIET")))
			exit (EXIT_SUCCESS);

		einfon("Would start");
		while (argc-- > 0)
			printf(" %s", *argv++);
		printf("\n");
		eindent();
		if (uid != 0)
			einfo("as user id %d", uid);
		if (gid != 0)
			einfo("as group id %d", gid);
		if (ch_root)
			einfo("in root `%s'", ch_root);
		if (ch_dir)
			einfo("in dir `%s'", ch_dir);
		if (nicelevel != 0)
			einfo("with a priority of %d", nicelevel);
		if (name)
			einfo ("with a process name of %s", name);
		eoutdent();
		exit(EXIT_SUCCESS);
	}

	ebeginv("Detaching to start `%s'", exec);
	eindentv();

	/* Remove existing pidfile */
	if (pidfile)
		unlink(pidfile);

	if (background)
		signal_setup(SIGCHLD, handle_signal);

	if ((pid = fork()) == -1)
		eerrorx("%s: fork: %s", applet, strerror(errno));

	/* Child process - lets go! */
	if (pid == 0) {
		pid_t mypid = getpid();
		umask(numask);

#ifdef TIOCNOTTY
		tty_fd = open("/dev/tty", O_RDWR);
#endif

		devnull_fd = open("/dev/null", O_RDWR);

		if (nicelevel) {
			if (setpriority(PRIO_PROCESS, mypid, nicelevel) == -1)
				eerrorx("%s: setpritory %d: %s",
				    applet, nicelevel,
				    strerror(errno));
		}

		if (ionicec != -1 &&
		    ioprio_set(1, mypid, ionicec | ioniced) == -1)
			eerrorx("%s: ioprio_set %d %d: %s", applet,
			    ionicec, ioniced, strerror(errno));

		if (ch_root && chroot(ch_root) < 0)
			eerrorx("%s: chroot `%s': %s",
			    applet, ch_root, strerror(errno));

		if (ch_dir && chdir(ch_dir) < 0)
			eerrorx("%s: chdir `%s': %s",
			    applet, ch_dir, strerror(errno));

		if (makepidfile && pidfile) {
			fp = fopen(pidfile, "w");
			if (! fp)
				eerrorx("%s: fopen `%s': %s", applet, pidfile,
				    strerror(errno));
			fprintf(fp, "%d\n", mypid);
			fclose(fp);
		}

#ifdef HAVE_PAM
		if (changeuser != NULL) {
			pamr = pam_start("start-stop-daemon",
			    changeuser, &conv, &pamh);

			if (pamr == PAM_SUCCESS)
				pamr = pam_acct_mgmt(pamh, PAM_SILENT);
			if (pamr == PAM_SUCCESS)
				pamr = pam_open_session(pamh, PAM_SILENT);
			if (pamr != PAM_SUCCESS)
				eerrorx("%s: pam error: %s",
					applet, pam_strerror(pamh, pamr));
		}
#endif

		if (gid && setgid(gid))
			eerrorx("%s: unable to set groupid to %d",
			    applet, gid);
		if (changeuser && initgroups(changeuser, gid))
			eerrorx("%s: initgroups (%s, %d)",
			    applet, changeuser, gid);
		if (uid && setuid(uid))
			eerrorx ("%s: unable to set userid to %d",
			    applet, uid);

		/* Close any fd's to the passwd database */
		endpwent();

#ifdef TIOCNOTTY
		ioctl(tty_fd, TIOCNOTTY, 0);
		close(tty_fd);
#endif

		/* Clean the environment of any RC_ variables */
		env_list = rc_stringlist_new();
		i = 0;
		while (environ[i])
			rc_stringlist_add(env_list, environ[i++]);

#ifdef HAVE_PAM
		if (changeuser != NULL) {
			pamenv = (const char *const *)pam_getenvlist(pamh);
			if (pamenv) {
				while (*pamenv) {
					/* Don't add strings unless they set a var */
					if (strchr(*pamenv, '='))
						putenv(xstrdup(*pamenv));
					else
						unsetenv(*pamenv);
					pamenv++;
				}
			}
		}
#endif

		TAILQ_FOREACH(env, env_list, entries) {
			if ((strncmp(env->value, "RC_", 3) == 0 &&
				strncmp(env->value, "RC_SERVICE=", 10) != 0 &&
				strncmp(env->value, "RC_SVCNAME=", 10) != 0) ||
			    strncmp(env->value, "SSD_NICELEVEL=", 14) == 0)
			{
				p = strchr(env->value, '=');
				*p = '\0';
				unsetenv(env->value);
				continue;
			}
		}
		rc_stringlist_free(env_list);

		/* For the path, remove the rcscript bin dir from it */
		if ((token = getenv("PATH"))) {
			len = strlen(token);
			newpath = np = xmalloc(len + 1);
			while (token && *token) {
				p = strchr(token, ':');
				if (p) {
					*p++ = '\0';
					while (*p == ':')
						p++;
				}
				if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 &&
				    strcmp(token, RC_LIBEXECDIR "/sbin") != 0)
				{
					len = strlen(token);
					if (np != newpath)
						*np++ = ':';
					memcpy(np, token, len);
					np += len;
				}
				token = p;
			}
			*np = '\0';
			unsetenv("PATH");
			setenv("PATH", newpath, 1);
		}

		stdin_fd = devnull_fd;
		stdout_fd = devnull_fd;
		stderr_fd = devnull_fd;
		if (redirect_stdout) {
			if ((stdout_fd = open(redirect_stdout,
				    O_WRONLY | O_CREAT | O_APPEND,
				    S_IRUSR | S_IWUSR)) == -1)
				eerrorx("%s: unable to open the logfile"
				    " for stdout `%s': %s",
				    applet, redirect_stdout, strerror(errno));
		}
		if (redirect_stderr) {
			if ((stderr_fd = open(redirect_stderr,
				    O_WRONLY | O_CREAT | O_APPEND,
				    S_IRUSR | S_IWUSR)) == -1)
				eerrorx("%s: unable to open the logfile"
				    " for stderr `%s': %s",
				    applet, redirect_stderr, strerror(errno));
		}

		if (background)
			dup2(stdin_fd, STDIN_FILENO);
		if (background || redirect_stdout || rc_yesno(getenv("EINFO_QUIET")))
			dup2(stdout_fd, STDOUT_FILENO);
		if (background || redirect_stderr || rc_yesno(getenv("EINFO_QUIET")))
			dup2(stderr_fd, STDERR_FILENO);

		for (i = getdtablesize() - 1; i >= 3; --i)
			close(i);

		setsid();
		execvp(exec, argv);
#ifdef HAVE_PAM
		if (changeuser != NULL && pamr == PAM_SUCCESS)
			pam_close_session(pamh, PAM_SILENT);
#endif
		eerrorx("%s: failed to exec `%s': %s",
		    applet, exec,strerror(errno));
	}
예제 #4
0
파일: rc-selinux.c 프로젝트: OpenRC/openrc
void selinux_setup(char **argv)
{
    char *new_context = NULL;
    char *curr_context = NULL;
    context_t curr_con;
    char *curr_t = NULL;
    char *run_init_t = NULL;

    /* Return, if selinux is disabled. */
    if (is_selinux_enabled() < 1) {
        return;
    }

    if (read_context_file(RUN_INIT_FILE, &run_init_t) != 0) {
        /* assume a reasonable default, rather than bailing out */
        run_init_t = xstrdup("run_init_t");
        ewarn("Assuming SELinux run_init type is %s", run_init_t);
    }

    /* Get our current context. */
    if (getcon(&curr_context) < 0) {
        if (errno == ENOENT) {
            /* should only hit this if proc is not mounted.  this
             * happens on Gentoo right after init starts, when
             * the init script processing starts.
             */
            goto out;
        } else {
            perror("getcon");
            exit(1);
        }
    }

    /* extract the type from the context */
    curr_con = context_new(curr_context);
    if (!curr_con) {
        free(curr_context);
        goto out;
    }

    curr_t = context_type_get(curr_con);
    if (!curr_t) {
        context_free(curr_con);
        free(curr_context);
        goto out;
    }

    curr_t = xstrdup(curr_t);
    /* dont need them anymore so free() now */
    context_free(curr_con);
    free(curr_context);

    /* if we are not in the run_init domain, we should not do anything */
    if (strncmp(run_init_t, curr_t, strlen(run_init_t)) != 0) {
        goto out;
    }

    free(curr_t);
    free(run_init_t);

    if (check_auth() != 0) {
        eerrorx("Authentication failed.");
    }

    /* Get the context for the script to be run in. */
    if (read_context_file(INITRC_FILE, &new_context) != 0) {
        /* assume a reasonable default, rather than bailing out */
        new_context = xstrdup("system_u:system_r:initrc_t");
        ewarn("Assuming SELinux initrc context is %s", new_context);
    }

    /* Set the new context */
    if (setexeccon(new_context) < 0) {
        eerrorx("Could not set SELinux exec context to %s.", new_context);
    }

    free(new_context);

    /*
     * exec will recycle ptys so try and use open_init_pty if it exists
     * which will open the pty with initrc_devpts_t, if it doesnt exist,
     * fall back to plain exec
     */
    if (!access("/usr/sbin/open_init_pty", X_OK)) {
        if (execvp("/usr/sbin/open_init_pty", argv)) {
            perror("execvp");
            exit(-1);
        }
    } else if (execvp(argv[1], argv + 1)) {
        perror("execvp");
        exit(-1);
    }

out:
    free(run_init_t);
    free(curr_t);
}
예제 #5
0
void
setup_connections(void)
{
    int i;
    struct linger linger;
    struct sockaddr_in s_in;
    u_short port;
    u_short sigport;
    u_short dataport;

    header = (odexm_header *) buf;

    /*
     * setup file descriptors
     */
    for (;;) {
	errno = 0;
	i = dup(0);
	if (i == -1) {
	    efatal("dup failed");
	}
	if (i > 2)
	    break;
    }
    errdesc = i;
    if (dup2(i, 0) < 0)
	efatal("dup2 #0 failed");
    if (dup2(i, 1) < 0)
	efatal("dup2 #1 failed");
    if (dup2(i, 2) < 0)
	efatal("dup2 #2 failed");
    (void) close(i);
    errdesc = 2;

    /*
     * setup main (command) connection
     */
    i = 1;
    if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)) < 0)
	ewarn("setsockopt (SO_KEEPALIVE)");
#ifdef DONT_SO_LINGER
    if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&i, sizeof(i)) < 0 )
#else
    linger.l_onoff = 1;
    linger.l_linger = 60;
    if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger))
                   < 0)
#endif
	ewarn("setsockopt (SO_LINGER)");
    i = sizeof(peername);
    if (getpeername(0, (struct sockaddr *)&peername, &i) < 0)
	efatal("getpeername");
    i = sizeof(sockname);
    if (getsockname(0, (struct sockaddr *)&sockname, &i) < 0)
	efatal("getsockname");
    if (debug)
	diag("connection from %s (%d)",
	     inet_ntoa(peername.sin_addr), ntohs(peername.sin_port));

    /*
     * get flags
     */
    if (read(0, &flags, sizeof(flags)) != sizeof(flags))
	efatal("server read");

    if ( flags == 1 || flags == 3 )
      debug = 1;
    /* if */
    if ( flags > 1 )
      batch = 1;
    /* if */

    /*
     * setup control (signal) connection
     */
    if (read(0, (char *)&sigport, sizeof(sigport)) != sizeof(sigport))
	efatal("server read");
    sigsock = socket(AF_INET, SOCK_STREAM, 0);
    if (sigsock < 0)
	efatal("socket");
    memcpy (&s_in, &sockname, sizeof(s_in));
    s_in.sin_port = 0;
    if (bind(sigsock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("bind");
    i = sizeof(s_in);
    if (getsockname(sigsock, (struct sockaddr *)&s_in, &i) < 0)
	efatal("getsockname");
    port = s_in.sin_port;
    if (write(1, (char *)&port, sizeof(port)) != sizeof(port))
	efatal("write");
    memcpy(&s_in, &peername, sizeof(s_in));
    s_in.sin_port = sigport;
    if (connect(sigsock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("connect");

    /*
     * start control process (actually parent)
     */
    setup_control();
    /*
     * safe now for debugging
     */

    /*
     * setup data transfer connection
     */
    if (debug)
	diag("reading data port");
    if (read(0, (char *)&dataport, sizeof(dataport)) != sizeof(dataport))
	efatal("server read");
    if (debug)
	diag("data port %d", ntohs(dataport));
    datasock = socket(AF_INET, SOCK_STREAM, 0);
    if (datasock < 0)
	efatal("socket");
    memcpy(&s_in, &sockname, sizeof(s_in));
    s_in.sin_port = 0;
    if (bind(datasock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("bind");
    i = sizeof(s_in);
    if (getsockname(datasock, (struct sockaddr *)&s_in, &i) < 0)
	efatal("getsockname");
    port = s_in.sin_port;
    if (debug)
	diag("sending data port %d", ntohs(port));
    if (write(1, (char *)&port, sizeof(port)) != sizeof(port))
	efatal("write");
    memcpy(&s_in, &peername, sizeof(s_in));
    s_in.sin_port = dataport;
    if (connect(datasock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("connect");
    if (debug)
	diag("connected to dataport");
    if ( batch )
      compat_sock = datasock;
    else
      compat_sock = 0;
    /* if */
}
예제 #6
0
int main(int argc,char **argv) {
    int i,srv_sock,j,retval,ptype;
    struct sockaddr_in srv_sa;
    int clientfds[MAX_CLIENTS];
    char *clientsas[MAX_CLIENTS];
    int client_cnt = 0;
    int block_size = 1024;
    int maxfd = 0;
    int c;
    char *srvhost = NULL;
    short srvport = DEF_SRV_PORT;
    int proto = DEF_PROTO;
    int debug = 0;
    char *buf = NULL;
    fd_set rfds;
    fd_set static_rfds;

    /* grab some quick args, hostname, port, tcp, udp... */
    while ((c = getopt(argc,argv,"h:p:tudb:")) != -1) {
	switch(c) {
	case 'h':
	    srvhost = optarg;
	    break;
	case 'p':
	    srvport = atoi(optarg);
	    break;
	case 't':
	    proto = SOCK_STREAM;
	    break;
	case 'u':
	    proto = SOCK_DGRAM;
	    fatal("no udp support yet!");
	    break;
	case 'd':
	    ++debug;
	    break;
	case 'b':
	    block_size = atoi(optarg);
	    break;
	default:
	    break;
	}
    }

    if ((buf = (char *)malloc(sizeof(char)*block_size)) == NULL) {
	efatal("no memory for data buf");
    }
    
    if ((retval = fill_sockaddr(srvhost,srvport,&srv_sa)) != 0) {
	if (retval == -1) {
	    fatal("bad port");
	}
	else {
	    efatal("host lookup failed");
	}
    }

    /* startup server... */
    if ((srv_sock = socket(AF_INET,proto,0)) == -1) {
	efatal("could not get socket");
    }

    if (bind(srv_sock,
	     (struct sockaddr *)&srv_sa,
	     sizeof(struct sockaddr_in)
	     ) < 0) {
	efatal("could not bind");
    }

    if (proto == PROTO_TCP) {
	if (listen(srv_sock,8) < 0) {
	    efatal("could not listen");
	}
    }

    /* daemonize... */
    if (!debug) {
	daemon(0,0);
    }

    for (i = 0; i < MAX_CLIENTS; ++i) {
	clientfds[i] = -1;
	clientsas[i] = (char *)malloc(MAX_NAME_LEN + 1);
    }

    FD_ZERO(&static_rfds);
    FD_SET(srv_sock,&static_rfds);
    maxfd = srv_sock;
    
    /* listen and read forever */
    while (1) {
	/* reset fdsets */
	memcpy(&rfds,&static_rfds,sizeof(static_rfds));

	retval = select(maxfd+1,&rfds,NULL,NULL,NULL);
	
	if (retval > 0) {
	    if (FD_ISSET(srv_sock,&rfds)) {
		struct sockaddr_in client_sin;
		socklen_t slen;
		int client_fd;

		slen = sizeof(client_sin);

		if ((client_fd = accept(srv_sock,
					(struct sockaddr *)&client_sin,
					&slen)) < 0) {
		    warn("accept failed");
		}
		else if (client_cnt >= MAX_CLIENTS) {
		    warn("already at max clients");
		}
		else {
		    /* add new client... */
		    for (i = 0; i < MAX_CLIENTS; ++i) {
			if (clientfds[i] == -1) {
			    break;
			}
		    }
		    
		    clientfds[i] = client_fd;
		    if (client_fd > maxfd) {
			maxfd = client_fd;
		    }
		    
		    FD_SET(client_fd,&static_rfds);
		    
		    if (debug) {
			fprintf(stdout,
				"connect from %s:%d\n",
				inet_ntoa(client_sin.sin_addr),
				ntohs(client_sin.sin_port));
		    }
		    
		    char *addr = inet_ntoa(client_sin.sin_addr);
		    int addrlen = strlen(addr);
		    
		    strncpy(clientsas[i],
			    addr,
			    (addrlen > MAX_NAME_LEN)?MAX_NAME_LEN:addrlen);
		    /* null term if strncpy couldn't */
		    if (addrlen > MAX_NAME_LEN) {
			clientsas[i][MAX_NAME_LEN] = '\0';
		    }
		    
		    ++client_cnt;
		}
	    }
	    else {
		for (i = 0; i < MAX_CLIENTS; ++i) {
		    if (clientfds[i] > -1) {
			if (FD_ISSET(clientfds[i],&rfds)) {
			    /* read a block, or as much as possible */
			    retval = read(clientfds[i],buf,block_size);

			    /* dead client, pretty much */
			    if (retval <= 0) {
				if (debug) {
				    fprintf(stdout,
					    "disconnect from %s\n",
					    clientsas[i]);
				}

				close(clientfds[i]);
				FD_CLR(clientfds[i],&static_rfds);
				clientfds[i] = -1;

				--client_cnt;
			    }
			    else if (debug > 2 ) {
				fprintf(stdout,
					"DEBUG: read %d bytes from %s\n",
					retval,
					clientsas[i]);
			    }
			}
		    }
		}
	    }
	}
	else if (retval < 0) {
	    /* error... */
	    ewarn("error in select");
	}
    }

    return -1;
}
예제 #7
0
static int daemond_pid_openlocked( daemond_pid * pid, int recurse ) {
	int r,err;
	int created;
	int fd;
	int failures;
	int ready = 0;
	char * file = pid->pidfile;
	struct stat sh,sf;
	//debug("locking file %s", file);

	if (recurse > 5) {
		die("Fall into recursion during lock tries");
	}
	
	while(!ready) {
		if (file_exists( file )) {
			//debug("file `%s' exists", file);
			fd = open(file, O_RDWR);
			if (fd == -1) {
				switch(errno) {
					case ENOENT:
						if ( ++failures < 5 ) {
							warn("failed open, try again");
							break;
						} else {
							warn ("failed open in 5 times");
							return -1;
						}
					default:
						ewarn("error too bad");
						ready = 1;
				}
			} else {
				//debug("file opened r/w");
				ready = 1;
			}
		} else {
			warn("file not exists");
			fd = open(file, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IROTH);
			if (fd == -1) {
				switch(errno) {
					case EEXIST:
						if ( ++failures < 5 ) {
							warn("failed create, try again");
							break;
						} else {
							warn ("failed create in 5 times");
							return -1;
						}
					default:
						ewarn("error too bad");
						ready = 1;
				}
			} else {
				debug("file created r/w; fd=%d", fd);
				ready = 1;
				created = 1;
			}
		}
	}
	
	//debug("call flock on %d",fd);
	r = flock(fd, LOCK_EX|LOCK_NB);
	
	if (r == 0) {
		//debug("flock successful");
		if ( fstat(fd, &sh) == -1) {
			die("Can't get stat on locked filehandle: %s", strerror(errno));
		}
		if ( stat( file, &sf ) == -1) {
			switch(errno) {
				case ENOENT:
					break;
				default:
					die("Can't stat on file `%s': %s",file,strerror(errno));
			}
			close(fd);
			return daemond_pid_openlocked(pid, recurse + 1);
		}
		if ( sh.st_dev != sf.st_dev || sh.st_ino != sf.st_ino ) {
			warn("dev/ino on file `%s' mismatch with opened filehandle. reopen", file);
			close(fd);
			return daemond_pid_openlocked(pid, recurse + 1);
		}
		pid->locked = 1;
		pid->owner = getpid();
		pid->fd = fd;
		pid->handle = fdopen(fd,"w+");
		if (!pid->handle)
			die("failed fdopen: %s",ERR);
		
	} else {
		err = errno;
		warn("%d: lock failed: %s", getpid(), strerror(err));
		close(fd);
	}
	return r;
}