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