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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26#
27
28# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
29export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
30
31# Make sure all math stuff runs in the "C" locale to avoid problems
32# with alternative # radix point representations (e.g. ',' instead of
33# '.' in de_DE.*-locales). This needs to be set _before_ any
34# floating-point constants are defined in this script).
35if [[ "${LC_ALL}" != "" ]] ; then
36    export \
37        LC_MONETARY="${LC_ALL}" \
38        LC_MESSAGES="${LC_ALL}" \
39        LC_COLLATE="${LC_ALL}" \
40        LC_CTYPE="${LC_ALL}"
41        unset LC_ALL
42fi
43export LC_NUMERIC=C
44
45function fatal_error
46{
47    print -u 2 "${progname}: $@"
48    exit 1
49}
50
51
52function usage
53{
54    OPTIND=0
55    getopts -a "${progname}" "${multifollow_usage}" OPT '-?'
56    exit 2
57}
58
59# program start
60builtin basename
61builtin cat
62
63typeset progname="$(basename "${0}")"
64
65typeset -r multifollow_usage=$'+
66[-?\n@(#)\$Id: multifollow (Roland Mainz) 2009-04-08 \$\n]
67[-author?Roland Mainz <roland.mainz@nrubsig.org>]
68[+NAME?multifollow - use tail -f on multiple files]
69[+DESCRIPTION?\bmultifollow\b is a small utilty which can "follow" multiple
70	files similar to tail -f.]
71
72[ file ... ]
73
74[+SEE ALSO?\bksh93\b(1), \btail\b(1)]
75'
76
77while getopts -a "${progname}" "${multifollow_usage}" OPT ; do 
78#    printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
79    case ${OPT} in
80        *)    usage ;;
81    esac
82done
83shift $((OPTIND-1))
84
85# expecting at least one more arguments
86(($# >= 1)) || usage
87
88builtin -f libshell.so.1 poll || fatal_error "poll builtin not found."
89
90typeset -a files
91integer numfiles=0
92integer i
93
94# register trap to cleanup child processes
95trap 'for ((i=0 ; i < numfiles ; i++ )) ; do kill -TERM ${files[i].childpid} ; done' EXIT
96
97# setup "tail -f" childs, FIFOs and information for the "poll" builtin
98for (( ; $# > 0 ; numfiles++ )) ; do
99    typeset files[${numfiles}]=(
100        typeset name="$1"
101        typeset pipename="/tmp/multifollow_pipe_${PPID}_$$_${numfiles}"
102        integer childpid=-1
103
104        # poll(1) information
105        integer fd="-1"
106	typeset events="POLLIN"
107	typeset revents=""
108    )
109
110    mkfifo "${files[${numfiles}].pipename}"
111    redirect {files[numfiles].fd}<> "${files[numfiles].pipename}"
112
113    tail -f "${files[${numfiles}].name}" >"${files[${numfiles}].pipename}" &
114    files[${numfiles}].childpid=$!
115
116    rm "${files[${numfiles}].pipename}"
117    
118    shift
119done
120
121typeset do_poll=true
122
123# event loop
124while true ; do
125    if ${do_poll} ; then
126        for ((i=0 ; i < numfiles ; i++ )) ; do
127	    files[i].revents=""
128	done
129        poll files
130    fi
131    do_poll=true
132    
133    for ((i=0 ; i < numfiles ; i++ )) ; do
134        if [[ "${files[i].revents}" != "" ]] ; then
135	    # todo: investigate why we have to use "do_poll" at all - AFAIK it
136	    # should be sufficient to call "poll" and get "revents" set if there
137	    # are any remaining data...
138	    if read -t0 -u${files[i].fd} line ; then
139	        print -- "#${i}: ${line}"
140		do_poll=false        
141	    fi
142	fi
143    done
144done
145
146fatal_error "not reached."
147# EOF.
148