/* This file is part of pload - a program to monitor ppp activity for X Copyright (C) 1999-2000 Matt Smith 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 #include #include #include #include #include #include #include #include #include #include #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 : 1024 : show dividing lines every n bytes/s for in data\n" " -outdiv : 1024 : show dividing lines every n bytes/s for out data\n" " -logscale : False : use base 10 logarithmic scale for rate charts\n" " -minscale : 1 : minimum chart scale n\n" " -jumpscroll : 1 : jump n pixels on new data, 1 for smooth\n" " -update : 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 : 10 : average data over n points, 1 for no average\n" " -device : ppp0 : monitor device X\n" " -hl : default : chart highlight color\n" " -incolor : red : receive chart foreground color\n" " -outcolor : darkgreen : send chart foreground color\n" " -fg : default : foreground color\n" " -bg : default : background color\n" " -fn : default : label font\n" #ifdef LINUXPROC " -noproc : False : don't use proc interface, use ioctl\n" #endif " -iformat : %%t %%r in : format for inbound label\n" " -oformat : %%t %%r out : format for outbound label\n" " -ncmsg : No Connection : label to show when offline\n" "\nsee the manual page for more information\n\n"); exit(EXIT_FAILURE); }