1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program (see the file COPYING); if not, write to the 18 * Free Software Foundation, Inc., 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 * 21 **************************************************************** 22 */ 23 24#include <sys/types.h> 25#include <sys/stat.h> /* mkdir() declaration */ 26#include <signal.h> 27 28#include "config.h" 29#include "screen.h" 30#include "extern.h" 31 32#ifdef SVR4 33# include <sys/resource.h> 34#endif 35 36extern struct layer *flayer; 37 38extern int eff_uid, real_uid; 39extern int eff_gid, real_gid; 40extern struct mline mline_old; 41extern struct mchar mchar_blank; 42extern unsigned char *null, *blank; 43 44#ifdef HAVE_FDWALK 45static int close_func __P((void *, int)); 46#endif 47 48char * 49SaveStr(str) 50register const char *str; 51{ 52 register char *cp; 53 54 if ((cp = malloc(strlen(str) + 1)) == NULL) 55 Panic(0, strnomem); 56 else 57 strcpy(cp, str); 58 return cp; 59} 60 61char * 62SaveStrn(str, n) 63register const char *str; 64int n; 65{ 66 register char *cp; 67 68 if ((cp = malloc(n + 1)) == NULL) 69 Panic(0, strnomem); 70 else 71 { 72 bcopy((char *)str, cp, n); 73 cp[n] = 0; 74 } 75 return cp; 76} 77 78/* cheap strstr replacement */ 79char * 80InStr(str, pat) 81char *str; 82const char *pat; 83{ 84 int npat = strlen(pat); 85 for (;*str; str++) 86 if (!strncmp(str, pat, npat)) 87 return str; 88 return 0; 89} 90 91#ifndef HAVE_STRERROR 92char * 93strerror(err) 94int err; 95{ 96 extern int sys_nerr; 97 extern char *sys_errlist[]; 98 99 static char er[20]; 100 if (err > 0 && err < sys_nerr) 101 return sys_errlist[err]; 102 sprintf(er, "Error %d", err); 103 return er; 104} 105#endif 106 107void 108centerline(str, y) 109char *str; 110int y; 111{ 112 int l, n; 113 114 ASSERT(flayer); 115 n = strlen(str); 116 if (n > flayer->l_width - 1) 117 n = flayer->l_width - 1; 118 l = (flayer->l_width - 1 - n) / 2; 119 LPutStr(flayer, str, n, &mchar_blank, l, y); 120} 121 122void 123leftline(str, y) 124char *str; 125int y; 126{ 127 int l, n; 128 struct mchar mchar_dol; 129 130 mchar_dol = mchar_blank; 131 mchar_dol.image = '$'; 132 133 ASSERT(flayer); 134 l = n = strlen(str); 135 if (n > flayer->l_width - 1) 136 n = flayer->l_width - 1; 137 LPutStr(flayer, str, n, &mchar_blank, 0, y); 138 if (n != l) 139 LPutChar(flayer, &mchar_dol, n, y); 140} 141 142 143char * 144Filename(s) 145char *s; 146{ 147 register char *p = s; 148 149 if (p) 150 while (*p) 151 if (*p++ == '/') 152 s = p; 153 return s; 154} 155 156char * 157stripdev(nam) 158char *nam; 159{ 160#ifdef apollo 161 char *p; 162 163 if (nam == NULL) 164 return NULL; 165# ifdef SVR4 166 /* unixware has /dev/pts012 as synonym for /dev/pts/12 */ 167 if (!strncmp(nam, "/dev/pts", 8) && nam[8] >= '0' && nam[8] <= '9') 168 { 169 static char b[13]; 170 sprintf(b, "pts/%d", atoi(nam + 8)); 171 return b; 172 } 173# endif /* SVR4 */ 174 if (p = strstr(nam,"/dev/")) 175 return p + 5; 176#else /* apollo */ 177 if (nam == NULL) 178 return NULL; 179 if (strncmp(nam, "/dev/", 5) == 0) 180 return nam + 5; 181#endif /* apollo */ 182 return nam; 183} 184 185 186/* 187 * Signal handling 188 */ 189 190#ifdef POSIX 191sigret_t (*xsignal(sig, func)) 192# ifndef __APPLE__ 193 __P(SIGPROTOARG) 194# else 195() 196# endif 197int sig; 198sigret_t (*func) __P(SIGPROTOARG); 199{ 200 struct sigaction osa, sa; 201 sa.sa_handler = func; 202 (void)sigemptyset(&sa.sa_mask); 203#ifdef SA_RESTART 204 sa.sa_flags = (sig == SIGCHLD ? SA_RESTART : 0); 205#else 206 sa.sa_flags = 0; 207#endif 208 if (sigaction(sig, &sa, &osa)) 209 return (sigret_t (*)__P(SIGPROTOARG))-1; 210 return osa.sa_handler; 211} 212 213#else 214# ifdef hpux 215/* 216 * hpux has berkeley signal semantics if we use sigvector, 217 * but not, if we use signal, so we define our own signal() routine. 218 */ 219void (*xsignal(sig, func)) __P(SIGPROTOARG) 220int sig; 221void (*func) __P(SIGPROTOARG); 222{ 223 struct sigvec osv, sv; 224 225 sv.sv_handler = func; 226 sv.sv_mask = sigmask(sig); 227 sv.sv_flags = SV_BSDSIG; 228 if (sigvector(sig, &sv, &osv) < 0) 229 return (void (*)__P(SIGPROTOARG))(BADSIG); 230 return osv.sv_handler; 231} 232# endif /* hpux */ 233#endif /* POSIX */ 234 235 236/* 237 * uid/gid handling 238 */ 239 240#ifdef HAVE_SETEUID 241 242void 243xseteuid(euid) 244int euid; 245{ 246 if (seteuid(euid) == 0) 247 return; 248 seteuid(0); 249 if (seteuid(euid)) 250 Panic(errno, "seteuid"); 251} 252 253void 254xsetegid(egid) 255int egid; 256{ 257 if (setegid(egid)) 258 Panic(errno, "setegid"); 259} 260 261#else /* HAVE_SETEUID */ 262# ifdef HAVE_SETREUID 263 264void 265xseteuid(euid) 266int euid; 267{ 268 int oeuid; 269 270 oeuid = geteuid(); 271 if (oeuid == euid) 272 return; 273 if ((int)getuid() != euid) 274 oeuid = getuid(); 275 if (setreuid(oeuid, euid)) 276 Panic(errno, "setreuid"); 277} 278 279void 280xsetegid(egid) 281int egid; 282{ 283 int oegid; 284 285 oegid = getegid(); 286 if (oegid == egid) 287 return; 288 if ((int)getgid() != egid) 289 oegid = getgid(); 290 if (setregid(oegid, egid)) 291 Panic(errno, "setregid"); 292} 293 294# endif /* HAVE_SETREUID */ 295#endif /* HAVE_SETEUID */ 296 297 298 299#ifdef NEED_OWN_BCOPY 300void 301xbcopy(s1, s2, len) 302register char *s1, *s2; 303register int len; 304{ 305 if (s1 < s2 && s2 < s1 + len) 306 { 307 s1 += len; 308 s2 += len; 309 while (len-- > 0) 310 *--s2 = *--s1; 311 } 312 else 313 while (len-- > 0) 314 *s2++ = *s1++; 315} 316#endif /* NEED_OWN_BCOPY */ 317 318void 319bclear(p, n) 320char *p; 321int n; 322{ 323 bcopy((char *)blank, p, n); 324} 325 326 327void 328Kill(pid, sig) 329int pid, sig; 330{ 331 if (pid < 2) 332 return; 333 (void) kill(pid, sig); 334} 335 336#ifdef HAVE_FDWALK 337/* 338 * Modern versions of Solaris include fdwalk(3c) which allows efficient 339 * implementation of closing open descriptors; this is helpful because 340 * the default file descriptor limit has risen to 65k. 341 */ 342static int 343close_func(cb_data, fd) 344void *cb_data; 345int fd; 346{ 347 int except = *(int *)cb_data; 348 if (fd > 2 && fd != except) 349 (void)close(fd); 350 return (0); 351} 352 353void 354closeallfiles(except) 355int except; 356{ 357 (void)fdwalk(close_func, &except); 358} 359 360#else /* HAVE_FDWALK */ 361 362void 363closeallfiles(except) 364int except; 365{ 366 int f; 367#ifdef SVR4 368 struct rlimit rl; 369 370 if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) && rl.rlim_max != RLIM_INFINITY) 371 f = rl.rlim_max; 372 else 373#endif /* SVR4 */ 374#if defined(SYSV) && defined(NOFILE) && !defined(ISC) 375 f = NOFILE; 376#else /* SYSV && !ISC */ 377 f = getdtablesize(); 378#endif /* SYSV && !ISC */ 379 while (--f > 2) 380 if (f != except) 381 close(f); 382} 383 384#endif /* HAVE_FDWALK */ 385 386 387/* 388 * Security - switch to real uid 389 */ 390 391#ifndef USE_SETEUID 392static int UserPID; 393static sigret_t (*Usersigcld)__P(SIGPROTOARG); 394#endif 395static int UserSTAT; 396 397int 398UserContext() 399{ 400#ifndef USE_SETEUID 401 if (eff_uid == real_uid && eff_gid == real_gid) 402 return 1; 403 Usersigcld = signal(SIGCHLD, SIG_DFL); 404 debug("UserContext: forking.\n"); 405 switch (UserPID = fork()) 406 { 407 case -1: 408 Msg(errno, "fork"); 409 return -1; 410 case 0: 411 signal(SIGHUP, SIG_DFL); 412 signal(SIGINT, SIG_IGN); 413 signal(SIGQUIT, SIG_DFL); 414 signal(SIGTERM, SIG_DFL); 415# ifdef BSDJOBS 416 signal(SIGTTIN, SIG_DFL); 417 signal(SIGTTOU, SIG_DFL); 418# endif 419 setuid(real_uid); 420 setgid(real_gid); 421 return 1; 422 default: 423 return 0; 424 } 425#else 426 xseteuid(real_uid); 427 xsetegid(real_gid); 428 return 1; 429#endif 430} 431 432void 433UserReturn(val) 434int val; 435{ 436#ifndef USE_SETEUID 437 if (eff_uid == real_uid && eff_gid == real_gid) 438 UserSTAT = val; 439 else 440 _exit(val); 441#else 442 xseteuid(eff_uid); 443 xsetegid(eff_gid); 444 UserSTAT = val; 445#endif 446} 447 448int 449UserStatus() 450{ 451#ifndef USE_SETEUID 452 int i; 453# ifdef BSDWAIT 454 union wait wstat; 455# else 456 int wstat; 457# endif 458 459 if (eff_uid == real_uid && eff_gid == real_gid) 460 return UserSTAT; 461 if (UserPID < 0) 462 return -1; 463 while ((errno = 0, i = wait(&wstat)) != UserPID) 464 if (i < 0 && errno != EINTR) 465 break; 466 (void) signal(SIGCHLD, Usersigcld); 467 if (i == -1) 468 return -1; 469 return WEXITSTATUS(wstat); 470#else 471 return UserSTAT; 472#endif 473} 474 475#ifndef HAVE_RENAME 476int 477rename (old, new) 478char *old; 479char *new; 480{ 481 if (link(old, new) < 0) 482 return -1; 483 return unlink(old); 484} 485#endif 486 487 488int 489AddXChar(buf, ch) 490char *buf; 491int ch; 492{ 493 char *p = buf; 494 495 if (ch < ' ' || ch == 0x7f) 496 { 497 *p++ = '^'; 498 *p++ = ch ^ 0x40; 499 } 500 else if (ch >= 0x80) 501 { 502 *p++ = '\\'; 503 *p++ = (ch >> 6 & 7) + '0'; 504 *p++ = (ch >> 3 & 7) + '0'; 505 *p++ = (ch >> 0 & 7) + '0'; 506 } 507 else 508 *p++ = ch; 509 return p - buf; 510} 511 512int 513AddXChars(buf, len, str) 514char *buf, *str; 515int len; 516{ 517 char *p; 518 519 if (str == 0) 520 { 521 *buf = 0; 522 return 0; 523 } 524 len -= 4; /* longest sequence produced by AddXChar() */ 525 for (p = buf; p < buf + len && *str; str++) 526 { 527 if (*str == ' ') 528 *p++ = *str; 529 else 530 p += AddXChar(p, *str); 531 } 532 *p = 0; 533 return p - buf; 534} 535 536 537#ifdef DEBUG 538void 539opendebug(new, shout) 540int new, shout; 541{ 542 char buf[256]; 543 544#ifdef _MODE_T 545 mode_t oumask = umask(0); 546#else 547 int oumask = umask(0); 548#endif 549 550 ASSERT(!dfp); 551 552 (void) mkdir(DEBUGDIR, 0777); 553 sprintf(buf, shout ? "%s/SCREEN.%d" : "%s/screen.%d", DEBUGDIR, getpid()); 554 if (!(dfp = fopen(buf, new ? "w" : "a"))) 555 dfp = stderr; 556 else 557 (void)chmod(buf, 0666); 558 559 (void)umask(oumask); 560 debug("opendebug: done.\n"); 561} 562#endif /* DEBUG */ 563 564void 565sleep1000(msec) 566int msec; 567 568{ 569 struct timeval t; 570 571 t.tv_sec = (long) (msec / 1000); 572 t.tv_usec = (long) ((msec % 1000) * 1000); 573 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); 574} 575 576 577/* 578 * This uses either setenv() or putenv(). If it is putenv() we cannot dare 579 * to free the buffer after putenv(), unless it it the one found in putenv.c 580 */ 581void 582xsetenv(var, value) 583char *var; 584char *value; 585{ 586#ifndef USESETENV 587 char *buf; 588 int l; 589 590 if ((buf = (char *)malloc((l = strlen(var)) + 591 strlen(value) + 2)) == NULL) 592 { 593 Msg(0, strnomem); 594 return; 595 } 596 strcpy(buf, var); 597 buf[l] = '='; 598 strcpy(buf + l + 1, value); 599 putenv(buf); 600# ifdef NEEDPUTENV 601 /* 602 * we use our own putenv(), knowing that it does a malloc() 603 * the string space, we can free our buf now. 604 */ 605 free(buf); 606# else /* NEEDSETENV */ 607 /* 608 * For all sysv-ish systems that link a standard putenv() 609 * the string-space buf is added to the environment and must not 610 * be freed, or modified. 611 * We are sorry to say that memory is lost here, when setting 612 * the same variable again and again. 613 */ 614# endif /* NEEDSETENV */ 615#else /* USESETENV */ 616# if defined(linux) || defined(__convex__) || (BSD >= 199103) 617 setenv(var, value, 1); 618# else 619 setenv(var, value); 620# endif /* linux || convex || BSD >= 199103 */ 621#endif /* USESETENV */ 622} 623 624#ifdef TERMINFO 625/* 626 * This is a replacement for the buggy _delay function from the termcap 627 * emulation of libcurses, which ignores ospeed. 628 */ 629int 630_delay(delay, outc) 631register int delay; 632int (*outc) __P((int)); 633{ 634 int pad; 635 extern short ospeed; 636 static short osp2pad[] = { 637 0,2000,1333,909,743,666,500,333,166,83,55,41,20,10,5,2,1,1 638 }; 639 640 if (ospeed <= 0 || ospeed >= (int)(sizeof(osp2pad)/sizeof(*osp2pad))) 641 return 0; 642 pad =osp2pad[ospeed]; 643 delay = (delay + pad / 2) / pad; 644 while (delay-- > 0) 645 (*outc)(0); 646 return 0; 647} 648 649# ifdef linux 650 651/* stupid stupid linux ncurses! It won't to padding with 652 * zeros but sleeps instead. This breaks CalcCost, of course. 653 * Also, the ncurses wait functions use a global variable 654 * to store the current outc function. Oh well... 655 */ 656 657int (*save_outc) __P((int)); 658 659# undef tputs 660 661void 662xtputs(str, affcnt, outc) 663char *str; 664int affcnt; 665int (*outc) __P((int)); 666{ 667 extern int tputs __P((const char *, int, int (*)(int))); 668 save_outc = outc; 669 tputs(str, affcnt, outc); 670} 671 672int 673_nc_timed_wait(mode, ms, tlp) 674int mode, ms, *tlp; 675{ 676 _delay(ms * 10, save_outc); 677 return 0; 678} 679 680# endif /* linux */ 681 682#endif /* TERMINFO */ 683 684 685 686#ifndef USEVARARGS 687 688# define xva_arg(s, t, tn) (*(t *)(s += xsnoff(tn, 0, 0), s - xsnoff(tn, 0, 0))) 689# define xva_list char * 690 691static int 692xsnoff(a, b, c) 693int a; 694char *b; 695int c; 696{ 697 return a ? (char *)&c - (char *)&b : (char *)&b - (char *)&a; 698} 699 700int 701xsnprintf(s, n, fmt, p1, p2, p3, p4, p5, p6) 702char *s; 703int n; 704char *fmt; 705unsigned long p1, p2, p3, p4, p5, p6; 706{ 707 int xvsnprintf __P((char *, int, char *, xva_list)); 708 return xvsnprintf(s, n, fmt, (char *)&fmt + xsnoff(1, 0, 0)); 709} 710 711#else 712 713# define xva_arg(s, t, tn) va_arg(s, t) 714# define xva_list va_list 715 716#endif 717 718 719#if !defined(USEVARARGS) || !defined(HAVE_VSNPRINTF) 720 721int 722xvsnprintf(s, n, fmt, stack) 723char *s; 724int n; 725char *fmt; 726xva_list stack; 727{ 728 char *f, *sf = 0; 729 int i, on, argl = 0; 730 char myf[10], buf[20]; 731 char *arg, *myfp; 732 733 on = n; 734 f = fmt; 735 arg = 0; 736 while(arg || (sf = index(f, '%')) || (sf = f + strlen(f))) 737 { 738 if (arg == 0) 739 { 740 arg = f; 741 argl = sf - f; 742 } 743 if (argl) 744 { 745 i = argl > n - 1 ? n - 1 : argl; 746 strncpy(s, arg, i); 747 s += i; 748 n -= i; 749 if (i < argl) 750 { 751 *s = 0; 752 return on; 753 } 754 } 755 arg = 0; 756 if (sf == 0) 757 continue; 758 f = sf; 759 sf = 0; 760 if (!*f) 761 break; 762 myfp = myf; 763 *myfp++ = *f++; 764 while (((*f >= '0' && *f <='9') || *f == '#') && myfp - myf < 8) 765 *myfp++ = *f++; 766 *myfp++ = *f; 767 *myfp = 0; 768 if (!*f++) 769 break; 770 switch(f[-1]) 771 { 772 case '%': 773 arg = "%"; 774 break; 775 case 'c': 776 case 'o': 777 case 'd': 778 case 'x': 779 i = xva_arg(stack, int, 0); 780 sprintf(buf, myf, i); 781 arg = buf; 782 break; 783 case 's': 784 arg = xva_arg(stack, char *, 1); 785 if (arg == 0) 786 arg = "NULL"; 787 break; 788 default: 789 arg = ""; 790 break; 791 } 792 argl = strlen(arg); 793 } 794 *s = 0; 795 return on - n; 796} 797 798#endif 799