source: trunk/third/tcsh/sh.hist.c @ 21797

Revision 21797, 11.1 KB checked in by ghudson, 20 years ago (diff)
Log interactive commands run as root on cluster machines.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.hist.c,v 1.2 2005-04-22 18:27:11 ghudson Exp $ */
2/*
3 * sh.hist.c: Shell history expansions and substitutions
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by the University of
20 *      California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37#include "sh.h"
38
39RCSID("$Id: sh.hist.c,v 1.2 2005-04-22 18:27:11 ghudson Exp $")
40
41#include "tc.h"
42
43extern bool histvalid;
44extern Char histline[];
45Char HistLit = 0;
46
47static  bool    heq     __P((struct wordent *, struct wordent *));
48static  void    hfree   __P((struct Hist *));
49static  void    dohist1 __P((struct Hist *, int *, int));
50static  void    phist   __P((struct Hist *, int));
51
52#define HIST_ONLY       0x01
53#define HIST_SAVE       0x02
54#define HIST_LOAD       0x04
55#define HIST_REV        0x08
56#define HIST_CLEAR      0x10
57#define HIST_MERGE      0x20
58#define HIST_TIME       0x40
59
60/*
61 * C shell
62 */
63
64#include <syslog.h>
65
66void
67savehist(sp, mflg)
68    struct wordent *sp;
69    bool mflg;
70{
71    register struct Hist *hp, *np;
72    register int histlen = 0;
73    Char   *cp;
74    char buf[INBUFSIZE];
75    static int do_log = -1;
76
77    /* throw away null lines */
78    if (sp && sp->next->word[0] == '\n')
79        return;
80    cp = varval(STRhistory);
81    if (*cp) {
82        register Char *p = cp;
83
84        while (*p) {
85            if (!Isdigit(*p)) {
86                histlen = 0;
87                break;
88            }
89            histlen = histlen * 10 + *p++ - '0';
90        }
91    }
92    for (hp = &Histlist; (np = hp->Hnext) != NULL;)
93        if (eventno - np->Href >= histlen || histlen == 0)
94            hp->Hnext = np->Hnext, hfree(np);
95        else
96            hp = np;
97    if (sp) {
98        hp = enthist(++eventno, sp, 1, mflg);
99        if (do_log == -1) {
100            do_log = (geteuid() == 0
101                      && access("/var/athena/iscluster", R_OK) == 0);
102        }
103        if (do_log) {
104            fmthist('R', hp, buf, INBUFSIZE);
105            syslog(LOG_NOTICE, "Cluster root command (%d): %s",
106                   (int) getuid(), buf);
107        }
108    }
109}
110
111static bool
112heq(a0, b0)
113    struct wordent *a0, *b0;
114{
115    struct wordent *a = a0->next, *b = b0->next;
116
117    for (;;) {
118        if (Strcmp(a->word, b->word) != 0)
119            return 0;
120        a = a->next;
121        b = b->next;
122        if (a == a0)
123            return (b == b0) ? 1 : 0;
124        if (b == b0)
125            return 0;
126    }
127}
128
129
130struct Hist *
131enthist(event, lp, docopy, mflg)
132    int     event;
133    register struct wordent *lp;
134    bool    docopy;
135    bool    mflg;
136{
137    extern time_t Htime;
138    struct Hist *p = NULL, *pp = &Histlist;
139    int n, r;
140    register struct Hist *np;
141    Char *dp;
142   
143    if ((dp = varval(STRhistdup)) != STRNULL) {
144        if (eq(dp, STRerase)) {
145            /* masaoki@akebono.tky.hp.com (Kobayashi Masaoki) */
146            struct Hist *px;
147            for (p = pp; (px = p, p = p->Hnext) != NULL;)
148                if (heq(lp, &(p->Hlex))){
149                    px->Hnext = p->Hnext;
150                    n = p->Hnum + 1;
151                    hfree(p);
152                    for (p = px->Hnext; p != NULL; p = p->Hnext)
153                        p->Href = n--;
154                    break;
155                }
156        }
157        else if (eq(dp, STRall)) {
158            for (p = pp; (p = p->Hnext) != NULL;)
159                if (heq(lp, &(p->Hlex))) {
160                    eventno--;
161                    break;
162                }
163        }
164        else if (eq(dp, STRprev)) {
165            if (pp->Hnext && heq(lp, &(pp->Hnext->Hlex))) {
166                p = pp->Hnext;
167                eventno--;
168            }
169        }
170    }
171
172    np = p ? p : (struct Hist *) xmalloc((size_t) sizeof(*np));
173
174    /* Pick up timestamp set by lex() in Htime if reading saved history */
175    if (Htime != (time_t) 0) {
176        np->Htime = Htime;
177        Htime = 0;
178    }
179    else
180        (void) time(&(np->Htime));
181
182    if (p == np)
183        return np;
184
185    np->Hnum = np->Href = event;
186    if (docopy) {
187        copylex(&np->Hlex, lp);
188        if (histvalid)
189            np->histline = Strsave(histline);
190        else
191            np->histline = NULL;
192    }
193    else {
194        np->Hlex.next = lp->next;
195        lp->next->prev = &np->Hlex;
196        np->Hlex.prev = lp->prev;
197        lp->prev->next = &np->Hlex;
198        np->histline = NULL;
199    }
200    if (mflg)
201      {
202        while ((p = pp->Hnext) && (p->Htime > np->Htime))
203          pp = p;
204        while (p && p->Htime == np->Htime)
205          {
206            if (heq(&p->Hlex, &np->Hlex))
207              {
208                eventno--;
209                hfree(np);
210                return (p);
211              }
212            pp = p;
213            p = p->Hnext;
214          }
215        for (p = Histlist.Hnext; p != pp->Hnext; p = p->Hnext)
216          {
217            n = p->Hnum; r = p->Href;
218            p->Hnum = np->Hnum; p->Href = np->Href;
219            np->Hnum = n; np->Href = r;
220          }
221      }
222    np->Hnext = pp->Hnext;
223    pp->Hnext = np;
224    return (np);
225}
226
227static void
228hfree(hp)
229    register struct Hist *hp;
230{
231
232    freelex(&hp->Hlex);
233    if (hp->histline)
234        xfree((ptr_t) hp->histline);
235    xfree((ptr_t) hp);
236}
237
238
239/*ARGSUSED*/
240void
241dohist(vp, c)
242    Char  **vp;
243    struct command *c;
244{
245    int     n, hflg = 0;
246
247    USE(c);
248    if (getn(varval(STRhistory)) == 0)
249        return;
250    if (setintr)
251#ifdef BSDSIGS
252        (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
253#else
254        (void) sigrelse(SIGINT);
255#endif
256    while (*++vp && **vp == '-') {
257        Char   *vp2 = *vp;
258
259        while (*++vp2)
260            switch (*vp2) {
261            case 'c':
262                hflg |= HIST_CLEAR;
263                break;
264            case 'h':
265                hflg |= HIST_ONLY;
266                break;
267            case 'r':
268                hflg |= HIST_REV;
269                break;
270            case 'S':
271                hflg |= HIST_SAVE;
272                break;
273            case 'L':
274                hflg |= HIST_LOAD;
275                break;
276            case 'M':
277                hflg |= HIST_MERGE;
278                break;
279            case 'T':
280                hflg |= HIST_TIME;
281                break;
282            default:
283                stderror(ERR_HISTUS, "chrSLMT");
284                break;
285            }
286    }
287
288    if (hflg & HIST_CLEAR) {
289        struct Hist *np, *hp;
290        for (hp = &Histlist; (np = hp->Hnext) != NULL;)
291            hp->Hnext = np->Hnext, hfree(np);
292    }
293
294    if (hflg & (HIST_LOAD | HIST_MERGE)) {
295        loadhist(*vp, (hflg & HIST_MERGE) ? 1 : 0);
296        return;
297    }
298    else if (hflg & HIST_SAVE) {
299        rechist(*vp, 1);
300        return;
301    }
302    if (*vp)
303        n = getn(*vp);
304    else {
305        n = getn(varval(STRhistory));
306    }
307    dohist1(Histlist.Hnext, &n, hflg);
308}
309
310static void
311dohist1(hp, np, hflg)
312    struct Hist *hp;
313    int    *np, hflg;
314{
315    bool    print = (*np) > 0;
316
317    for (; hp != 0; hp = hp->Hnext) {
318        (*np)--;
319        hp->Href++;
320        if ((hflg & HIST_REV) == 0) {
321            dohist1(hp->Hnext, np, hflg);
322            if (print)
323                phist(hp, hflg);
324            return;
325        }
326        if (*np >= 0)
327            phist(hp, hflg);
328    }
329}
330
331static void
332phist(hp, hflg)
333    register struct Hist *hp;
334    int     hflg;
335{
336    extern bool output_raw;
337    if (hflg & HIST_ONLY) {
338       /*
339        * Control characters have to be written as is (output_raw).
340        * This way one can preserve special characters (like tab) in
341        * the history file.
342        * From: mveksler@vnet.ibm.com (Veksler Michael)
343        */
344        output_raw= 1;
345        if (hflg & HIST_TIME)
346            /*
347             * Make file entry with history time in format:
348             * "+NNNNNNNNNN" (10 digits, left padded with ascii '0')
349             */
350
351            xprintf("#+%010lu\n", hp->Htime);
352
353        if (HistLit && hp->histline)
354            xprintf("%S\n", hp->histline);
355        else
356            prlex(&hp->Hlex);
357        output_raw= 0;
358    }
359    else {
360        Char   *cp = str2short("%h\t%T\t%R\n");
361        Char buf[INBUFSIZE];
362        struct varent *vp = adrof(STRhistory);
363
364        if (vp && vp->vec[0] && vp->vec[1])
365            cp = vp->vec[1];
366
367        tprintf(FMT_HISTORY, buf, cp, INBUFSIZE, NULL, hp->Htime, (ptr_t) hp);
368        for (cp = buf; *cp;)
369            xputchar(*cp++);
370    }
371}
372
373
374void
375fmthist(fmt, ptr, buf, bufsiz)
376    int fmt;
377    ptr_t ptr;
378    char *buf;
379    size_t bufsiz;
380{
381    struct Hist *hp = (struct Hist *) ptr;
382    switch (fmt) {
383    case 'h':
384        (void) xsnprintf(buf, bufsiz, "%6d", hp->Hnum);
385        break;
386    case 'R':
387        if (HistLit && hp->histline)
388            (void) xsnprintf(buf, bufsiz, "%S", hp->histline);
389        else {
390            Char ibuf[INBUFSIZE], *ip;
391            char *p;
392            (void) sprlex(ibuf, sizeof(ibuf), &hp->Hlex);
393            for (p = buf, ip = ibuf; (*p++ = (CHAR & *ip++)) != '\0'; )
394                continue;
395        }
396        break;
397    default:
398        buf[0] = '\0';
399        break;
400    }
401       
402}
403
404void
405rechist(fname, ref)
406    Char *fname;
407    int ref;
408{
409    Char    *snum;
410    int     fp, ftmp, oldidfds;
411    struct varent *shist;
412    static Char   *dumphist[] = {STRhistory, STRmhT, 0, 0};
413
414    if (fname == NULL && !ref)
415        return;
416    /*
417     * If $savehist is just set, we use the value of $history
418     * else we use the value in $savehist
419     */
420    if (((snum = varval(STRsavehist)) == STRNULL) &&
421        ((snum = varval(STRhistory)) == STRNULL))
422        snum = STRmaxint;
423
424
425    if (fname == NULL) {
426        if ((fname = varval(STRhistfile)) == STRNULL)
427            fname = Strspl(varval(STRhome), &STRtildothist[1]);
428        else
429            fname = Strsave(fname);
430    }
431    else
432        fname = globone(fname, G_ERROR);
433
434    /*
435     * The 'savehist merge' feature is intended for an environment
436     * with numerous shells beeing in simultaneous use. Imagine
437     * any kind of window system. All these shells 'share' the same
438     * ~/.history file for recording their command line history.
439     * Currently the automatic merge can only succeed when the shells
440     * nicely quit one after another.
441     *
442     * Users that like to nuke their environment require here an atomic
443     *  loadhist-creat-dohist(dumphist)-close
444     * sequence.
445     *
446     * jw.
447     */
448    /*
449     * We need the didfds stuff before loadhist otherwise
450     * exec in a script will fail to print if merge is set.
451     * From: mveksler@iil.intel.com (Veksler Michael)
452     */
453    oldidfds = didfds;
454    didfds = 0;
455    if ((shist = adrof(STRsavehist)) != NULL)
456        if (shist->vec[1] && eq(shist->vec[1], STRmerge))
457            loadhist(fname, 1);
458    fp = creat(short2str(fname), 0600);
459    if (fp == -1) {
460        didfds = oldidfds;
461        return;
462    }
463    ftmp = SHOUT;
464    SHOUT = fp;
465    dumphist[2] = snum;
466    dohist(dumphist, NULL);
467    (void) close(fp);
468    SHOUT = ftmp;
469    didfds = oldidfds;
470    xfree((ptr_t) fname);
471}
472
473
474void
475loadhist(fname, mflg)
476    Char *fname;
477    bool mflg;
478{
479    static Char   *loadhist_cmd[] = {STRsource, NULL, NULL, NULL};
480    loadhist_cmd[1] = mflg ? STRmm : STRmh;
481
482    if (fname != NULL)
483        loadhist_cmd[2] = fname;
484    else if ((fname = varval(STRhistfile)) != STRNULL)
485        loadhist_cmd[2] = fname;
486    else
487        loadhist_cmd[2] = STRtildothist;
488
489    dosource(loadhist_cmd, NULL);
490}
Note: See TracBrowser for help on using the repository browser.