static void TimerService(int data) { struct btTimer *tp, *exp, *next; tp = TimerList; if (tp) { tp->rest = 0; /* Multiple timers might expire at once. Create a list of expired timers */ exp = NULL; do { tp->state = TIMER_EXPIRED; next = tp->next; tp->enext = exp; exp = tp; tp = next; } while (tp && tp->rest == 0); TimerList = tp; if (TimerList != NULL) /* Any timers remaining ? */ timer_InitService(1); /* Restart the Timer Service */ else timer_TermService(); /* Stop the Timer Service */ /* Process all expired timers */ while (exp) { ExpiredList = exp->enext; exp->enext = NULL; if (exp->func) (*exp->func)(exp->arg); exp = ExpiredList; } } }
static void StopTimerNoBlock(struct pppTimer *tp) { struct itimerval itimer; struct pppTimer *t, *pt; /* * A RUNNING timer must be removed from TimerList (->next list). * A STOPPED timer isn't in any list, but may have a bogus [e]next field. * An EXPIRED timer is in the ->enext list. */ if (tp->state == TIMER_STOPPED) return; pt = NULL; for (t = TimerList; t != tp && t != NULL; t = t->next) pt = t; if (t) { if (pt) pt->next = t->next; else { TimerList = t->next; if (TimerList == NULL) /* Last one ? */ timer_TermService(); /* Terminate Timer Service */ } if (t->next) { if (!pt && getitimer(ITIMER_REAL, &itimer) == 0) t->next->rest += RESTVAL(itimer); /* t (tp) was the first in the list */ else t->next->rest += t->rest; if (!pt && t->next->rest > 0) /* t->next is now the first in the list */ timer_InitService(1); } } else { /* Search for any pending expired timers */ pt = NULL; for (t = ExpiredList; t != tp && t != NULL; t = t->enext) pt = t; if (t) { if (pt) pt->enext = t->enext; else ExpiredList = t->enext; } else if (tp->state == TIMER_RUNNING) log_Printf(LogERROR, "Oops, %s timer not found!!\n", tp->name); } tp->next = tp->enext = NULL; tp->state = TIMER_STOPPED; }
static void TimerService(void) { struct pppTimer *tp, *exp, *next; if (log_IsKept(LogTIMER)) { static time_t t; /* Only show timers globally every second */ time_t n = time(NULL); if (n > t) timer_Show(LogTIMER, NULL); t = n; } tp = TimerList; if (tp) { tp->rest = 0; /* Multiple timers might expire at once. Create a list of expired timers */ exp = NULL; do { tp->state = TIMER_EXPIRED; next = tp->next; tp->enext = exp; exp = tp; tp = next; } while (tp && tp->rest == 0); TimerList = tp; if (TimerList != NULL) /* Any timers remaining ? */ timer_InitService(1); /* Restart the Timer Service */ else timer_TermService(); /* Stop the Timer Service */ /* Process all expired timers */ while (exp) { ExpiredList = exp->enext; exp->enext = NULL; if (exp->func) (*exp->func)(exp->arg); exp = ExpiredList; } } }
static void chap_StartChild(struct chap *chap, char *prog, const char *name) { char *argv[MAXARGS], *nargv[MAXARGS]; int argc, fd; int in[2], out[2]; pid_t pid; if (chap->child.fd != -1) { log_Printf(LogWARN, "Chap: %s: Program already running\n", prog); return; } if (pipe(in) == -1) { log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); return; } if (pipe(out) == -1) { log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno)); close(in[0]); close(in[1]); return; } pid = getpid(); switch ((chap->child.pid = fork())) { case -1: log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno)); close(in[0]); close(in[1]); close(out[0]); close(out[1]); chap->child.pid = 0; return; case 0: timer_TermService(); if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) { if (argc < 0) { log_Printf(LogWARN, "CHAP: Invalid command syntax\n"); _exit(255); } _exit(0); } close(in[1]); close(out[0]); if (out[1] == STDIN_FILENO) out[1] = dup(out[1]); dup2(in[0], STDIN_FILENO); dup2(out[1], STDOUT_FILENO); close(STDERR_FILENO); if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) { log_Printf(LogALERT, "Chap: Failed to open %s: %s\n", _PATH_DEVNULL, strerror(errno)); exit(1); } for (fd = getdtablesize(); fd > STDERR_FILENO; fd--) fcntl(fd, F_SETFD, 1); #ifndef NOSUID setuid(ID0realuid()); #endif command_Expand(nargv, argc, (char const *const *)argv, chap->auth.physical->dl->bundle, 0, pid); execvp(nargv[0], nargv); printf("exec() of %s failed: %s\n", nargv[0], strerror(errno)); _exit(255); default: close(in[0]); close(out[1]); chap->child.fd = out[0]; chap->child.buf.len = 0; write(in[1], chap->auth.in.name, strlen(chap->auth.in.name)); write(in[1], "\n", 1); write(in[1], chap->challenge.peer + 1, *chap->challenge.peer); write(in[1], "\n", 1); write(in[1], name, strlen(name)); write(in[1], "\n", 1); close(in[1]); break; } }
struct device * exec_Create(struct physical *p) { struct execdevice *dev; dev = NULL; if (p->fd < 0) { if (*p->name.full == '!') { int fids[2], type; if ((dev = malloc(sizeof *dev)) == NULL) { log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n", p->link.name, strerror(errno)); return NULL; } dev->fd_out = -1; p->fd--; /* We own the device but maybe can't use it - change fd */ type = physical_IsSync(p) ? SOCK_DGRAM : SOCK_STREAM; if (socketpair(AF_UNIX, type, PF_UNSPEC, fids) < 0) { log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n", strerror(errno)); free(dev); dev = NULL; } else { static int child_status; /* This variable is abused ! */ int stat, argc, i, ret, wret, pidpipe[2]; pid_t pid, realpid; char *argv[MAXARGS]; stat = fcntl(fids[0], F_GETFL, 0); if (stat > 0) { stat |= O_NONBLOCK; fcntl(fids[0], F_SETFL, stat); } realpid = getpid(); if (pipe(pidpipe) == -1) { log_Printf(LogPHASE, "Unable to pipe for line exec: %s\n", strerror(errno)); close(fids[1]); close(fids[0]); free(dev); dev = NULL; } else switch ((pid = fork())) { case -1: log_Printf(LogPHASE, "Unable to fork for line exec: %s\n", strerror(errno)); close(pidpipe[0]); close(pidpipe[1]); close(fids[1]); close(fids[0]); break; case 0: close(pidpipe[0]); close(fids[0]); timer_TermService(); #ifndef NOSUID setuid(ID0realuid()); #endif child_status = 0; switch ((pid = vfork())) { case 0: close(pidpipe[1]); break; case -1: ret = errno; log_Printf(LogPHASE, "Unable to vfork to drop parent: %s\n", strerror(errno)); close(pidpipe[1]); _exit(ret); default: write(pidpipe[1], &pid, sizeof pid); close(pidpipe[1]); _exit(child_status); /* The error from exec() ! */ } log_Printf(LogDEBUG, "Exec'ing ``%s''\n", p->name.base); if ((argc = MakeArgs(p->name.base, argv, VECSIZE(argv), PARSE_REDUCE|PARSE_NOHASH)) < 0) { log_Printf(LogWARN, "Syntax error in exec command\n"); _exit(ESRCH); } command_Expand(argv, argc, (char const *const *)argv, p->dl->bundle, 0, realpid); dup2(fids[1], STDIN_FILENO); dup2(fids[1], STDOUT_FILENO); dup2(fids[1], STDERR_FILENO); for (i = getdtablesize(); i > STDERR_FILENO; i--) fcntl(i, F_SETFD, 1); execvp(*argv, argv); child_status = errno; /* Only works for vfork() */ printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status)); _exit(child_status); break; default: close(pidpipe[1]); close(fids[1]); if (read(pidpipe[0], &p->session_owner, sizeof p->session_owner) != sizeof p->session_owner) p->session_owner = (pid_t)-1; close(pidpipe[0]); while ((wret = waitpid(pid, &stat, 0)) == -1 && errno == EINTR) ; if (wret == -1) { log_Printf(LogWARN, "Waiting for child process: %s\n", strerror(errno)); close(fids[0]); p->session_owner = (pid_t)-1; break; } else if (WIFSIGNALED(stat)) { log_Printf(LogWARN, "Child process received sig %d !\n", WTERMSIG(stat)); close(fids[0]); p->session_owner = (pid_t)-1; break; } else if (WIFSTOPPED(stat)) { log_Printf(LogWARN, "Child process received stop sig %d !\n", WSTOPSIG(stat)); /* I guess that's ok.... */ } else if ((ret = WEXITSTATUS(stat))) { log_Printf(LogWARN, "Cannot exec \"%s\": %s\n", p->name.base, strerror(ret)); close(fids[0]); p->session_owner = (pid_t)-1; break; } p->fd = fids[0]; log_Printf(LogDEBUG, "Using descriptor %d for child\n", p->fd); } } } } else { struct stat st; if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFIFO)) { if ((dev = malloc(sizeof *dev)) == NULL) log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n", p->link.name, strerror(errno)); else if (p->fd == STDIN_FILENO) { log_Printf(LogPHASE, "%s: Using stdin/stdout to communicate with " "parent (pipe mode)\n", p->link.name); dev->fd_out = dup(STDOUT_FILENO); /* Hook things up so that we monitor dev->fd_out */ p->desc.UpdateSet = exec_UpdateSet; p->desc.IsSet = exec_IsSet; } else dev->fd_out = -1; } } if (dev) { memcpy(&dev->dev, &baseexecdevice, sizeof dev->dev); physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE); if (p->cfg.cd.necessity != CD_DEFAULT) log_Printf(LogWARN, "Carrier settings ignored\n"); return &dev->dev; } return NULL; }