xref: /titanic_52/usr/src/cmd/ast/libshell/common/scripts/multifollow.sh (revision 906afcb89d0412cc073b95c2d701a804a8cdb62c)
1*906afcb8SAndy Fiddaman#!/usr/bin/ksh93
2*906afcb8SAndy Fiddaman
3*906afcb8SAndy Fiddaman#
4*906afcb8SAndy Fiddaman# CDDL HEADER START
5*906afcb8SAndy Fiddaman#
6*906afcb8SAndy Fiddaman# The contents of this file are subject to the terms of the
7*906afcb8SAndy Fiddaman# Common Development and Distribution License (the "License").
8*906afcb8SAndy Fiddaman# You may not use this file except in compliance with the License.
9*906afcb8SAndy Fiddaman#
10*906afcb8SAndy Fiddaman# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*906afcb8SAndy Fiddaman# or http://www.opensolaris.org/os/licensing.
12*906afcb8SAndy Fiddaman# See the License for the specific language governing permissions
13*906afcb8SAndy Fiddaman# and limitations under the License.
14*906afcb8SAndy Fiddaman#
15*906afcb8SAndy Fiddaman# When distributing Covered Code, include this CDDL HEADER in each
16*906afcb8SAndy Fiddaman# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*906afcb8SAndy Fiddaman# If applicable, add the following below this CDDL HEADER, with the
18*906afcb8SAndy Fiddaman# fields enclosed by brackets "[]" replaced with your own identifying
19*906afcb8SAndy Fiddaman# information: Portions Copyright [yyyy] [name of copyright owner]
20*906afcb8SAndy Fiddaman#
21*906afcb8SAndy Fiddaman# CDDL HEADER END
22*906afcb8SAndy Fiddaman#
23*906afcb8SAndy Fiddaman
24*906afcb8SAndy Fiddaman#
25*906afcb8SAndy Fiddaman# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26*906afcb8SAndy Fiddaman#
27*906afcb8SAndy Fiddaman
28*906afcb8SAndy Fiddaman# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
29*906afcb8SAndy Fiddamanexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
30*906afcb8SAndy Fiddaman
31*906afcb8SAndy Fiddaman# Make sure all math stuff runs in the "C" locale to avoid problems
32*906afcb8SAndy Fiddaman# with alternative # radix point representations (e.g. ',' instead of
33*906afcb8SAndy Fiddaman# '.' in de_DE.*-locales). This needs to be set _before_ any
34*906afcb8SAndy Fiddaman# floating-point constants are defined in this script).
35*906afcb8SAndy Fiddamanif [[ "${LC_ALL}" != "" ]] ; then
36*906afcb8SAndy Fiddaman    export \
37*906afcb8SAndy Fiddaman        LC_MONETARY="${LC_ALL}" \
38*906afcb8SAndy Fiddaman        LC_MESSAGES="${LC_ALL}" \
39*906afcb8SAndy Fiddaman        LC_COLLATE="${LC_ALL}" \
40*906afcb8SAndy Fiddaman        LC_CTYPE="${LC_ALL}"
41*906afcb8SAndy Fiddaman        unset LC_ALL
42*906afcb8SAndy Fiddamanfi
43*906afcb8SAndy Fiddamanexport LC_NUMERIC=C
44*906afcb8SAndy Fiddaman
45*906afcb8SAndy Fiddamanfunction fatal_error
46*906afcb8SAndy Fiddaman{
47*906afcb8SAndy Fiddaman    print -u 2 "${progname}: $@"
48*906afcb8SAndy Fiddaman    exit 1
49*906afcb8SAndy Fiddaman}
50*906afcb8SAndy Fiddaman
51*906afcb8SAndy Fiddaman
52*906afcb8SAndy Fiddamanfunction usage
53*906afcb8SAndy Fiddaman{
54*906afcb8SAndy Fiddaman    OPTIND=0
55*906afcb8SAndy Fiddaman    getopts -a "${progname}" "${multifollow_usage}" OPT '-?'
56*906afcb8SAndy Fiddaman    exit 2
57*906afcb8SAndy Fiddaman}
58*906afcb8SAndy Fiddaman
59*906afcb8SAndy Fiddaman# program start
60*906afcb8SAndy Fiddamanbuiltin basename
61*906afcb8SAndy Fiddamanbuiltin cat
62*906afcb8SAndy Fiddaman
63*906afcb8SAndy Fiddamantypeset progname="$(basename "${0}")"
64*906afcb8SAndy Fiddaman
65*906afcb8SAndy Fiddamantypeset -r multifollow_usage=$'+
66*906afcb8SAndy Fiddaman[-?\n@(#)\$Id: multifollow (Roland Mainz) 2009-04-08 \$\n]
67*906afcb8SAndy Fiddaman[-author?Roland Mainz <roland.mainz@nrubsig.org>]
68*906afcb8SAndy Fiddaman[+NAME?multifollow - use tail -f on multiple files]
69*906afcb8SAndy Fiddaman[+DESCRIPTION?\bmultifollow\b is a small utilty which can "follow" multiple
70*906afcb8SAndy Fiddaman	files similar to tail -f.]
71*906afcb8SAndy Fiddaman
72*906afcb8SAndy Fiddaman[ file ... ]
73*906afcb8SAndy Fiddaman
74*906afcb8SAndy Fiddaman[+SEE ALSO?\bksh93\b(1), \btail\b(1)]
75*906afcb8SAndy Fiddaman'
76*906afcb8SAndy Fiddaman
77*906afcb8SAndy Fiddamanwhile getopts -a "${progname}" "${multifollow_usage}" OPT ; do
78*906afcb8SAndy Fiddaman#    printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
79*906afcb8SAndy Fiddaman    case ${OPT} in
80*906afcb8SAndy Fiddaman        *)    usage ;;
81*906afcb8SAndy Fiddaman    esac
82*906afcb8SAndy Fiddamandone
83*906afcb8SAndy Fiddamanshift $((OPTIND-1))
84*906afcb8SAndy Fiddaman
85*906afcb8SAndy Fiddaman# expecting at least one more arguments
86*906afcb8SAndy Fiddaman(($# >= 1)) || usage
87*906afcb8SAndy Fiddaman
88*906afcb8SAndy Fiddamanbuiltin -f libshell.so.1 poll || fatal_error "poll builtin not found."
89*906afcb8SAndy Fiddaman
90*906afcb8SAndy Fiddamantypeset -a files
91*906afcb8SAndy Fiddamaninteger numfiles=0
92*906afcb8SAndy Fiddamaninteger i
93*906afcb8SAndy Fiddaman
94*906afcb8SAndy Fiddaman# register trap to cleanup child processes
95*906afcb8SAndy Fiddamantrap 'for ((i=0 ; i < numfiles ; i++ )) ; do kill -TERM ${files[i].childpid} ; done' EXIT
96*906afcb8SAndy Fiddaman
97*906afcb8SAndy Fiddaman# setup "tail -f" childs, FIFOs and information for the "poll" builtin
98*906afcb8SAndy Fiddamanfor (( ; $# > 0 ; numfiles++ )) ; do
99*906afcb8SAndy Fiddaman    typeset files[${numfiles}]=(
100*906afcb8SAndy Fiddaman        typeset name="$1"
101*906afcb8SAndy Fiddaman        typeset pipename="/tmp/multifollow_pipe_${PPID}_$$_${numfiles}"
102*906afcb8SAndy Fiddaman        integer childpid=-1
103*906afcb8SAndy Fiddaman
104*906afcb8SAndy Fiddaman        # poll(1) information
105*906afcb8SAndy Fiddaman        integer fd="-1"
106*906afcb8SAndy Fiddaman	typeset events="POLLIN"
107*906afcb8SAndy Fiddaman	typeset revents=""
108*906afcb8SAndy Fiddaman    )
109*906afcb8SAndy Fiddaman
110*906afcb8SAndy Fiddaman    mkfifo "${files[${numfiles}].pipename}"
111*906afcb8SAndy Fiddaman    redirect {files[numfiles].fd}<> "${files[numfiles].pipename}"
112*906afcb8SAndy Fiddaman
113*906afcb8SAndy Fiddaman    tail -f "${files[${numfiles}].name}" >"${files[${numfiles}].pipename}" &
114*906afcb8SAndy Fiddaman    files[${numfiles}].childpid=$!
115*906afcb8SAndy Fiddaman
116*906afcb8SAndy Fiddaman    rm "${files[${numfiles}].pipename}"
117*906afcb8SAndy Fiddaman
118*906afcb8SAndy Fiddaman    shift
119*906afcb8SAndy Fiddamandone
120*906afcb8SAndy Fiddaman
121*906afcb8SAndy Fiddamantypeset do_poll=true
122*906afcb8SAndy Fiddaman
123*906afcb8SAndy Fiddaman# event loop
124*906afcb8SAndy Fiddamanwhile true ; do
125*906afcb8SAndy Fiddaman    if ${do_poll} ; then
126*906afcb8SAndy Fiddaman        for ((i=0 ; i < numfiles ; i++ )) ; do
127*906afcb8SAndy Fiddaman	    files[i].revents=""
128*906afcb8SAndy Fiddaman	done
129*906afcb8SAndy Fiddaman        poll files
130*906afcb8SAndy Fiddaman    fi
131*906afcb8SAndy Fiddaman    do_poll=true
132*906afcb8SAndy Fiddaman
133*906afcb8SAndy Fiddaman    for ((i=0 ; i < numfiles ; i++ )) ; do
134*906afcb8SAndy Fiddaman        if [[ "${files[i].revents}" != "" ]] ; then
135*906afcb8SAndy Fiddaman	    # todo: investigate why we have to use "do_poll" at all - AFAIK it
136*906afcb8SAndy Fiddaman	    # should be sufficient to call "poll" and get "revents" set if there
137*906afcb8SAndy Fiddaman	    # are any remaining data...
138*906afcb8SAndy Fiddaman	    if read -t0 -u${files[i].fd} line ; then
139*906afcb8SAndy Fiddaman	        print -- "#${i}: ${line}"
140*906afcb8SAndy Fiddaman		do_poll=false
141*906afcb8SAndy Fiddaman	    fi
142*906afcb8SAndy Fiddaman	fi
143*906afcb8SAndy Fiddaman    done
144*906afcb8SAndy Fiddamandone
145*906afcb8SAndy Fiddaman
146*906afcb8SAndy Fiddamanfatal_error "not reached."
147*906afcb8SAndy Fiddaman# EOF.
148