1 #ifndef lint 2 static char sccsid[] = "@(#)acucntrl.c 5.8 (Berkeley) 02/12/86"; 3 #endif 4 5 /* acucntrl - turn around tty line between dialin and dialout 6 * 7 * Usage: acucntrl {enable,disable} /dev/ttydX 8 * 9 * History: 10 * First written by Allan Wilkes (fisher!allan) 11 * 12 * Modified June 8,1983 by W.Sebok (astrovax!wls) to poke kernel rather 13 * than use kernel hack to turn on/off modem control, using subroutine 14 * stolen from program written by Tsutomu Shimomura 15 * {astrovax,escher}!tsutomu 16 * 17 * Worked over many times by W.Sebok (i.e. hacked to death) 18 * 19 * Operation: 20 * disable (i.e. setup for dialing out) 21 * (1) check input arguments 22 * (2) look in /etc/utmp to check that the line is not in use by another 23 * (3) disable modem control on terminal 24 * (4) check for carrier on device 25 * (5) change owner of device to real id 26 * (6) edit /etc/ttys, changing the first character of the appropriate 27 * line to 0 28 * (7) send a hangup to process 1 to poke init to disable getty 29 * (8) post uid name in capitals in /etc/utmp to let world know device has 30 * been grabbed 31 * (9) make sure that DTR is on 32 * 33 * enable (i.e.) restore for dialin 34 * (1) check input arguments 35 * (2) look in /etc/utmp to check that the line is not in use by another 36 * (3) make sure modem control on terminal is disabled 37 * (4) turn off DTR to make sure line is hung up 38 * (5) condition line: clear exclusive use and set hangup on close modes 39 * (6) turn on modem control 40 * (7) edit /etc/ttys, changing the first character of the appropriate 41 * line to 1 42 * (8) send a hangup to process 1 to poke init to enable getty 43 * (9) clear uid name for /etc/utmp 44 */ 45 46 /* #define SENSECARRIER */ 47 48 #include "uucp.h" 49 #include <sys/buf.h> 50 #include <signal.h> 51 #include <sys/conf.h> 52 #ifdef BSD4_2 53 #include <vaxuba/ubavar.h> 54 #else 55 #include <sys/ubavar.h> 56 #endif 57 #include <sys/stat.h> 58 #include <nlist.h> 59 #include <sgtty.h> 60 #include <utmp.h> 61 #include <pwd.h> 62 #include <stdio.h> 63 #include <sys/file.h> 64 65 #define NDZLINE 8 /* lines/dz */ 66 #define NDHLINE 16 /* lines/dh */ 67 #define NDMFLINE 8 /* lines/dmf */ 68 69 #define DZ11 1 70 #define DH11 2 71 #define DMF 3 72 73 #define NLVALUE(val) (nl[val].n_value) 74 75 struct nlist nl[] = { 76 #define CDEVSW 0 77 { "_cdevsw" }, 78 79 #define DZOPEN 1 80 { "_dzopen" }, 81 #define DZINFO 2 82 { "_dzinfo" }, 83 #define NDZ11 3 84 { "_dz_cnt" }, 85 #define DZSCAR 4 86 { "_dzsoftCAR" }, 87 88 #define DHOPEN 5 89 { "_dhopen" }, 90 #define DHINFO 6 91 { "_dhinfo" }, 92 #define NDH11 7 93 { "_ndh11" }, 94 #define DHSCAR 8 95 { "_dhsoftCAR" }, 96 97 #define DMFOPEN 9 98 { "_dmfopen" }, 99 #define DMFINFO 10 100 { "_dmfinfo" }, 101 #define NDMF 11 102 { "_ndmf" }, 103 #define DMFSCAR 12 104 { "_dmfsoftCAR" }, 105 106 { "\0" } 107 }; 108 109 #define ENABLE 1 110 #define DISABLE 0 111 112 char Etcutmp[] = "/etc/utmp"; 113 char Etcttys[] = "/etc/ttys"; 114 #ifdef BSD4_3 115 FILE *ttysfile, *nttysfile; 116 char NEtcttys[] = "/etc/ttys.new"; 117 extern long ftell(); 118 #endif BSD4_3 119 char Devhome[] = "/dev"; 120 121 char usage[] = "Usage: acucntrl {dis|en}able ttydX\n"; 122 123 struct utmp utmp; 124 char resettty, resetmodem; 125 int etcutmp; 126 off_t utmploc; 127 off_t ttyslnbeg; 128 129 #define NAMSIZ sizeof(utmp.ut_name) 130 #define LINSIZ sizeof(utmp.ut_line) 131 132 main(argc, argv) 133 int argc; char *argv[]; 134 { 135 register char *p; 136 register int i; 137 char uname[NAMSIZ], Uname[NAMSIZ]; 138 int enable ; 139 char *device; 140 int devfile; 141 int uid, gid; 142 off_t lseek(); 143 struct passwd *getpwuid(); 144 char *rindex(); 145 extern int errno; 146 extern char *sys_errlist[]; 147 148 /* check input arguments */ 149 if (argc!=3) { 150 fprintf(stderr, usage); 151 exit(1); 152 } 153 154 /* interpret command type */ 155 if (prefix(argv[1], "disable") || strcmp(argv[1], "dialout")==0) 156 enable = 0; 157 else if (prefix(argv[1], "enable") || strcmp(argv[1], "dialin")==0) 158 enable = 1; 159 else { 160 fprintf(stderr, usage); 161 exit(1); 162 } 163 164 device = rindex(argv[2], '/'); 165 device = (device == NULL) ? argv[2]: device+1; 166 167 /* only recognize devices of the form ttydX */ 168 if (strncmp(device, "ttyd", 4)!=0) { 169 fprintf(stderr, "Bad Device Name %s", device); 170 exit(1); 171 } 172 173 opnttys(device); 174 175 /* Get nlist info */ 176 nlist("/vmunix", nl); 177 178 /* Chdir to /dev */ 179 if(chdir(Devhome) < 0) { 180 fprintf(stderr, "Cannot chdir to %s: %s\r\n", 181 Devhome, sys_errlist[errno]); 182 exit(1); 183 } 184 185 /* Get uid information */ 186 uid = getuid(); 187 gid = getgid(); 188 189 p = getpwuid(uid)->pw_name; 190 if (p==NULL) { 191 fprintf(stderr, "cannot get uid name\n"); 192 exit(1); 193 } 194 195 /* to upper case */ 196 i = 0; 197 do { 198 uname[i] = *p; 199 Uname[i] = (*p>='a' && *p<='z') ? (*p - ('a'-'A')) : *p; 200 i++; p++; 201 } while (*p && i<NAMSIZ); 202 203 204 /* check to see if line is being used */ 205 if( (etcutmp = open(Etcutmp, 2)) < 0) { 206 fprintf(stderr, "On open %s open: %s\n", 207 Etcutmp, sys_errlist[errno]); 208 exit(1); 209 } 210 211 (void)lseek(etcutmp, utmploc, 0); 212 213 i = read(etcutmp, (char *)&utmp, sizeof(struct utmp)); 214 215 if( 216 i == sizeof(struct utmp) && 217 utmp.ut_line[0] != '\0' && 218 utmp.ut_name[0] != '\0' && 219 ( 220 !upcase(utmp.ut_name, NAMSIZ) || 221 ( 222 uid != 0 && 223 strncmp(utmp.ut_name, Uname, NAMSIZ) != 0 224 ) 225 ) 226 ) { 227 fprintf(stderr, "%s in use by %s\n", device, utmp.ut_name); 228 exit(2); 229 } 230 231 /* Disable modem control */ 232 if (setmodem(device, DISABLE) < 0) { 233 fprintf(stderr, "Unable to disable modem control\n"); 234 exit(1); 235 } 236 237 if (enable) { 238 if((devfile = open(device, 1)) < 0) { 239 fprintf(stderr, "On open of %s: %s\n", 240 device, sys_errlist[errno]); 241 (void)setmodem(device, resetmodem); 242 exit(1); 243 } 244 /* Try one last time to hang up */ 245 if (ioctl(devfile, (int)TIOCCDTR, (char *)0) < 0) 246 fprintf(stderr, "On TIOCCDTR ioctl: %s\n", 247 sys_errlist[errno]); 248 249 if (ioctl(devfile, (int)TIOCNXCL, (char *)0) < 0) 250 fprintf(stderr, 251 "Cannot clear Exclusive Use on %s: %s\n", 252 device, sys_errlist[errno]); 253 254 if (ioctl(devfile, (int)TIOCHPCL, (char *)0) < 0) 255 fprintf(stderr, 256 "Cannot set hangup on close on %s: %s\n", 257 device, sys_errlist[errno]); 258 259 i = resetmodem; 260 261 if (setmodem(device, ENABLE) < 0) { 262 fprintf(stderr, "Cannot Enable modem control\n"); 263 (void)setmodem(device, i); 264 exit(1); 265 } 266 resetmodem=i; 267 268 if (settys(ENABLE)) { 269 fprintf(stderr, "%s already enabled\n", device); 270 } else { 271 pokeinit(device, Uname, enable); 272 } 273 post(device, ""); 274 275 } else { 276 #if defined(TIOCMGET) && defined(SENSECARRIER) 277 if (uid!=0) { 278 int linestat = 0; 279 280 /* check for presence of carrier */ 281 sleep(2); /* need time after modem control turnoff */ 282 283 if((devfile = open(device, 1)) < 0) { 284 fprintf(stderr, "On open of %s: %s\n", 285 device, sys_errlist[errno]); 286 (void)setmodem(device, resetmodem); 287 exit(1); 288 } 289 290 (void)ioctl(devfile, TIOCMGET, &linestat); 291 292 if (linestat&TIOCM_CAR) { 293 fprintf(stderr, "%s is in use (Carrier On)\n", 294 device); 295 (void)setmodem(device, resetmodem); 296 exit(2); 297 } 298 (void)close(devfile); 299 } 300 #endif TIOCMGET 301 /* chown device */ 302 if(chown(device, uid, gid) < 0) 303 fprintf(stderr, "Cannot chown %s: %s\n", 304 device, sys_errlist[errno]); 305 306 307 /* poke init */ 308 if(settys(DISABLE)) { 309 fprintf(stderr, "%s already disabled\n", device); 310 } else { 311 pokeinit(device, Uname, enable); 312 } 313 post(device, Uname); 314 if((devfile = open(device, O_RDWR|O_NDELAY)) < 0) { 315 fprintf(stderr, "On %s open: %s\n", 316 device, sys_errlist[errno]); 317 } else { 318 if(ioctl(devfile, (int)TIOCSDTR, (char *)0) < 0) 319 fprintf(stderr, 320 "Cannot set DTR on %s: %s\n", 321 device, sys_errlist[errno]); 322 } 323 } 324 325 exit(0); 326 } 327 328 /* return true if no lower case */ 329 upcase(str, len) 330 register char *str; 331 register int len; 332 { 333 for (; *str, --len >= 0 ; str++) 334 if (*str>='a' && *str<='z') 335 return(0); 336 return(1); 337 } 338 339 /* Post name to public */ 340 post(device, name) 341 char *device, *name; 342 { 343 (void)time((time_t *)&utmp.ut_time); 344 strncpy(utmp.ut_line, device, LINSIZ); 345 strncpy(utmp.ut_name, name, NAMSIZ); 346 if (lseek(etcutmp, utmploc, 0) < 0) 347 fprintf(stderr, "on lseek in /etc/utmp: %s", 348 sys_errlist[errno]); 349 if (write(etcutmp, (char *)&utmp, sizeof(utmp)) < 0) 350 fprintf(stderr, "on write in /etc/utmp: %s", 351 sys_errlist[errno]); 352 } 353 354 /* poke process 1 and wait for it to do its thing */ 355 pokeinit(device, uname, enable) 356 char *uname, *device; int enable; 357 { 358 struct utmp utmp; 359 register int i; 360 361 post(device, uname); 362 363 /* poke init */ 364 if (kill(1, SIGHUP)) { 365 fprintf(stderr, 366 "Cannot send hangup to init process: %s\n", 367 sys_errlist[errno]); 368 (void)settys(resettty); 369 (void)setmodem(device, resetmodem); 370 exit(1); 371 } 372 373 if (enable) 374 return; 375 376 /* wait till init has responded, clearing the utmp entry */ 377 i = 100; 378 do { 379 sleep(1); 380 if (lseek(etcutmp, utmploc, 0) < 0) 381 fprintf(stderr, "On lseek in /etc/utmp: %s", 382 sys_errlist[errno]); 383 if (read(etcutmp, (char *)&utmp, sizeof utmp) < 0) 384 fprintf(stderr, "On read from /etc/utmp: %s", 385 sys_errlist[errno]); 386 } while (utmp.ut_name[0] != '\0' && --i > 0); 387 } 388 389 #ifdef BSD4_3 390 /* identify terminal line in ttys */ 391 opnttys(device) 392 char *device; 393 { 394 register int ndevice; 395 register char *p; 396 char *index(); 397 char linebuf[BUFSIZ]; 398 399 ttysfile = NULL; 400 do { 401 if (ttysfile != NULL) { 402 fclose(ttysfile); 403 sleep(5); 404 } 405 ttysfile = fopen(Etcttys, "r"); 406 if(ttysfile == NULL) { 407 fprintf(stderr, "Cannot open %s: %s\n", Etcttys, 408 sys_errlist[errno]); 409 exit(1); 410 } 411 } while (flock(fileno(ttysfile), LOCK_NB|LOCK_EX) < 0); 412 nttysfile = fopen(NEtcttys, "w"); 413 if(nttysfile == NULL) { 414 fprintf(stderr, "Cannot open %s: %s\n", Etcttys, 415 sys_errlist[errno]); 416 exit(1); 417 } 418 419 ndevice = strlen(device); 420 #ifndef BRL4_2 421 utmploc = sizeof(utmp); 422 #else BRL4_2 423 utmploc = 0; 424 #endif BRL4_2 425 426 while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) { 427 if(strncmp(device, linebuf, ndevice) == 0) 428 return; 429 ttyslnbeg += strlen(linebuf); 430 if (linebuf[0] != '#' && linebuf[0] != '\0') 431 utmploc += sizeof(utmp); 432 if (fputs(linebuf, nttysfile) == NULL) { 433 fprintf(stderr, "On %s write: %s\n", 434 Etcttys, sys_errlist[errno]); 435 exit(1); 436 } 437 438 } 439 fprintf(stderr, "%s not found in %s\n", device, Etcttys); 440 exit(1); 441 } 442 443 /* modify appropriate line in /etc/ttys to turn on/off the device */ 444 settys(enable) 445 int enable; 446 { 447 register char *cp, *cp2; 448 char lbuf[BUFSIZ]; 449 int i; 450 char c1, c2; 451 452 (void) fseek(ttysfile, ttyslnbeg, 0); 453 if(fgets(lbuf, BUFSIZ, ttysfile) == NULL) { 454 fprintf(stderr, "On %s read: %s\n", 455 Etcttys, sys_errlist[errno]); 456 exit(1); 457 } 458 /* format is now */ 459 /* ttyd0 std.100 dialup on secure # comment */ 460 /* except, 2nd item may have embedded spaces inside quotes, Hubert */ 461 cp = lbuf; 462 for (i=0;*cp && i<3;i++) { 463 if (*cp == '"') { 464 cp++; 465 while (*cp && *cp != '"') 466 cp++; 467 if (*cp != '\0') 468 cp++; 469 }else { 470 while (*cp && *cp != ' ' && *cp != '\t') 471 cp++; 472 } 473 while (*cp && (*cp == ' ' || *cp == '\t')) 474 cp++; 475 } 476 if (*cp == '\0') { 477 fprintf(stderr,"Badly formatted line in /etc/ttys:\n%s", lbuf); 478 exit(1); 479 } 480 c1 = *--cp; 481 *cp++ = '\0'; 482 cp2 = cp; 483 while (*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') 484 cp++; 485 if (*cp == '\0') { 486 fprintf(stderr,"Badly formatted line in /etc/ttys:\n%s", lbuf); 487 exit(1); 488 } 489 c2 = *cp; 490 *cp++ = '\0'; 491 while (*cp && (*cp == ' ' || *cp == '\t')) 492 cp++; 493 resettty = strcmp("on", cp2) != 0; 494 fprintf(nttysfile,"%s%c%s%c%s", lbuf, c1, enable ? "on" : "off", c2, cp); 495 if (ferror(nttysfile)) { 496 fprintf(stderr, "On %s fprintf: %s\n", 497 NEtcttys, sys_errlist[errno]); 498 exit(1); 499 } 500 while(fgets(lbuf, sizeof(lbuf) - 1, ttysfile) != NULL) { 501 if (fputs(lbuf, nttysfile) == NULL) { 502 fprintf(stderr, "On %s write: %s\n", 503 NEtcttys, sys_errlist[errno]); 504 exit(1); 505 } 506 } 507 508 if (enable^resettty) 509 (void) unlink(NEtcttys); 510 else { 511 struct stat statb; 512 if (stat(Etcttys, &statb) == 0) { 513 fchmod(fileno(nttysfile) ,statb.st_mode); 514 fchown(fileno(nttysfile), statb.st_uid, statb.st_gid); 515 } 516 (void) rename(NEtcttys, Etcttys); 517 } 518 (void) fclose(nttysfile); 519 (void) fclose(ttysfile); 520 return enable^resettty; 521 } 522 523 #else !BSD4_3 524 525 /* identify terminal line in ttys */ 526 opnttys(device) 527 char *device; 528 { 529 register FILE *ttysfile; 530 register int ndevice, lnsiz; 531 register char *p; 532 char *index(); 533 char linebuf[BUFSIZ]; 534 535 ttysfile = fopen(Etcttys, "r"); 536 if(ttysfile == NULL) { 537 fprintf(stderr, "Cannot open %s: %s\n", Etcttys, 538 sys_errlist[errno]); 539 exit(1); 540 } 541 542 ndevice = strlen(device); 543 ttyslnbeg = 0; 544 utmploc = 0; 545 546 while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) { 547 lnsiz = strlen(linebuf); 548 if ((p = index(linebuf, '\n')) != NULL) 549 *p = '\0'; 550 if(strncmp(device, &linebuf[2], ndevice) == 0) { 551 (void)fclose(ttysfile); 552 return; 553 } 554 ttyslnbeg += lnsiz; 555 utmploc += sizeof(utmp); 556 } 557 fprintf(stderr, "%s not found in %s\n", device, Etcttys); 558 exit(1); 559 } 560 561 /* modify appropriate line in /etc/ttys to turn on/off the device */ 562 settys(enable) 563 int enable; 564 { 565 int ittysfil; 566 char out, in; 567 568 ittysfil = open(Etcttys, 2); 569 if(ittysfil < 0) { 570 fprintf(stderr, "Cannot open %s for output: %s\n", 571 Etcttys, sys_errlist[errno]); 572 exit(1); 573 } 574 (void)lseek(ittysfil, ttyslnbeg, 0); 575 if(read(ittysfil, &in, 1)<0) { 576 fprintf(stderr, "On %s write: %s\n", 577 Etcttys, sys_errlist[errno]); 578 exit(1); 579 } 580 resettty = (in == '1'); 581 out = enable ? '1' : '0'; 582 (void)lseek(ittysfil, ttyslnbeg, 0); 583 if(write(ittysfil, &out, 1)<0) { 584 fprintf(stderr, "On %s write: %s\n", 585 Etcttys, sys_errlist[errno]); 586 exit(1); 587 } 588 (void)close(ittysfil); 589 return(in==out); 590 } 591 #endif !BSD4_3 592 593 /* 594 * Excerpted from (June 8, 1983 W.Sebok) 595 * > ttymodem.c - enable/disable modem control for tty lines. 596 * > 597 * > Knows about DZ11s and DH11/DM11s. 598 * > 23.3.83 - TS 599 * > modified to know about DMF's (hasn't been tested) Nov 8, 1984 - WLS 600 */ 601 602 603 setmodem(ttyline, enable) 604 char *ttyline; int enable; 605 { 606 dev_t dev; 607 int kmem; 608 int unit, line, nlines, addr, tflags; 609 int devtype=0; 610 char cflags; short sflags; 611 #ifdef BSD4_2 612 int flags; 613 #else 614 short flags; 615 #endif 616 struct uba_device *ubinfo; 617 struct stat statb; 618 struct cdevsw cdevsw; 619 620 if(nl[CDEVSW].n_type == 0) { 621 fprintf(stderr, "No namelist.\n"); 622 return(-1); 623 } 624 625 if((kmem = open("/dev/kmem", 2)) < 0) { 626 fprintf(stderr, "/dev/kmem open: %s\n", sys_errlist[errno]); 627 return(-1); 628 } 629 630 if(stat(ttyline, &statb) < 0) { 631 fprintf(stderr, "%s stat: %s\n", ttyline, sys_errlist[errno]); 632 return(-1); 633 } 634 635 if((statb.st_mode&S_IFMT) != S_IFCHR) { 636 fprintf(stderr, "%s is not a character device.\n",ttyline); 637 return(-1); 638 } 639 640 dev = statb.st_rdev; 641 (void)lseek(kmem, 642 (off_t) &(((struct cdevsw *)NLVALUE(CDEVSW))[major(dev)]),0); 643 (void)read(kmem, (char *) &cdevsw, sizeof cdevsw); 644 645 if((int)(cdevsw.d_open) == NLVALUE(DZOPEN)) { 646 devtype = DZ11; 647 unit = minor(dev) / NDZLINE; 648 line = minor(dev) % NDZLINE; 649 addr = (int) &(((int *)NLVALUE(DZINFO))[unit]); 650 (void)lseek(kmem, (off_t) NLVALUE(NDZ11), 0); 651 } else if((int)(cdevsw.d_open) == NLVALUE(DHOPEN)) { 652 devtype = DH11; 653 unit = minor(dev) / NDHLINE; 654 line = minor(dev) % NDHLINE; 655 addr = (int) &(((int *)NLVALUE(DHINFO))[unit]); 656 (void)lseek(kmem, (off_t) NLVALUE(NDH11), 0); 657 } else if((int)(cdevsw.d_open) == NLVALUE(DMFOPEN)) { 658 devtype = DMF; 659 unit = minor(dev) / NDMFLINE; 660 line = minor(dev) % NDMFLINE; 661 addr = (int) &(((int *)NLVALUE(DMFINFO))[unit]); 662 (void)lseek(kmem, (off_t) NLVALUE(NDMF), 0); 663 } else { 664 fprintf(stderr, "Device %s (%d/%d) unknown.\n", ttyline, 665 major(dev), minor(dev)); 666 return(-1); 667 } 668 669 (void)read(kmem, (char *) &nlines, sizeof nlines); 670 if(minor(dev) >= nlines) { 671 fprintf(stderr, "Sub-device %d does not exist (only %d).\n", 672 minor(dev), nlines); 673 return(-1); 674 } 675 676 (void)lseek(kmem, (off_t)addr, 0); 677 (void)read(kmem, (char *) &ubinfo, sizeof ubinfo); 678 (void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0); 679 (void)read(kmem, (char *) &flags, sizeof flags); 680 681 tflags = 1<<line; 682 resetmodem = ((flags&tflags) == 0); 683 flags = enable ? (flags & ~tflags) : (flags | tflags); 684 (void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0); 685 (void)write(kmem, (char *) &flags, sizeof flags); 686 switch(devtype) { 687 case DZ11: 688 if((addr = NLVALUE(DZSCAR)) == 0) { 689 fprintf(stderr, "No dzsoftCAR.\n"); 690 return(-1); 691 } 692 cflags = flags; 693 (void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0); 694 (void)write(kmem, (char *) &cflags, sizeof cflags); 695 break; 696 case DH11: 697 if((addr = NLVALUE(DHSCAR)) == 0) { 698 fprintf(stderr, "No dhsoftCAR.\n"); 699 return(-1); 700 } 701 sflags = flags; 702 (void)lseek(kmem, (off_t) &(((short *)addr)[unit]), 0); 703 (void)write(kmem, (char *) &sflags, sizeof sflags); 704 break; 705 case DMF: 706 if((addr = NLVALUE(DMFSCAR)) == 0) { 707 fprintf(stderr, "No dmfsoftCAR.\n"); 708 return(-1); 709 } 710 cflags = flags; 711 (void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0); 712 (void)write(kmem, (char *) &flags, sizeof cflags); 713 break; 714 default: 715 fprintf(stderr, "Unknown device type\n"); 716 return(-1); 717 } 718 return(0); 719 } 720 721 prefix(s1, s2) 722 register char *s1, *s2; 723 { 724 register char c; 725 726 while ((c = *s1++) == *s2++) 727 if (c == '\0') 728 return (1); 729 return (c == '\0'); 730 } 731