xref: /titanic_41/usr/src/lib/libshell/common/scripts/multifollow.sh (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
17c2fbfb3SApril Chin#!/usr/bin/ksh93
27c2fbfb3SApril Chin
37c2fbfb3SApril Chin#
47c2fbfb3SApril Chin# CDDL HEADER START
57c2fbfb3SApril Chin#
67c2fbfb3SApril Chin# The contents of this file are subject to the terms of the
77c2fbfb3SApril Chin# Common Development and Distribution License (the "License").
87c2fbfb3SApril Chin# You may not use this file except in compliance with the License.
97c2fbfb3SApril Chin#
107c2fbfb3SApril Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
117c2fbfb3SApril Chin# or http://www.opensolaris.org/os/licensing.
127c2fbfb3SApril Chin# See the License for the specific language governing permissions
137c2fbfb3SApril Chin# and limitations under the License.
147c2fbfb3SApril Chin#
157c2fbfb3SApril Chin# When distributing Covered Code, include this CDDL HEADER in each
167c2fbfb3SApril Chin# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
177c2fbfb3SApril Chin# If applicable, add the following below this CDDL HEADER, with the
187c2fbfb3SApril Chin# fields enclosed by brackets "[]" replaced with your own identifying
197c2fbfb3SApril Chin# information: Portions Copyright [yyyy] [name of copyright owner]
207c2fbfb3SApril Chin#
217c2fbfb3SApril Chin# CDDL HEADER END
227c2fbfb3SApril Chin#
237c2fbfb3SApril Chin
247c2fbfb3SApril Chin#
25*3e14f97fSRoger A. Faulkner# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
267c2fbfb3SApril Chin#
277c2fbfb3SApril Chin
287c2fbfb3SApril Chin# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
297c2fbfb3SApril Chinexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
307c2fbfb3SApril Chin
317c2fbfb3SApril Chin# Make sure all math stuff runs in the "C" locale to avoid problems
327c2fbfb3SApril Chin# with alternative # radix point representations (e.g. ',' instead of
337c2fbfb3SApril Chin# '.' in de_DE.*-locales). This needs to be set _before_ any
347c2fbfb3SApril Chin# floating-point constants are defined in this script).
357c2fbfb3SApril Chinif [[ "${LC_ALL}" != "" ]] ; then
367c2fbfb3SApril Chin    export \
377c2fbfb3SApril Chin        LC_MONETARY="${LC_ALL}" \
387c2fbfb3SApril Chin        LC_MESSAGES="${LC_ALL}" \
397c2fbfb3SApril Chin        LC_COLLATE="${LC_ALL}" \
407c2fbfb3SApril Chin        LC_CTYPE="${LC_ALL}"
417c2fbfb3SApril Chin        unset LC_ALL
427c2fbfb3SApril Chinfi
437c2fbfb3SApril Chinexport LC_NUMERIC=C
447c2fbfb3SApril Chin
457c2fbfb3SApril Chinfunction fatal_error
467c2fbfb3SApril Chin{
477c2fbfb3SApril Chin    print -u 2 "${progname}: $@"
487c2fbfb3SApril Chin    exit 1
497c2fbfb3SApril Chin}
507c2fbfb3SApril Chin
517c2fbfb3SApril Chin
527c2fbfb3SApril Chinfunction usage
537c2fbfb3SApril Chin{
547c2fbfb3SApril Chin    OPTIND=0
557c2fbfb3SApril Chin    getopts -a "${progname}" "${multifollow_usage}" OPT '-?'
567c2fbfb3SApril Chin    exit 2
577c2fbfb3SApril Chin}
587c2fbfb3SApril Chin
597c2fbfb3SApril Chin# program start
607c2fbfb3SApril Chinbuiltin basename
617c2fbfb3SApril Chinbuiltin cat
627c2fbfb3SApril Chin
637c2fbfb3SApril Chintypeset progname="$(basename "${0}")"
647c2fbfb3SApril Chin
657c2fbfb3SApril Chintypeset -r multifollow_usage=$'+
6634f9b3eeSRoland Mainz[-?\n@(#)\$Id: multifollow (Roland Mainz) 2009-04-08 \$\n]
677c2fbfb3SApril Chin[-author?Roland Mainz <roland.mainz@nrubsig.org>]
687c2fbfb3SApril Chin[+NAME?multifollow - use tail -f on multiple files]
697c2fbfb3SApril Chin[+DESCRIPTION?\bmultifollow\b is a small utilty which can "follow" multiple
707c2fbfb3SApril Chin	files similar to tail -f.]
717c2fbfb3SApril Chin
727c2fbfb3SApril Chin[ file ... ]
737c2fbfb3SApril Chin
747c2fbfb3SApril Chin[+SEE ALSO?\bksh93\b(1), \btail\b(1)]
757c2fbfb3SApril Chin'
767c2fbfb3SApril Chin
777c2fbfb3SApril Chinwhile getopts -a "${progname}" "${multifollow_usage}" OPT ; do
787c2fbfb3SApril Chin#    printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
797c2fbfb3SApril Chin    case ${OPT} in
807c2fbfb3SApril Chin        *)    usage ;;
817c2fbfb3SApril Chin    esac
827c2fbfb3SApril Chindone
837c2fbfb3SApril Chinshift $((OPTIND-1))
847c2fbfb3SApril Chin
857c2fbfb3SApril Chin# expecting at least one more arguments
867c2fbfb3SApril Chin(($# >= 1)) || usage
877c2fbfb3SApril Chin
887c2fbfb3SApril Chinbuiltin -f libshell.so.1 poll || fatal_error "poll builtin not found."
897c2fbfb3SApril Chin
907c2fbfb3SApril Chintypeset -a files
917c2fbfb3SApril Chininteger numfiles=0
927c2fbfb3SApril Chininteger i
937c2fbfb3SApril Chin
947c2fbfb3SApril Chin# register trap to cleanup child processes
957c2fbfb3SApril Chintrap 'for ((i=0 ; i < numfiles ; i++ )) ; do kill -TERM ${files[i].childpid} ; done' EXIT
967c2fbfb3SApril Chin
977c2fbfb3SApril Chin# setup "tail -f" childs, FIFOs and information for the "poll" builtin
987c2fbfb3SApril Chinfor (( ; $# > 0 ; numfiles++ )) ; do
997c2fbfb3SApril Chin    typeset files[${numfiles}]=(
1007c2fbfb3SApril Chin        typeset name="$1"
1017c2fbfb3SApril Chin        typeset pipename="/tmp/multifollow_pipe_${PPID}_$$_${numfiles}"
1027c2fbfb3SApril Chin        integer childpid=-1
1037c2fbfb3SApril Chin
1047c2fbfb3SApril Chin        # poll(1) information
1057c2fbfb3SApril Chin        integer fd="-1"
1067c2fbfb3SApril Chin	typeset events="POLLIN"
1077c2fbfb3SApril Chin	typeset revents=""
1087c2fbfb3SApril Chin    )
1097c2fbfb3SApril Chin
1107c2fbfb3SApril Chin    mkfifo "${files[${numfiles}].pipename}"
1117c2fbfb3SApril Chin    redirect {files[numfiles].fd}<> "${files[numfiles].pipename}"
1127c2fbfb3SApril Chin
1137c2fbfb3SApril Chin    tail -f "${files[${numfiles}].name}" >"${files[${numfiles}].pipename}" &
1147c2fbfb3SApril Chin    files[${numfiles}].childpid=$!
1157c2fbfb3SApril Chin
1167c2fbfb3SApril Chin    rm "${files[${numfiles}].pipename}"
1177c2fbfb3SApril Chin
1187c2fbfb3SApril Chin    shift
1197c2fbfb3SApril Chindone
1207c2fbfb3SApril Chin
1217c2fbfb3SApril Chintypeset do_poll=true
1227c2fbfb3SApril Chin
1237c2fbfb3SApril Chin# event loop
1247c2fbfb3SApril Chinwhile true ; do
1257c2fbfb3SApril Chin    if ${do_poll} ; then
1267c2fbfb3SApril Chin        for ((i=0 ; i < numfiles ; i++ )) ; do
1277c2fbfb3SApril Chin	    files[i].revents=""
1287c2fbfb3SApril Chin	done
1297c2fbfb3SApril Chin        poll files
1307c2fbfb3SApril Chin    fi
1317c2fbfb3SApril Chin    do_poll=true
1327c2fbfb3SApril Chin
1337c2fbfb3SApril Chin    for ((i=0 ; i < numfiles ; i++ )) ; do
1347c2fbfb3SApril Chin        if [[ "${files[i].revents}" != "" ]] ; then
1357c2fbfb3SApril Chin	    # todo: investigate why we have to use "do_poll" at all - AFAIK it
1367c2fbfb3SApril Chin	    # should be sufficient to call "poll" and get "revents" set if there
1377c2fbfb3SApril Chin	    # are any remaining data...
1387c2fbfb3SApril Chin	    if read -t0 -u${files[i].fd} line ; then
1397c2fbfb3SApril Chin	        print -- "#${i}: ${line}"
1407c2fbfb3SApril Chin		do_poll=false
1417c2fbfb3SApril Chin	    fi
1427c2fbfb3SApril Chin	fi
1437c2fbfb3SApril Chin    done
1447c2fbfb3SApril Chindone
1457c2fbfb3SApril Chin
1467c2fbfb3SApril Chinfatal_error "not reached."
1477c2fbfb3SApril Chin# EOF.
148