📄 main.c
字号:
} else { while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) continue; fatal("error waiting for (dis)connection process: %m"); } --conn_running; } return (status == 0 ? 0 : -1);}/* * run-program - execute a program with given arguments, * but don't wait for it. * If the program can't be executed, logs an error unless * must_exist is 0 and the program file doesn't exist. * Returns -1 if it couldn't fork, 0 if the file doesn't exist * or isn't an executable plain file, or the process ID of the child. * If done != NULL, (*done)(arg) will be called later (within * reap_kids) iff the return value is > 0. */pid_trun_program(prog, args, must_exist, done, arg) char *prog; char **args; int must_exist; void (*done) __P((void *)); void *arg;{ int pid; struct stat sbuf; /* * First check if the file exists and is executable. * We don't use access() because that would use the * real user-id, which might not be root, and the script * might be accessible only to root. */ errno = EINVAL; if (stat(prog, &sbuf) < 0 || !S_ISREG(sbuf.st_mode) || (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) { if (must_exist || errno != ENOENT) warn("Can't execute %s: %m", prog); return 0; } pid = fork(); if (pid == -1) { error("Failed to create child process for %s: %m", prog); return -1; } if (pid == 0) { int new_fd; /* Leave the current location */ (void) setsid(); /* No controlling tty. */ (void) umask (S_IRWXG|S_IRWXO); (void) chdir ("/"); /* no current directory. */ setuid(0); /* set real UID = root */ setgid(getegid()); /* Ensure that nothing of our device environment is inherited. */ sys_close(); closelog(); close (0); close (1); close (2); close (ttyfd); /* tty interface to the ppp device */ if (real_ttyfd >= 0) close(real_ttyfd); /* Don't pass handles to the PPP device, even by accident. */ new_fd = open (_PATH_DEVNULL, O_RDWR); if (new_fd >= 0) { if (new_fd != 0) { dup2 (new_fd, 0); /* stdin <- /dev/null */ close (new_fd); } dup2 (0, 1); /* stdout -> /dev/null */ dup2 (0, 2); /* stderr -> /dev/null */ }#ifdef BSD /* Force the priority back to zero if pppd is running higher. */ if (setpriority (PRIO_PROCESS, 0, 0) < 0) warn("can't reset priority to 0: %m"); #endif /* SysV recommends a second fork at this point. */ /* run the program */ execve(prog, args, script_env); if (must_exist || errno != ENOENT) { /* have to reopen the log, there's nowhere else for the message to go. */ reopen_log(); syslog(LOG_ERR, "Can't execute %s: %m", prog); closelog(); } _exit(-1); } if (debug) dbglog("Script %s started (pid %d)", prog, pid); record_child(pid, prog, done, arg); return pid;}/* * record_child - add a child process to the list for reap_kids * to use. */static voidrecord_child(pid, prog, done, arg) int pid; char *prog; void (*done) __P((void *)); void *arg;{ struct subprocess *chp; ++n_children; chp = (struct subprocess *) malloc(sizeof(struct subprocess)); if (chp == NULL) { warn("losing track of %s process", prog); } else { chp->pid = pid; chp->prog = prog; chp->done = done; chp->arg = arg; chp->next = children; children = chp; }}/* * reap_kids - get status from any dead child processes, * and log a message for abnormal terminations. */static intreap_kids(waitfor) int waitfor;{ int pid, status; struct subprocess *chp, **prevp; got_sigchld = 0; if (n_children == 0) return 0; while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1 && pid != 0) { --n_children; for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) { if (chp->pid == pid) { *prevp = chp->next; break; } } if (WIFSIGNALED(status)) { warn("Child process %s (pid %d) terminated with signal %d", (chp? chp->prog: "??"), pid, WTERMSIG(status)); } else if (debug) dbglog("Script %s finished (pid %d), status = 0x%x", (chp? chp->prog: "??"), pid, status); if (chp && chp->done) (*chp->done)(chp->arg); if (chp) free(chp); } if (pid == -1) { if (errno == ECHILD) return -1; if (errno != EINTR) error("Error waiting for child process: %m"); } return 0;}/* * novm - log an error message saying we ran out of memory, and die. */voidnovm(msg) char *msg;{ fatal("Virtual memory exhausted allocating %s\n", msg);}/* * script_setenv - set an environment variable value to be used * for scripts that we run (e.g. ip-up, auth-up, etc.) */voidscript_setenv(var, value) char *var, *value;{ size_t vl = strlen(var) + strlen(value) + 2; int i; char *p, *newstring; newstring = (char *) malloc(vl); if (newstring == 0) return; slprintf(newstring, vl, "%s=%s", var, value); /* check if this variable is already set */ if (script_env != 0) { for (i = 0; (p = script_env[i]) != 0; ++i) { if (strncmp(p, var, vl) == 0 && p[vl] == '=') { free(p); script_env[i] = newstring; return; } } } else { /* no space allocated for script env. ptrs. yet */ i = 0; script_env = (char **) malloc(16 * sizeof(char *)); if (script_env == 0) return; s_env_nalloc = 16; } /* reallocate script_env with more space if needed */ if (i + 1 >= s_env_nalloc) { int new_n = i + 17; char **newenv = (char **) realloc((void *)script_env, new_n * sizeof(char *)); if (newenv == 0) return; script_env = newenv; s_env_nalloc = new_n; } script_env[i] = newstring; script_env[i+1] = 0;}/* * script_unsetenv - remove a variable from the environment * for scripts. */voidscript_unsetenv(var) char *var;{ int vl = strlen(var); int i; char *p; if (script_env == 0) return; for (i = 0; (p = script_env[i]) != 0; ++i) { if (strncmp(p, var, vl) == 0 && p[vl] == '=') { free(p); while ((script_env[i] = script_env[i+1]) != 0) ++i; break; } }}/* * start_charshunt - create a child process to run the character shunt. */static intstart_charshunt(ifd, ofd) int ifd, ofd;{ int cpid; cpid = fork(); if (cpid == -1) { error("Can't fork process for character shunt: %m"); return 0; } if (cpid == 0) { /* child */ close(pty_slave); setuid(uid); if (getuid() != uid) fatal("setuid failed"); setgid(getgid()); if (!nodetach) log_to_fd = -1; charshunt(ifd, ofd, record_file); exit(0); } charshunt_pid = cpid; close(pty_master); pty_master = -1; ttyfd = pty_slave; record_child(cpid, "pppd (charshunt)", charshunt_done, NULL); return 1;}static voidcharshunt_done(arg) void *arg;{ charshunt_pid = 0;}/* * charshunt - the character shunt, which passes characters between * the pty master side and the serial port (or stdin/stdout). * This runs as the user (not as root). * (We assume ofd >= ifd which is true the way this gets called. :-). */static voidcharshunt(ifd, ofd, record_file) int ifd, ofd; char *record_file;{ int n, nfds; fd_set ready, writey; u_char *ibufp, *obufp; int nibuf, nobuf; int flags; int pty_readable, stdin_readable; struct timeval lasttime; FILE *recordf = NULL; /* * Reset signal handlers. */ signal(SIGHUP, SIG_IGN); /* Hangup */ signal(SIGINT, SIG_DFL); /* Interrupt */ signal(SIGTERM, SIG_DFL); /* Terminate */ signal(SIGCHLD, SIG_DFL); signal(SIGUSR1, SIG_DFL); signal(SIGUSR2, SIG_DFL); signal(SIGABRT, SIG_DFL); signal(SIGALRM, SIG_DFL); signal(SIGFPE, SIG_DFL); signal(SIGILL, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGSEGV, SIG_DFL);#ifdef SIGBUS signal(SIGBUS, SIG_DFL);#endif#ifdef SIGEMT signal(SIGEMT, SIG_DFL);#endif#ifdef SIGPOLL signal(SIGPOLL, SIG_DFL);#endif#ifdef SIGPROF signal(SIGPROF, SIG_DFL);#endif#ifdef SIGSYS signal(SIGSYS, SIG_DFL);#endif#ifdef SIGTRAP signal(SIGTRAP, SIG_DFL);#endif#ifdef SIGVTALRM signal(SIGVTALRM, SIG_DFL);#endif#ifdef SIGXCPU signal(SIGXCPU, SIG_DFL);#endif#ifdef SIGXFSZ signal(SIGXFSZ, SIG_DFL);#endif /* * Open the record file if required. */ if (record_file != NULL) { recordf = fopen(record_file, "a"); if (recordf == NULL) error("Couldn't create record file %s: %m", record_file); } /* set all the fds to non-blocking mode */ flags = fcntl(pty_master, F_GETFL); if (flags == -1 || fcntl(pty_master, F_SETFL, flags | O_NONBLOCK) == -1) warn("couldn't set pty master to nonblock: %m"); flags = fcntl(ifd, F_GETFL); if (flags == -1 || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1) warn("couldn't set %s to nonblock: %m", (ifd==0? "stdin": "tty")); if (ofd != ifd) { flags = fcntl(ofd, F_GETFL); if (flags == -1 || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1) warn("couldn't set stdout to nonblock: %m"); } nibuf = nobuf = 0; ibufp = obufp = NULL; pty_readable = stdin_readable = 1; nfds = (ofd > pty_master? ofd: pty_master) + 1; if (recordf != NULL) { gettimeofday(&lasttime, NULL); putc(7, recordf); /* put start marker */ putc(lasttime.tv_sec >> 24, recordf); putc(lasttime.tv_sec >> 16, recordf); putc(lasttime.tv_sec >> 8, recordf); putc(lasttime.tv_sec, recordf); lasttime.tv_usec = 0; } while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) { FD_ZERO(&ready); FD_ZERO(&writey); if (nibuf != 0) FD_SET(pty_master, &writey); else if (stdin_readable) FD_SET(ifd, &ready); if (nobuf != 0) FD_SET(ofd, &writey); else if (pty_readable) FD_SET(pty_master, &ready); if (select(nfds, &ready, &writey, NULL, NULL) < 0) { if (errno != EINTR) fatal("select"); continue; } if (FD_ISSET(ifd, &ready)) { ibufp = inpacket_buf; nibuf = read(ifd, ibufp, sizeof(inpacket_buf)); if (nibuf < 0 && errno == EIO) nibuf = 0; if (nibuf < 0) { if (!(errno == EINTR || errno == EAGAIN)) { error("Error reading standard input: %m"); break; } nibuf = 0; } else if (nibuf == 0) { /* end of file from stdin */ stdin_readable = 0; /* do a 0-length write, hopefully this will generate an EOF (hangup) on the slave side. */ write(pty_master, inpacket_buf, 0); if (recordf) if (!record_write(recordf, 4, NULL, 0, &lasttime)) recordf = NULL; } else { FD_SET(pty_master, &writey); if (recordf) if (!record_write(recordf, 2, ibufp, nibuf, &lasttime)) recordf = NULL; } } if (FD_ISSET(pty_master, &ready)) { obufp = outpacket_buf; nobuf = read(pty_master, obufp, sizeof(outpacket_buf)); if (nobuf < 0 && errno == EIO) nobuf = 0; if (nobuf < 0) { if (!(errno == EINTR || errno == EAGAIN)) { error("Error reading pseudo-tty master: %m"); break; } nobuf = 0; } else if (nobuf == 0) { /* end of file from the pty - slave side has closed */ pty_readable = 0; stdin_readable = 0; /* pty is not writable now */ nibuf = 0; close(ofd); if (recordf) if (!record_write(recordf, 3, NULL, 0, &lasttime)) recordf = NULL; } else { FD_SET(ofd, &writey); if (recordf) if (!record_write(recordf, 1, obufp, nobuf, &lasttime)) recordf = NULL; } } if (FD_ISSET(ofd, &writey)) { n = write(ofd, obufp, nobuf); if (n < 0) { if (errno != EIO) { error("Error writing standard output: %m"); break; } pty_readable = 0; nobuf = 0; } else { obufp += n; nobuf -= n; } } if (FD_ISSET(pty_master, &writey)) { n = write(pty_master, ibufp, nibuf); if (n < 0) { if (errno != EIO) { error("Error writing pseudo-tty master: %m"); break; } stdin_readable = 0; nibuf = 0; } else { ibufp += n; nibuf -= n; } } } exit(0);}static intrecord_write(f, code, buf, nb, tp) FILE *f; int code; u_char *buf; int nb; struct timeval *tp;{ struct timeval now; int diff; gettimeofday(&now, NULL); now.tv_usec /= 100000; /* actually 1/10 s, not usec now */ diff = (now.tv_sec - tp->tv_sec) * 10 + (now.tv_usec - tp->tv_usec); if (diff > 0) { if (diff > 255) { putc(5, f); putc(diff >> 24, f); putc(diff >> 16, f); putc(diff >> 8, f); putc(diff, f); } else { putc(6, f); putc(diff, f); } *tp = now; } putc(code, f); if (buf != NULL) { putc(nb >> 8, f); putc(nb, f); fwrite(buf, nb, 1, f); } fflush(f); if (ferror(f)) { error("Error writing record file: %m"); return 0; } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -