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