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; }
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; }
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)); }
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); }
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 */ }
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; }
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; }