10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include "ex.h" 350Sstevel@tonic-gate #include "ex_argv.h" 360Sstevel@tonic-gate #include "ex_temp.h" 370Sstevel@tonic-gate #include "ex_tty.h" 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <locale.h> 400Sstevel@tonic-gate #include <stdio.h> 410Sstevel@tonic-gate #ifdef TRACE 420Sstevel@tonic-gate unsigned char tttrace[BUFSIZ]; 430Sstevel@tonic-gate #endif 440Sstevel@tonic-gate 450Sstevel@tonic-gate #define EQ(a, b) (strcmp(a, b) == 0) 460Sstevel@tonic-gate 470Sstevel@tonic-gate char *strrchr(); 480Sstevel@tonic-gate void init_re(void); 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * The code for ex is divided as follows: 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * ex.c Entry point and routines handling interrupt, hangup 540Sstevel@tonic-gate * signals; initialization code. 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * ex_addr.c Address parsing routines for command mode decoding. 570Sstevel@tonic-gate * Routines to set and check address ranges on commands. 580Sstevel@tonic-gate * 590Sstevel@tonic-gate * ex_cmds.c Command mode command decoding. 600Sstevel@tonic-gate * 610Sstevel@tonic-gate * ex_cmds2.c Subroutines for command decoding and processing of 620Sstevel@tonic-gate * file names in the argument list. Routines to print 630Sstevel@tonic-gate * messages and reset state when errors occur. 640Sstevel@tonic-gate * 650Sstevel@tonic-gate * ex_cmdsub.c Subroutines which implement command mode functions 660Sstevel@tonic-gate * such as append, delete, join. 670Sstevel@tonic-gate * 680Sstevel@tonic-gate * ex_data.c Initialization of options. 690Sstevel@tonic-gate * 700Sstevel@tonic-gate * ex_get.c Command mode input routines. 710Sstevel@tonic-gate * 720Sstevel@tonic-gate * ex_io.c General input/output processing: file i/o, unix 730Sstevel@tonic-gate * escapes, filtering, source commands, preserving 740Sstevel@tonic-gate * and recovering. 750Sstevel@tonic-gate * 760Sstevel@tonic-gate * ex_put.c Terminal driving and optimizing routines for low-level 770Sstevel@tonic-gate * output (cursor-positioning); output line formatting 780Sstevel@tonic-gate * routines. 790Sstevel@tonic-gate * 800Sstevel@tonic-gate * ex_re.c Global commands, substitute, regular expression 810Sstevel@tonic-gate * compilation and execution. 820Sstevel@tonic-gate * 830Sstevel@tonic-gate * ex_set.c The set command. 840Sstevel@tonic-gate * 850Sstevel@tonic-gate * ex_subr.c Loads of miscellaneous subroutines. 860Sstevel@tonic-gate * 870Sstevel@tonic-gate * ex_temp.c Editor buffer routines for main buffer and also 880Sstevel@tonic-gate * for named buffers (Q registers if you will.) 890Sstevel@tonic-gate * 900Sstevel@tonic-gate * ex_tty.c Terminal dependent initializations from termcap 910Sstevel@tonic-gate * data base, grabbing of tty modes (at beginning 920Sstevel@tonic-gate * and after escapes). 930Sstevel@tonic-gate * 940Sstevel@tonic-gate * ex_unix.c Routines for the ! command and its variations. 950Sstevel@tonic-gate * 960Sstevel@tonic-gate * ex_v*.c Visual/open mode routines... see ex_v.c for a 970Sstevel@tonic-gate * guide to the overall organization. 980Sstevel@tonic-gate */ 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * This sets the Version of ex/vi for both the exstrings file and 1020Sstevel@tonic-gate * the version command (":ver"). 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* variable used by ":ver" command */ 1060Sstevel@tonic-gate unsigned char *Version = (unsigned char *)"Version SVR4.0, Solaris 2.5.0"; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate /* 1090Sstevel@tonic-gate * NOTE: when changing the Version number, it must be changed in the 1100Sstevel@tonic-gate * following files: 1110Sstevel@tonic-gate * 1120Sstevel@tonic-gate * port/READ_ME 1130Sstevel@tonic-gate * port/ex.c 1140Sstevel@tonic-gate * port/ex.news 1150Sstevel@tonic-gate * 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate #ifdef XPG4 1180Sstevel@tonic-gate unsigned char *savepat = (unsigned char *) NULL; /* firstpat storage */ 1190Sstevel@tonic-gate #endif /* XPG4 */ 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Main procedure. Process arguments and then 1230Sstevel@tonic-gate * transfer control to the main command processing loop 1240Sstevel@tonic-gate * in the routine commands. We are entered as either "ex", "edit", "vi" 1250Sstevel@tonic-gate * or "view" and the distinction is made here. For edit we just diddle options; 1260Sstevel@tonic-gate * for vi we actually force an early visual command. 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate static unsigned char cryptkey[19]; /* contents of encryption key */ 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate static void usage(unsigned char *); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate static int validate_exrc(unsigned char *); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate int 1350Sstevel@tonic-gate main(int ac, unsigned char *av[]) 1360Sstevel@tonic-gate { 1370Sstevel@tonic-gate extern char *optarg; 1380Sstevel@tonic-gate extern int optind; 1390Sstevel@tonic-gate unsigned char *rcvname = 0; 1400Sstevel@tonic-gate unsigned char *cp; 1410Sstevel@tonic-gate int c; 1420Sstevel@tonic-gate unsigned char *cmdnam; 1430Sstevel@tonic-gate bool recov = 0; 1440Sstevel@tonic-gate bool ivis = 0; 1450Sstevel@tonic-gate bool itag = 0; 1460Sstevel@tonic-gate bool fast = 0; 1470Sstevel@tonic-gate extern int verbose; 1480Sstevel@tonic-gate int argcounter = 0; 1490Sstevel@tonic-gate extern int tags_flag; /* Set if tag file is not sorted (-S flag) */ 1500Sstevel@tonic-gate unsigned char scratch [PATH_MAX+1]; /* temp for sourcing rc file(s) */ 1510Sstevel@tonic-gate int vret = 0; 1520Sstevel@tonic-gate unsigned char exrcpath [PATH_MAX+1]; /* temp for sourcing rc file(s) */ 1530Sstevel@tonic-gate int toptseen = 0; 1540Sstevel@tonic-gate #ifdef TRACE 1550Sstevel@tonic-gate unsigned char *tracef; 1560Sstevel@tonic-gate #endif 1570Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1580Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 1590Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 1600Sstevel@tonic-gate #endif 1610Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Immediately grab the tty modes so that we won't 1650Sstevel@tonic-gate * get messed up if an interrupt comes in quickly. 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate gTTY(2); 1680Sstevel@tonic-gate normf = tty; 1690Sstevel@tonic-gate ppid = getpid(); 1700Sstevel@tonic-gate /* Note - this will core dump if you didn't -DSINGLE in CFLAGS */ 1710Sstevel@tonic-gate lines = 24; 1720Sstevel@tonic-gate columns = 80; /* until defined right by setupterm */ 1730Sstevel@tonic-gate /* 1740Sstevel@tonic-gate * Defend against d's, v's, w's, and a's in directories of 1750Sstevel@tonic-gate * path leading to our true name. 1760Sstevel@tonic-gate */ 1770Sstevel@tonic-gate if ((cmdnam = (unsigned char *)strrchr(av[0], '/')) != 0) 1780Sstevel@tonic-gate cmdnam++; 1790Sstevel@tonic-gate else 1800Sstevel@tonic-gate cmdnam = av[0]; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate if (EQ(cmdnam, "vi")) 1830Sstevel@tonic-gate ivis = 1; 1840Sstevel@tonic-gate else if (EQ(cmdnam, "view")) { 1850Sstevel@tonic-gate ivis = 1; 1860Sstevel@tonic-gate value(vi_READONLY) = 1; 1870Sstevel@tonic-gate } else if (EQ(cmdnam, "vedit")) { 1880Sstevel@tonic-gate ivis = 1; 1890Sstevel@tonic-gate value(vi_NOVICE) = 1; 1900Sstevel@tonic-gate value(vi_REPORT) = 1; 1910Sstevel@tonic-gate value(vi_MAGIC) = 0; 1920Sstevel@tonic-gate value(vi_SHOWMODE) = 1; 1930Sstevel@tonic-gate } else if (EQ(cmdnam, "edit")) { 1940Sstevel@tonic-gate value(vi_NOVICE) = 1; 1950Sstevel@tonic-gate value(vi_REPORT) = 1; 1960Sstevel@tonic-gate value(vi_MAGIC) = 0; 1970Sstevel@tonic-gate value(vi_SHOWMODE) = 1; 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate #ifdef XPG4 2010Sstevel@tonic-gate { 2020Sstevel@tonic-gate struct winsize jwin; 2030Sstevel@tonic-gate char *envptr; 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate envlines = envcolumns = -1; 2060Sstevel@tonic-gate oldlines = oldcolumns = -1; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate if (ioctl(0, TIOCGWINSZ, &jwin) != -1) { 2090Sstevel@tonic-gate oldlines = jwin.ws_row; 2100Sstevel@tonic-gate oldcolumns = jwin.ws_col; 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate if ((envptr = getenv("LINES")) != NULL && 2140Sstevel@tonic-gate *envptr != '\0' && isdigit(*envptr)) { 2150Sstevel@tonic-gate if ((envlines = atoi(envptr)) <= 0) { 2160Sstevel@tonic-gate envlines = -1; 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate if ((envptr = getenv("COLUMNS")) != NULL && 2210Sstevel@tonic-gate *envptr != '\0' && isdigit(*envptr)) { 2220Sstevel@tonic-gate if ((envcolumns = atoi(envptr)) <= 0) { 2230Sstevel@tonic-gate envcolumns = -1; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate #endif /* XPG4 */ 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate draino(); 2300Sstevel@tonic-gate pstop(); 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2330Sstevel@tonic-gate * Initialize interrupt handling. 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate oldhup = signal(SIGHUP, SIG_IGN); 2360Sstevel@tonic-gate if (oldhup == SIG_DFL) 2370Sstevel@tonic-gate signal(SIGHUP, onhup); 2380Sstevel@tonic-gate oldquit = signal(SIGQUIT, SIG_IGN); 2390Sstevel@tonic-gate ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL; 2400Sstevel@tonic-gate if (signal(SIGTERM, SIG_IGN) == SIG_DFL) 2410Sstevel@tonic-gate signal(SIGTERM, onhup); 2420Sstevel@tonic-gate if (signal(SIGEMT, SIG_IGN) == SIG_DFL) 2430Sstevel@tonic-gate signal(SIGEMT, onemt); 2440Sstevel@tonic-gate signal(SIGILL, oncore); 2450Sstevel@tonic-gate signal(SIGTRAP, oncore); 2460Sstevel@tonic-gate signal(SIGIOT, oncore); 2470Sstevel@tonic-gate signal(SIGFPE, oncore); 2480Sstevel@tonic-gate signal(SIGBUS, oncore); 2490Sstevel@tonic-gate signal(SIGSEGV, oncore); 2500Sstevel@tonic-gate signal(SIGPIPE, oncore); 2510Sstevel@tonic-gate init_re(); 2520Sstevel@tonic-gate while (1) { 2530Sstevel@tonic-gate #ifdef TRACE 2540Sstevel@tonic-gate while ((c = getopt(ac, (char **)av, "VU:Lc:Tvt:rlw:xRCsS")) != 2550Sstevel@tonic-gate EOF) 2560Sstevel@tonic-gate #else 2570Sstevel@tonic-gate while ((c = getopt(ac, (char **)av, 258*597Sceastha "VLc:vt:rlw:xRCsS")) != EOF) 2590Sstevel@tonic-gate #endif 2600Sstevel@tonic-gate switch (c) { 2610Sstevel@tonic-gate case 's': 2620Sstevel@tonic-gate hush = 1; 2630Sstevel@tonic-gate value(vi_AUTOPRINT) = 0; 2640Sstevel@tonic-gate fast++; 2650Sstevel@tonic-gate break; 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate case 'R': 2680Sstevel@tonic-gate value(vi_READONLY) = 1; 2690Sstevel@tonic-gate break; 2700Sstevel@tonic-gate case 'S': 2710Sstevel@tonic-gate tags_flag = 1; 2720Sstevel@tonic-gate break; 2730Sstevel@tonic-gate #ifdef TRACE 2740Sstevel@tonic-gate case 'T': 2750Sstevel@tonic-gate tracef = (unsigned char *)"trace"; 2760Sstevel@tonic-gate goto trace; 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate case 'U': 2790Sstevel@tonic-gate tracef = tttrace; 2800Sstevel@tonic-gate strcpy(tracef, optarg); 2810Sstevel@tonic-gate trace: 2820Sstevel@tonic-gate trace = fopen((char *)tracef, "w"); 2830Sstevel@tonic-gate #define tracbuf NULL 2840Sstevel@tonic-gate if (trace == NULL) 2850Sstevel@tonic-gate printf("Trace create error\n"); 2860Sstevel@tonic-gate else 2870Sstevel@tonic-gate setbuf(trace, (char *)tracbuf); 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate #endif 2900Sstevel@tonic-gate case 'c': 2910Sstevel@tonic-gate if (optarg != NULL) 2920Sstevel@tonic-gate firstpat = (unsigned char *)optarg; 2930Sstevel@tonic-gate else 2940Sstevel@tonic-gate firstpat = (unsigned char *)""; 2950Sstevel@tonic-gate break; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate case 'l': 2980Sstevel@tonic-gate value(vi_LISP) = 1; 2990Sstevel@tonic-gate value(vi_SHOWMATCH) = 1; 3000Sstevel@tonic-gate break; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate case 'r': 3030Sstevel@tonic-gate if (av[optind] && (c = av[optind][0]) && 3040Sstevel@tonic-gate c != '-') { 3050Sstevel@tonic-gate if ((strlen(av[optind])) >= 3060Sstevel@tonic-gate sizeof (savedfile)) { 3070Sstevel@tonic-gate (void) fprintf(stderr, gettext( 308*597Sceastha "Recovered file name" 309*597Sceastha " too long\n")); 3100Sstevel@tonic-gate exit(1); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate rcvname = (unsigned char *)av[optind]; 3140Sstevel@tonic-gate optind++; 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate case 'L': 3180Sstevel@tonic-gate recov++; 3190Sstevel@tonic-gate break; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate case 'V': 3220Sstevel@tonic-gate verbose = 1; 3230Sstevel@tonic-gate break; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate case 't': 3260Sstevel@tonic-gate if (toptseen) { 3270Sstevel@tonic-gate usage(cmdnam); 3280Sstevel@tonic-gate exit(1); 3290Sstevel@tonic-gate } else { 3300Sstevel@tonic-gate toptseen++; 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate itag = 1; 3330Sstevel@tonic-gate if (strlcpy(lasttag, optarg, 3340Sstevel@tonic-gate sizeof (lasttag)) >= sizeof (lasttag)) { 3350Sstevel@tonic-gate (void) fprintf(stderr, gettext("Tag" 3360Sstevel@tonic-gate " file name too long\n")); 3370Sstevel@tonic-gate exit(1); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate break; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate case 'w': 3420Sstevel@tonic-gate defwind = 0; 3430Sstevel@tonic-gate if (optarg[0] == NULL) 3440Sstevel@tonic-gate defwind = 3; 3450Sstevel@tonic-gate else for (cp = (unsigned char *)optarg; 3460Sstevel@tonic-gate isdigit(*cp); cp++) 3470Sstevel@tonic-gate defwind = 10*defwind + *cp - '0'; 3480Sstevel@tonic-gate if (defwind < 0) 3490Sstevel@tonic-gate defwind = 3; 3500Sstevel@tonic-gate break; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate case 'C': 3530Sstevel@tonic-gate crflag = 1; 3540Sstevel@tonic-gate xflag = 1; 3550Sstevel@tonic-gate break; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate case 'x': 3580Sstevel@tonic-gate /* encrypted mode */ 3590Sstevel@tonic-gate xflag = 1; 3600Sstevel@tonic-gate crflag = -1; 3610Sstevel@tonic-gate break; 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate case 'v': 3640Sstevel@tonic-gate ivis = 1; 3650Sstevel@tonic-gate break; 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate default: 3680Sstevel@tonic-gate usage(cmdnam); 3690Sstevel@tonic-gate exit(1); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate if (av[optind] && av[optind][0] == '+' && 3720Sstevel@tonic-gate av[optind-1] && strcmp(av[optind-1], "--")) { 3730Sstevel@tonic-gate firstpat = &av[optind][1]; 3740Sstevel@tonic-gate optind++; 3750Sstevel@tonic-gate continue; 3760Sstevel@tonic-gate } else if (av[optind] && av[optind][0] == '-' && 3770Sstevel@tonic-gate av[optind-1] && strcmp(av[optind-1], "--")) { 3780Sstevel@tonic-gate hush = 1; 3790Sstevel@tonic-gate value(vi_AUTOPRINT) = 0; 3800Sstevel@tonic-gate fast++; 3810Sstevel@tonic-gate optind++; 3820Sstevel@tonic-gate continue; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate break; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 387*597Sceastha if (isatty(0) == 0) { 388*597Sceastha /* 389*597Sceastha * If -V option is set and input is coming in via 390*597Sceastha * stdin then vi behavior should be ignored. The vi 391*597Sceastha * command should act like ex and only process ex commands 392*597Sceastha * and echo the input ex commands to stderr 393*597Sceastha */ 394*597Sceastha if (verbose == 1) { 395*597Sceastha ivis = 0; 396*597Sceastha } 397*597Sceastha 398*597Sceastha /* 399*597Sceastha * If the standard input is not a terminal device, 400*597Sceastha * it is as if the -s option has been specified. 401*597Sceastha */ 402*597Sceastha if (ivis == 0) { 403*597Sceastha hush = 1; 404*597Sceastha value(vi_AUTOPRINT) = 0; 405*597Sceastha fast++; 406*597Sceastha } 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate ac -= optind; 4100Sstevel@tonic-gate av = &av[optind]; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate for (argcounter = 0; argcounter < ac; argcounter++) { 4130Sstevel@tonic-gate if ((strlen(av[argcounter])) >= sizeof (savedfile)) { 4140Sstevel@tonic-gate (void) fprintf(stderr, gettext("File argument" 415*597Sceastha " too long\n")); 4160Sstevel@tonic-gate exit(1); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate #ifdef SIGTSTP 4210Sstevel@tonic-gate if (!hush && signal(SIGTSTP, SIG_IGN) == SIG_DFL) 4220Sstevel@tonic-gate signal(SIGTSTP, onsusp), dosusp++; 4230Sstevel@tonic-gate #endif 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if (xflag) { 4260Sstevel@tonic-gate permflag = 1; 4270Sstevel@tonic-gate if ((kflag = run_setkey(perm, 4280Sstevel@tonic-gate (key = (unsigned char *)getpass( 4290Sstevel@tonic-gate gettext("Enter key:"))))) == -1) { 4300Sstevel@tonic-gate kflag = 0; 4310Sstevel@tonic-gate xflag = 0; 4320Sstevel@tonic-gate smerror(gettext("Encryption facility not available\n")); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate if (kflag == 0) 4350Sstevel@tonic-gate crflag = 0; 4360Sstevel@tonic-gate else { 4370Sstevel@tonic-gate strcpy(cryptkey, "CrYpTkEy=XXXXXXXXX"); 4380Sstevel@tonic-gate strcpy(cryptkey + 9, key); 4390Sstevel@tonic-gate if (putenv((char *)cryptkey) != 0) 4400Sstevel@tonic-gate smerror(gettext(" Cannot copy key to environment")); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate #ifndef PRESUNEUC 4450Sstevel@tonic-gate /* 4460Sstevel@tonic-gate * Perform locale-specific initialization 4470Sstevel@tonic-gate */ 4480Sstevel@tonic-gate (void) localize(); 4490Sstevel@tonic-gate #endif /* PRESUNEUC */ 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * Initialize end of core pointers. 4530Sstevel@tonic-gate * Normally we avoid breaking back to fendcore after each 4540Sstevel@tonic-gate * file since this can be expensive (much core-core copying). 4550Sstevel@tonic-gate * If your system can scatter load processes you could do 4560Sstevel@tonic-gate * this as ed does, saving a little core, but it will probably 4570Sstevel@tonic-gate * not often make much difference. 4580Sstevel@tonic-gate */ 4590Sstevel@tonic-gate fendcore = (line *) sbrk(0); 4600Sstevel@tonic-gate endcore = fendcore - 2; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * If we are doing a recover and no filename 4640Sstevel@tonic-gate * was given, then execute an exrecover command with 4650Sstevel@tonic-gate * the -r option to type out the list of saved file names. 4660Sstevel@tonic-gate * Otherwise set the remembered file name to the first argument 4670Sstevel@tonic-gate * file name so the "recover" initial command will find it. 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate if (recov) { 4700Sstevel@tonic-gate if (ac == 0 && (rcvname == NULL || *rcvname == NULL)) { 4710Sstevel@tonic-gate ppid = 0; 4720Sstevel@tonic-gate setrupt(); 4730Sstevel@tonic-gate execlp(EXRECOVER, "exrecover", "-r", (char *)0); 4740Sstevel@tonic-gate filioerr(EXRECOVER); 4750Sstevel@tonic-gate exit(++errcnt); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate if (rcvname && *rcvname) 4780Sstevel@tonic-gate (void) strlcpy(savedfile, rcvname, sizeof (savedfile)); 4790Sstevel@tonic-gate else { 4800Sstevel@tonic-gate (void) strlcpy(savedfile, *av++, sizeof (savedfile)); 4810Sstevel@tonic-gate ac--; 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* 4860Sstevel@tonic-gate * Initialize the argument list. 4870Sstevel@tonic-gate */ 4880Sstevel@tonic-gate argv0 = av; 4890Sstevel@tonic-gate argc0 = ac; 4900Sstevel@tonic-gate args0 = av[0]; 4910Sstevel@tonic-gate erewind(); 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * Initialize a temporary file (buffer) and 4950Sstevel@tonic-gate * set up terminal environment. Read user startup commands. 4960Sstevel@tonic-gate */ 4970Sstevel@tonic-gate if (setexit() == 0) { 4980Sstevel@tonic-gate setrupt(); 4990Sstevel@tonic-gate intty = isatty(0); 5000Sstevel@tonic-gate value(vi_PROMPT) = intty; 5010Sstevel@tonic-gate if (((cp = (unsigned char *)getenv("SHELL")) != NULL) && 5020Sstevel@tonic-gate (*cp != '\0')) { 5030Sstevel@tonic-gate if (strlen(cp) < sizeof (shell)) { 5040Sstevel@tonic-gate (void) strlcpy(shell, cp, sizeof (shell)); 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate if (fast) 5080Sstevel@tonic-gate setterm("dumb"); 5090Sstevel@tonic-gate else { 5100Sstevel@tonic-gate gettmode(); 5110Sstevel@tonic-gate cp = (unsigned char *)getenv("TERM"); 5120Sstevel@tonic-gate if (cp == NULL || *cp == '\0') 5130Sstevel@tonic-gate cp = (unsigned char *)"unknown"; 5140Sstevel@tonic-gate setterm(cp); 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * Bring up some code from init() 5200Sstevel@tonic-gate * This is still done in init later. This 5210Sstevel@tonic-gate * avoids null pointer problems 5220Sstevel@tonic-gate */ 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate dot = zero = truedol = unddol = dol = fendcore; 5250Sstevel@tonic-gate one = zero+1; 5260Sstevel@tonic-gate { 5270Sstevel@tonic-gate register int i; 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate for (i = 0; i <= 'z'-'a'+1; i++) 5300Sstevel@tonic-gate names[i] = 1; 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate if (setexit() == 0 && !fast) { 5340Sstevel@tonic-gate if ((globp = 535*597Sceastha (unsigned char *) getenv("EXINIT")) && *globp) { 5360Sstevel@tonic-gate if (ivis) 5370Sstevel@tonic-gate inexrc = 1; 5380Sstevel@tonic-gate commands(1, 1); 5390Sstevel@tonic-gate inexrc = 0; 5400Sstevel@tonic-gate } else { 5410Sstevel@tonic-gate globp = 0; 5420Sstevel@tonic-gate if ((cp = (unsigned char *) getenv("HOME")) != 5430Sstevel@tonic-gate 0 && *cp) { 5440Sstevel@tonic-gate strncpy(scratch, cp, sizeof (scratch) - 1); 5450Sstevel@tonic-gate strncat(scratch, "/.exrc", 5460Sstevel@tonic-gate sizeof (scratch) - 1 - strlen(scratch)); 5470Sstevel@tonic-gate if (ivis) 548*597Sceastha inexrc = 1; 5490Sstevel@tonic-gate if ((vret = validate_exrc(scratch)) == 0) { 5500Sstevel@tonic-gate source(scratch, 1); 5510Sstevel@tonic-gate } else { 5520Sstevel@tonic-gate if (vret == -1) { 5530Sstevel@tonic-gate error(gettext( 5540Sstevel@tonic-gate "Not owner of .exrc " 5550Sstevel@tonic-gate "or .exrc is group or " 5560Sstevel@tonic-gate "world writable")); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate inexrc = 0; 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * Allow local .exrc if the "exrc" option was set. This 5650Sstevel@tonic-gate * loses if . is $HOME, but nobody should notice unless 5660Sstevel@tonic-gate * they do stupid things like putting a version command 5670Sstevel@tonic-gate * in .exrc. 5680Sstevel@tonic-gate * Besides, they should be using EXINIT, not .exrc, right? 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate if (value(vi_EXRC)) { 5720Sstevel@tonic-gate if (ivis) 5730Sstevel@tonic-gate inexrc = 1; 5740Sstevel@tonic-gate if ((cp = (unsigned char *) getenv("PWD")) != 0 && 5750Sstevel@tonic-gate *cp) { 5760Sstevel@tonic-gate strncpy(exrcpath, cp, sizeof (exrcpath) - 1); 5770Sstevel@tonic-gate strncat(exrcpath, "/.exrc", 5780Sstevel@tonic-gate sizeof (exrcpath) - 1 - strlen(exrcpath)); 5790Sstevel@tonic-gate if (strcmp(scratch, exrcpath) != 0) { 5800Sstevel@tonic-gate if ((vret = 5810Sstevel@tonic-gate validate_exrc(exrcpath)) == 0) { 5820Sstevel@tonic-gate source(exrcpath, 1); 5830Sstevel@tonic-gate } else { 5840Sstevel@tonic-gate if (vret == -1) { 5850Sstevel@tonic-gate error(gettext( 5860Sstevel@tonic-gate "Not owner of " 5870Sstevel@tonic-gate ".exrc or .exrc " 5880Sstevel@tonic-gate "is group or world " 5890Sstevel@tonic-gate "writable")); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate inexrc = 0; 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate init(); /* moved after prev 2 chunks to fix directory option */ 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /* 6010Sstevel@tonic-gate * Initial processing. Handle tag, recover, and file argument 6020Sstevel@tonic-gate * implied next commands. If going in as 'vi', then don't do 6030Sstevel@tonic-gate * anything, just set initev so we will do it later (from within 6040Sstevel@tonic-gate * visual). 6050Sstevel@tonic-gate */ 6060Sstevel@tonic-gate if (setexit() == 0) { 6070Sstevel@tonic-gate if (recov) 6080Sstevel@tonic-gate globp = (unsigned char *)"recover"; 6090Sstevel@tonic-gate else if (itag) { 6100Sstevel@tonic-gate globp = ivis ? (unsigned char *)"tag" : 6110Sstevel@tonic-gate (unsigned char *)"tag|p"; 6120Sstevel@tonic-gate #ifdef XPG4 6130Sstevel@tonic-gate if (firstpat != NULL) { 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * if the user specified the -t and -c 6160Sstevel@tonic-gate * flags together, then we service these 6170Sstevel@tonic-gate * commands here. -t is handled first. 6180Sstevel@tonic-gate */ 6190Sstevel@tonic-gate savepat = firstpat; 6200Sstevel@tonic-gate firstpat = NULL; 6210Sstevel@tonic-gate inglobal = 1; 6220Sstevel@tonic-gate commands(1, 1); 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* now handle the -c argument: */ 6250Sstevel@tonic-gate globp = savepat; 6260Sstevel@tonic-gate commands(1, 1); 6270Sstevel@tonic-gate inglobal = 0; 6280Sstevel@tonic-gate globp = savepat = NULL; 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate /* the above isn't sufficient for ex mode: */ 6310Sstevel@tonic-gate if (!ivis) { 6320Sstevel@tonic-gate setdot(); 6330Sstevel@tonic-gate nonzero(); 6340Sstevel@tonic-gate plines(addr1, addr2, 1); 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate #endif /* XPG4 */ 6380Sstevel@tonic-gate } else if (argc) 6390Sstevel@tonic-gate globp = (unsigned char *)"next"; 6400Sstevel@tonic-gate if (ivis) 6410Sstevel@tonic-gate initev = globp; 6420Sstevel@tonic-gate else if (globp) { 6430Sstevel@tonic-gate inglobal = 1; 6440Sstevel@tonic-gate commands(1, 1); 6450Sstevel@tonic-gate inglobal = 0; 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * Vi command... go into visual. 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate if (ivis) { 6530Sstevel@tonic-gate /* 6540Sstevel@tonic-gate * Don't have to be upward compatible 6550Sstevel@tonic-gate * by starting editing at line $. 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate #ifdef XPG4 6580Sstevel@tonic-gate if (!itag && (dol > zero)) 6590Sstevel@tonic-gate #else /* XPG4 */ 6600Sstevel@tonic-gate if (dol > zero) 6610Sstevel@tonic-gate #endif /* XPG4 */ 6620Sstevel@tonic-gate dot = one; 6630Sstevel@tonic-gate globp = (unsigned char *)"visual"; 6640Sstevel@tonic-gate if (setexit() == 0) 6650Sstevel@tonic-gate commands(1, 1); 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * Clear out trash in state accumulated by startup, 6700Sstevel@tonic-gate * and then do the main command loop for a normal edit. 6710Sstevel@tonic-gate * If you quit out of a 'vi' command by doing Q or ^\, 6720Sstevel@tonic-gate * you also fall through to here. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate seenprompt = 1; 6750Sstevel@tonic-gate ungetchar(0); 6760Sstevel@tonic-gate globp = 0; 6770Sstevel@tonic-gate initev = 0; 6780Sstevel@tonic-gate setlastchar('\n'); 6790Sstevel@tonic-gate setexit(); 6800Sstevel@tonic-gate commands(0, 0); 6810Sstevel@tonic-gate cleanup(1); 6820Sstevel@tonic-gate exit(errcnt); 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Initialization, before editing a new file. 6870Sstevel@tonic-gate * Main thing here is to get a new buffer (in fileinit), 6880Sstevel@tonic-gate * rest is peripheral state resetting. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate init() 6910Sstevel@tonic-gate { 6920Sstevel@tonic-gate register int i; 6930Sstevel@tonic-gate void (*pstat)(); 6940Sstevel@tonic-gate fileinit(); 6950Sstevel@tonic-gate dot = zero = truedol = unddol = dol = fendcore; 6960Sstevel@tonic-gate one = zero+1; 6970Sstevel@tonic-gate undkind = UNDNONE; 6980Sstevel@tonic-gate chng = 0; 6990Sstevel@tonic-gate edited = 0; 7000Sstevel@tonic-gate for (i = 0; i <= 'z'-'a'+1; i++) 7010Sstevel@tonic-gate names[i] = 1; 7020Sstevel@tonic-gate anymarks = 0; 7030Sstevel@tonic-gate if (xflag) { 7040Sstevel@tonic-gate xtflag = 1; 7050Sstevel@tonic-gate /* ignore SIGINT before crypt process */ 7060Sstevel@tonic-gate pstat = signal(SIGINT, SIG_IGN); 7070Sstevel@tonic-gate if (tpermflag) 7080Sstevel@tonic-gate (void) crypt_close(tperm); 7090Sstevel@tonic-gate tpermflag = 1; 7100Sstevel@tonic-gate if (makekey(tperm) != 0) { 7110Sstevel@tonic-gate xtflag = 0; 7120Sstevel@tonic-gate smerror(gettext( 7130Sstevel@tonic-gate "Warning--Cannot encrypt temporary buffer\n")); 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate signal(SIGINT, pstat); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate /* 7200Sstevel@tonic-gate * Return last component of unix path name p. 7210Sstevel@tonic-gate */ 7220Sstevel@tonic-gate unsigned char * 7230Sstevel@tonic-gate tailpath(p) 7240Sstevel@tonic-gate register unsigned char *p; 7250Sstevel@tonic-gate { 7260Sstevel@tonic-gate register unsigned char *r; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate for (r = p; *p; p++) 7290Sstevel@tonic-gate if (*p == '/') 7300Sstevel@tonic-gate r = p+1; 7310Sstevel@tonic-gate return (r); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate /* 7360Sstevel@tonic-gate * validate_exrc - verify .exrc as belonging to the user. 7370Sstevel@tonic-gate * The file uid should match the process ruid, 7380Sstevel@tonic-gate * and the file should be writable only by the owner. 7390Sstevel@tonic-gate */ 7400Sstevel@tonic-gate static int 7410Sstevel@tonic-gate validate_exrc(unsigned char *exrc_path) 7420Sstevel@tonic-gate { 7430Sstevel@tonic-gate struct stat64 exrc_stat; 7440Sstevel@tonic-gate int process_uid; 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate if (stat64((char *)exrc_path, &exrc_stat) == -1) 7470Sstevel@tonic-gate return (0); /* ignore if .exrec is not found */ 7480Sstevel@tonic-gate process_uid = geteuid(); 7490Sstevel@tonic-gate /* if not root, uid must match file owner */ 7500Sstevel@tonic-gate if (process_uid && process_uid != exrc_stat.st_uid) 7510Sstevel@tonic-gate return (-1); 7520Sstevel@tonic-gate if ((exrc_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) 7530Sstevel@tonic-gate return (-1); 7540Sstevel@tonic-gate return (0); 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate /* 7580Sstevel@tonic-gate * print usage message to stdout 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate static void 7610Sstevel@tonic-gate usage(unsigned char *name) 7620Sstevel@tonic-gate { 7630Sstevel@tonic-gate char buf[160]; 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate #ifdef TRACE 7660Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 767*597Sceastha "Usage: %s [- | -s] [-l] [-L] [-wn] " 768*597Sceastha "[-R] [-S] [-r [file]] [-t tag] [-T] [-U tracefile]\n" 769*597Sceastha "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name); 7700Sstevel@tonic-gate #else 7710Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 772*597Sceastha "Usage: %s [- | -s] [-l] [-L] [-wn] " 773*597Sceastha "[-R] [-S] [-r [file]] [-t tag]\n" 774*597Sceastha "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name); 7750Sstevel@tonic-gate #endif 7760Sstevel@tonic-gate (void) write(2, buf, strlen(buf)); 7770Sstevel@tonic-gate } 778