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 134*802Scf46844 void init(void); 135*802Scf46844 1360Sstevel@tonic-gate int 137*802Scf46844 main(int ac, char *av[]) 1380Sstevel@tonic-gate { 1390Sstevel@tonic-gate extern char *optarg; 1400Sstevel@tonic-gate extern int optind; 1410Sstevel@tonic-gate unsigned char *rcvname = 0; 1420Sstevel@tonic-gate unsigned char *cp; 1430Sstevel@tonic-gate int c; 1440Sstevel@tonic-gate unsigned char *cmdnam; 1450Sstevel@tonic-gate bool recov = 0; 1460Sstevel@tonic-gate bool ivis = 0; 1470Sstevel@tonic-gate bool itag = 0; 1480Sstevel@tonic-gate bool fast = 0; 1490Sstevel@tonic-gate extern int verbose; 1500Sstevel@tonic-gate int argcounter = 0; 1510Sstevel@tonic-gate extern int tags_flag; /* Set if tag file is not sorted (-S flag) */ 1520Sstevel@tonic-gate unsigned char scratch [PATH_MAX+1]; /* temp for sourcing rc file(s) */ 1530Sstevel@tonic-gate int vret = 0; 1540Sstevel@tonic-gate unsigned char exrcpath [PATH_MAX+1]; /* temp for sourcing rc file(s) */ 1550Sstevel@tonic-gate int toptseen = 0; 1560Sstevel@tonic-gate #ifdef TRACE 1570Sstevel@tonic-gate unsigned char *tracef; 1580Sstevel@tonic-gate #endif 1590Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1600Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 1610Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 1620Sstevel@tonic-gate #endif 1630Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate /* 1660Sstevel@tonic-gate * Immediately grab the tty modes so that we won't 1670Sstevel@tonic-gate * get messed up if an interrupt comes in quickly. 1680Sstevel@tonic-gate */ 169*802Scf46844 (void) gTTY(2); 1700Sstevel@tonic-gate normf = tty; 1710Sstevel@tonic-gate ppid = getpid(); 1720Sstevel@tonic-gate /* Note - this will core dump if you didn't -DSINGLE in CFLAGS */ 1730Sstevel@tonic-gate lines = 24; 1740Sstevel@tonic-gate columns = 80; /* until defined right by setupterm */ 1750Sstevel@tonic-gate /* 1760Sstevel@tonic-gate * Defend against d's, v's, w's, and a's in directories of 1770Sstevel@tonic-gate * path leading to our true name. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate if ((cmdnam = (unsigned char *)strrchr(av[0], '/')) != 0) 1800Sstevel@tonic-gate cmdnam++; 1810Sstevel@tonic-gate else 182*802Scf46844 cmdnam = (unsigned char *)av[0]; 1830Sstevel@tonic-gate 184*802Scf46844 if (EQ((char *)cmdnam, "vi")) 1850Sstevel@tonic-gate ivis = 1; 1860Sstevel@tonic-gate else if (EQ(cmdnam, "view")) { 1870Sstevel@tonic-gate ivis = 1; 1880Sstevel@tonic-gate value(vi_READONLY) = 1; 1890Sstevel@tonic-gate } else if (EQ(cmdnam, "vedit")) { 1900Sstevel@tonic-gate ivis = 1; 1910Sstevel@tonic-gate value(vi_NOVICE) = 1; 1920Sstevel@tonic-gate value(vi_REPORT) = 1; 1930Sstevel@tonic-gate value(vi_MAGIC) = 0; 1940Sstevel@tonic-gate value(vi_SHOWMODE) = 1; 1950Sstevel@tonic-gate } else if (EQ(cmdnam, "edit")) { 1960Sstevel@tonic-gate value(vi_NOVICE) = 1; 1970Sstevel@tonic-gate value(vi_REPORT) = 1; 1980Sstevel@tonic-gate value(vi_MAGIC) = 0; 1990Sstevel@tonic-gate value(vi_SHOWMODE) = 1; 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate #ifdef XPG4 2030Sstevel@tonic-gate { 2040Sstevel@tonic-gate struct winsize jwin; 2050Sstevel@tonic-gate char *envptr; 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate envlines = envcolumns = -1; 2080Sstevel@tonic-gate oldlines = oldcolumns = -1; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate if (ioctl(0, TIOCGWINSZ, &jwin) != -1) { 2110Sstevel@tonic-gate oldlines = jwin.ws_row; 2120Sstevel@tonic-gate oldcolumns = jwin.ws_col; 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate if ((envptr = getenv("LINES")) != NULL && 2160Sstevel@tonic-gate *envptr != '\0' && isdigit(*envptr)) { 2170Sstevel@tonic-gate if ((envlines = atoi(envptr)) <= 0) { 2180Sstevel@tonic-gate envlines = -1; 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if ((envptr = getenv("COLUMNS")) != NULL && 2230Sstevel@tonic-gate *envptr != '\0' && isdigit(*envptr)) { 2240Sstevel@tonic-gate if ((envcolumns = atoi(envptr)) <= 0) { 2250Sstevel@tonic-gate envcolumns = -1; 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate #endif /* XPG4 */ 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate draino(); 2320Sstevel@tonic-gate pstop(); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* 2350Sstevel@tonic-gate * Initialize interrupt handling. 2360Sstevel@tonic-gate */ 2370Sstevel@tonic-gate oldhup = signal(SIGHUP, SIG_IGN); 2380Sstevel@tonic-gate if (oldhup == SIG_DFL) 2390Sstevel@tonic-gate signal(SIGHUP, onhup); 2400Sstevel@tonic-gate oldquit = signal(SIGQUIT, SIG_IGN); 2410Sstevel@tonic-gate ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL; 2420Sstevel@tonic-gate if (signal(SIGTERM, SIG_IGN) == SIG_DFL) 2430Sstevel@tonic-gate signal(SIGTERM, onhup); 2440Sstevel@tonic-gate if (signal(SIGEMT, SIG_IGN) == SIG_DFL) 2450Sstevel@tonic-gate signal(SIGEMT, onemt); 2460Sstevel@tonic-gate signal(SIGILL, oncore); 2470Sstevel@tonic-gate signal(SIGTRAP, oncore); 2480Sstevel@tonic-gate signal(SIGIOT, oncore); 2490Sstevel@tonic-gate signal(SIGFPE, oncore); 2500Sstevel@tonic-gate signal(SIGBUS, oncore); 2510Sstevel@tonic-gate signal(SIGSEGV, oncore); 2520Sstevel@tonic-gate signal(SIGPIPE, oncore); 2530Sstevel@tonic-gate init_re(); 2540Sstevel@tonic-gate while (1) { 2550Sstevel@tonic-gate #ifdef TRACE 2560Sstevel@tonic-gate while ((c = getopt(ac, (char **)av, "VU:Lc:Tvt:rlw:xRCsS")) != 2570Sstevel@tonic-gate EOF) 2580Sstevel@tonic-gate #else 2590Sstevel@tonic-gate while ((c = getopt(ac, (char **)av, 260597Sceastha "VLc:vt:rlw:xRCsS")) != EOF) 2610Sstevel@tonic-gate #endif 2620Sstevel@tonic-gate switch (c) { 2630Sstevel@tonic-gate case 's': 2640Sstevel@tonic-gate hush = 1; 2650Sstevel@tonic-gate value(vi_AUTOPRINT) = 0; 2660Sstevel@tonic-gate fast++; 2670Sstevel@tonic-gate break; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate case 'R': 2700Sstevel@tonic-gate value(vi_READONLY) = 1; 2710Sstevel@tonic-gate break; 2720Sstevel@tonic-gate case 'S': 2730Sstevel@tonic-gate tags_flag = 1; 2740Sstevel@tonic-gate break; 2750Sstevel@tonic-gate #ifdef TRACE 2760Sstevel@tonic-gate case 'T': 2770Sstevel@tonic-gate tracef = (unsigned char *)"trace"; 2780Sstevel@tonic-gate goto trace; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate case 'U': 2810Sstevel@tonic-gate tracef = tttrace; 2820Sstevel@tonic-gate strcpy(tracef, optarg); 2830Sstevel@tonic-gate trace: 2840Sstevel@tonic-gate trace = fopen((char *)tracef, "w"); 2850Sstevel@tonic-gate #define tracbuf NULL 2860Sstevel@tonic-gate if (trace == NULL) 287*802Scf46844 viprintf("Trace create error\n"); 2880Sstevel@tonic-gate else 2890Sstevel@tonic-gate setbuf(trace, (char *)tracbuf); 2900Sstevel@tonic-gate break; 2910Sstevel@tonic-gate #endif 2920Sstevel@tonic-gate case 'c': 2930Sstevel@tonic-gate if (optarg != NULL) 2940Sstevel@tonic-gate firstpat = (unsigned char *)optarg; 2950Sstevel@tonic-gate else 2960Sstevel@tonic-gate firstpat = (unsigned char *)""; 2970Sstevel@tonic-gate break; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate case 'l': 3000Sstevel@tonic-gate value(vi_LISP) = 1; 3010Sstevel@tonic-gate value(vi_SHOWMATCH) = 1; 3020Sstevel@tonic-gate break; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate case 'r': 3050Sstevel@tonic-gate if (av[optind] && (c = av[optind][0]) && 3060Sstevel@tonic-gate c != '-') { 3070Sstevel@tonic-gate if ((strlen(av[optind])) >= 3080Sstevel@tonic-gate sizeof (savedfile)) { 3090Sstevel@tonic-gate (void) fprintf(stderr, gettext( 310597Sceastha "Recovered file name" 311597Sceastha " too long\n")); 3120Sstevel@tonic-gate exit(1); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate rcvname = (unsigned char *)av[optind]; 3160Sstevel@tonic-gate optind++; 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate case 'L': 3200Sstevel@tonic-gate recov++; 3210Sstevel@tonic-gate break; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate case 'V': 3240Sstevel@tonic-gate verbose = 1; 3250Sstevel@tonic-gate break; 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate case 't': 3280Sstevel@tonic-gate if (toptseen) { 3290Sstevel@tonic-gate usage(cmdnam); 3300Sstevel@tonic-gate exit(1); 3310Sstevel@tonic-gate } else { 3320Sstevel@tonic-gate toptseen++; 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate itag = 1; 3350Sstevel@tonic-gate if (strlcpy(lasttag, optarg, 3360Sstevel@tonic-gate sizeof (lasttag)) >= sizeof (lasttag)) { 3370Sstevel@tonic-gate (void) fprintf(stderr, gettext("Tag" 3380Sstevel@tonic-gate " file name too long\n")); 3390Sstevel@tonic-gate exit(1); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate break; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate case 'w': 3440Sstevel@tonic-gate defwind = 0; 3450Sstevel@tonic-gate if (optarg[0] == NULL) 3460Sstevel@tonic-gate defwind = 3; 3470Sstevel@tonic-gate else for (cp = (unsigned char *)optarg; 3480Sstevel@tonic-gate isdigit(*cp); cp++) 3490Sstevel@tonic-gate defwind = 10*defwind + *cp - '0'; 3500Sstevel@tonic-gate if (defwind < 0) 3510Sstevel@tonic-gate defwind = 3; 3520Sstevel@tonic-gate break; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate case 'C': 3550Sstevel@tonic-gate crflag = 1; 3560Sstevel@tonic-gate xflag = 1; 3570Sstevel@tonic-gate break; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate case 'x': 3600Sstevel@tonic-gate /* encrypted mode */ 3610Sstevel@tonic-gate xflag = 1; 3620Sstevel@tonic-gate crflag = -1; 3630Sstevel@tonic-gate break; 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate case 'v': 3660Sstevel@tonic-gate ivis = 1; 3670Sstevel@tonic-gate break; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate default: 3700Sstevel@tonic-gate usage(cmdnam); 3710Sstevel@tonic-gate exit(1); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate if (av[optind] && av[optind][0] == '+' && 3740Sstevel@tonic-gate av[optind-1] && strcmp(av[optind-1], "--")) { 375*802Scf46844 firstpat = (unsigned char *)&av[optind][1]; 3760Sstevel@tonic-gate optind++; 3770Sstevel@tonic-gate continue; 3780Sstevel@tonic-gate } else if (av[optind] && av[optind][0] == '-' && 3790Sstevel@tonic-gate av[optind-1] && strcmp(av[optind-1], "--")) { 3800Sstevel@tonic-gate hush = 1; 3810Sstevel@tonic-gate value(vi_AUTOPRINT) = 0; 3820Sstevel@tonic-gate fast++; 3830Sstevel@tonic-gate optind++; 3840Sstevel@tonic-gate continue; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate break; 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 389597Sceastha if (isatty(0) == 0) { 390597Sceastha /* 391597Sceastha * If -V option is set and input is coming in via 392597Sceastha * stdin then vi behavior should be ignored. The vi 393597Sceastha * command should act like ex and only process ex commands 394597Sceastha * and echo the input ex commands to stderr 395597Sceastha */ 396597Sceastha if (verbose == 1) { 397597Sceastha ivis = 0; 398597Sceastha } 399597Sceastha 400597Sceastha /* 401597Sceastha * If the standard input is not a terminal device, 402597Sceastha * it is as if the -s option has been specified. 403597Sceastha */ 404597Sceastha if (ivis == 0) { 405597Sceastha hush = 1; 406597Sceastha value(vi_AUTOPRINT) = 0; 407597Sceastha fast++; 408597Sceastha } 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate ac -= optind; 4120Sstevel@tonic-gate av = &av[optind]; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate for (argcounter = 0; argcounter < ac; argcounter++) { 4150Sstevel@tonic-gate if ((strlen(av[argcounter])) >= sizeof (savedfile)) { 4160Sstevel@tonic-gate (void) fprintf(stderr, gettext("File argument" 417597Sceastha " too long\n")); 4180Sstevel@tonic-gate exit(1); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate #ifdef SIGTSTP 4230Sstevel@tonic-gate if (!hush && signal(SIGTSTP, SIG_IGN) == SIG_DFL) 4240Sstevel@tonic-gate signal(SIGTSTP, onsusp), dosusp++; 4250Sstevel@tonic-gate #endif 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate if (xflag) { 4280Sstevel@tonic-gate permflag = 1; 4290Sstevel@tonic-gate if ((kflag = run_setkey(perm, 4300Sstevel@tonic-gate (key = (unsigned char *)getpass( 4310Sstevel@tonic-gate gettext("Enter key:"))))) == -1) { 4320Sstevel@tonic-gate kflag = 0; 4330Sstevel@tonic-gate xflag = 0; 4340Sstevel@tonic-gate smerror(gettext("Encryption facility not available\n")); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate if (kflag == 0) 4370Sstevel@tonic-gate crflag = 0; 4380Sstevel@tonic-gate else { 4390Sstevel@tonic-gate strcpy(cryptkey, "CrYpTkEy=XXXXXXXXX"); 4400Sstevel@tonic-gate strcpy(cryptkey + 9, key); 4410Sstevel@tonic-gate if (putenv((char *)cryptkey) != 0) 4420Sstevel@tonic-gate smerror(gettext(" Cannot copy key to environment")); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate #ifndef PRESUNEUC 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * Perform locale-specific initialization 4490Sstevel@tonic-gate */ 450*802Scf46844 localize(); 4510Sstevel@tonic-gate #endif /* PRESUNEUC */ 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * Initialize end of core pointers. 4550Sstevel@tonic-gate * Normally we avoid breaking back to fendcore after each 4560Sstevel@tonic-gate * file since this can be expensive (much core-core copying). 4570Sstevel@tonic-gate * If your system can scatter load processes you could do 4580Sstevel@tonic-gate * this as ed does, saving a little core, but it will probably 4590Sstevel@tonic-gate * not often make much difference. 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate fendcore = (line *) sbrk(0); 4620Sstevel@tonic-gate endcore = fendcore - 2; 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate /* 4650Sstevel@tonic-gate * If we are doing a recover and no filename 4660Sstevel@tonic-gate * was given, then execute an exrecover command with 4670Sstevel@tonic-gate * the -r option to type out the list of saved file names. 4680Sstevel@tonic-gate * Otherwise set the remembered file name to the first argument 4690Sstevel@tonic-gate * file name so the "recover" initial command will find it. 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate if (recov) { 4720Sstevel@tonic-gate if (ac == 0 && (rcvname == NULL || *rcvname == NULL)) { 4730Sstevel@tonic-gate ppid = 0; 4740Sstevel@tonic-gate setrupt(); 4750Sstevel@tonic-gate execlp(EXRECOVER, "exrecover", "-r", (char *)0); 4760Sstevel@tonic-gate filioerr(EXRECOVER); 4770Sstevel@tonic-gate exit(++errcnt); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate if (rcvname && *rcvname) 4800Sstevel@tonic-gate (void) strlcpy(savedfile, rcvname, sizeof (savedfile)); 4810Sstevel@tonic-gate else { 4820Sstevel@tonic-gate (void) strlcpy(savedfile, *av++, sizeof (savedfile)); 4830Sstevel@tonic-gate ac--; 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* 4880Sstevel@tonic-gate * Initialize the argument list. 4890Sstevel@tonic-gate */ 490*802Scf46844 argv0 = (unsigned char **)av; 4910Sstevel@tonic-gate argc0 = ac; 492*802Scf46844 args0 = (unsigned char *)av[0]; 4930Sstevel@tonic-gate erewind(); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate /* 4960Sstevel@tonic-gate * Initialize a temporary file (buffer) and 4970Sstevel@tonic-gate * set up terminal environment. Read user startup commands. 4980Sstevel@tonic-gate */ 4990Sstevel@tonic-gate if (setexit() == 0) { 5000Sstevel@tonic-gate setrupt(); 5010Sstevel@tonic-gate intty = isatty(0); 5020Sstevel@tonic-gate value(vi_PROMPT) = intty; 5030Sstevel@tonic-gate if (((cp = (unsigned char *)getenv("SHELL")) != NULL) && 5040Sstevel@tonic-gate (*cp != '\0')) { 5050Sstevel@tonic-gate if (strlen(cp) < sizeof (shell)) { 5060Sstevel@tonic-gate (void) strlcpy(shell, cp, sizeof (shell)); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate if (fast) 510*802Scf46844 setterm((unsigned char *)"dumb"); 5110Sstevel@tonic-gate else { 5120Sstevel@tonic-gate gettmode(); 5130Sstevel@tonic-gate cp = (unsigned char *)getenv("TERM"); 5140Sstevel@tonic-gate if (cp == NULL || *cp == '\0') 5150Sstevel@tonic-gate cp = (unsigned char *)"unknown"; 5160Sstevel@tonic-gate setterm(cp); 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate /* 5210Sstevel@tonic-gate * Bring up some code from init() 5220Sstevel@tonic-gate * This is still done in init later. This 5230Sstevel@tonic-gate * avoids null pointer problems 5240Sstevel@tonic-gate */ 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate dot = zero = truedol = unddol = dol = fendcore; 5270Sstevel@tonic-gate one = zero+1; 5280Sstevel@tonic-gate { 529*802Scf46844 int i; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate for (i = 0; i <= 'z'-'a'+1; i++) 5320Sstevel@tonic-gate names[i] = 1; 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate if (setexit() == 0 && !fast) { 5360Sstevel@tonic-gate if ((globp = 537597Sceastha (unsigned char *) getenv("EXINIT")) && *globp) { 5380Sstevel@tonic-gate if (ivis) 5390Sstevel@tonic-gate inexrc = 1; 5400Sstevel@tonic-gate commands(1, 1); 5410Sstevel@tonic-gate inexrc = 0; 5420Sstevel@tonic-gate } else { 5430Sstevel@tonic-gate globp = 0; 5440Sstevel@tonic-gate if ((cp = (unsigned char *) getenv("HOME")) != 5450Sstevel@tonic-gate 0 && *cp) { 5460Sstevel@tonic-gate strncpy(scratch, cp, sizeof (scratch) - 1); 5470Sstevel@tonic-gate strncat(scratch, "/.exrc", 5480Sstevel@tonic-gate sizeof (scratch) - 1 - strlen(scratch)); 5490Sstevel@tonic-gate if (ivis) 550597Sceastha inexrc = 1; 5510Sstevel@tonic-gate if ((vret = validate_exrc(scratch)) == 0) { 5520Sstevel@tonic-gate source(scratch, 1); 5530Sstevel@tonic-gate } else { 5540Sstevel@tonic-gate if (vret == -1) { 5550Sstevel@tonic-gate error(gettext( 5560Sstevel@tonic-gate "Not owner of .exrc " 5570Sstevel@tonic-gate "or .exrc is group or " 5580Sstevel@tonic-gate "world writable")); 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate inexrc = 0; 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate /* 5660Sstevel@tonic-gate * Allow local .exrc if the "exrc" option was set. This 5670Sstevel@tonic-gate * loses if . is $HOME, but nobody should notice unless 5680Sstevel@tonic-gate * they do stupid things like putting a version command 5690Sstevel@tonic-gate * in .exrc. 5700Sstevel@tonic-gate * Besides, they should be using EXINIT, not .exrc, right? 5710Sstevel@tonic-gate */ 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate if (value(vi_EXRC)) { 5740Sstevel@tonic-gate if (ivis) 5750Sstevel@tonic-gate inexrc = 1; 5760Sstevel@tonic-gate if ((cp = (unsigned char *) getenv("PWD")) != 0 && 5770Sstevel@tonic-gate *cp) { 5780Sstevel@tonic-gate strncpy(exrcpath, cp, sizeof (exrcpath) - 1); 5790Sstevel@tonic-gate strncat(exrcpath, "/.exrc", 5800Sstevel@tonic-gate sizeof (exrcpath) - 1 - strlen(exrcpath)); 5810Sstevel@tonic-gate if (strcmp(scratch, exrcpath) != 0) { 5820Sstevel@tonic-gate if ((vret = 5830Sstevel@tonic-gate validate_exrc(exrcpath)) == 0) { 5840Sstevel@tonic-gate source(exrcpath, 1); 5850Sstevel@tonic-gate } else { 5860Sstevel@tonic-gate if (vret == -1) { 5870Sstevel@tonic-gate error(gettext( 5880Sstevel@tonic-gate "Not owner of " 5890Sstevel@tonic-gate ".exrc or .exrc " 5900Sstevel@tonic-gate "is group or world " 5910Sstevel@tonic-gate "writable")); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate inexrc = 0; 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate init(); /* moved after prev 2 chunks to fix directory option */ 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* 6030Sstevel@tonic-gate * Initial processing. Handle tag, recover, and file argument 6040Sstevel@tonic-gate * implied next commands. If going in as 'vi', then don't do 6050Sstevel@tonic-gate * anything, just set initev so we will do it later (from within 6060Sstevel@tonic-gate * visual). 6070Sstevel@tonic-gate */ 6080Sstevel@tonic-gate if (setexit() == 0) { 6090Sstevel@tonic-gate if (recov) 6100Sstevel@tonic-gate globp = (unsigned char *)"recover"; 6110Sstevel@tonic-gate else if (itag) { 6120Sstevel@tonic-gate globp = ivis ? (unsigned char *)"tag" : 6130Sstevel@tonic-gate (unsigned char *)"tag|p"; 6140Sstevel@tonic-gate #ifdef XPG4 6150Sstevel@tonic-gate if (firstpat != NULL) { 6160Sstevel@tonic-gate /* 6170Sstevel@tonic-gate * if the user specified the -t and -c 6180Sstevel@tonic-gate * flags together, then we service these 6190Sstevel@tonic-gate * commands here. -t is handled first. 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate savepat = firstpat; 6220Sstevel@tonic-gate firstpat = NULL; 6230Sstevel@tonic-gate inglobal = 1; 6240Sstevel@tonic-gate commands(1, 1); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* now handle the -c argument: */ 6270Sstevel@tonic-gate globp = savepat; 6280Sstevel@tonic-gate commands(1, 1); 6290Sstevel@tonic-gate inglobal = 0; 6300Sstevel@tonic-gate globp = savepat = NULL; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate /* the above isn't sufficient for ex mode: */ 6330Sstevel@tonic-gate if (!ivis) { 6340Sstevel@tonic-gate setdot(); 6350Sstevel@tonic-gate nonzero(); 6360Sstevel@tonic-gate plines(addr1, addr2, 1); 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate #endif /* XPG4 */ 6400Sstevel@tonic-gate } else if (argc) 6410Sstevel@tonic-gate globp = (unsigned char *)"next"; 6420Sstevel@tonic-gate if (ivis) 6430Sstevel@tonic-gate initev = globp; 6440Sstevel@tonic-gate else if (globp) { 6450Sstevel@tonic-gate inglobal = 1; 6460Sstevel@tonic-gate commands(1, 1); 6470Sstevel@tonic-gate inglobal = 0; 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * Vi command... go into visual. 6530Sstevel@tonic-gate */ 6540Sstevel@tonic-gate if (ivis) { 6550Sstevel@tonic-gate /* 6560Sstevel@tonic-gate * Don't have to be upward compatible 6570Sstevel@tonic-gate * by starting editing at line $. 6580Sstevel@tonic-gate */ 6590Sstevel@tonic-gate #ifdef XPG4 6600Sstevel@tonic-gate if (!itag && (dol > zero)) 6610Sstevel@tonic-gate #else /* XPG4 */ 6620Sstevel@tonic-gate if (dol > zero) 6630Sstevel@tonic-gate #endif /* XPG4 */ 6640Sstevel@tonic-gate dot = one; 6650Sstevel@tonic-gate globp = (unsigned char *)"visual"; 6660Sstevel@tonic-gate if (setexit() == 0) 6670Sstevel@tonic-gate commands(1, 1); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * Clear out trash in state accumulated by startup, 6720Sstevel@tonic-gate * and then do the main command loop for a normal edit. 6730Sstevel@tonic-gate * If you quit out of a 'vi' command by doing Q or ^\, 6740Sstevel@tonic-gate * you also fall through to here. 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate seenprompt = 1; 6770Sstevel@tonic-gate ungetchar(0); 6780Sstevel@tonic-gate globp = 0; 6790Sstevel@tonic-gate initev = 0; 6800Sstevel@tonic-gate setlastchar('\n'); 6810Sstevel@tonic-gate setexit(); 6820Sstevel@tonic-gate commands(0, 0); 6830Sstevel@tonic-gate cleanup(1); 684*802Scf46844 return (errcnt); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* 6880Sstevel@tonic-gate * Initialization, before editing a new file. 6890Sstevel@tonic-gate * Main thing here is to get a new buffer (in fileinit), 6900Sstevel@tonic-gate * rest is peripheral state resetting. 6910Sstevel@tonic-gate */ 692*802Scf46844 void 693*802Scf46844 init(void) 6940Sstevel@tonic-gate { 695*802Scf46844 int i; 6960Sstevel@tonic-gate void (*pstat)(); 6970Sstevel@tonic-gate fileinit(); 6980Sstevel@tonic-gate dot = zero = truedol = unddol = dol = fendcore; 6990Sstevel@tonic-gate one = zero+1; 7000Sstevel@tonic-gate undkind = UNDNONE; 7010Sstevel@tonic-gate chng = 0; 7020Sstevel@tonic-gate edited = 0; 7030Sstevel@tonic-gate for (i = 0; i <= 'z'-'a'+1; i++) 7040Sstevel@tonic-gate names[i] = 1; 7050Sstevel@tonic-gate anymarks = 0; 7060Sstevel@tonic-gate if (xflag) { 7070Sstevel@tonic-gate xtflag = 1; 7080Sstevel@tonic-gate /* ignore SIGINT before crypt process */ 7090Sstevel@tonic-gate pstat = signal(SIGINT, SIG_IGN); 7100Sstevel@tonic-gate if (tpermflag) 7110Sstevel@tonic-gate (void) crypt_close(tperm); 7120Sstevel@tonic-gate tpermflag = 1; 7130Sstevel@tonic-gate if (makekey(tperm) != 0) { 7140Sstevel@tonic-gate xtflag = 0; 7150Sstevel@tonic-gate smerror(gettext( 7160Sstevel@tonic-gate "Warning--Cannot encrypt temporary buffer\n")); 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate signal(SIGINT, pstat); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * Return last component of unix path name p. 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate unsigned char * 7260Sstevel@tonic-gate tailpath(p) 727*802Scf46844 unsigned char *p; 7280Sstevel@tonic-gate { 729*802Scf46844 unsigned char *r; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate for (r = p; *p; p++) 7320Sstevel@tonic-gate if (*p == '/') 7330Sstevel@tonic-gate r = p+1; 7340Sstevel@tonic-gate return (r); 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate /* 7390Sstevel@tonic-gate * validate_exrc - verify .exrc as belonging to the user. 7400Sstevel@tonic-gate * The file uid should match the process ruid, 7410Sstevel@tonic-gate * and the file should be writable only by the owner. 7420Sstevel@tonic-gate */ 7430Sstevel@tonic-gate static int 7440Sstevel@tonic-gate validate_exrc(unsigned char *exrc_path) 7450Sstevel@tonic-gate { 7460Sstevel@tonic-gate struct stat64 exrc_stat; 7470Sstevel@tonic-gate int process_uid; 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate if (stat64((char *)exrc_path, &exrc_stat) == -1) 7500Sstevel@tonic-gate return (0); /* ignore if .exrec is not found */ 7510Sstevel@tonic-gate process_uid = geteuid(); 7520Sstevel@tonic-gate /* if not root, uid must match file owner */ 7530Sstevel@tonic-gate if (process_uid && process_uid != exrc_stat.st_uid) 7540Sstevel@tonic-gate return (-1); 7550Sstevel@tonic-gate if ((exrc_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) 7560Sstevel@tonic-gate return (-1); 7570Sstevel@tonic-gate return (0); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * print usage message to stdout 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate static void 7640Sstevel@tonic-gate usage(unsigned char *name) 7650Sstevel@tonic-gate { 7660Sstevel@tonic-gate char buf[160]; 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate #ifdef TRACE 7690Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 770597Sceastha "Usage: %s [- | -s] [-l] [-L] [-wn] " 771597Sceastha "[-R] [-S] [-r [file]] [-t tag] [-T] [-U tracefile]\n" 772597Sceastha "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name); 7730Sstevel@tonic-gate #else 7740Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 775597Sceastha "Usage: %s [- | -s] [-l] [-L] [-wn] " 776597Sceastha "[-R] [-S] [-r [file]] [-t tag]\n" 777597Sceastha "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name); 7780Sstevel@tonic-gate #endif 7790Sstevel@tonic-gate (void) write(2, buf, strlen(buf)); 7800Sstevel@tonic-gate } 781