40 41#ifndef NOALIAS 42#ifdef __FreeBSD__ 43#include <alias.h> 44#else 45#include "alias.h" 46#endif 47#endif 48#include "layer.h" 49#include "probe.h" 50#include "mbuf.h" 51#include "log.h" 52#include "defs.h" 53#include "id.h" 54#include "timer.h" 55#include "fsm.h" 56#include "lqr.h" 57#include "hdlc.h" 58#include "lcp.h" 59#include "ccp.h" 60#include "iplist.h" 61#include "throughput.h" 62#include "slcompress.h" 63#include "ipcp.h" 64#include "filter.h" 65#include "descriptor.h" 66#include "link.h" 67#include "mp.h" 68#ifndef NORADIUS 69#include "radius.h" 70#endif 71#include "bundle.h" 72#include "auth.h" 73#include "systems.h" 74#include "sig.h" 75#include "main.h" 76#include "server.h" 77#include "prompt.h" 78#include "chat.h" 79#include "chap.h" 80#include "cbcp.h" 81#include "datalink.h" 82#include "iface.h" 83 84#ifndef O_NONBLOCK 85#ifdef O_NDELAY 86#define O_NONBLOCK O_NDELAY 87#endif 88#endif 89 90static void DoLoop(struct bundle *); 91static void TerminalStop(int); 92static const char *ex_desc(int); 93 94static struct bundle *SignalBundle; 95static struct prompt *SignalPrompt; 96 97void 98Cleanup(int excode) 99{ 100 SignalBundle->CleaningUp = 1; 101 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 102} 103 104void 105AbortProgram(int excode) 106{ 107 server_Close(SignalBundle); 108 log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 109 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 110 bundle_Destroy(SignalBundle); 111 log_Close(); 112 exit(excode); 113} 114 115static void 116CloseConnection(int signo) 117{ 118 /* NOTE, these are manual, we've done a setsid() */ 119 sig_signal(SIGINT, SIG_IGN); 120 log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 121 bundle_Down(SignalBundle, CLOSE_STAYDOWN); 122 sig_signal(SIGINT, CloseConnection); 123} 124 125static void 126CloseSession(int signo) 127{ 128 log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 129 Cleanup(EX_TERM); 130} 131 132static pid_t BGPid = 0; 133 134static void 135KillChild(int signo) 136{ 137 signal(signo, SIG_IGN); 138 log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 139 kill(BGPid, SIGINT); 140} 141 142static void 143TerminalCont(int signo) 144{ 145 signal(SIGCONT, SIG_DFL); 146 prompt_Continue(SignalPrompt); 147} 148 149static void 150TerminalStop(int signo) 151{ 152 prompt_Suspend(SignalPrompt); 153 signal(SIGCONT, TerminalCont); 154 raise(SIGSTOP); 155} 156 157static void 158BringDownServer(int signo) 159{ 160 /* Drops all child prompts too ! */ 161 server_Close(SignalBundle); 162} 163 164static const char * 165ex_desc(int ex) 166{ 167 static char num[12]; /* Used immediately if returned */ 168 static const char *desc[] = { 169 "normal", "start", "sock", "modem", "dial", "dead", "done", 170 "reboot", "errdead", "hangup", "term", "nodial", "nologin" 171 }; 172 173 if (ex >= 0 && ex < sizeof desc / sizeof *desc) 174 return desc[ex]; 175 snprintf(num, sizeof num, "%d", ex); 176 return num; 177} 178 179static void 180Usage(void) 181{ 182 fprintf(stderr, 183 "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" 184#ifndef NOALIAS 185 " [ -alias ]" 186#endif 187 " [system ...]\n"); 188 exit(EX_START); 189} 190 191static int 192ProcessArgs(int argc, char **argv, int *mode, int *alias) 193{ 194 int optc, newmode, arg; 195 char *cp; 196 197 optc = 0; 198 *mode = PHYS_INTERACTIVE; 199 *alias = 0; 200 for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 201 cp = argv[arg] + 1; 202 newmode = Nam2mode(cp); 203 switch (newmode) { 204 case PHYS_NONE: 205 if (strcmp(cp, "alias") == 0) { 206#ifdef NOALIAS 207 log_Printf(LogWARN, "Cannot load alias library (compiled out)\n"); 208#else 209 *alias = 1; 210#endif 211 optc--; /* this option isn't exclusive */ 212 } else 213 Usage(); 214 break; 215 216 case PHYS_ALL: 217 Usage(); 218 break; 219 220 default: 221 *mode = newmode; 222 } 223 } 224 225 if (optc > 1) { 226 fprintf(stderr, "You may specify only one mode.\n"); 227 exit(EX_START); 228 } 229 230 if (*mode == PHYS_AUTO && arg == argc) { 231 fprintf(stderr, "A system must be specified in auto mode.\n"); 232 exit(EX_START); 233 } 234 235 return arg; /* Don't SetLabel yet ! */ 236} 237 238static void 239CheckLabel(const char *label, struct prompt *prompt, int mode) 240{ 241 const char *err; 242 243 if ((err = system_IsValid(label, prompt, mode)) != NULL) { 244 fprintf(stderr, "%s: %s\n", label, err); 245 if (mode == PHYS_DIRECT) 246 log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 247 label, err); 248 log_Close(); 249 exit(1); 250 } 251} 252 253 254int 255main(int argc, char **argv) 256{ 257 char *name; 258 const char *lastlabel; 259 int nfds, mode, alias, label, arg; 260 struct bundle *bundle; 261 struct prompt *prompt; 262 263 nfds = getdtablesize(); 264 if (nfds >= FD_SETSIZE) 265 /* 266 * If we've got loads of file descriptors, make sure they're all 267 * closed. If they aren't, we may end up with a seg fault when our 268 * `fd_set's get too big when select()ing ! 269 */ 270 while (--nfds > 2) 271 close(nfds); 272 273 name = strrchr(argv[0], '/'); 274 log_Open(name ? name + 1 : argv[0]); 275 276#ifndef NOALIAS 277 PacketAliasInit(); 278#endif 279 label = ProcessArgs(argc, argv, &mode, &alias); 280 281 /* 282 * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 283 * output occasionally.... I must find the real reason some time. To 284 * display the dodgy behaviour, comment out this bit, make yourself a large 285 * routing table and then run ppp in interactive mode. The `show route' 286 * command will drop chunks of data !!! 287 */ 288 if (mode == PHYS_INTERACTIVE) { 289 close(STDIN_FILENO); 290 if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 291 fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 292 return 2; 293 } 294 } 295 296 /* Allow output for the moment (except in direct mode) */ 297 if (mode == PHYS_DIRECT) 298 prompt = NULL; 299 else 300 SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 301 302 ID0init(); 303 if (ID0realuid() != 0) { 304 char conf[200], *ptr; 305 306 snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 307 do {
| 41 42#ifndef NOALIAS 43#ifdef __FreeBSD__ 44#include <alias.h> 45#else 46#include "alias.h" 47#endif 48#endif 49#include "layer.h" 50#include "probe.h" 51#include "mbuf.h" 52#include "log.h" 53#include "defs.h" 54#include "id.h" 55#include "timer.h" 56#include "fsm.h" 57#include "lqr.h" 58#include "hdlc.h" 59#include "lcp.h" 60#include "ccp.h" 61#include "iplist.h" 62#include "throughput.h" 63#include "slcompress.h" 64#include "ipcp.h" 65#include "filter.h" 66#include "descriptor.h" 67#include "link.h" 68#include "mp.h" 69#ifndef NORADIUS 70#include "radius.h" 71#endif 72#include "bundle.h" 73#include "auth.h" 74#include "systems.h" 75#include "sig.h" 76#include "main.h" 77#include "server.h" 78#include "prompt.h" 79#include "chat.h" 80#include "chap.h" 81#include "cbcp.h" 82#include "datalink.h" 83#include "iface.h" 84 85#ifndef O_NONBLOCK 86#ifdef O_NDELAY 87#define O_NONBLOCK O_NDELAY 88#endif 89#endif 90 91static void DoLoop(struct bundle *); 92static void TerminalStop(int); 93static const char *ex_desc(int); 94 95static struct bundle *SignalBundle; 96static struct prompt *SignalPrompt; 97 98void 99Cleanup(int excode) 100{ 101 SignalBundle->CleaningUp = 1; 102 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 103} 104 105void 106AbortProgram(int excode) 107{ 108 server_Close(SignalBundle); 109 log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 110 bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 111 bundle_Destroy(SignalBundle); 112 log_Close(); 113 exit(excode); 114} 115 116static void 117CloseConnection(int signo) 118{ 119 /* NOTE, these are manual, we've done a setsid() */ 120 sig_signal(SIGINT, SIG_IGN); 121 log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 122 bundle_Down(SignalBundle, CLOSE_STAYDOWN); 123 sig_signal(SIGINT, CloseConnection); 124} 125 126static void 127CloseSession(int signo) 128{ 129 log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 130 Cleanup(EX_TERM); 131} 132 133static pid_t BGPid = 0; 134 135static void 136KillChild(int signo) 137{ 138 signal(signo, SIG_IGN); 139 log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 140 kill(BGPid, SIGINT); 141} 142 143static void 144TerminalCont(int signo) 145{ 146 signal(SIGCONT, SIG_DFL); 147 prompt_Continue(SignalPrompt); 148} 149 150static void 151TerminalStop(int signo) 152{ 153 prompt_Suspend(SignalPrompt); 154 signal(SIGCONT, TerminalCont); 155 raise(SIGSTOP); 156} 157 158static void 159BringDownServer(int signo) 160{ 161 /* Drops all child prompts too ! */ 162 server_Close(SignalBundle); 163} 164 165static const char * 166ex_desc(int ex) 167{ 168 static char num[12]; /* Used immediately if returned */ 169 static const char *desc[] = { 170 "normal", "start", "sock", "modem", "dial", "dead", "done", 171 "reboot", "errdead", "hangup", "term", "nodial", "nologin" 172 }; 173 174 if (ex >= 0 && ex < sizeof desc / sizeof *desc) 175 return desc[ex]; 176 snprintf(num, sizeof num, "%d", ex); 177 return num; 178} 179 180static void 181Usage(void) 182{ 183 fprintf(stderr, 184 "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" 185#ifndef NOALIAS 186 " [ -alias ]" 187#endif 188 " [system ...]\n"); 189 exit(EX_START); 190} 191 192static int 193ProcessArgs(int argc, char **argv, int *mode, int *alias) 194{ 195 int optc, newmode, arg; 196 char *cp; 197 198 optc = 0; 199 *mode = PHYS_INTERACTIVE; 200 *alias = 0; 201 for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 202 cp = argv[arg] + 1; 203 newmode = Nam2mode(cp); 204 switch (newmode) { 205 case PHYS_NONE: 206 if (strcmp(cp, "alias") == 0) { 207#ifdef NOALIAS 208 log_Printf(LogWARN, "Cannot load alias library (compiled out)\n"); 209#else 210 *alias = 1; 211#endif 212 optc--; /* this option isn't exclusive */ 213 } else 214 Usage(); 215 break; 216 217 case PHYS_ALL: 218 Usage(); 219 break; 220 221 default: 222 *mode = newmode; 223 } 224 } 225 226 if (optc > 1) { 227 fprintf(stderr, "You may specify only one mode.\n"); 228 exit(EX_START); 229 } 230 231 if (*mode == PHYS_AUTO && arg == argc) { 232 fprintf(stderr, "A system must be specified in auto mode.\n"); 233 exit(EX_START); 234 } 235 236 return arg; /* Don't SetLabel yet ! */ 237} 238 239static void 240CheckLabel(const char *label, struct prompt *prompt, int mode) 241{ 242 const char *err; 243 244 if ((err = system_IsValid(label, prompt, mode)) != NULL) { 245 fprintf(stderr, "%s: %s\n", label, err); 246 if (mode == PHYS_DIRECT) 247 log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 248 label, err); 249 log_Close(); 250 exit(1); 251 } 252} 253 254 255int 256main(int argc, char **argv) 257{ 258 char *name; 259 const char *lastlabel; 260 int nfds, mode, alias, label, arg; 261 struct bundle *bundle; 262 struct prompt *prompt; 263 264 nfds = getdtablesize(); 265 if (nfds >= FD_SETSIZE) 266 /* 267 * If we've got loads of file descriptors, make sure they're all 268 * closed. If they aren't, we may end up with a seg fault when our 269 * `fd_set's get too big when select()ing ! 270 */ 271 while (--nfds > 2) 272 close(nfds); 273 274 name = strrchr(argv[0], '/'); 275 log_Open(name ? name + 1 : argv[0]); 276 277#ifndef NOALIAS 278 PacketAliasInit(); 279#endif 280 label = ProcessArgs(argc, argv, &mode, &alias); 281 282 /* 283 * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 284 * output occasionally.... I must find the real reason some time. To 285 * display the dodgy behaviour, comment out this bit, make yourself a large 286 * routing table and then run ppp in interactive mode. The `show route' 287 * command will drop chunks of data !!! 288 */ 289 if (mode == PHYS_INTERACTIVE) { 290 close(STDIN_FILENO); 291 if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 292 fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 293 return 2; 294 } 295 } 296 297 /* Allow output for the moment (except in direct mode) */ 298 if (mode == PHYS_DIRECT) 299 prompt = NULL; 300 else 301 SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 302 303 ID0init(); 304 if (ID0realuid() != 0) { 305 char conf[200], *ptr; 306 307 snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 308 do {
|
309 log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 310 conf); 311 return -1; 312 } 313 ptr = conf + strlen(conf)-2; 314 while (ptr > conf && *ptr != '/') 315 *ptr-- = '\0'; 316 } while (ptr >= conf); 317 } 318 319 if (label < argc) 320 for (arg = label; arg < argc; arg++) 321 CheckLabel(argv[arg], prompt, mode); 322 else 323 CheckLabel("default", prompt, mode); 324 325 prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(mode)); 326 327 if ((bundle = bundle_Create(TUN_PREFIX, mode, (const char **)argv)) == NULL) { 328 log_Printf(LogWARN, "bundle_Create: %s\n", strerror(errno)); 329 return EX_START; 330 } 331 332 /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 333 334 if (prompt) { 335 prompt->bundle = bundle; /* couldn't do it earlier */ 336 prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 337 } 338 SignalBundle = bundle; 339 bundle->AliasEnabled = alias; 340 if (alias) 341 bundle->cfg.opt |= OPT_IFACEALIAS; 342 343 if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 344 prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 345 346 sig_signal(SIGHUP, CloseSession); 347 sig_signal(SIGTERM, CloseSession); 348 sig_signal(SIGINT, CloseConnection); 349 sig_signal(SIGQUIT, CloseSession); 350 sig_signal(SIGALRM, SIG_IGN); 351 signal(SIGPIPE, SIG_IGN); 352 353 if (mode == PHYS_INTERACTIVE) 354 sig_signal(SIGTSTP, TerminalStop); 355 356 sig_signal(SIGUSR2, BringDownServer); 357 358 lastlabel = argc == 2 ? bundle->argv1 : argv[argc - 1]; 359 for (arg = label; arg < argc; arg++) { 360 /* In case we use LABEL or ``set enddisc label'' */ 361 bundle_SetLabel(bundle, lastlabel); 362 system_Select(bundle, arg == 1 ? bundle->argv1 : argv[arg], 363 CONFFILE, prompt, NULL); 364 } 365 366 if (label < argc) 367 /* In case the last label did a ``load'' */ 368 bundle_SetLabel(bundle, lastlabel); 369 370 if (mode == PHYS_AUTO && 371 bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 372 prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 373 "in auto mode.\n"); 374 AbortProgram(EX_START); 375 } 376 377 if (mode != PHYS_INTERACTIVE) { 378 if (mode != PHYS_DIRECT) { 379 int bgpipe[2]; 380 pid_t bgpid; 381 382 if (mode == PHYS_BACKGROUND && pipe(bgpipe)) { 383 log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 384 AbortProgram(EX_SOCK); 385 } 386 387 bgpid = fork(); 388 if (bgpid == -1) { 389 log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 390 AbortProgram(EX_SOCK); 391 } 392 393 if (bgpid) { 394 char c = EX_NORMAL; 395 396 if (mode == PHYS_BACKGROUND) { 397 close(bgpipe[1]); 398 BGPid = bgpid; 399 /* If we get a signal, kill the child */ 400 signal(SIGHUP, KillChild); 401 signal(SIGTERM, KillChild); 402 signal(SIGINT, KillChild); 403 signal(SIGQUIT, KillChild); 404 405 /* Wait for our child to close its pipe before we exit */ 406 if (read(bgpipe[0], &c, 1) != 1) { 407 prompt_Printf(prompt, "Child exit, no status.\n"); 408 log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 409 } else if (c == EX_NORMAL) { 410 prompt_Printf(prompt, "PPP enabled.\n"); 411 log_Printf(LogPHASE, "Parent: PPP enabled.\n"); 412 } else { 413 prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); 414 log_Printf(LogPHASE, "Parent: Child failed (%s).\n", 415 ex_desc((int) c)); 416 } 417 close(bgpipe[0]); 418 } 419 return c; 420 } else if (mode == PHYS_BACKGROUND) { 421 close(bgpipe[0]); 422 bundle->notify.fd = bgpipe[1]; 423 } 424 425 bundle_LockTun(bundle); /* we have a new pid */ 426 427 /* -auto, -dedicated, -ddial & -background */ 428 prompt_Destroy(prompt, 0); 429 close(STDOUT_FILENO); 430 close(STDERR_FILENO); 431 close(STDIN_FILENO); 432 setsid(); 433 } else { 434 /* -direct: STDIN_FILENO gets used by modem_Open */ 435 prompt_TtyInit(NULL); 436 close(STDOUT_FILENO); 437 close(STDERR_FILENO); 438 } 439 } else { 440 /* Interactive mode */ 441 close(STDERR_FILENO); 442 prompt_TtyInit(prompt); 443 prompt_TtyCommandMode(prompt); 444 prompt_Required(prompt); 445 } 446 447 log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(mode)); 448 DoLoop(bundle); 449 AbortProgram(EX_NORMAL); 450 451 return EX_NORMAL; 452} 453 454static void 455DoLoop(struct bundle *bundle) 456{ 457 fd_set rfds, wfds, efds; 458 int i, nfds, nothing_done; 459 struct probe probe; 460 461 probe_Init(&probe); 462 463 do { 464 nfds = 0; 465 FD_ZERO(&rfds); 466 FD_ZERO(&wfds); 467 FD_ZERO(&efds); 468 469 /* All our datalinks, the tun device and the MP socket */ 470 descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 471 472 /* All our prompts and the diagnostic socket */ 473 descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); 474 475 if (bundle_IsDead(bundle)) 476 /* Don't select - we'll be here forever */ 477 break; 478 479 /* 480 * It's possible that we've had a signal since we last checked. If 481 * we don't check again before calling select(), we may end up stuck 482 * after having missed the event.... sig_Handle() tries to be as 483 * quick as possible if nothing is likely to have happened. 484 * This is only really likely if we block in open(... O_NONBLOCK) 485 * which will happen with a misconfigured device. 486 */ 487 if (sig_Handle()) 488 continue; 489 490 i = select(nfds, &rfds, &wfds, &efds, NULL); 491 492 if (i < 0 && errno != EINTR) { 493 log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 494 if (log_IsKept(LogTIMER)) { 495 struct timeval t; 496 497 for (i = 0; i <= nfds; i++) { 498 if (FD_ISSET(i, &rfds)) { 499 log_Printf(LogTIMER, "Read set contains %d\n", i); 500 FD_CLR(i, &rfds); 501 t.tv_sec = t.tv_usec = 0; 502 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 503 log_Printf(LogTIMER, "The culprit !\n"); 504 break; 505 } 506 } 507 if (FD_ISSET(i, &wfds)) { 508 log_Printf(LogTIMER, "Write set contains %d\n", i); 509 FD_CLR(i, &wfds); 510 t.tv_sec = t.tv_usec = 0; 511 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 512 log_Printf(LogTIMER, "The culprit !\n"); 513 break; 514 } 515 } 516 if (FD_ISSET(i, &efds)) { 517 log_Printf(LogTIMER, "Error set contains %d\n", i); 518 FD_CLR(i, &efds); 519 t.tv_sec = t.tv_usec = 0; 520 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 521 log_Printf(LogTIMER, "The culprit !\n"); 522 break; 523 } 524 } 525 } 526 } 527 break; 528 } 529 530 log_Printf(LogTIMER, "Select returns %d\n", i); 531 532 sig_Handle(); 533 534 if (i <= 0) 535 continue; 536 537 for (i = 0; i <= nfds; i++) 538 if (FD_ISSET(i, &efds)) { 539 log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 540 /* We deal gracefully with link descriptor exceptions */ 541 if (!bundle_Exception(bundle, i)) { 542 log_Printf(LogERROR, "Exception cannot be handled !\n"); 543 break; 544 } 545 } 546 547 if (i <= nfds) 548 break; 549 550 nothing_done = 1; 551 552 if (descriptor_IsSet(&server.desc, &rfds)) { 553 descriptor_Read(&server.desc, bundle, &rfds); 554 nothing_done = 0; 555 } 556 557 if (descriptor_IsSet(&bundle->desc, &rfds)) { 558 descriptor_Read(&bundle->desc, bundle, &rfds); 559 nothing_done = 0; 560 } 561 562 if (descriptor_IsSet(&bundle->desc, &wfds)) 563 if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) { 564 /* 565 * This is disasterous. The OS has told us that something is 566 * writable, and all our write()s have failed. Rather than 567 * going back immediately to do our UpdateSet()s and select(), 568 * we sleep for a bit to avoid gobbling up all cpu time. 569 */ 570 struct timeval t; 571 572 t.tv_sec = 0; 573 t.tv_usec = 100000; 574 select(0, NULL, NULL, NULL, &t); 575 } 576 } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle)); 577 578 log_Printf(LogDEBUG, "DoLoop done.\n"); 579}
| 312 log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 313 conf); 314 return -1; 315 } 316 ptr = conf + strlen(conf)-2; 317 while (ptr > conf && *ptr != '/') 318 *ptr-- = '\0'; 319 } while (ptr >= conf); 320 } 321 322 if (label < argc) 323 for (arg = label; arg < argc; arg++) 324 CheckLabel(argv[arg], prompt, mode); 325 else 326 CheckLabel("default", prompt, mode); 327 328 prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(mode)); 329 330 if ((bundle = bundle_Create(TUN_PREFIX, mode, (const char **)argv)) == NULL) { 331 log_Printf(LogWARN, "bundle_Create: %s\n", strerror(errno)); 332 return EX_START; 333 } 334 335 /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 336 337 if (prompt) { 338 prompt->bundle = bundle; /* couldn't do it earlier */ 339 prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 340 } 341 SignalBundle = bundle; 342 bundle->AliasEnabled = alias; 343 if (alias) 344 bundle->cfg.opt |= OPT_IFACEALIAS; 345 346 if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 347 prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 348 349 sig_signal(SIGHUP, CloseSession); 350 sig_signal(SIGTERM, CloseSession); 351 sig_signal(SIGINT, CloseConnection); 352 sig_signal(SIGQUIT, CloseSession); 353 sig_signal(SIGALRM, SIG_IGN); 354 signal(SIGPIPE, SIG_IGN); 355 356 if (mode == PHYS_INTERACTIVE) 357 sig_signal(SIGTSTP, TerminalStop); 358 359 sig_signal(SIGUSR2, BringDownServer); 360 361 lastlabel = argc == 2 ? bundle->argv1 : argv[argc - 1]; 362 for (arg = label; arg < argc; arg++) { 363 /* In case we use LABEL or ``set enddisc label'' */ 364 bundle_SetLabel(bundle, lastlabel); 365 system_Select(bundle, arg == 1 ? bundle->argv1 : argv[arg], 366 CONFFILE, prompt, NULL); 367 } 368 369 if (label < argc) 370 /* In case the last label did a ``load'' */ 371 bundle_SetLabel(bundle, lastlabel); 372 373 if (mode == PHYS_AUTO && 374 bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 375 prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 376 "in auto mode.\n"); 377 AbortProgram(EX_START); 378 } 379 380 if (mode != PHYS_INTERACTIVE) { 381 if (mode != PHYS_DIRECT) { 382 int bgpipe[2]; 383 pid_t bgpid; 384 385 if (mode == PHYS_BACKGROUND && pipe(bgpipe)) { 386 log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 387 AbortProgram(EX_SOCK); 388 } 389 390 bgpid = fork(); 391 if (bgpid == -1) { 392 log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 393 AbortProgram(EX_SOCK); 394 } 395 396 if (bgpid) { 397 char c = EX_NORMAL; 398 399 if (mode == PHYS_BACKGROUND) { 400 close(bgpipe[1]); 401 BGPid = bgpid; 402 /* If we get a signal, kill the child */ 403 signal(SIGHUP, KillChild); 404 signal(SIGTERM, KillChild); 405 signal(SIGINT, KillChild); 406 signal(SIGQUIT, KillChild); 407 408 /* Wait for our child to close its pipe before we exit */ 409 if (read(bgpipe[0], &c, 1) != 1) { 410 prompt_Printf(prompt, "Child exit, no status.\n"); 411 log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 412 } else if (c == EX_NORMAL) { 413 prompt_Printf(prompt, "PPP enabled.\n"); 414 log_Printf(LogPHASE, "Parent: PPP enabled.\n"); 415 } else { 416 prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); 417 log_Printf(LogPHASE, "Parent: Child failed (%s).\n", 418 ex_desc((int) c)); 419 } 420 close(bgpipe[0]); 421 } 422 return c; 423 } else if (mode == PHYS_BACKGROUND) { 424 close(bgpipe[0]); 425 bundle->notify.fd = bgpipe[1]; 426 } 427 428 bundle_LockTun(bundle); /* we have a new pid */ 429 430 /* -auto, -dedicated, -ddial & -background */ 431 prompt_Destroy(prompt, 0); 432 close(STDOUT_FILENO); 433 close(STDERR_FILENO); 434 close(STDIN_FILENO); 435 setsid(); 436 } else { 437 /* -direct: STDIN_FILENO gets used by modem_Open */ 438 prompt_TtyInit(NULL); 439 close(STDOUT_FILENO); 440 close(STDERR_FILENO); 441 } 442 } else { 443 /* Interactive mode */ 444 close(STDERR_FILENO); 445 prompt_TtyInit(prompt); 446 prompt_TtyCommandMode(prompt); 447 prompt_Required(prompt); 448 } 449 450 log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(mode)); 451 DoLoop(bundle); 452 AbortProgram(EX_NORMAL); 453 454 return EX_NORMAL; 455} 456 457static void 458DoLoop(struct bundle *bundle) 459{ 460 fd_set rfds, wfds, efds; 461 int i, nfds, nothing_done; 462 struct probe probe; 463 464 probe_Init(&probe); 465 466 do { 467 nfds = 0; 468 FD_ZERO(&rfds); 469 FD_ZERO(&wfds); 470 FD_ZERO(&efds); 471 472 /* All our datalinks, the tun device and the MP socket */ 473 descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 474 475 /* All our prompts and the diagnostic socket */ 476 descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); 477 478 if (bundle_IsDead(bundle)) 479 /* Don't select - we'll be here forever */ 480 break; 481 482 /* 483 * It's possible that we've had a signal since we last checked. If 484 * we don't check again before calling select(), we may end up stuck 485 * after having missed the event.... sig_Handle() tries to be as 486 * quick as possible if nothing is likely to have happened. 487 * This is only really likely if we block in open(... O_NONBLOCK) 488 * which will happen with a misconfigured device. 489 */ 490 if (sig_Handle()) 491 continue; 492 493 i = select(nfds, &rfds, &wfds, &efds, NULL); 494 495 if (i < 0 && errno != EINTR) { 496 log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 497 if (log_IsKept(LogTIMER)) { 498 struct timeval t; 499 500 for (i = 0; i <= nfds; i++) { 501 if (FD_ISSET(i, &rfds)) { 502 log_Printf(LogTIMER, "Read set contains %d\n", i); 503 FD_CLR(i, &rfds); 504 t.tv_sec = t.tv_usec = 0; 505 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 506 log_Printf(LogTIMER, "The culprit !\n"); 507 break; 508 } 509 } 510 if (FD_ISSET(i, &wfds)) { 511 log_Printf(LogTIMER, "Write set contains %d\n", i); 512 FD_CLR(i, &wfds); 513 t.tv_sec = t.tv_usec = 0; 514 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 515 log_Printf(LogTIMER, "The culprit !\n"); 516 break; 517 } 518 } 519 if (FD_ISSET(i, &efds)) { 520 log_Printf(LogTIMER, "Error set contains %d\n", i); 521 FD_CLR(i, &efds); 522 t.tv_sec = t.tv_usec = 0; 523 if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 524 log_Printf(LogTIMER, "The culprit !\n"); 525 break; 526 } 527 } 528 } 529 } 530 break; 531 } 532 533 log_Printf(LogTIMER, "Select returns %d\n", i); 534 535 sig_Handle(); 536 537 if (i <= 0) 538 continue; 539 540 for (i = 0; i <= nfds; i++) 541 if (FD_ISSET(i, &efds)) { 542 log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 543 /* We deal gracefully with link descriptor exceptions */ 544 if (!bundle_Exception(bundle, i)) { 545 log_Printf(LogERROR, "Exception cannot be handled !\n"); 546 break; 547 } 548 } 549 550 if (i <= nfds) 551 break; 552 553 nothing_done = 1; 554 555 if (descriptor_IsSet(&server.desc, &rfds)) { 556 descriptor_Read(&server.desc, bundle, &rfds); 557 nothing_done = 0; 558 } 559 560 if (descriptor_IsSet(&bundle->desc, &rfds)) { 561 descriptor_Read(&bundle->desc, bundle, &rfds); 562 nothing_done = 0; 563 } 564 565 if (descriptor_IsSet(&bundle->desc, &wfds)) 566 if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) { 567 /* 568 * This is disasterous. The OS has told us that something is 569 * writable, and all our write()s have failed. Rather than 570 * going back immediately to do our UpdateSet()s and select(), 571 * we sleep for a bit to avoid gobbling up all cpu time. 572 */ 573 struct timeval t; 574 575 t.tv_sec = 0; 576 t.tv_usec = 100000; 577 select(0, NULL, NULL, NULL, &t); 578 } 579 } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle)); 580 581 log_Printf(LogDEBUG, "DoLoop done.\n"); 582}
|