/*-
 * Copyright (c) 2003 Michael Reifenberger (Michael@Reifenberger.com)
 * All rights reserved.
 *
 * since this software is derived from gstat(8) the following applies also:
 *
 * Copyright (c) 2003 Poul-Henning Kamp
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The names of the authors may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: src/usr.sbin/gstat/gstat.c,v 1.5 2003/03/22 09:47:02 keramida Exp $
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <paths.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <err.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <libgeom.h>
#include <sys/resource.h>
#include <devstat.h>
#include <sys/devicestat.h>

static int time_I = 3600;

static void stop_da( const char *name );
static void stop_others( const char *name );
static void usage(void);

struct devs {
	char name[7];
	uint64_t lastt;
};

int
main(int argc, char **argv)
{
	int error, i;
	struct devstat *gsp, *gsq;
	struct stat sb;
	char path[32];
	void *sp, *sq;
	double dt;
	struct timespec tp, tq;
	struct gmesh gmp;
	struct gprovider *pp;
	struct gident *gid;
	struct devs *devs, *devp;
	char *p;
	uint64_t u64;
	time_t ltime;
	while ((i = getopt( argc, argv, "I:" ) ) != -1 ) {
		switch ( i ) {
		case 'I':
			p = NULL;
			i = strtoul( optarg, &p, 0 );
			if ( p == optarg || errno == EINVAL ||
			    errno == ERANGE ) {
				errx( 1, "Invalid argument to -I" );
			} else if ( !strcmp( p, "h" ) )
				i *= 3600;
			else if ( !strcmp( p, "m" ) )
				i *= 60;
			else if ( !strcmp( p, "s" ) )
				i *= 1;
			time_I = i;
			break;
		case '?':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;
	if ( argc == 0 )
		usage();
	devs = calloc( argc, sizeof( struct devs ) );
	devp = devs;
	for( i = 0; i < argc; i++ ) {
		sprintf( path, "/dev/%s", argv[i] );
		error = stat( path, &sb );
		if( error != 0 ) {
			errx( 1, "Error %d accessing %s", errno, path );
		}
		snprintf( devs[i].name, 6, argv[i] ); 
		devs[i].lastt = 1;
	}
	error = daemon( 0, 0 );
	if( error != 0 )
		errx( 1, "Error %d running as daemon", errno );
	i = geom_gettree( &gmp );
	if ( i != 0 )
		err( 1, "geom_gettree = %d", i );
	error = geom_stats_open();
	if ( error )
		err( 1, "geom_stats_open()" );
	sq = NULL;
	sq = geom_stats_snapshot_get();
	if ( sq == NULL )
		err( 1, "geom_stats_snapshot()" );
	geom_stats_snapshot_timestamp( sq, &tq );
	while ( 1 ) {
		sleep( time_I );
		sp = geom_stats_snapshot_get();
		if ( sp == NULL )
			err( 1, "geom_stats_snapshot()" );
		geom_stats_snapshot_timestamp( sp, &tp );
		dt = tp.tv_sec - tq.tv_sec;
		dt += ( tp.tv_nsec - tq.tv_nsec ) * 1e-9;
		tq = tp;
	
		geom_stats_snapshot_reset( sp );
		geom_stats_snapshot_reset( sq );
		while( 1 ) {
			gsp = geom_stats_snapshot_next( sp );
			gsq = geom_stats_snapshot_next( sq );
			if ( gsp == NULL || gsq == NULL )
				break;
			if ( gsp->id == NULL )
				continue;
			gid = geom_lookupid( &gmp, gsp->id );
			if ( gid == NULL ) {
				geom_deletetree( &gmp );
				i = geom_gettree( &gmp );
				if ( i != 0 )
					err( 1, "geom_gettree = %d", i );
				gid = geom_lookupid( &gmp, gsp->id );
			}
			if ( gid == NULL )
				continue;
			if ( gid != NULL && gid->lg_what == ISCONSUMER )
				continue;
			if ( gsp->sequence0 != gsp->sequence1 ) {
				continue;
			}
			devstat_compute_statistics( gsp, gsq, dt, 
			    DSM_TOTAL_TRANSFERS, &u64,
			    DSM_NONE );
			*gsq = *gsp;
			pp = gid->lg_ptr;
			i = strlen( pp->lg_name );
			ltime = time( NULL );
			for( i = 0; i < argc; i++ ) {
				if( ( strncmp( pp->lg_name, devs[i].name, 6 ) == 0 ) ) {
					if( ( u64 == 0 ) &&( devs[i].lastt != 0 ) ) {
						syslog( LOG_LOCAL0 | LOG_INFO, 
							"%s: %4ju@%s\n", pp->lg_name, 
							(uintmax_t)u64, ctime( &ltime ) );
						if( pp->lg_name[0] == 'd' && pp->lg_name[1] == 'a' ) {
							stop_da( pp->lg_name );
//						} else if ( pp->name[0] == 'a' && pp->name[1] == 'd' ) {
						} else {
							stop_others( pp->lg_name );
						}
						devs[i].lastt = 0;
					} else if( u64 != 0 ) {
						devs[i].lastt = u64;
					}
				}
			}
		}
		geom_stats_snapshot_free( sp );
	}
	exit (0);
}

static void stop_da( const char *name ) {
	char cmd[256];
	snprintf( cmd, 256,
		"/sbin/camcontrol stop %s"
		"| /usr/bin/logger -p local0.info -t gstopd 2>&1", name );
	system( cmd );
}

static void stop_others( const char *name ) {
	char cmd[256];
	snprintf( cmd, 256,
		"/bin/echo 'would stop %s' if it where implemented"
		"| /usr/bin/logger -p local0.info -t gstopd 2>&1", name );
	system( cmd );
}

static void usage(void)
{
        fprintf(stderr, "usage: gstopd [-I interval] daX ...\n");
        exit(1);
        /* NOTREACHED */
}


syntax highlighted by Code2HTML, v. 0.9.1