| 1 | static char *sccsid = "@(#)cu.c 4.7 (Berkeley) 82/10/21"; |
| 2 | |
| 3 | #include <stdio.h> |
| 4 | #include <signal.h> |
| 5 | #include <sgtty.h> |
| 6 | |
| 7 | /* |
| 8 | * defs that come from uucp.h |
| 9 | */ |
| 10 | #define NAMESIZE 15 |
| 11 | #define FAIL -1 |
| 12 | #define SAME 0 |
| 13 | #define SLCKTIME 5400 /* system/device timeout (LCK.. files) in seconds */ |
| 14 | #define ASSERT(e, f, v) if (!(e)) {\ |
| 15 | fprintf(stderr, "AERROR - (%s) ", "e");\ |
| 16 | fprintf(stderr, f, v);\ |
| 17 | cleanup(FAIL);\ |
| 18 | } |
| 19 | |
| 20 | /* |
| 21 | * cu telno [-t] [-s speed] [-l line] [-a acu] [-p] |
| 22 | * |
| 23 | * -t is for dial-out to terminal. |
| 24 | * speeds are: 110, 134, 150, 300, 1200, 2400. 300 is default. |
| 25 | * |
| 26 | * -p says strip parity of characters transmitted. (to compensate |
| 27 | * for c100's) |
| 28 | * |
| 29 | * Escape with `~' at beginning of line. |
| 30 | * Ordinary diversions are ~<, ~> and ~>>. |
| 31 | * Silent output diversions are ~>: and ~>>:. |
| 32 | * Terminate output diversion with ~> alone. |
| 33 | * Quit is ~. and ~! gives local command or shell. |
| 34 | * Also ~$ for canned procedure pumping remote. |
| 35 | * ~%put from [to] and ~%take from [to] invoke builtins |
| 36 | */ |
| 37 | |
| 38 | #define CRLF "\r\n" |
| 39 | #define wrc(ds) write(ds,&c,1) |
| 40 | |
| 41 | |
| 42 | char *devcul = "/dev/cul0"; |
| 43 | char *devcua = "/dev/cua0"; |
| 44 | char *lspeed = "300"; |
| 45 | |
| 46 | int ln; /* fd for comm line */ |
| 47 | char tkill, terase; /* current input kill & erase */ |
| 48 | int efk; /* process of id of listener */ |
| 49 | char c; |
| 50 | char oc; |
| 51 | |
| 52 | char *connmsg[] = { |
| 53 | "", |
| 54 | "line busy", |
| 55 | "call dropped", |
| 56 | "no carrier", |
| 57 | "can't fork", |
| 58 | "acu access", |
| 59 | "tty access", |
| 60 | "tty hung", |
| 61 | "usage: cu telno [-t] [-s speed] [-l line] [-a acu]", |
| 62 | "lock failed: line busy" |
| 63 | }; |
| 64 | |
| 65 | rdc(ds) { |
| 66 | |
| 67 | ds=read(ds,&c,1); |
| 68 | oc = c; |
| 69 | c &= 0177; |
| 70 | return (ds); |
| 71 | } |
| 72 | |
| 73 | int intr; |
| 74 | |
| 75 | sig2() |
| 76 | { |
| 77 | signal(SIGINT, SIG_IGN); |
| 78 | intr = 1; |
| 79 | } |
| 80 | |
| 81 | int set14; |
| 82 | |
| 83 | xsleep(n) |
| 84 | { |
| 85 | xalarm(n); |
| 86 | pause(); |
| 87 | xalarm(0); |
| 88 | } |
| 89 | |
| 90 | xalarm(n) |
| 91 | { |
| 92 | set14=n; |
| 93 | alarm(n); |
| 94 | } |
| 95 | |
| 96 | sig14() |
| 97 | { |
| 98 | signal(SIGALRM, sig14); |
| 99 | if (set14) alarm(1); |
| 100 | } |
| 101 | |
| 102 | int dout; |
| 103 | int nhup; |
| 104 | int dbflag; |
| 105 | int pflag; /* strip parity on chars sent to remote */ |
| 106 | int nullbrk; /* turn breaks (nulls) into dels */ |
| 107 | int pipes[2] = { -1, -1 }; |
| 108 | |
| 109 | /* |
| 110 | * main: get connection, set speed for line. |
| 111 | * spawn child to invoke rd to read from line, output to fd 1 |
| 112 | * main line invokes wr to read tty, write to line |
| 113 | */ |
| 114 | main(ac,av) |
| 115 | char *av[]; |
| 116 | { |
| 117 | int fk; |
| 118 | int speed; |
| 119 | char *telno; |
| 120 | struct sgttyb stbuf; |
| 121 | int cleanup(); |
| 122 | |
| 123 | signal(SIGALRM, sig14); |
| 124 | signal(SIGINT, cleanup); |
| 125 | signal(SIGHUP, cleanup); |
| 126 | signal(SIGQUIT, cleanup); |
| 127 | if (ac < 2) { |
| 128 | prf(connmsg[8]); |
| 129 | exit(8); |
| 130 | } |
| 131 | for (; ac > 1; av++,ac--) { |
| 132 | if (av[1][0] != '-') |
| 133 | telno = av[1]; |
| 134 | else switch(av[1][1]) { |
| 135 | case 't': |
| 136 | dout = 1; |
| 137 | --ac; |
| 138 | continue; |
| 139 | case 'b': |
| 140 | nullbrk++; |
| 141 | continue; |
| 142 | case 'd': |
| 143 | dbflag++; |
| 144 | continue; |
| 145 | case 'p': |
| 146 | pflag++; |
| 147 | continue; |
| 148 | case 's': |
| 149 | lspeed = av[2]; ++av; --ac; |
| 150 | break; |
| 151 | case 'l': |
| 152 | devcul = av[2]; ++av; --ac; |
| 153 | break; |
| 154 | case 'a': |
| 155 | devcua = av[2]; ++av; --ac; |
| 156 | break; |
| 157 | case '0': case '1': case '2': case '3': case '4': |
| 158 | case '5': case '6': case '7': case '8': case '9': |
| 159 | devcua[strlen(devcua)-1] = av[1][1]; |
| 160 | devcul[strlen(devcul)-1] = av[1][1]; |
| 161 | break; |
| 162 | default: |
| 163 | prf("Bad flag %s", av[1]); |
| 164 | break; |
| 165 | } |
| 166 | } |
| 167 | if (!exists(devcua) || !exists(devcul)) |
| 168 | exit(9); |
| 169 | ln = conn(devcul, devcua, telno); |
| 170 | if (ln < 0) { |
| 171 | prf("Connect failed: %s",connmsg[-ln]); |
| 172 | cleanup(-ln); |
| 173 | } |
| 174 | switch(atoi(lspeed)) { |
| 175 | case 110: |
| 176 | speed = B110;break; |
| 177 | case 150: |
| 178 | speed = B150;break; |
| 179 | default: |
| 180 | case 300: |
| 181 | speed = B300;break; |
| 182 | case 1200: |
| 183 | speed = B1200;break; |
| 184 | case 2400: |
| 185 | speed = B2400;break; |
| 186 | } |
| 187 | stbuf.sg_ispeed = speed; |
| 188 | stbuf.sg_ospeed = speed; |
| 189 | stbuf.sg_flags = EVENP|ODDP; |
| 190 | if (!dout) { |
| 191 | stbuf.sg_flags |= RAW; |
| 192 | stbuf.sg_flags &= ~ECHO; |
| 193 | } |
| 194 | ioctl(ln, TIOCSETP, &stbuf); |
| 195 | ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL); |
| 196 | ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL); |
| 197 | prf("Connected"); |
| 198 | pipe(pipes); |
| 199 | if (dout) |
| 200 | fk = -1; |
| 201 | else |
| 202 | fk = fork(); |
| 203 | nhup = (int)signal(SIGINT, SIG_IGN); |
| 204 | if (fk == 0) { |
| 205 | chwrsig(); |
| 206 | rd(); |
| 207 | prf("\007Lost carrier"); |
| 208 | cleanup(3); |
| 209 | } |
| 210 | mode(1); |
| 211 | efk = fk; |
| 212 | wr(); |
| 213 | mode(0); |
| 214 | if (fk != -1) kill(fk, SIGKILL); |
| 215 | wait((int *)NULL); |
| 216 | stbuf.sg_ispeed = 0; |
| 217 | stbuf.sg_ospeed = 0; |
| 218 | ioctl(ln, TIOCSETP, &stbuf); |
| 219 | prf("Disconnected"); |
| 220 | cleanup(0); |
| 221 | } |
| 222 | |
| 223 | /* |
| 224 | * conn: establish dial-out connection. |
| 225 | * Example: fd = conn("/dev/ttyh","/dev/dn1","4500"); |
| 226 | * Returns descriptor open to tty for reading and writing. |
| 227 | * Negative values (-1...-7) denote errors in connmsg. |
| 228 | * Uses alarm and fork/wait; requires sig14 handler. |
| 229 | * Be sure to disconnect tty when done, via HUPCL or stty 0. |
| 230 | */ |
| 231 | |
| 232 | conn(dev,acu,telno) |
| 233 | char *dev, *acu, *telno; |
| 234 | { |
| 235 | struct sgttyb stbuf; |
| 236 | extern errno; |
| 237 | char *p, *q, b[30]; |
| 238 | char *ltail, *atail; |
| 239 | char *rindex(); |
| 240 | int er, fk, dn, dh, t; |
| 241 | er=0; |
| 242 | fk=(-1); |
| 243 | atail = rindex(acu, '/')+1; |
| 244 | if (mlock(atail) == FAIL) { |
| 245 | er = 9; |
| 246 | goto X; |
| 247 | } |
| 248 | ltail = rindex(dev, '/')+1; |
| 249 | if (mlock(ltail) == FAIL) { |
| 250 | er = 9; |
| 251 | delock(atail); |
| 252 | goto X; |
| 253 | } |
| 254 | if ((dn=open(acu,1))<0) { |
| 255 | er=(errno == 6? 1:5); |
| 256 | goto X; |
| 257 | } |
| 258 | if ((fk=fork()) == (-1)) { |
| 259 | er=4; |
| 260 | goto X; |
| 261 | } |
| 262 | if (fk == 0) { |
| 263 | open(dev,2); |
| 264 | for (;;) pause(); |
| 265 | } |
| 266 | xsleep(2); |
| 267 | /* |
| 268 | * copy phone #, assure EON |
| 269 | */ |
| 270 | p=b; |
| 271 | q=telno; |
| 272 | while (*p++=(*q++)) |
| 273 | ; |
| 274 | p--; |
| 275 | if (*(p-1)!='<') { |
| 276 | /*if (*(p-1)!='-') *p++='-';*/ |
| 277 | *p++='<'; |
| 278 | } |
| 279 | t=p-b; |
| 280 | xalarm(5*t); |
| 281 | t=write(dn,b,t); |
| 282 | xalarm(0); |
| 283 | if (t<0) { |
| 284 | er=2; |
| 285 | goto X; |
| 286 | } |
| 287 | /* close(dn) */ |
| 288 | xalarm(40); /* was 5; sometimes missed carrier */ |
| 289 | dh = open(dev,2); |
| 290 | xalarm(0); |
| 291 | if (dh<0) { |
| 292 | er=(errno == 4? 3:6); |
| 293 | goto X; |
| 294 | } |
| 295 | ioctl(dh, TIOCGETP, &stbuf); |
| 296 | stbuf.sg_flags &= ~ECHO; |
| 297 | xalarm(10); |
| 298 | ioctl(dh, TIOCSETP, &stbuf); |
| 299 | ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL); |
| 300 | xalarm(0); |
| 301 | X: |
| 302 | if (er) close(dn); |
| 303 | delock(atail); |
| 304 | if (fk!=(-1)) { |
| 305 | kill(fk, SIGKILL); |
| 306 | xalarm(10); |
| 307 | while ((t=wait((int *)NULL))!=(-1) && t!=fk); |
| 308 | xalarm(0); |
| 309 | } |
| 310 | return (er? -er:dh); |
| 311 | } |
| 312 | |
| 313 | /* |
| 314 | * wr: write to remote: 0 -> line. |
| 315 | * ~. terminate |
| 316 | * ~<file send file |
| 317 | * ~! local login-style shell |
| 318 | * ~!cmd execute cmd locally |
| 319 | * ~$proc execute proc locally, send output to line |
| 320 | * ~%cmd execute builtin cmd (put and take) |
| 321 | * ~# send 1-sec break |
| 322 | * ~^Z suspend cu process. |
| 323 | */ |
| 324 | |
| 325 | wr() |
| 326 | { |
| 327 | int ds,fk,lcl,x; |
| 328 | char *p,b[600]; |
| 329 | for (;;) { |
| 330 | p=b; |
| 331 | while (rdc(0) == 1) { |
| 332 | if (p == b) lcl=(c == '~'); |
| 333 | if (p == b+1 && b[0] == '~') lcl=(c!='~'); |
| 334 | if (nullbrk && c == 0) oc=c=0177; /* fake break kludge */ |
| 335 | if (!lcl) { |
| 336 | if(!pflag)c = oc; |
| 337 | if (wrc(ln) == 0) { |
| 338 | prf("line gone"); return; |
| 339 | } |
| 340 | c &= 0177; |
| 341 | } |
| 342 | if (lcl) { |
| 343 | if (c == 0177) c=tkill; |
| 344 | if (c == '\r' || c == '\n') goto A; |
| 345 | if (!dout) wrc(0); |
| 346 | } |
| 347 | *p++=c; |
| 348 | if (c == terase) { |
| 349 | p=p-2; |
| 350 | if (p<b) p=b; |
| 351 | } |
| 352 | if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b; |
| 353 | } |
| 354 | return; |
| 355 | A: |
| 356 | if (!dout) echo(""); |
| 357 | *p=0; |
| 358 | switch (b[1]) { |
| 359 | case '.': |
| 360 | case '\004': |
| 361 | return; |
| 362 | case '#': |
| 363 | ioctl(ln, TIOCSBRK, 0); |
| 364 | sleep(1); |
| 365 | ioctl(ln, TIOCCBRK, 0); |
| 366 | continue; |
| 367 | case '!': |
| 368 | case '$': |
| 369 | fk = fork(); |
| 370 | if (fk == 0) { |
| 371 | char *getenv(); |
| 372 | char *shell = getenv("SHELL"); |
| 373 | if (shell == 0) shell = "/bin/sh"; |
| 374 | close(1); |
| 375 | dup(b[1] == '$'? ln:2); |
| 376 | close(ln); |
| 377 | mode(0); |
| 378 | if (!nhup) signal(SIGINT, SIG_DFL); |
| 379 | if (b[2] == 0) execl(shell,shell,0); |
| 380 | /* if (b[2] == 0) execl(shell,"-",0); */ |
| 381 | else execl(shell,"sh","-c",b+2,0); |
| 382 | prf("Can't execute shell"); |
| 383 | exit(~0); |
| 384 | } |
| 385 | if (fk!=(-1)) { |
| 386 | while (wait(&x)!=fk); |
| 387 | } |
| 388 | mode(1); |
| 389 | if (b[1] == '!') echo("!"); |
| 390 | else { |
| 391 | if (dout) echo("$"); |
| 392 | } |
| 393 | break; |
| 394 | case '<': |
| 395 | if (b[2] == 0) break; |
| 396 | if ((ds=open(b+2,0))<0) { |
| 397 | prf("Can't divert %s",b+1); |
| 398 | break; |
| 399 | } |
| 400 | intr=x=0; |
| 401 | mode(2); |
| 402 | if (!nhup) signal(SIGINT, sig2); |
| 403 | while (!intr && rdc(ds) == 1) { |
| 404 | if (wrc(ln) == 0) { |
| 405 | x=1; |
| 406 | break; |
| 407 | } |
| 408 | } |
| 409 | signal(SIGINT, SIG_IGN); |
| 410 | close(ds); |
| 411 | mode(1); |
| 412 | if (x) return; |
| 413 | if (dout) echo("<"); |
| 414 | break; |
| 415 | case '>': |
| 416 | case ':': |
| 417 | { |
| 418 | register char *q; |
| 419 | |
| 420 | if(pipes[1]==-1) { |
| 421 | prf("Can't tell other demon to divert"); |
| 422 | break; |
| 423 | } |
| 424 | q = b+1; |
| 425 | if(*q=='>') q++; |
| 426 | write(pipes[1],q,strlen(q)+1); |
| 427 | if(dbflag) prf("msg to be delivered:"),prf(q); |
| 428 | if (efk != -1) kill(efk,SIGEMT); |
| 429 | } |
| 430 | break; |
| 431 | #ifdef SIGTSTP |
| 432 | #define CTRLZ 26 |
| 433 | case CTRLZ: |
| 434 | mode(0); |
| 435 | kill(getpid(), SIGTSTP); |
| 436 | mode(1); |
| 437 | break; |
| 438 | #endif |
| 439 | case '%': |
| 440 | dopercen(&b[2]); |
| 441 | break; |
| 442 | default: |
| 443 | prf("Use `~~' to start line with `~'"); |
| 444 | } |
| 445 | continue; |
| 446 | } |
| 447 | } |
| 448 | |
| 449 | dopercen(line) |
| 450 | register char *line; |
| 451 | { |
| 452 | char *args[10]; |
| 453 | register narg, f; |
| 454 | int rcount; |
| 455 | for (narg = 0; narg < 10;) { |
| 456 | while(*line == ' ' || *line == '\t') |
| 457 | line++; |
| 458 | if (*line == '\0') |
| 459 | break; |
| 460 | args[narg++] = line; |
| 461 | while(*line != '\0' && *line != ' ' && *line != '\t') |
| 462 | line++; |
| 463 | if (*line == '\0') |
| 464 | break; |
| 465 | *line++ = '\0'; |
| 466 | } |
| 467 | if (equal(args[0], "take")) { |
| 468 | if (narg < 2) { |
| 469 | prf("usage: ~%%take from [to]"); |
| 470 | return; |
| 471 | } |
| 472 | if (narg < 3) |
| 473 | args[2] = args[1]; |
| 474 | write(pipes[1], ">:/dev/null",sizeof(">:/dev/null")); |
| 475 | if(dbflag) prf("sending take message"); |
| 476 | if (efk != -1) kill(efk,SIGEMT); |
| 477 | xsleep(5); |
| 478 | wrln("echo '~>"); |
| 479 | wrln(args[2]); |
| 480 | wrln("'; tee /dev/null <"); |
| 481 | wrln(args[1]); |
| 482 | wrln(";echo '~>'\n"); |
| 483 | return; |
| 484 | } else if (equal(args[0], "put")) { |
| 485 | if (narg < 2) { |
| 486 | prf("usage: ~%%put from [to]"); |
| 487 | return; |
| 488 | } |
| 489 | if (narg < 3) |
| 490 | args[2] = args[1]; |
| 491 | if ((f = open(args[1], 0)) < 0) { |
| 492 | prf("cannot open: %s", args[1]); |
| 493 | return; |
| 494 | } |
| 495 | wrln("stty -echo;cat >"); |
| 496 | wrln(args[2]); |
| 497 | wrln(";stty echo\n"); |
| 498 | xsleep(5); |
| 499 | intr = 0; |
| 500 | if (!nhup) |
| 501 | signal(SIGINT, sig2); |
| 502 | mode(2); |
| 503 | rcount = 0; |
| 504 | while(!intr && rdc(f) == 1) { |
| 505 | rcount++; |
| 506 | if (c == tkill || c == terase) |
| 507 | wrln("\\"); |
| 508 | if (wrc(ln) != 1) { |
| 509 | xsleep(2); |
| 510 | if (wrc(ln) != 1) { |
| 511 | prf("character missed"); |
| 512 | intr = 1; |
| 513 | break; |
| 514 | } |
| 515 | } |
| 516 | } |
| 517 | signal(SIGINT, SIG_IGN); |
| 518 | close(f); |
| 519 | if (intr) { |
| 520 | wrln("\n"); |
| 521 | prf("stopped after %d bytes", rcount); |
| 522 | } |
| 523 | wrln("\004"); |
| 524 | xsleep(5); |
| 525 | mode(1); |
| 526 | return; |
| 527 | } |
| 528 | prf("~%%%s unknown\n", args[0]); |
| 529 | } |
| 530 | |
| 531 | equal(s1, s2) |
| 532 | register char *s1, *s2; |
| 533 | { |
| 534 | while (*s1++ == *s2) |
| 535 | if (*s2++ == '\0') |
| 536 | return(1); |
| 537 | return(0); |
| 538 | } |
| 539 | |
| 540 | wrln(s) |
| 541 | register char *s; |
| 542 | { |
| 543 | while (*s) |
| 544 | write(ln, s++, 1); |
| 545 | } |
| 546 | /* chwrsig: Catch orders from wr process |
| 547 | * to instigate diversion |
| 548 | */ |
| 549 | int whoami; |
| 550 | chwrsig(){ |
| 551 | int readmsg(); |
| 552 | whoami = getpid(); |
| 553 | signal(SIGEMT,readmsg); |
| 554 | } |
| 555 | int ds,slnt,taking; |
| 556 | int justrung; |
| 557 | readmsg(){ |
| 558 | static char dobuff[128], morejunk[256]; |
| 559 | int n; |
| 560 | justrung = 1; |
| 561 | signal(SIGEMT,readmsg); |
| 562 | if(dbflag) { |
| 563 | prf("About to read from pipe"); |
| 564 | } |
| 565 | n = read(pipes[0],morejunk,256); |
| 566 | if(dbflag) { |
| 567 | prf("diversion mesg recieved is"); |
| 568 | prf(morejunk); |
| 569 | prf(CRLF); |
| 570 | } |
| 571 | dodiver(morejunk); |
| 572 | } |
| 573 | dodiver(msg) |
| 574 | char *msg; |
| 575 | { |
| 576 | register char *cp = msg; |
| 577 | |
| 578 | if (*cp=='>') cp++; |
| 579 | if (*cp==':') { |
| 580 | cp++; |
| 581 | if(*cp==0) { |
| 582 | slnt ^= 1; |
| 583 | return; |
| 584 | } else { |
| 585 | slnt = 1; |
| 586 | } |
| 587 | } |
| 588 | if (ds >= 0) close(ds); |
| 589 | if (*cp==0) { |
| 590 | slnt = 0; |
| 591 | ds = -1; |
| 592 | return; |
| 593 | } |
| 594 | if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644); |
| 595 | lseek(ds, (long)0, 2); |
| 596 | if(ds < 0) prf("Creat failed:"), prf(cp); |
| 597 | if (ds<0) prf("Can't divert %s",cp+1); |
| 598 | } |
| 599 | |
| 600 | |
| 601 | /* |
| 602 | * rd: read from remote: line -> 1 |
| 603 | * catch: diversion caught by interrupt routine |
| 604 | */ |
| 605 | |
| 606 | #define ORDIN 0 |
| 607 | #define SAWCR 1 |
| 608 | #define EOL 2 |
| 609 | #define SAWTL 3 |
| 610 | #define DIVER 4 |
| 611 | |
| 612 | rd() |
| 613 | { |
| 614 | extern int ds,slnt; |
| 615 | char rb[600], lb[600], *rlim, *llim, c; |
| 616 | register char *p,*q; |
| 617 | int cnt, state = 0, mustecho, oldslnt; |
| 618 | |
| 619 | ds=(-1); |
| 620 | p = lb; llim = lb+600; |
| 621 | agin: |
| 622 | while((cnt = read(ln,rb,600)) > 0) { |
| 623 | if(!slnt) write(1,rb,cnt); |
| 624 | if(ds < 0) continue; |
| 625 | oldslnt = slnt; |
| 626 | for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) { |
| 627 | c = *q++ & 0177; |
| 628 | if(p < llim) *p++ = c; |
| 629 | switch(state) { |
| 630 | case ORDIN: |
| 631 | if(c=='\r') state = SAWCR; |
| 632 | break; |
| 633 | case SAWCR: |
| 634 | if(c=='\n') { |
| 635 | state = EOL; |
| 636 | p--; |
| 637 | p[-1] = '\n'; |
| 638 | } else state = ORDIN; |
| 639 | break; |
| 640 | case EOL: |
| 641 | state = (c=='~' ? SAWTL : |
| 642 | (c=='\r' ? SAWCR : ORDIN)); |
| 643 | break; |
| 644 | case SAWTL: |
| 645 | state = (c=='>' ? DIVER : |
| 646 | (c=='\r' ? SAWCR : ORDIN)); |
| 647 | break; |
| 648 | case DIVER: |
| 649 | if(c=='\r') { |
| 650 | p--; |
| 651 | } else if (c=='\n') { |
| 652 | state = ORDIN; |
| 653 | p[-1] = 0; |
| 654 | dodiver(lb+2); |
| 655 | c = 0; p = lb; |
| 656 | } |
| 657 | } |
| 658 | if(slnt==0 && oldslnt) { |
| 659 | if(c=='\n') { |
| 660 | write(ln,lb,p-lb-1); |
| 661 | write(ln,CRLF,sizeof(CRLF)); |
| 662 | } else if(q==rlim) { |
| 663 | write(ln,lb,p-lb); |
| 664 | c = '\n'; /*force flush to file*/ |
| 665 | } |
| 666 | } |
| 667 | if(c=='\n') { |
| 668 | if(ds >= 0) |
| 669 | write(ds,lb,p-lb); |
| 670 | p = lb; |
| 671 | } |
| 672 | } |
| 673 | } |
| 674 | if(justrung) { |
| 675 | justrung = 0; |
| 676 | goto agin; |
| 677 | } |
| 678 | } |
| 679 | |
| 680 | struct {char lobyte; char hibyte;}; |
| 681 | mode(f) |
| 682 | { |
| 683 | struct sgttyb stbuf; |
| 684 | if (dout) return; |
| 685 | ioctl(0, TIOCGETP, &stbuf); |
| 686 | tkill = stbuf.sg_kill; |
| 687 | terase = stbuf.sg_erase; |
| 688 | if (f == 0) { |
| 689 | stbuf.sg_flags &= ~RAW; |
| 690 | stbuf.sg_flags |= ECHO|CRMOD; |
| 691 | } |
| 692 | if (f == 1) { |
| 693 | stbuf.sg_flags |= RAW; |
| 694 | stbuf.sg_flags &= ~(ECHO|CRMOD); |
| 695 | } |
| 696 | if (f == 2) { |
| 697 | stbuf.sg_flags &= ~RAW; |
| 698 | stbuf.sg_flags &= ~(ECHO|CRMOD); |
| 699 | } |
| 700 | ioctl(0, TIOCSETP, &stbuf); |
| 701 | } |
| 702 | |
| 703 | echo(s) |
| 704 | char *s; |
| 705 | { |
| 706 | char *p; |
| 707 | for (p=s;*p;p++); |
| 708 | if (p>s) write(0,s,p-s); |
| 709 | write(0,CRLF, sizeof(CRLF)); |
| 710 | } |
| 711 | |
| 712 | prf(f, s) |
| 713 | char *f; |
| 714 | char *s; |
| 715 | { |
| 716 | fprintf(stderr, f, s); |
| 717 | fprintf(stderr, CRLF); |
| 718 | } |
| 719 | |
| 720 | exists(devname) |
| 721 | char *devname; |
| 722 | { |
| 723 | if (access(devname, 0)==0) |
| 724 | return(1); |
| 725 | prf("%s does not exist", devname); |
| 726 | return(0); |
| 727 | } |
| 728 | |
| 729 | cleanup(code) |
| 730 | { |
| 731 | rmlock(NULL); |
| 732 | exit(code); |
| 733 | } |
| 734 | |
| 735 | /* |
| 736 | * This code is taken directly from uucp and follows the same |
| 737 | * conventions. This is important since uucp and cu should |
| 738 | * respect each others locks. |
| 739 | */ |
| 740 | |
| 741 | /* ulockf 3.2 10/26/79 11:40:29 */ |
| 742 | /* #include "uucp.h" */ |
| 743 | #include <sys/types.h> |
| 744 | #include <sys/stat.h> |
| 745 | |
| 746 | |
| 747 | |
| 748 | /******* |
| 749 | * ulockf(file, atime) |
| 750 | * char *file; |
| 751 | * time_t atime; |
| 752 | * |
| 753 | * ulockf - this routine will create a lock file (file). |
| 754 | * If one already exists, the create time is checked for |
| 755 | * older than the age time (atime). |
| 756 | * If it is older, an attempt will be made to unlink it |
| 757 | * and create a new one. |
| 758 | * |
| 759 | * return codes: 0 | FAIL |
| 760 | */ |
| 761 | |
| 762 | ulockf(file, atime) |
| 763 | char *file; |
| 764 | time_t atime; |
| 765 | { |
| 766 | struct stat stbuf; |
| 767 | time_t ptime; |
| 768 | int ret; |
| 769 | static int pid = -1; |
| 770 | static char tempfile[NAMESIZE]; |
| 771 | |
| 772 | if (pid < 0) { |
| 773 | pid = getpid(); |
| 774 | sprintf(tempfile, "/usr/spool/uucp/LTMP.%d", pid); |
| 775 | } |
| 776 | if (onelock(pid, tempfile, file) == -1) { |
| 777 | /* lock file exists */ |
| 778 | /* get status to check age of the lock file */ |
| 779 | ret = stat(file, &stbuf); |
| 780 | if (ret != -1) { |
| 781 | time(&ptime); |
| 782 | if ((ptime - stbuf.st_ctime) < atime) { |
| 783 | /* file not old enough to delete */ |
| 784 | return(FAIL); |
| 785 | } |
| 786 | } |
| 787 | ret = unlink(file); |
| 788 | ret = onelock(pid, tempfile, file); |
| 789 | if (ret != 0) |
| 790 | return(FAIL); |
| 791 | } |
| 792 | stlock(file); |
| 793 | return(0); |
| 794 | } |
| 795 | |
| 796 | |
| 797 | #define MAXLOCKS 10 /* maximum number of lock files */ |
| 798 | char *Lockfile[MAXLOCKS]; |
| 799 | int Nlocks = 0; |
| 800 | |
| 801 | /*** |
| 802 | * stlock(name) put name in list of lock files |
| 803 | * char *name; |
| 804 | * |
| 805 | * return codes: none |
| 806 | */ |
| 807 | |
| 808 | stlock(name) |
| 809 | char *name; |
| 810 | { |
| 811 | char *p; |
| 812 | extern char *calloc(); |
| 813 | int i; |
| 814 | |
| 815 | for (i = 0; i < Nlocks; i++) { |
| 816 | if (Lockfile[i] == NULL) |
| 817 | break; |
| 818 | } |
| 819 | ASSERT(i < MAXLOCKS, "TOO MANY LOCKS %d", i); |
| 820 | if (i >= Nlocks) |
| 821 | i = Nlocks++; |
| 822 | p = calloc(strlen(name) + 1, sizeof (char)); |
| 823 | ASSERT(p != NULL, "CAN NOT ALLOCATE FOR %s", name); |
| 824 | strcpy(p, name); |
| 825 | Lockfile[i] = p; |
| 826 | return; |
| 827 | } |
| 828 | |
| 829 | |
| 830 | /*** |
| 831 | * rmlock(name) remove all lock files in list |
| 832 | * char *name; or name |
| 833 | * |
| 834 | * return codes: none |
| 835 | */ |
| 836 | |
| 837 | rmlock(name) |
| 838 | char *name; |
| 839 | { |
| 840 | int i; |
| 841 | |
| 842 | for (i = 0; i < Nlocks; i++) { |
| 843 | if (Lockfile[i] == NULL) |
| 844 | continue; |
| 845 | if (name == NULL |
| 846 | || strcmp(name, Lockfile[i]) == SAME) { |
| 847 | unlink(Lockfile[i]); |
| 848 | free(Lockfile[i]); |
| 849 | Lockfile[i] = NULL; |
| 850 | } |
| 851 | } |
| 852 | return; |
| 853 | } |
| 854 | |
| 855 | |
| 856 | /* this stuff from pjw */ |
| 857 | /* /usr/pjw/bin/recover - check pids to remove unnecessary locks */ |
| 858 | /* isalock(name) returns 0 if the name is a lock */ |
| 859 | /* unlock(name) unlocks name if it is a lock*/ |
| 860 | /* onelock(pid,tempfile,name) makes lock a name |
| 861 | on behalf of pid. Tempfile must be in the same |
| 862 | file system as name. */ |
| 863 | /* lock(pid,tempfile,names) either locks all the |
| 864 | names or none of them */ |
| 865 | isalock(name) char *name; |
| 866 | { |
| 867 | struct stat xstat; |
| 868 | if(stat(name,&xstat)<0) return(0); |
| 869 | if(xstat.st_size!=sizeof(int)) return(0); |
| 870 | return(1); |
| 871 | } |
| 872 | unlock(name) char *name; |
| 873 | { |
| 874 | if(isalock(name)) return(unlink(name)); |
| 875 | else return(-1); |
| 876 | } |
| 877 | onelock(pid,tempfile,name) char *tempfile,*name; |
| 878 | { int fd; |
| 879 | fd=creat(tempfile,0444); |
| 880 | if(fd<0) return(-1); |
| 881 | write(fd,(char *) &pid,sizeof(int)); |
| 882 | close(fd); |
| 883 | if(link(tempfile,name)<0) |
| 884 | { unlink(tempfile); |
| 885 | return(-1); |
| 886 | } |
| 887 | unlink(tempfile); |
| 888 | return(0); |
| 889 | } |
| 890 | lock(pid,tempfile,names) char *tempfile,**names; |
| 891 | { int i,j; |
| 892 | for(i=0;names[i]!=0;i++) |
| 893 | { if(onelock(pid,tempfile,names[i])==0) continue; |
| 894 | for(j=0;j<i;j++) unlink(names[j]); |
| 895 | return(-1); |
| 896 | } |
| 897 | return(0); |
| 898 | } |
| 899 | |
| 900 | #define LOCKPRE "/usr/spool/uucp/LCK." |
| 901 | |
| 902 | /*** |
| 903 | * delock(s) remove a lock file |
| 904 | * char *s; |
| 905 | * |
| 906 | * return codes: 0 | FAIL |
| 907 | */ |
| 908 | |
| 909 | delock(s) |
| 910 | char *s; |
| 911 | { |
| 912 | char ln[30]; |
| 913 | |
| 914 | sprintf(ln, "%s.%s", LOCKPRE, s); |
| 915 | rmlock(ln); |
| 916 | } |
| 917 | |
| 918 | |
| 919 | /*** |
| 920 | * mlock(sys) create system lock |
| 921 | * char *sys; |
| 922 | * |
| 923 | * return codes: 0 | FAIL |
| 924 | */ |
| 925 | |
| 926 | mlock(sys) |
| 927 | char *sys; |
| 928 | { |
| 929 | char lname[30]; |
| 930 | sprintf(lname, "%s.%s", LOCKPRE, sys); |
| 931 | return(ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0); |
| 932 | } |
| 933 | |
| 934 | |
| 935 | |
| 936 | /*** |
| 937 | * ultouch() update access and modify times for lock files |
| 938 | * |
| 939 | * return code - none |
| 940 | */ |
| 941 | |
| 942 | ultouch() |
| 943 | { |
| 944 | time_t time(); |
| 945 | int i; |
| 946 | struct ut { |
| 947 | time_t actime; |
| 948 | time_t modtime; |
| 949 | } ut; |
| 950 | |
| 951 | ut.actime = time(&ut.modtime); |
| 952 | for (i = 0; i < Nlocks; i++) { |
| 953 | if (Lockfile[i] == NULL) |
| 954 | continue; |
| 955 | utime(Lockfile[i], &ut); |
| 956 | } |
| 957 | return; |
| 958 | } |