/*
This file is part of pload - a program to monitor ppp activity for X
Copyright (C) 1999-2000 Matt Smith <mdsmith@engr.utk.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/StripChart.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include "pload.h"
#include "pload.xbm"
/************* Function Prototypes ********/
static void GetIChartPoint(Widget,XtPointer,XtPointer);
static void GetOChartPoint(Widget,XtPointer,XtPointer);
static void Usage(void);
static void HandleExit(void);
static void CheckForWMExit(Widget, XtPointer, XEvent*, Boolean*);
static void CheckForIconState(Widget, XtPointer, XEvent*, Boolean*);
static void update(XtPointer, XtIntervalId*);
static void make_label(char*,unsigned long,double,double);
static void do_rate(char*,double);
static void do_total(char*, double);
/************* Global Variables **********/
static char progver[]= VERSION;
static char buff[128];
static if_data ifd;
static XtAppContext context;
static Widget toplevel, topform, iform, oform;
static Widget ilabel, ichart, ochart, olabel;
static Arg arglist[8];
static int i;
static Atom wm_delete_window;
static char *Progname;
static int iconstate;
static XrmOptionDescRec options[] =
{
{"-minscale", "*minScale", XrmoptionSepArg, NULL},
{"-indiv", "*inDiv", XrmoptionSepArg, (XtPointer)1024},
{"-outdiv", "*outDiv", XrmoptionSepArg, (XtPointer)1024},
{"-hl", "*highlight", XrmoptionSepArg, NULL},
{"-jumpscroll", "*jumpScroll", XrmoptionSepArg, NULL},
{"-update", "*update", XrmoptionSepArg, NULL},
{"-in", "*showOut", XrmoptionNoArg, "False"},
{"-out", "*showIn", XrmoptionNoArg, "False"},
{"-nolabel", "*showLabel", XrmoptionNoArg, "False"},
{"-device", "*device", XrmoptionSepArg, NULL},
{"-incolor", "*ichart.foreground", XrmoptionSepArg, NULL},
{"-outcolor", "*ochart.foreground", XrmoptionSepArg, NULL},
{"-average", "*averagePoints", XrmoptionSepArg, (XtPointer)10},
{"-horiz", "*horiz", XrmoptionNoArg, "True"},
{"-nochart", "*showChart", XrmoptionNoArg, "False"},
{"-logscale", "*logScale", XrmoptionNoArg, "True"},
#ifdef LINUXPROC
{"-noproc", "*useProc", XrmoptionNoArg, "False"},
#endif
{"-ncmsg", "*noConnectMsg", XrmoptionSepArg, NULL},
{"-iformat", "*inFormat", XrmoptionSepArg, NULL},
{"-oformat", "*outFormat", XrmoptionSepArg, NULL},
};
static String default_resources[] =
{
#if 0
"*minscale : 3",
"*ilabel.background : red",
"*olabel.background : lightblue",
"*ochart.background : pink",
"*ichart.background : yellow",
#endif
"*update : 1",
"*ichart.foreground : red",
"*ichart.jumpScroll : 1",
"*ochart.foreground : darkgreen",
"*ochart.jumpScroll : 1",
"*topform*borderWidth : 0",
/* "*topform*font : fixed", */
/* "*Pload.geometry : 180x200", */ /* vertical */
/* "*Pload.geometry : 300x120", */ /* horizontal */
/* "*Pload.geometry : 180x35", */ /* labels only */
"*showIn : True",
"*showOut : True",
"*device : ppp0",
"*showLabel : True",
"*averagePoints : 10",
"*inDiv : 1024",
"*outDiv : 1024",
"*horiz : False",
"*showChart : True",
"*logScale : False",
#ifdef LINUXPROC
"*useProc : True",
#endif
"*noConnectMsg : No Connection",
"*inFormat : %t %r in",
"*outFormat : %t %r out",
NULL};
typedef struct
{
String device;
String ncMsg;
String ifmt;
String ofmt;
Boolean showIn;
Boolean showOut;
Boolean showLabel;
Boolean horiz;
Boolean showChart;
#ifdef LINUXPROC
Boolean useProc;
#endif
Boolean logScale;
int avgpts;
int indiv;
int outdiv;
int update;
} PloadResources;
/* another global */
static PloadResources resources;
static XtResource pload_resources[] = {
{
"averagePoints", /* Resource name */
"AveragePoints", /* Resource class */
XtRInt, /* Represenation type */
sizeof(int), /* size of representation type */
XtOffsetOf(PloadResources, avgpts), /* Offset from base */
XtRImmediate, /* Representation of specified default */
(XtPointer)10 /* Address of default resource */
},
{
"logScale",
XtCBoolean,
XtRBoolean,
sizeof(Boolean),
XtOffsetOf(PloadResources, logScale),
XtRImmediate,
(XtPointer)False
},
{
"showChart",
XtCBoolean,
XtRBoolean,
sizeof(Boolean),
XtOffsetOf(PloadResources, showChart),
XtRImmediate,
(XtPointer)True
},
{
"update",
"Update",
XtRInt,
sizeof(int),
XtOffsetOf(PloadResources, update),
XtRImmediate,
(XtPointer)1
},
#ifdef LINUXPROC
{
"useProc",
XtCBoolean,
XtRBoolean,
sizeof(Boolean),
XtOffsetOf(PloadResources, useProc),
XtRImmediate,
(XtPointer)True
},
#endif
{
"horiz",
XtCBoolean,
XtRBoolean,
sizeof(Boolean),
XtOffsetOf(PloadResources, horiz),
XtRImmediate,
(XtPointer)False
},
{
"inDiv",
"InDiv",
XtRInt,
sizeof(int),
XtOffsetOf(PloadResources, indiv),
XtRImmediate,
(XtPointer)1024
},
{
"outDiv",
"OutDiv",
XtRInt,
sizeof(int),
XtOffsetOf(PloadResources, outdiv),
XtRImmediate,
(XtPointer)1024
},
{
"device",
XtCString,
XtRString,
sizeof(String),
XtOffsetOf(PloadResources, device),
XtRString,
"ppp0"
},
{
"noConnectMsg",
XtCString,
XtRString,
sizeof(String),
XtOffsetOf(PloadResources, ncMsg),
XtRString,
"No Connection"
},
{
"inFormat",
XtCString,
XtRString,
sizeof(String),
XtOffsetOf(PloadResources, ifmt),
XtRString,
"%t %r in"
},
{
"outFormat",
XtCString,
XtRString,
sizeof(String),
XtOffsetOf(PloadResources, ofmt),
XtRString,
"%t %r out"
},
{
"showLabel",
XtCBoolean,
XtRBoolean,
sizeof(Boolean),
XtOffsetOf(PloadResources, showLabel),
XtRImmediate,
(XtPointer)True
},
{
"showIn",
XtCBoolean,
XtRBoolean,
sizeof(Boolean),
XtOffsetOf(PloadResources, showIn),
XtRImmediate,
(XtPointer)True
},
{
"showOut",
XtCBoolean,
XtRBoolean,
sizeof(Boolean),
XtOffsetOf(PloadResources, showOut),
XtRImmediate,
(XtPointer)True
}
};
/************* Main () ******************/
int main (int argc, char *argv[])
{
Progname = argv[0];
toplevel = XtAppInitialize (
&context, /* context */
"Pload", /* app name, class */
options, /* options */
XtNumber(options), /* num_options */
&argc, argv, /* command line */
default_resources, /* fallback resources */
NULL, ZERO);
/* all command line options are handled as X resources,
if an unknown option, like "-help" is found, show usage
and exit */
if (argc != 1) Usage();
XtGetApplicationResources(
toplevel, /* widget */
(XtPointer) &resources, /* where to put */
pload_resources, /* XtResourceList */
XtNumber(pload_resources), /* Cardinal num_resources */
NULL, ZERO);
/* set the title to reflect the device monitored */
i=0;
sprintf(buff, "Pload: %s", resources.device);
XtSetArg(arglist[i], XtNtitle, buff); i++;
XtSetValues(toplevel, arglist, i);
#ifdef LINUXPROC
ifd_initialize(&ifd, resources.device,
resources.avgpts,resources.useProc);
#else
ifd_initialize(&ifd, resources.device,
resources.avgpts,0);
#endif
/* set the default icon */
i=0;
XtSetArg(
arglist[i], /* Arg */
XtNiconPixmap, /* String name */
XCreateBitmapFromData( /* XtArgVal */
XtDisplay(toplevel), /* Display* */
XtScreen(toplevel)->root, /* Drawable d */
(char *)pload_bits, /* char *data */
pload_width, /* unsigned */
pload_height)); i++; /* unsigned */
XtSetValues(toplevel, arglist, i);
/* get notified of a change in icon state */
XtAddEventHandler(
toplevel, /* Widget w */
StructureNotifyMask, /* EventMask mask */
False, /* Boolean nonmaskable */
CheckForIconState, /* XtEventHandler proc */
NULL); /* XtPointer client_data */
/******* create the topform widget *************/
i=0;
XtSetArg(arglist[i], XtNdefaultDistance, 0); i++;
topform = XtCreateManagedWidget (
"topform", formWidgetClass,
toplevel,
arglist, i);
/******* create two more forms ***************/
if (resources.showIn)
{
i=0;
XtSetArg(arglist[i], XtNdefaultDistance, 0); i++;
XtSetArg(arglist[i], XtNbottom, XawRubber); i++;
XtSetArg(arglist[i], XtNresizable, True); i++;
iform = XtCreateManagedWidget (
"iform", formWidgetClass,
topform,
arglist, i);
}
if (resources.showOut)
{
i=0;
XtSetArg(arglist[i], XtNdefaultDistance, 0); i++;
XtSetArg(arglist[i], XtNtop, XawRubber); i++;
XtSetArg(arglist[i], XtNresizable, True); i++;
if (resources.showIn)
{
if (resources.horiz)
{
XtSetArg(arglist[i], XtNfromHoriz, iform);
i++;
}
else
{
XtSetArg(arglist[i], XtNfromVert, iform);
i++;
}
}
oform = XtCreateManagedWidget (
"oform", formWidgetClass,
topform,
arglist, i);
}
/* Gee, were those if statements tacked on later ? */
if (resources.showIn)
{
if (resources.showLabel)
{
/* create a label widget */
i=0;
/* XtSetArg(arglist[i], XtNlabel, "starting..."); i++; */
XtSetArg(arglist[i], XtNjustify, XtJustifyLeft); i++;
XtSetArg(arglist[i], XtNbottom, XawChainTop); i++;
XtSetArg(arglist[i], XtNtop, XawChainTop); i++;
XtSetArg(arglist[i], XtNresizable, True); i++;
ilabel = XtCreateManagedWidget (
"ilabel", labelWidgetClass, /* name, widgetclass */
iform, /* parent */
arglist, i ); /* arglist, num_args */
}
if (resources.showChart)
{
/* create a stripchart widget */
i=0;
if (resources.showLabel)
{
XtSetArg(arglist[i], XtNfromVert, ilabel); i++;
}
XtSetArg(arglist[i], XtNtop, XawChainTop); i++;
ichart = XtCreateManagedWidget (
"ichart", stripChartWidgetClass,/* name, widgetclass */
iform, /* parent */
arglist, i ); /* arglist, num_args */
/* add a callback for the stripchart */
XtAddCallback(
ichart, /* widget */
XtNgetValue, /* callback name */
GetIChartPoint, /* callback proc */
NULL ); /* client data */
}
}
if (resources.showOut)
{
if (resources.showLabel)
{
/***********************************************************/
/* create another label widget */
i=0;
/* XtSetArg(arglist[i], XtNlabel, "starting..."); i++; */
XtSetArg(arglist[i], XtNjustify, XtJustifyLeft); i++;
XtSetArg(arglist[i], XtNbottom, XawChainTop); i++;
XtSetArg(arglist[i], XtNtop, XawChainTop); i++;
XtSetArg(arglist[i], XtNresizable, True); i++;
olabel = XtCreateManagedWidget (
"olabel", labelWidgetClass, /* name, widgetclass */
oform, /* parent */
arglist, i ); /* arglist, num_args */
}
/**********************************************************/
/* add another stripchart */
if (resources.showChart)
{
i=0;
if (resources.showLabel)
{
XtSetArg(arglist[i], XtNfromVert, olabel); i++;
}
XtSetArg(arglist[i], XtNtop, XawChainTop); i++;
ochart = XtCreateManagedWidget (
"ochart", stripChartWidgetClass,/* name, widgetclass */
oform, /* parent */
arglist, i ); /* arglist, num_args */
/* add a callback for the stripchart */
XtAddCallback(
ochart, /* widget */
XtNgetValue, /* callback name */
GetOChartPoint, /* callback proc */
NULL ); /* client data */
}
}
/* manage and realize initial widget tree */
XtRealizeWidget(toplevel);
/* register interest in WM_DELETE_WINDOW */
HandleExit();
/* manually update */
update(0,0);
/* submit to the great X */
XtAppMainLoop(context);
return 0;
}
void update(XtPointer data, XtIntervalId *id)
{
get_stat(&ifd);
if ( (resources.showLabel && resources.showIn) ||
(iconstate == IconicState) )
{
if (ifd.in_bytes == 0UL)
sprintf(buff,"%s",resources.ncMsg);
else
make_label(resources.ifmt, ifd.in_bytes,
ifd.in_rate, ifd.in_max);
}
if ( resources.showLabel && resources.showIn )
XtVaSetValues(ilabel, XtNlabel, buff, NULL);
if (iconstate == IconicState)
XtVaSetValues(toplevel, XtNiconName, buff, NULL);
if (resources.showLabel && resources.showOut)
{
if (ifd.out_bytes == 0UL)
sprintf(buff,"%s",resources.ncMsg);
else
make_label(resources.ofmt, ifd.out_bytes,
ifd.out_rate, ifd.out_max);
XtVaSetValues(olabel, XtNlabel, buff, NULL);
}
XtAppAddTimeOut(context, 1000*resources.update, update, NULL);
return;
}
void GetIChartPoint( Widget w, /* not used */
XtPointer client_data, /* not used */
XtPointer call_data) /* *double point to return */
{
/* the update function handles refreshing the interface data */
double d = ifd.in_rate / (double)resources.indiv;
if (resources.logScale) d = (d < 1.0) ? 0.0 : log10(d);
*(double *)call_data = d;
return;
}
void GetOChartPoint( Widget w, /* not used */
XtPointer client_data, /* not used */
XtPointer call_data) /* *double point to return */
{
double d = ifd.out_rate / (double)resources.outdiv;
if (resources.logScale) d = (d < 1.0) ? 0.0 : log10(d);
*(double *)call_data = d;
return;
}
void HandleExit()
{
wm_delete_window = XInternAtom(
XtDisplay(toplevel), /* Display *display */
"WM_DELETE_WINDOW", /* char *atom_name */
False); /* Bool only_if_exits */
(void)XSetWMProtocols(
XtDisplay(toplevel), /* Display *display */
XtWindow(toplevel), /* Window w */
&wm_delete_window, /* Atom *protocols */
1); /* int count */
XtAddEventHandler(
toplevel, /* Widget w */
NoEventMask, /* EventMask mask */
True, /* Bool nonmaskable */
CheckForWMExit, /* XtEventHandler */
NULL); /* XtPointer client_data */
}
void CheckForIconState( Widget w,
XtPointer client_data,
XEvent *event,
Boolean *dispatch)
{
switch(event->type)
{
case UnmapNotify: iconstate = IconicState; break;
case MapNotify: iconstate = NormalState;
default: break;
}
}
void CheckForWMExit( Widget w,
XtPointer client_data,
XEvent *event,
Boolean *dispatch)
{
if ((event->type == ClientMessage) &&
(event->xclient.data.l[0] == wm_delete_window))
{
/* unload */
ifd_stop(&ifd);
XtDestroyApplicationContext(XtWidgetToApplicationContext(w));
exit(EXIT_SUCCESS);
}
return;
}
void do_total(char *b, double total)
{
if (total < 1024.0)
sprintf(b, "%s%0.0f B", b, total);
else if (total < (1024.0*1024.0))
sprintf(b, "%s%0.2f kB", b, total/1024.0);
else if (total < (1024.0*1024.0*1024.0))
sprintf(b, "%s%0.2f MB", b, total/1024.0/1024.0);
else
sprintf(b, "%s%0.2f GB", b, total/1024.0/1024.0/1024.0);
return;
}
void do_rate(char *b, double rate)
{
if (rate < 1024.0)
sprintf(b, "%s%0.0f B/s",b, rate);
else if (rate < (1024.0*1024.0))
sprintf(b, "%s%0.2f kB/s",b, rate/1024.0);
else if (rate < (1024.0*1024.0*1024.0))
sprintf(b, "%s%0.2f MB/s",b, rate/1024.0/1024.0);
else
sprintf(b, "%s%0.2f GB/s", b, rate/1024.0/1024.0/1024.0);
return;
}
/* stores label in global 'buff' */
void make_label(char *fmt, unsigned long total, double rate, double max)
{
char *p;
int i;
*buff = '\0';
for(p=fmt;*p;p++)
{
if (*p == '%')
{
p++;
switch(*p)
{
case 't':
do_total(buff, (double)total);
break;
case 'r':
do_rate(buff, rate);
break;
case 'M':
do_rate(buff, max);
break;
case 'd':
sprintf(buff, "%s", resources.device);
break;
case '%': /* literal % */
i = strlen(buff);
*(buff + i) = *p;
*(buff + i+1) = '\0';
break;
default:
fprintf(stderr,
"Unknown format specifier: %%%c\n",*p);
break;
}
}
else
{
/* sprintf(buf, "%s%c", buf, *p); */
i = strlen(buff);
*(buff + i) = *p;
*(buff + i+1) = '\0';
}
assert(strlen(buff) < sizeof(buff));
}
return;
}
void Usage()
{
fprintf(stderr,
"\n%s : show data for a network interface (ppp)\n", progver);
fprintf(stderr,
"Usage: %s [options]\n", Progname);
fprintf(stderr,
" where options includes, in addition to standard toolkit options,\n"
" option default description\n"
" -indiv <n> : 1024 : show dividing lines every n bytes/s for in data\n"
" -outdiv <n> : 1024 : show dividing lines every n bytes/s for out data\n"
" -logscale : False : use base 10 logarithmic scale for rate charts\n"
" -minscale <n> : 1 : minimum chart scale n\n"
" -jumpscroll <n> : 1 : jump n pixels on new data, 1 for smooth\n"
" -update <n> : 1 : update chart every n seconds\n"
" -in : False : only show receive chart\n"
" -out : False : only show send chart\n"
" -horiz : False : arrange horizontally\n"
" -nolabel : False : don't show text labels\n"
" -nochart : False : don't show charts (labels only)\n"
" -average <n> : 10 : average data over n points, 1 for no average\n"
" -device <X> : ppp0 : monitor device X\n"
" -hl <color> : default : chart highlight color\n"
" -incolor <color> : red : receive chart foreground color\n"
" -outcolor <color>: darkgreen : send chart foreground color\n"
" -fg <color> : default : foreground color\n"
" -bg <color> : default : background color\n"
" -fn <fontspec> : default : label font\n"
#ifdef LINUXPROC
" -noproc : False : don't use proc interface, use ioctl\n"
#endif
" -iformat <fmt> : %%t %%r in : format for inbound label\n"
" -oformat <fmt> : %%t %%r out : format for outbound label\n"
" -ncmsg <message> : No Connection : label to show when offline\n"
"\nsee the manual page for more information\n\n");
exit(EXIT_FAILURE);
}
syntax highlighted by Code2HTML, v. 0.9.1