+1.3 / 8-Mar-04
+
+ - Fix: support for 64bit counters
+ - Fix: 'yesterday' was showing 01.01. with new databases
+ - Fix: free space warning changed from 1% to 1MB
+ - Fix: minor security exploit
+ - A man page has been included
+ - Hourly output with textgraphical view
+ - kBs are visible when traffic is under 1000 MB
+ - Webpage moved to http://humdi.net/vnstat/
+ - Minor visual updates
+
+
1.2 / 7-Oct-03
- - Changed file paths to conform with FHS (http://www.pathname.com/fhs/).
+ - Changed file paths to conform with FHS (http://www.pathname.com/fhs/)
/usr/local/bin/vnstat -> /usr/bin/vnstat
/var/spool/vnstat -> /var/lib/vnstat
- - Added FAQ.
- - Included sample scripts for pppd users.
- - Support for 64bit counters in /proc/net/dev.
+ - Added FAQ
+ - Included sample scripts for pppd users
+ - Support for 64bit counters in /proc/net/dev
(Thanks to Stephan van Hienen for the test account)
- Actual date is shown if the previous day in the database isn't
- yesterday.
- - Weekly and last 7 days traffic can be shown.
+ yesterday
+ - Weekly and last 7 days traffic can be shown.
(Thanks to Derk-Jan Hartman for the suggestion)
- - Average kB/s meter.
- - --testkernel fixed.
- - Documentation for --dumpdb included in the README.
+ - Average kB/s meter
+ - --testkernel fixed
+ - Documentation for --dumpdb included in the README
1.1 / 13-Jul-03
- - Support for multiple interfaces.
- - Date checking (update shouldn't be before previous update).
- - New database structure.
- - Possibility to change date output format.
- - Test tool for faulty kernels.
- - Parseable output.
- - Better support for ppp/dsl users.
- - Free diskspace check.
- - Possibility to change month rotation day (like 25. instead of 1.).
- - Daily/monthly traffic estimation.
+ - Support for multiple interfaces
+ - Date checking (update shouldn't be before previous update)
+ - New database structure
+ - Possibility to change date output format
+ - Test tool for faulty kernels
+ - Parseable output
+ - Better support for ppp/dsl users
+ - Free diskspace check
+ - Possibility to change month rotation day (like 25. instead of 1.)
+ - Daily/monthly traffic estimation
22-Nov-02
- Renamed the cron script file that would be installed to /etc/cron.d
from vnstat.cron to vnstat because debian systems didn't execute scripts
- containing dots. (Thanks to frangen / Simo Salminen for this note)
+ containing dots (Thanks to frangen / Simo Salminen for this note)
1.0 / 23-Sep-02
- - Initial public release.
+ - Initial public release
That FAQ is located at
- http://torus.lnet.lut.fi/vnstat/FAQ
+ http://humdi.net/vnstat/FAQ
since that's the easiest way to keep it always updated.
-(Updated 7.10.2003 based on version 1.2)
+(Updated 8.3.2003 based on version 1.3)
+
+'I don't read manuals' install
+::::::::::::::::::::::::::::::
+
+ make && make install ; vnstat --testkernel && vnstat -u -i eth0
+
Installing vnStat
:::::::::::::::::
vnstat -u -i eth0
Repeat that for every other interface you wish to use. After that wait
- for about 1 MB of network traffic (and 5 min).
+ for about 10 kB of network traffic (and 5 min).
vnstat
0-55/5 * * * * ~/bin/vnstat -u
If you found yourself using a strange editor then 'man vi' should help.
- After that wait for about 1 MB of network traffic (and 5 min).
+ After that wait for about 10 kB of network traffic (and 5 min).
vnstat
+# bin, man and cron dirs
+BIN = $(DESTDIR)/usr/bin
+MAN = $(DESTDIR)/usr/share/man
+CRON = $(DESTDIR)/etc/cron.d
+
vnstat:
+make -C src vnstat
install:
@echo "Installing vnStat..."
- @if [ -d /var/spool/vnstat ]; then echo "Moving old database(s) to new location..."; mv -f /var/spool/vnstat /var/lib/; fi
- mkdir -p /var/lib/vnstat
+ @if [ -d $(DESTDIR)/var/spool/vnstat ]; then echo "Moving old database(s) to new location..."; mv -f $(DESTDIR)/var/spool/vnstat $(DESTDIR)/var/lib/; fi
- @if [ -x /usr/local/bin/vnstat ]; then echo "Removing old binary..."; rm -f /usr/local/bin/vnstat; fi
+ @if [ -x $(DESTDIR)/usr/local/bin/vnstat ]; then echo "Removing old binary..."; rm -f $(DESTDIR)/usr/local/bin/vnstat; fi
- @if [ -d /etc/ppp/ip-up.d ]; then echo "Installing ppp/ip-up script"; cp -f pppd/vnstat_ip-up /etc/ppp/ip-up.d/vnstat; fi
- @if [ -d /etc/ppp/ip-down.d ]; then echo "Installing ppp/ip-down script"; cp -f pppd/vnstat_ip-down /etc/ppp/ip-down.d/vnstat; fi
+ @if [ -d $(DESTDIR)/etc/ppp/ip-up.d ]; then echo "Installing ppp/ip-up script"; cp -f pppd/vnstat_ip-up $(DESTDIR)/etc/ppp/ip-up.d/vnstat; fi
+ @if [ -d $(DESTDIR)/etc/ppp/ip-down.d ]; then echo "Installing ppp/ip-down script"; cp -f pppd/vnstat_ip-down $(DESTDIR)/etc/ppp/ip-down.d/vnstat; fi
- install -m 755 src/vnstat /usr/bin
- install -m 644 cron/vnstat /etc/cron.d
+ install -d $(BIN) $(MAN)/man1 $(CRON) $(DESTDIR)/var/lib/vnstat
+ install -m 755 src/vnstat $(BIN)
+ install -m 644 man/vnstat.1 $(MAN)/man1
+ install -m 644 cron/vnstat $(CRON)
uninstall:
@echo "Uninstalling vnStat..."
@echo
@echo "Press CTRL-C to abort within 10 sec."
@sleep 10
- rm -fr /var/lib/vnstat
- rm -f /usr/bin/vnstat
- rm -f /etc/cron.d/vnstat
- rm -f /etc/ppp/ip-up.d/vnstat
- rm -f /etc/ppp/ip-down.d/vnstat
+ rm -fr $(DESTDIR)/var/lib/vnstat
+ rm -f $(BIN)/vnstat
+ rm -f $(MAN)/man1/vnstat.1
+ rm -f $(CRON)/vnstat
+ rm -f $(DESTDIR)/etc/ppp/ip-up.d/vnstat
+ rm -f $(DESTDIR)/etc/ppp/ip-down.d/vnstat
-(Updated 7.10.2003 based on version 1.2)
+(Updated 8.3.2003 based on version 1.3)
What is vnStat
::::::::::::::
:::::::::::::::
First you should install vnStat. See the INSTALL file, it contains all needed
- information needed in the installing process. Users of version 1.0 should
- see the UPGRADE file first.
+ information for the installing process. Users of version 1.0 should see the
+ UPGRADE file first.
Available options
:::::::::::::::::
- The idea of this section is to explain to use of options that vnStat provides.
- Few simple options aren't listed. A complete list is available with
- 'vnstat -h'.
-
--u, --update
-
- vnStat will try to update the database whenever this option is specified.
- Use with -i to update a single interface or create a new database. Otherwise
- all enabled databases will be updated.
-
--r, --reset
-
- This will reset the internal counters in the database for the selected
- interface. Use this if the interface goes down and back up, otherwise
- that interface will get some extra traffic to its database.
-
---enable enable interface
---disable disable interface
-
- These two are probably useful especially for ppp users. If the interface
- goes down it should be disabled in order to avoid errors. Add something
- like 'vnstat -r --disable -i ppp0' to the script that's executed when
- the interface goes down and 'vnstat --enable -i ppp0' to the up script.
- Example scripts are available in the pppd directory. The location where
- those scripts should be installed will likely vary between distributions.
- Afaik for at least Debian and SuSe that's /etc/ppp/ip-up.d and
- /etc/ppp/ip-down.d. Gentoo uses the files /etc/ppp/ip-up and /etc/ip-down.
-
---nick
-
- It's possible to give a nickname for each interface in order to make
- identifying easier. -u is required with -nick. Displaying of the nick
- can be disabled by changing the nick to be the same as the name of the
- interface.
-
---rebuildtotal
-
- This will reset the total traffic counters and recount those using recorded
- months.
-
---dumpdb
-
- Instead of showing the database with a formated output, this output will
- dump the whole database in a format that should be easy to parse with most
- script languages. Use this for example with php or perl to make a custom
- webpage. The dump uses ; as field delimeter.
-
- active;1 1 if the selected interface is enabled
- interface;eth0 name for the interface
- nick;inet nick (if given)
- created;1023895272 creation date in Unix time
- (seconds since '00:00:00 1970-01-01 UTC')
- updated;1065467100 when the database was updated
- totalrx;569605 all time total received MB
- totaltx;2023708 all time total transmitted MB
- currx;621673719 last seen rx value in /proc/net/dev
- curtx;981730184 last seen rx value in /proc/net/dev
- totalrxk;644 total rx kB counter
- totaltxk;494 total tx kB counter
- btime;1059414541 system boot time in Unix time
-
- Then follows 30 lines like the following
-
- d;0;1065387600;584;3564;1
-
- where d = days, 0 = day number in database (0 is today), 1065387600 date in
- Unix time, 584 = rx MB, 3564 = tx MB and 1 tells that vnStat has filled this
- value and its in use.
-
- m;0;1064955600;4304;17677;1 (x12)
- t;0;1043722416;7499;30662;1 (x10)
-
- m = months and t = top10, all other fields are in the same order as in days.
-
--D, --debug
-
- Some debug output is included within vnStat and that output can be activated
- with this option. The output is somewhat self explaining and should give some
- clues what vnStat is doing.
-
--tr, --traffic
-
- This will make vnStat calculation how much traffic goes through the selected
- interface during the given time. The time will be 5 seconds if a number
- parameter isn't included.
-
---testkernel
-
- For some reason, there's few kernels that don't keep the boot time correct.
- This option will test if the btime stays always to same like it should or
- if it's shifting. Only /proc/stat is accessed so there's no black magic
- or strange tricks included.
+ A list of commonly used options is available with 'vnstat --help'. The
+ complete list can be accessed with 'vnstat --longhelp'. See the man(1)
+ page for option explanations.
Usage tips
Contacting the author
:::::::::::::::::::::
- email: Teemu Toivola <tst@iki.fi>
+ email: Teemu Toivola <tst at iki dot fi>
irc: Vergo (IRCNet)
+ forum: http://forums.humdi.net/
The current version of vnStat is always available from
- http://torus.lnet.lut.fi/vnstat/
-
- My email address is static, but the url for vnStat is likely to change
- some day. The project page at freshmeat http://freshmeat.net/projects/vnstat/
- will be updated after any change.
+ http://humdi.net/vnstat/
-(Updated 5.10.2003 based on version 1.2)
+(Updated 29.2.2004 based on version 1.3)
This file will try to explain how vnStat is supposed to be upgraded
from version 1.0. The makefile should handle upgrades from version 1.1
-to 1.2 without user interaction. But for those still using 1.0, please
+to 1.3 without user interaction. But for those still using 1.0, please
read the instructions once before executing step by step.
+But once again to make this clear:
+
+ The following instructions apply only for those upgrading from
+ version 1.0. Any other version can be upgraded by the Makefile itself.
+
+
What to do before installing?
:::::::::::::::::::::::::::::
would be /var/spool/vnstat/db and for singleuser it's ~/.vnstatdb
Copy that file to some other directory that isn't in any relation with
vnStat. All this is only for backup so the file can be removed once
- 1.2 has been installed and working.
+ 1.3 has been installed and working.
The next thing is to rename that database according to the interface it's
monitoring. Here's an example if the interface would be eth0.
Now your all set to continue the install process like the INSTALL file
tells. Remember that there's no need to uninstall version 1.0 before
- installing 1.2.
+ installing 1.3.
--- /dev/null
+.TH VNSTAT 1 "MARCH 2004" Linux "User Manuals"
+.SH NAME
+vnStat \- a console-based network traffic monitor
+.SH SYNOPSIS
+.B vnstat
+[
+.B \-Ddhmqrstuvw?
+] [
+.B \-i
+.I interface
+] [
+.B \-tr
+.I time
+] [
+.B \-\-cleartop
+] [
+.B \-\-days
+] [
+.B \-\-debug
+] [
+.B \-\-disable
+] [
+.B \-\-dumpdb
+] [
+.B \-\-enable
+] [
+.B \-\-help
+] [
+.B \-\-hours
+] [
+.B \-\-iface
+.I interface
+] [
+.B \-\-longhelp
+] [
+.B \-\-months
+] [
+.B \-\-nick
+.I nickname
+] [
+.B \-\-query
+] [
+.B \-\-rebuildtotal
+] [
+.B \-\-reset
+] [
+.B \-\-short
+] [
+.B \-\-testkernel
+] [
+.B \-\-top10
+] [
+.B \-\-traffic
+.I time
+] [
+.B \-\-update
+] [
+.B \-\-version
+] [
+.B \-\-weeks
+]
+.SH DESCRIPTION
+.B vnStat
+is a console-base network traffic monitor that keeps a log of
+daily and monthly network traffic for the selected interface(s).
+However, it isn't a packet sniffer. The traffic information is
+analyzed from the
+.BR proc (5)
+-filesystem, so that vnStat can be used without root permissions.
+.SH OPTIONS
+.TP
+.BI "-D, --debug"
+Show additional debug output.
+.TP
+.BI "-d, --days"
+Show traffic for days.
+.TP
+.BI "-h, --hours"
+Show traffic for the last 24 hours.
+.TP
+.BI "-i, --iface " interface
+Select one specific
+.I interface
+and apply actions to only it.
+.TP
+.BI "-m, --months"
+Show traffic for months.
+.TP
+.BI "-q, --query"
+Force database query mode.
+.TP
+.BI "-r, --reset"
+Reset the internal counters in the database for the selected
+interface. Use this if the interface goes down and back up,
+otherwise that interface will get some extra traffic to its database.
+.TP
+.BI "-s, --short"
+Use short output mode. This mode is also used if more than one
+database is available.
+.TP
+.BI "-t, --top10"
+Show all time top10 traffic days.
+.TP
+.BI "-tr " time
+Calculate how much traffic goes through the selected interface during
+the given
+.I time
+seconds. The
+.I time
+will be 5 seconds if a number parameter isn't included.
+.TP
+.BI "-u, --update"
+Update all enabled databases or only the one specified with
+.B -i
+parameter.
+.TP
+.BI "-v, --version"
+Show current version.
+.TP
+.BI "-w, --weeks"
+Show traffic for 7 days, current and previous week.
+.TP
+.BI "--cleartop"
+Remove all top10 entries.
+.TP
+.BI "--dumpdb"
+Instead of showing the database with a formated output, this output will
+dump the whole database in a format that should be easy to parse with most
+script languages. Use this for example with php or perl to make a custom
+webpage. The dump uses ; as field delimeter.
+
+ active;1 activity status
+ interface;eth0 name for the interface
+ nick;inet nick (if given)
+ created;1023895272 creation date in Unix time
+ updated;1065467100 when the database was updated
+ totalrx;569605 all time total received MB
+ totaltx;2023708 all time total transmitted MB
+ currx;621673719 latest rx value in /proc
+ curtx;981730184 latest tx value in /proc
+ totalrxk;644 total rx kB counter
+ totaltxk;494 total tx kB counter
+ btime;1059414541 system boot time in Unix time
+
+Then follows 30 lines like the following
+
+ d;0;1078696800;559;7433;68;557;1
+
+where d = days, 0 = day number in database (0 is today), 1077314401 date in
+Unix time, 559 = rx MB, 7433 = tx MB, 68 = rx kB, 557 = tx kB and 1 tells that
+vnStat has filled this value and it is in use.
+
+ m;0;1078092000;48649;139704;527;252;1 (x12)
+ t;0;1078351200;5979;47155;362;525;1 (x10)
+ h;0;1078699800;118265;516545 (x24)
+
+m = months, t = top10 and h = hours, all other fields are in the same order as in days
+except hours that doesn't have a separate kB value. For hours the forth and fifth fields
+have values in kB.
+.TP
+.BI "--enable, --disable"
+Enable or disable updates for selected interface. Useful for
+interfaces that aren't always available, like ppp0. If the interface
+goes down it should be disabled in order to avoid errors. Add something
+like
+.B "vnstat -r --disable -i ppp0"
+to the script that's executed when
+the interface goes down and
+.B "vnstat --enable -i ppp0"
+to the up script.
+.TP
+.BI "-?, --help"
+Show a command summary.
+.TP
+.BI "--longhelp"
+Show complete options list.
+.TP
+.BI "--nick " nickname
+Set the selected interfaces
+.I nickname
+as an alias the will be displayed in queries. Usage of
+.B -u
+is required to save the change.
+.TP
+.BI "--rebuildtotal"
+Reset the total traffic counters and recount those using recorded months.
+.TP
+.BI "--testkernel"
+Test if the kernel btime stays always to same like it should or
+if it's shifting.
+.SH FILES
+.I /var/lib/vnstat/
+.RS
+This directory contains all databases the program uses. Files are
+named according to the monitored interfaces.
+.SH EXAMPLES
+.BI "vnstat -u -i"
+.I interface
+forces a database update for
+.I interface
+or creates the database if it doesn't exist. This is usually the
+first command used after a fresh install.
+.PP
+.BI "vnstat -u -i"
+.I interface
+.BI "--nick"
+.I nick
+gives
+.I interface
+the nickname
+.I "nick"
+and that information will be later included with queries.
+.PP
+.BI "vnstat -u -r --disable -i
+.I interface
+resets the internal counters of
+.I interface
+and disables it from being updated before enabled again with the
+.BI "--enable"
+parameter. This feature is especially useful for interfaces like ppp0
+that aren't always active.
+.SH RESTRICTIONS
+64bit counters can't currently be automatically detected, therefore
+support must be specified before compiling.
+.PP
+Estimated traffic values are likely to be somewhat inaccurate if daily
+traffic is low because only the MB counter is used to calculate the
+estimate.
+.SH AUTHOR
+Teemu Toivola <tst at iki dot fi>
+.SH "SEE ALSO"
+.BR proc (5)
CC = gcc
-CFLAGS = -O2
+CFLAGS = -O2 -Wall
OBJS = proc.o db.o misc.o
+OBJS64 = proc64.o db.o misc.o
default: vnstat
vnstat: $(OBJS) vnstat.c vnstat.h
$(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS)
-64bit: $(OBJS) vnstat.c vnstat.h
- $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS) -DBLIMIT
+64bit: $(OBJS64) vnstat.c vnstat.h
+ $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS64) -DBLIMIT
single: $(OBJS) vnstat.c vnstat.h
$(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS) -DSINGLE
-64bitsingle: $(OBJS) vnstat.c vnstat.h
- $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS) -DSINGLE -DBLIMIT
+64bitsingle: $(OBJS64) vnstat.c vnstat.h
+ $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS64) -DSINGLE -DBLIMIT
proc.o: proc.c proc.h vnstat.h db.h
$(CC) $(CFLAGS) -c proc.c
+proc64.o: proc.c proc.h vnstat.h db.h
+ $(CC) $(CFLAGS) -c proc.c -o proc64.o -DBLIMIT
+
db.o: db.c db.h vnstat.h
$(CC) -O2 -c db.c
printf("Database loaded for interface \"%s\"...\n",data.interface);
/* convert old database to new format if necessary */
- if (data.version!=DBVERSION)
+ if (data.version!=DBVERSION) {
+ printf("Trying to convert database \"%s\" (v%d) to current db format\n", file, data.version);
convertdb(db);
+ }
fclose(db);
if (strcmp(data.interface,iface)) {
printf("It has now been replaced with \"%s\".\n\n",iface);
printf("You can ignore this message if you renamed the filename.\n");
if (strcmp(data.interface, data.nick)==0)
- strcpy(data.nick, iface);
- strcpy(data.interface, iface);
+ strncpy(data.nick, iface, 32);
+ strncpy(data.interface, iface, 32);
}
} else {
printf("Error:\nUnable to read database \"%s\".\n",file);
data.totaltxk=0;
data.lastupdated=time(NULL);
data.created=time(NULL);
+
+ /* days */
for (i=0;i<=29;i++) {
data.day[i].rx=0;
data.day[i].tx=0;
+ data.day[i].rxk=0;
+ data.day[i].txk=0;
data.day[i].date=0;
data.day[i].used=0;
}
+
+ /* months */
for (i=0;i<=11;i++) {
data.month[i].rx=0;
data.month[i].tx=0;
+ data.month[i].rxk=0;
+ data.month[i].txk=0;
data.month[i].month=0;
data.month[i].used=0;
}
+
+ /* top10 */
for (i=0;i<=9;i++) {
data.top10[i].rx=0;
data.top10[i].tx=0;
+ data.top10[i].rxk=0;
+ data.top10[i].txk=0;
data.top10[i].date=0;
data.top10[i].used=0;
}
+
+ /* hours */
+ for (i=0;i<=23;i++) {
+ data.hour[i].rx=0;
+ data.hour[i].tx=0;
+ data.hour[i].date=0;
+ }
data.day[0].used=data.month[0].used=1;
data.day[0].date=data.month[0].month=time(NULL);
data.btime=FPOINT-1;
{
FILE *db;
+ /* make sure version stays correct */
+ data.version=DBVERSION;
+
if ((db=fopen(file,"w"))!=NULL) {
data.lastupdated=time(NULL);
fwrite(&data,sizeof(DATA),1,db);
struct tm *d;
char datebuff[16];
char daytemp[128];
- uint64_t e_rx, e_tx, t_rx, t_tx;
+ uint64_t e_rx, e_tx, t_rx, t_tx, t_rxk, t_txk;
time_t current, yesterday;
current=time(NULL);
yesterday=current-86400;
- if (data.totalrx+data.totaltx==0) {
+ if (data.totalrx+data.totaltx==0 && (data.totalrxk/(float)10+data.totaltxk/(float)10)==0) {
printf(" %s: Not enough data available yet.\n", data.interface);
} else {
+ /* total with today and possible yesterday */
if (qmode==0) {
d=localtime(¤t);
/* change daytemp to yesterday if formated days match */
if (strcmp(datebuff, daytemp)==0) {
- strcpy(daytemp, "yesterday");
+ strncpy(daytemp, "yesterday", 32);
}
- printf("\t received: %'14Lu MB (%.1f%%)\n",data.totalrx,rx);
- printf("\ttransmitted: %'14Lu MB (%.1f%%)\n",data.totaltx,tx);
- printf("\t total: %'14Lu MB\n\n",data.totalrx+data.totaltx);
+ printf("\t received: ");
+ showint(data.totalrx, data.totalrxk, 14);
+ printf(" MB (%.1f%%)\n",rx);
+ printf("\ttransmitted: ");
+ showint(data.totaltx, data.totaltxk, 14);
+ printf(" MB (%.1f%%)\n",tx);
+ printf("\t total: ");
+ showint(data.totalrx+data.totaltx, data.totalrxk+data.totaltxk, 14);
+ printf(" MB\n\n");
+
+
printf("\t rx | tx | total\n");
printf("\t-----------------------+------------+-----------\n");
- printf("\t%9s %'7Lu MB | %'7Lu MB | %'7Lu MB\n",daytemp,data.day[1].rx,data.day[1].tx,data.day[1].rx+data.day[1].tx);
- printf("\t today %'7Lu MB | %'7Lu MB | %'7Lu MB\n",data.day[0].rx,data.day[0].tx,data.day[0].rx+data.day[0].tx);
+ if (data.day[1].date!=0) {
+ printf("\t%9s ",daytemp);
+ showint(data.day[1].rx, data.day[1].rxk, 7);
+ printf(" MB | ");
+ showint(data.day[1].tx, data.day[1].txk, 7);
+ printf(" MB | ");
+ showint(data.day[1].rx+data.day[1].tx, data.day[1].rxk+data.day[1].txk, 7);
+ printf(" MB\n");
+ }
+ printf("\t today ");
+ showint(data.day[0].rx, data.day[0].rxk, 7);
+ printf(" MB | ");
+ showint(data.day[0].tx, data.day[0].txk, 7);
+ printf(" MB | ");
+ showint(data.day[0].rx+data.day[0].tx, data.day[0].rxk+data.day[0].txk, 7);
+ printf(" MB\n");
printf("\t-----------------------+------------+-----------\n");
printf("\testimated %'7Lu MB | %'7Lu MB | %'7Lu MB\n",e_rx, e_tx, e_rx+e_tx);
+ /* days */
} else if (qmode==1) {
printf("\n");
if (data.day[i].used) {
d=localtime(&data.day[i].date);
strftime(datebuff, 16, DFORMAT, d);
- printf("\t %6s %'7Lu MB | %'7Lu MB | %'7Lu MB\n",datebuff, data.day[i].rx,data.day[i].tx,data.day[i].rx+data.day[i].tx);
+ printf("\t %6s ",datebuff);
+ showint(data.day[i].rx, data.day[i].rxk, 7);
+ printf(" MB | ");
+ showint(data.day[i].tx, data.day[i].txk, 7);
+ printf(" MB | ");
+ showint(data.day[i].rx+data.day[i].tx, data.day[i].rxk+data.day[i].txk, 7);
+ printf(" MB\n");
used++;
}
}
printf("\t estimated %'7Lu MB | %'7Lu MB | %'7Lu MB\n", e_rx, e_tx, e_rx+e_tx);
}
+ /* months */
} else if (qmode==2) {
printf("\n");
if (data.month[i].used) {
d=localtime(&data.month[i].month);
strftime(datebuff, 16, MFORMAT, d);
- printf("\t %7s %'9Lu MB | %'9Lu MB | %'9Lu MB\n",datebuff, data.month[i].rx,data.month[i].tx,data.month[i].rx+data.month[i].tx);
+ printf("\t %7s ",datebuff);
+ showint(data.month[i].rx, data.month[i].rxk, 9);
+ printf(" MB | ");
+ showint(data.month[i].tx, data.month[i].txk, 9);
+ printf(" MB | ");
+ showint(data.month[i].rx+data.month[i].tx, data.month[i].rxk+data.month[i].txk, 9);
+ printf(" MB\n");
used++;
}
}
e_tx=((data.month[0].tx)/(float)((d->tm_mday-1)*24+d->tm_hour))*(dmonth[d->tm_mon]*24);
printf("\testimated %'9Lu MB | %'9Lu MB | %'9Lu MB\n", e_rx, e_tx, e_rx+e_tx);
}
-
+
+ /* top10 */
} else if (qmode==3) {
printf("\n");
if (data.top10[i].used) {
d=localtime(&data.top10[i].date);
strftime(datebuff, 16, TFORMAT, d);
- printf("\t %2d %8s %'7Lu MB | %'7Lu MB | %'7Lu MB\n", i+1, datebuff, data.top10[i].rx,data.top10[i].tx,data.top10[i].rx+data.top10[i].tx);
+ printf("\t %2d %8s ", i+1, datebuff);
+ showint(data.top10[i].rx, data.top10[i].rxk, 7);
+ printf(" MB | ");
+ showint(data.top10[i].tx, data.top10[i].txk, 7);
+ printf(" MB | ");
+ showint(data.top10[i].rx+data.top10[i].tx, data.top10[i].rxk+data.top10[i].txk, 7);
+ printf(" MB\n");
used++;
}
}
printf("\t no data available\n");
printf("\t--------------------------------+-------------+-------------\n");
+ /* dumpdb */
} else if (qmode==4) {
printf("version;%d\n", data.version);
printf("btime;%Lu\n", data.btime);
for (i=0;i<=29;i++) {
- printf("d;%d;%d;%Lu;%Lu;%d\n",i, data.day[i].date, data.day[i].rx, data.day[i].tx, data.day[i].used);
+ printf("d;%d;%d;%Lu;%Lu;%d;%d;%d\n",i, data.day[i].date, data.day[i].rx, data.day[i].tx, data.day[i].rxk, data.day[i].txk, data.day[i].used);
}
for (i=0;i<=11;i++) {
- printf("m;%d;%d;%Lu;%Lu;%d\n",i, data.month[i].month, data.month[i].rx, data.month[i].tx, data.month[i].used);
+ printf("m;%d;%d;%Lu;%Lu;%d;%d;%d\n",i, data.month[i].month, data.month[i].rx, data.month[i].tx, data.month[i].rxk, data.month[i].txk, data.month[i].used);
}
for (i=0;i<=9;i++) {
- printf("t;%d;%d;%Lu;%Lu;%d\n",i,data.top10[i].date, data.top10[i].rx, data.top10[i].tx, data.top10[i].used);
+ printf("t;%d;%d;%Lu;%Lu;%d;%d;%d\n",i,data.top10[i].date, data.top10[i].rx, data.top10[i].tx, data.top10[i].rxk, data.top10[i].txk, data.top10[i].used);
}
+ for (i=0;i<=23;i++) {
+ printf("h;%d;%d;%Lu;%Lu\n",i,data.hour[i].date, data.hour[i].rx, data.hour[i].tx);
+ }
+
+ /* multiple dbs at one time */
} else if (qmode==5) {
if (strcmp(data.interface, data.nick)==0) {
/* change daytemp to yesterday if formated days match */
if (strcmp(datebuff, daytemp)==0) {
- strcpy(daytemp, "yesterday");
+ strncpy(daytemp, "yesterday", 32);
}
-
- printf(" %9s %'7Lu MB / %'7Lu MB / %'7Lu MB\n",daytemp,data.day[1].rx, data.day[1].tx, data.day[1].rx+data.day[1].tx);
- printf(" today %'7Lu MB / %'7Lu MB / %'7Lu MB / %'7Lu MB\n\n",data.day[0].rx, data.day[0].tx, data.day[0].rx+data.day[0].tx, e_rx+e_tx);
+
+ if (data.day[1].date!=0) {
+ printf(" %9s ",daytemp);
+ showint(data.day[1].rx, data.day[1].rxk, 7);
+ printf(" MB / ");
+ showint(data.day[1].tx, data.day[1].txk, 7);
+ printf(" MB / ");
+ showint(data.day[1].rx+data.day[1].tx, data.day[1].rxk+data.day[1].txk, 7);
+ printf(" MB\n");
+ }
+ printf(" today ");
+ showint(data.day[0].rx, data.day[0].rxk, 7);
+ printf(" MB / ");
+ showint(data.day[0].tx, data.day[0].txk, 7);
+ printf(" MB / ");
+ showint(data.day[0].rx+data.day[0].tx, data.day[0].rxk+data.day[0].txk, 7);
+ printf(" MB / %'7Lu MB\n\n",e_rx+e_tx);
+ /* last 7 */
} else if (qmode==6) {
printf("\n");
/* last 7 days */
used=0;
temp=0;
- t_rx=t_tx=0;
+ t_rx=t_tx=t_rxk=t_txk=0;
for (i=0;i<30;i++) {
if ((data.day[i].used) && (data.day[i].date>=current-604800)) {
- t_rx+=data.day[i].rx;
- t_tx+=data.day[i].tx;
+ addtraffic(&t_rx, &t_rxk, data.day[i].rx, data.day[i].rxk);
+ addtraffic(&t_tx, &t_txk, data.day[i].tx, data.day[i].txk);
used++;
}
}
if (used!=0) {
- printf("\t last 7 days %'9Lu MB | %'9Lu MB | %'9Lu MB\n", t_rx, t_tx, t_rx+t_tx);
+ printf("\t last 7 days ");
+ showint(t_rx, t_rxk, 9);
+ printf(" MB | ");
+ showint(t_tx, t_txk, 9);
+ printf(" MB | ");
+ showint(t_rx+t_tx, t_rxk+t_txk, 9);
+ printf(" MB\n");
temp++;
}
/* traffic for previous week */
used=0;
- t_rx=t_tx=0;
+ t_rx=t_tx=t_rxk=t_txk=0;
for (i=0;i<30;i++) {
if (data.day[i].used) {
d=localtime(&data.day[i].date);
strftime(daytemp, 16, "%V", d);
if (atoi(daytemp)==week-1) {
- t_rx+=data.day[i].rx;
- t_tx+=data.day[i].tx;
+ addtraffic(&t_rx, &t_rxk, data.day[i].rx, data.day[i].rxk);
+ addtraffic(&t_tx, &t_txk, data.day[i].tx, data.day[i].txk);
used++;
}
}
}
if (used!=0) {
- printf("\t last week %'9Lu MB | %'9Lu MB | %'9Lu MB\n", t_rx, t_tx, t_rx+t_tx);
+ printf("\t last week ");
+ showint(t_rx, t_rxk, 9);
+ printf(" MB | ");
+ showint(t_tx, t_txk, 9);
+ printf(" MB | ");
+ showint(t_rx+t_tx, t_rxk+t_txk, 9);
+ printf(" MB\n");
temp++;
}
/* this week */
used=0;
- t_rx=t_tx=0;
+ t_rx=t_tx=t_rxk=t_txk=0;
for (i=0;i<30;i++) {
if (data.day[i].used) {
d=localtime(&data.day[i].date);
strftime(daytemp, 16, "%V", d);
if (atoi(daytemp)==week) {
- t_rx+=data.day[i].rx;
- t_tx+=data.day[i].tx;
+ addtraffic(&t_rx, &t_rxk, data.day[i].rx, data.day[i].rxk);
+ addtraffic(&t_tx, &t_txk, data.day[i].tx, data.day[i].txk);
used++;
}
}
strftime(daytemp, 16, "%u", d);
e_rx=((t_rx)/(float)((atoi(daytemp)-1)*24+d->tm_hour)*168);
e_tx=((t_tx)/(float)((atoi(daytemp)-1)*24+d->tm_hour)*168);
- printf("\t current week %'9Lu MB | %'9Lu MB | %'9Lu MB\n", t_rx, t_tx, t_rx+t_tx);
+ printf("\t current week ");
+ showint(t_rx, t_rxk, 9);
+ printf(" MB | ");
+ showint(t_tx, t_txk, 9);
+ printf(" MB | ");
+ showint(t_rx+t_tx, t_rxk+t_txk, 9);
+ printf(" MB\n");
temp++;
}
if (used!=0)
printf("\t estimated %'9Lu MB | %'9Lu MB | %'9Lu MB\n", e_rx, e_tx, e_rx+e_tx);
+ /* hours */
+ } else if (qmode==7) {
+
+ showhours();
+
} else {
/* users shouldn't see this text... */
printf("Not such query mode: %d\n", qmode);
}
+void showhours(void)
+{
+ int i, j, k;
+ int tmax=0, max=0, s=0, dots=0;
+ char matrix[24][80];
+
+ int hour, min;
+ struct tm *d;
+
+ /* tmax = time max = current hour */
+ /* max = transfer max */
+
+ d=localtime(&data.lastupdated);
+ hour=d->tm_hour;
+ min=d->tm_min;
+
+ for (i=0;i<=23;i++) {
+ if (data.hour[i].date>=data.hour[tmax].date) {
+ tmax=i;
+ }
+ if (data.hour[i].rx>=max) {
+ max=data.hour[i].rx;
+ }
+ if (data.hour[i].tx>=max) {
+ max=data.hour[i].tx;
+ }
+ }
+
+ /* mr. proper */
+ for (i=0;i<24;i++) {
+ for (j=0;j<80;j++) {
+ matrix[i][j]=' ';
+ }
+ }
+
+
+ /* structure */
+ sprintf(matrix[11]," -+--------------------------------------------------------------------------->");
+ sprintf(matrix[14]," h rx (kB) tx (kB) h rx (kB) tx (kB) h rx (kB) tx (kB)");
+
+ for (i=10;i>1;i--)
+ matrix[i][2]='|';
+
+ matrix[1][2]='^';
+ matrix[12][2]='|';
+
+ /* title */
+ if (strcmp(data.interface, data.nick)==0) {
+ if (data.active)
+ sprintf(matrix[0]," %s", data.interface);
+ else
+ sprintf(matrix[0]," %s [disabled]", data.interface);
+ } else {
+ if (data.active)
+ sprintf(matrix[0]," %s (%s)", data.nick, data.interface);
+ else
+ sprintf(matrix[0]," %s (%s) [disabled]", data.nick, data.interface);
+ }
+
+ /* time to the corner */
+ sprintf(matrix[0]+74,"%02d:%02d", hour, min);
+
+ /* numbers under x-axel and graphics :) */
+ k=5;
+ for (i=23;i>=0;i--) {
+ s=tmax-i;
+ if (s<0)
+ s+=24;
+
+ sprintf(matrix[12]+k,"%02d ",s);
+
+ dots=10*(data.hour[s].rx/(float)max);
+ for (j=0;j<dots;j++)
+ matrix[10-j][k]='r';
+
+ dots=10*(data.hour[s].tx/(float)max);
+ for (j=0;j<dots;j++)
+ matrix[10-j][k+1]='t';
+
+ k=k+3;
+ }
+
+ /* hours and traffic */
+ for (i=0;i<=7;i++) {
+ s=tmax+i+1;
+ sprintf(matrix[15+i],"%02d %'10Lu %'10Lu %02d %'10Lu %'10Lu %02d %'10Lu %'10Lu",s%24, data.hour[s%24].rx, data.hour[s%24].tx, (s+8)%24, data.hour[(s+8)%24].rx, data.hour[(s+8)%24].tx, (s+16)%24, data.hour[(s+16)%24].rx, data.hour[(s+16)%24].tx);
+ }
+
+ /* clean \0 */
+ for (i=0;i<23;i++) {
+ for (j=0;j<80;j++) {
+ if (matrix[i][j]=='\0') {
+ matrix[i][j]=' ';
+ }
+ }
+ }
+
+ /* show matrix (yes, the last line isn't shown) */
+ for (i=0;i<23;i++) {
+ for (j=0;j<80;j++) {
+ printf("%c",matrix[i][j]);
+ }
+ printf("\n");
+ }
+
+}
+
+
+void cleanhours(void)
+{
+ int i, day, hour;
+ time_t current;
+ struct tm *d;
+
+ current=time(NULL);
+
+ /* remove old data if needed */
+ for (i=0;i<=23;i++) {
+ if (data.hour[i].date<=(current-86400)) { /* 86400 = 24 hours = too old */
+ data.hour[i].rx=0;
+ data.hour[i].tx=0;
+ if (debug) {
+ printf("Hour %d (%d) cleaned.\n",i, data.hour[i].date);
+ }
+ }
+ }
+
+ /* clean current if it's not from today to avoid incrementing old data */
+ d=localtime(¤t);
+ day=d->tm_mday;
+ hour=d->tm_hour;
+ d=localtime(&data.hour[hour].date);
+ if (d->tm_mday!=day) {
+ data.hour[hour].rx=0;
+ data.hour[hour].tx=0;
+ if (debug) {
+ printf("Current hour %d (%d) cleaned.\n",hour, data.hour[i].date);
+ }
+ data.hour[hour].date=current;
+ }
+}
+
void rotatedays(void)
{
int i, j;
for (i=29;i>=1;i--) {
data.day[i].rx=data.day[i-1].rx;
data.day[i].tx=data.day[i-1].tx;
+ data.day[i].rxk=data.day[i-1].rxk;
+ data.day[i].txk=data.day[i-1].txk;
data.day[i].date=data.day[i-1].date;
data.day[i].used=data.day[i-1].used;
}
data.day[0].rx=0;
data.day[0].tx=0;
+ data.day[0].rxk=0;
+ data.day[0].txk=0;
data.day[0].date=current;
if (debug) {
/* top10 update */
for (i=0;i<=9;i++) {
- if ( data.day[1].rx+data.day[1].tx > data.top10[i].rx+data.top10[i].tx ) {
+ if ( data.day[1].rx+data.day[1].tx >= data.top10[i].rx+data.top10[i].tx ) {
+
+ /* if MBs are same but kB smaller then continue searching */
+ if ( (data.day[1].rx+data.day[1].tx == data.top10[i].rx+data.top10[i].tx) && (data.day[1].rxk+data.day[1].txk <= data.top10[i].rxk+data.top10[i].txk) ) {
+ continue;
+ }
+
for (j=9;j>=i+1;j--) {
data.top10[j].rx=data.top10[j-1].rx;
data.top10[j].tx=data.top10[j-1].tx;
+ data.top10[j].rxk=data.top10[j-1].rxk;
+ data.top10[j].txk=data.top10[j-1].txk;
data.top10[j].date=data.top10[j-1].date;
data.top10[j].used=data.top10[j-1].used;
}
data.top10[i].rx=data.day[1].rx;
data.top10[i].tx=data.day[1].tx;
+ data.top10[i].rxk=data.day[1].rxk;
+ data.top10[i].txk=data.day[1].txk;
data.top10[i].date=data.day[1].date;
data.top10[i].used=data.day[1].used;
break;
for (i=11;i>=1;i--) {
data.month[i].rx=data.month[i-1].rx;
data.month[i].tx=data.month[i-1].tx;
+ data.month[i].rxk=data.month[i-1].rxk;
+ data.month[i].txk=data.month[i-1].txk;
data.month[i].month=data.month[i-1].month;
data.month[i].used=data.month[i-1].used;
}
data.month[0].rx=0;
data.month[0].tx=0;
+ data.month[0].rxk=0;
+ data.month[0].txk=0;
data.month[0].month=current;
if (debug) {
{
int i, days, mod;
DATA10 data10;
+ DATA12 data12;
time_t current;
struct tm *d;
int month=0, day;
int tm_mday, tm_mon, tm_year;
-
- printf("Converting database to new format\n");
+ int converted=0;
current=time(NULL);
d=localtime(¤t);
/* version 1.0 database format */
if (data.version==1) {
+ printf("Converting to db v2...\n");
+
rewind(db);
fread(&data10, sizeof(DATA10), 1, db);
/* set basic values */
- data.version=2;
- strcpy(data.interface, data10.interface);
- strcpy(data.nick, data10.interface);
- data.active=1;
- data.totalrx=data10.totalrx;
- data.totaltx=data10.totaltx;
- data.currx=data10.currx;
- data.curtx=data10.curtx;
- data.totalrxk=data10.totalrxk;
- data.totaltxk=data10.totaltxk;
- data.lastupdated=data10.lastupdated;
- data.created=data10.created;
- data.btime=data10.btime;
+ data12.version=2;
+ strncpy(data12.interface, data10.interface, 32);
+ strncpy(data12.nick, data10.interface, 32);
+ data12.active=1;
+ data12.totalrx=data10.totalrx;
+ data12.totaltx=data10.totaltx;
+ data12.currx=data10.currx;
+ data12.curtx=data10.curtx;
+ data12.totalrxk=data10.totalrxk;
+ data12.totaltxk=data10.totaltxk;
+ data12.lastupdated=data10.lastupdated;
+ data12.created=data10.created;
+ data12.btime=data10.btime;
/* days */
for (i=0; i<=29; i++) {
if (data10.day[i].rx+data10.day[i].tx>0) {
- data.day[i].rx=data10.day[i].rx;
- data.day[i].tx=data10.day[i].tx;
- data.day[i].date=current-(i*86400);
- data.day[i].used=1;
+ data12.day[i].rx=data10.day[i].rx;
+ data12.day[i].tx=data10.day[i].tx;
+ data12.day[i].date=current-(i*86400);
+ data12.day[i].used=1;
} else {
- data.day[i].rx=data.day[i].tx=0;
- data.day[i].used=0;
+ data12.day[i].rx=data12.day[i].tx=0;
+ data12.day[i].used=0;
}
}
/* months */
for (i=0; i<=11; i++) {
if (data10.month[i].rx+data10.month[i].tx>0) {
- data.month[i].rx=data10.month[i].rx;
- data.month[i].tx=data10.month[i].tx;
+ data12.month[i].rx=data10.month[i].rx;
+ data12.month[i].tx=data10.month[i].tx;
- data.month[i].month=current-(86400*days);
+ data12.month[i].month=current-(86400*days);
/* we have to do this modulo thing to get the number of days right */
mod=(d->tm_mon-i-1)%12;
if (mod<0)
mod=12+mod;
days+=dmonth[mod];
- data.month[i].used=1;
+ data12.month[i].used=1;
} else {
- data.month[i].rx=data.month[i].tx=0;
- data.month[i].used=0;
+ data12.month[i].rx=data12.month[i].tx=0;
+ data12.month[i].used=0;
}
}
/* top10 */
for (i=0; i<=9; i++) {
if (data10.top10[i].rx+data10.top10[i].tx>0) {
- data.top10[i].rx=data10.top10[i].rx;
- data.top10[i].tx=data10.top10[i].tx;
+ data12.top10[i].rx=data10.top10[i].rx;
+ data12.top10[i].tx=data10.top10[i].tx;
+ /* get day */
day=atoi(data10.top10[i].date+7);
+ /* parse month */
if (strncmp(data10.top10[i].date+4, "Jan", 3)==0) {
month=0;
} else if (strncmp(data10.top10[i].date+4, "Feb", 3)==0) {
month=11;
} else {
month=-1;
- printf("Conversion for date \"%s\" failed.\n",data10.top10[i].date);
+ printf("Convertion for date \"%s\" failed.\n",data10.top10[i].date);
printf("Reseting top10...\n");
}
if (month==-1)
break;
+ /* guess year */
d->tm_year=tm_year;
if ((month>tm_mon) || ((month==tm_mon) && (day>tm_mday)))
d->tm_year--;
d->tm_mday=day;
d->tm_mon=month;
- data.top10[i].date=mktime(d);
- data.top10[i].used=1;
+ data12.top10[i].date=mktime(d);
+ data12.top10[i].used=1;
} else {
- data.top10[i].used=0;
- data.top10[i].rx=data.top10[i].tx=0;
+ data12.top10[i].used=0;
+ data12.top10[i].rx=data12.top10[i].tx=0;
}
/* reset top10 if there was some problem */
if (month==-1) {
for (i=0; i<=9; i++) {
+ data12.top10[i].rx=data.top10[i].tx=0;
+ data12.top10[i].used=0;
+ }
+ }
+
+ converted=1;
+ }
+
+ /* version 1.1-1.2 database format */
+ if (data.version==2 || converted==1) {
+
+ printf("Converting to db v3...\n");
+
+ /* don't read from file if already in memory */
+ if (converted==0) {
+ rewind(db);
+ fread(&data12, sizeof(DATA12), 1, db);
+ }
+
+ /* set basic values */
+ data.version=3;
+ strncpy(data.interface, data12.interface, 32);
+ strncpy(data.nick, data12.nick, 32);
+ data.active=data12.active;
+ data.totalrx=data12.totalrx;
+ data.totaltx=data12.totaltx;
+ data.currx=data12.currx;
+ data.curtx=data12.curtx;
+ data.totalrxk=data12.totalrxk;
+ data.totaltxk=data12.totaltxk;
+ data.lastupdated=data12.lastupdated;
+ data.created=data12.created;
+ data.btime=data12.btime;
+
+ /* days */
+ for (i=0; i<=29; i++) {
+ if (data12.day[i].used) {
+ data.day[i].rx=data12.day[i].rx;
+ data.day[i].tx=data12.day[i].tx;
+ data.day[i].rxk=data.day[i].txk=0;
+ data.day[i].date=data12.day[i].date;
+ data.day[i].used=1;
+ } else {
+ data.day[i].rx=data.day[i].tx=0;
+ data.day[i].rxk=data.day[i].txk=0;
+ data.day[i].used=0;
+ }
+ }
+
+ /* months */
+ for (i=0; i<=11; i++) {
+ if (data12.month[i].used) {
+ data.month[i].rx=data12.month[i].rx;
+ data.month[i].tx=data12.month[i].tx;
+ data.month[i].rxk=data.month[i].txk=0;
+ data.month[i].month=data12.month[i].month;
+ data.month[i].used=1;
+ } else {
+ data.month[i].rx=data.month[i].tx=0;
+ data.month[i].rxk=data.month[i].txk=0;
+ data.month[i].used=0;
+ }
+ }
+
+ /* top10 */
+ for (i=0;i<=9;i++) {
+ if (data12.top10[i].used) {
+ data.top10[i].rx=data12.top10[i].rx;
+ data.top10[i].tx=data12.top10[i].tx;
+ data.top10[i].rxk=data.top10[i].txk=0;
+ data.top10[i].date=data12.top10[i].date;
+ data.top10[i].used=1;
+ } else {
data.top10[i].rx=data.top10[i].tx=0;
+ data.top10[i].rxk=data.top10[i].txk=0;
+ data.top10[i].date=0;
data.top10[i].used=0;
}
}
+
+ /* hours */
+ for (i=0;i<=23;i++) {
+ data.hour[i].rx=0;
+ data.hour[i].tx=0;
+ data.hour[i].date=0;
+ }
+
+ }
- /* unknown version */
- } else {
- printf("Error:\nUnknown database version \"%d\".\n", data.version);
+ /* unknown version */
+ if (data.version!=DBVERSION) {
+ printf("Error:\nUnable to convert database version \"%d\".\n", data.version);
exit(0);
}
+ printf("Convertion done.\n");
+}
+
+
+void showint(uint64_t mb, int kb, int len)
+{
+ char format[64];
+ int flen, kB;
+
+ while (kb>=1024) {
+ mb++;
+ kb-=1024;
+ }
+
+ kB=(kb*1000/1024)/10;
+
+ sprintf(format,"%'Lu",mb);
+ flen=strlen(format);
+
+ /* show decimals if there's enough space and if it looks nice :) */
+ if ((flen+3<=len) && (kb!=-1) && (mb<1000) && (kB!=0)) {
+ printf("%'*Lu.%02d", len-3, mb, kB);
+ } else {
+ printf("%'*Lu", len);
+ }
}
int readdb(char iface[32], char file[512]);
void writedb(char file[512], int newdb);
void showdb(int qmode);
+void showhours(void);
+void cleanhours(void);
void rotatedays(void);
void rotatemonths(void);
void convertdb(FILE *db);
+void showint(uint64_t mb, int kb, int len);
-/* version 1.0 database format */
+/* version 1.0 database format aka db v1 */
typedef struct {
char date[11];
uint64_t rx, tx;
DAY10 top10[10];
uint64_t btime;
} DATA10;
+
+
+/* version 1.1-1.2 database format aka db v2 */
+typedef struct {
+ time_t date;
+ uint64_t rx, tx;
+ int used;
+} DAY12;
+
+typedef struct {
+ time_t month;
+ uint64_t rx, tx;
+ int used;
+} MONTH12;
+
+typedef struct {
+ int version;
+ char interface[32];
+ char nick[32];
+ int active;
+ uint64_t totalrx, totaltx, currx, curtx;
+ int totalrxk, totaltxk;
+ time_t lastupdated, created;
+ DAY12 day[30];
+ MONTH12 month[12];
+ DAY12 top10[10];
+ uint64_t btime;
+} DATA12;
int spacecheck(char *path)
{
struct statfs buf;
- int free;
+ uint64_t free;
if (statfs(path, &buf)) {
perror("Free diskspace check");
exit(0);
}
- free=(buf.f_bavail/(float)buf.f_blocks)*100;
+ free=(buf.f_bavail/(float)1024)*buf.f_bsize;
- if (debug)
- printf("%d%% free space left\n", free);
+ if (debug) {
+ printf("bzise %d\n", buf.f_bsize);
+ printf("blocks %lu\n", buf.f_blocks);
+ printf("bfree %lu\n", buf.f_bfree);
+ printf("bavail %lu\n", buf.f_bavail);
+ printf("ffree %lu\n", buf.f_ffree);
+
+ printf("%Lu free space left\n", free);
+ }
- if (free<=1)
+ /* the database is less than 3kB but let's require */
+ /* 1MB to be on the safe side, anyway, the filesystem should */
+ /* always have more free space than that */
+ if (free<=1024)
return 0;
else
return 1;
}
if (strcmp(iface,"default")==0) {
- strcpy(inface,"eth0");
+ strncpy(inface,"eth0", 32);
} else {
- strcpy(inface,iface);
+ strncpy(inface,iface, 32);
}
check=0;
void parseproc(int newdb)
{
char temp[64];
- uint64_t rx, tx, rxchange=0, txchange=0, btime;
+ uint64_t rx, tx, rxchange=0, txchange=0, btime; /* rxchange = rx change in MB */
+ uint64_t krxchange=0, ktxchange=0; /* krxchange = rx change in kB */
time_t current;
struct tm *d;
- int day, month, year;
+ int day, month, year, hour, min, shift;
+ int rxkchange=0, txkchange=0; /* changes in the kB counters */
btime=strtoul(statline+6, (char **)NULL, 0);
if (newdb!=1) {
if (data.currx<=rx) {
rxchange=(rx-data.currx)/1024/1024;
- data.totalrxk+=((rx-data.currx)/1024)%1024;
+ krxchange=(rx-data.currx)/1024;
+ rxkchange=((rx-data.currx)/1024)%1024;
if (debug)
- printf("rx: %Lu - %Lu = %Lu\nrxk: %d\n",rx,data.currx,rx-data.currx,data.totalrxk);
+ printf("rx: %Lu - %Lu = %Lu\n",rx,data.currx,rx-data.currx);
} else {
rxchange=(FPOINT-data.currx+rx)/1024/1024;
- data.totalrxk+=((FPOINT-data.currx+rx)/1024)%1024;
+ krxchange=(FPOINT-data.currx+rx)/1024;
+ rxkchange=((FPOINT-data.currx+rx)/1024)%1024;
if (debug)
- printf("rx: %Lu - %Lu + %Lu = %Lu\nrxk: %d\n",FPOINT,data.currx,rx,FPOINT-data.currx+rx,data.totalrxk);
+ printf("rx: %Lu - %Lu + %Lu = %Lu\n",FPOINT,data.currx,rx,FPOINT-data.currx+rx);
}
}
- if (data.totalrxk>=1024) {
- rxchange++;
- data.totalrxk-=1024;
- }
-
- data.currx=rx;
- data.totalrx+=rxchange;
+ data.currx=rx;
+
+ addtraffic(&data.totalrx, &data.totalrxk, rxchange, rxkchange);
+
- /* get tx from procline, ugly code but it works */
+ /* get tx from procline, ugly hack */
sscanf(procline+7,"%s %s %s %s %s %s %s %s %s",temp,temp,temp,temp,temp,temp,temp,temp,temp);
#ifdef BLIMIT
if (newdb!=1) {
if (data.curtx<=tx) {
txchange=(tx-data.curtx)/1024/1024;
- data.totaltxk+=((tx-data.curtx)/1024)%1024;
+ ktxchange=(tx-data.curtx)/1024;
+ txkchange=((tx-data.curtx)/1024)%1024;
if (debug)
- printf("tx: %Lu - %Lu = %Lu\ntxk: %d\n",tx,data.curtx,tx-data.curtx,data.totaltxk);
+ printf("tx: %Lu - %Lu = %Lu\n",tx,data.curtx,tx-data.curtx);
} else {
txchange=(FPOINT-data.curtx+tx)/1024/1024;
- data.totaltxk+=((FPOINT-data.curtx+tx)/1024)%1024;
+ ktxchange=(FPOINT-data.curtx+tx)/1024;
+ txkchange=((FPOINT-data.curtx+tx)/1024)%1024;
if (debug)
- printf("tx: %Lu - %Lu + %Lu = %Lu\ntxk: %d\n",FPOINT,data.curtx,tx,FPOINT-data.curtx+tx,data.totaltxk);
+ printf("tx: %Lu - %Lu + %Lu = %Lu\n",FPOINT,data.curtx,tx,FPOINT-data.curtx+tx);
}
}
-
- if (data.totaltxk>=1024) {
- txchange++;
- data.totaltxk-=1024;
- }
-
+
data.curtx=tx;
- data.totaltx+=txchange;
- data.day[0].rx+=rxchange;
- data.day[0].tx+=txchange;
- data.month[0].rx+=rxchange;
- data.month[0].tx+=txchange;
+ addtraffic(&data.totaltx, &data.totaltxk, txchange, txkchange);
+
+ /* update days and months */
+ addtraffic(&data.day[0].rx, &data.day[0].rxk, rxchange, rxkchange);
+ addtraffic(&data.day[0].tx, &data.day[0].txk, txchange, txkchange);
+ addtraffic(&data.month[0].rx, &data.month[0].rxk, rxchange, rxkchange);
+ addtraffic(&data.month[0].tx, &data.month[0].txk, txchange, txkchange);
+ /* fill some variables from current date & time */
d=localtime(¤t);
day=d->tm_mday;
month=d->tm_mon;
year=d->tm_year;
+ hour=d->tm_hour;
+ min=d->tm_min;
+
+ /* shift traffic to previous hour when update happens at X:00 */
+ if (min==0) {
+ shift=hour;
+ hour--;
+ if (hour<0)
+ hour+=24; /* hour can't be -1 :) */
+ } else {
+ shift=hour;
+ }
+
+ /* clean and update hourly */
+ cleanhours();
+ data.hour[shift].date=current; /* avoid shifting timestamp */
+ data.hour[hour].rx+=krxchange;
+ data.hour[hour].tx+=ktxchange;
+ /* rotate days in database if needed */
d=localtime(&data.day[0].date);
if ((d->tm_mday!=day) || (d->tm_mon!=month) || (d->tm_year!=year))
rotatedays();
+ /* rotate months in database if needed */
d=localtime(&data.month[0].month);
if ((d->tm_mon!=month) && (day==atoi(MONTHROTATE)))
rotatemonths();
{
/* received bytes packets errs drop fifo frame compressed multicast */
/* transmitted bytes packets errs drop fifo colls carrier compressed */
- unsigned long int p1[16], p2[16];
- int i, j;
- char temp[64];
+ uint64_t p1[16], p2[16];
+ int i, j, len;
+ char temp[64], buffer[256];
/* less than 5 seconds if probably too inaccurate */
if (sampletime<5) {
if (procline[i]!=' ') {
sscanf(procline+i,"%s",temp);
i+=strlen(temp);
- if (debug)
- printf("%8d '%s'\n",j,temp);
#ifdef BLIMIT
p1[j]=strtoull(temp, (char **)NULL, 0);
#else
p1[j]=strtoul(temp, (char **)NULL, 0);
#endif
+ if (debug)
+ printf("%8d '%s' -> '%Lu'\n",j,temp,p1[j]);
j++;
}
}
/* wait sampletime and print some nice dots so that the user thinks
something is done :) */
- printf("Sampling %s (%d seconds average)",iface,sampletime);
+ sprintf(buffer,"Sampling %s (%d seconds average)",iface,sampletime);
+ printf("%s",buffer);
fflush(stdout);
sleep(sampletime/3);
printf(".");
if ((sampletime/3)*3!=sampletime) {
sleep(sampletime-((sampletime/3)*3));
}
- printf("\n");
-
+
+ len=strlen(buffer)+3;
+
+ for (i=0;i<len;i++)
+ printf("\b \b");
+
/* read those value again... */
j=0;
readproc(iface);
if (procline[i]!=' ') {
sscanf(procline+i,"%s",temp);
i+=strlen(temp);
- if (debug)
- printf("%8d '%s'\n",j,temp);
#ifdef BLIMIT
p2[j]=strtoull(temp, (char **)NULL, 0);
#else
p2[j]=strtoul(temp, (char **)NULL, 0);
#endif
+ if (debug)
+ printf("%8d '%s' -> '%Lu'\n",j,temp,p2[j]);
j++;
}
}
/* show the difference in a readable form */
- printf("\n rx %10.2f kB/s %5lu packets/s\n", (p2[0]-p1[0])/(float)sampletime/(float)1024, (p2[1]-p1[1])/sampletime);
- printf(" tx %10.2f kB/s %5lu packets/s\n\n", (p2[8]-p1[8])/(float)sampletime/(float)1024, (p2[9]-p1[9])/sampletime);
+ printf("%Lu packets sampled in %d seconds\n", (p2[1]-p1[1])+(p2[9]-p1[9]), sampletime);
+ printf("Traffic average for %s\n", iface);
+ printf("\n rx %10.2f kB/s %5Lu packets/s\n", (p2[0]-p1[0])/(float)sampletime/(float)1024, (uint64_t)((p2[1]-p1[1])/sampletime));
+ printf(" tx %10.2f kB/s %5Lu packets/s\n\n", (p2[8]-p1[8])/(float)sampletime/(float)1024, (uint64_t)((p2[9]-p1[9])/sampletime));
+}
+void addtraffic(uint64_t *destmb, int *destkb, uint64_t srcmb, int srckb)
+{
+ *destmb=*destmb+srcmb;
+ *destkb=*destkb+srckb;
+
+ while (*destkb>=1024) {
+ *destmb=*destmb+1;
+ *destkb=*destkb-1024;
+ }
}
void readproc(char iface[32]);
void parseproc(int newdb);
void trafficmeter(char iface[32], int sampletime);
+void addtraffic(uint64_t *destmb, int *destkb, uint64_t srcmb, int srckb);
/*
-vnStat - Copyright (c) 2003 Teemu Toivola <tst@iki.fi>
+vnStat - Copyright (c) 2002-04 Teemu Toivola <tst@iki.fi>
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
debug=0; /* debug disabled by default */
setlocale(LC_ALL, "en_US");
- strcpy(interface, "default");
- strcpy(definterface, DEFIFACE);
- strcpy(nick, "none");
+ strncpy(interface, "default", 32);
+ strncpy(definterface, DEFIFACE, 32);
+ strncpy(nick, "none", 32);
qmode=atoi(DEFQMODE);
sampletime=atoi(DEFSAMPTIME);
/* init dirname */
#ifdef SINGLE
- strcpy(dirname, getenv("HOME"));
+ strncpy(dirname, getenv("HOME"), 500);
strcat(dirname,"/.vnstat");
#else
- strcpy(dirname, DATABASEDIR);
+ strncpy(dirname, DATABASEDIR, 500);
#endif
/* check if the database dir exists and if it contains files */
if (files) {
query=1;
if (files>1)
- strcpy(definterface, DEFIFACE);
+ strncpy(definterface, DEFIFACE, 32);
}
closedir(dir);
} else {
for (currentarg=1; currentarg<argc; currentarg++) {
if (debug)
printf("arg %d: \"%s\"\n",currentarg,argv[currentarg]);
- if ((strcmp(argv[currentarg],"-h")==0) || (strcmp(argv[currentarg],"--help"))==0) {
+ if ((strcmp(argv[currentarg],"--longhelp"))==0) {
- printf(" vnStat %s by Teemu Toivola <tst@iki.fi>\n\n", VNSTATVERSION);
+ printf(" vnStat %s by Teemu Toivola <tst at iki dot fi>\n\n", VNSTATVERSION);
printf(" Update:\n");
- printf("\t -u, --update\t update database\n");
- printf("\t -r, --reset\t reset interface counters\n");
- printf("\t --enable\t enable interface\n");
- printf("\t --disable\t disable interface\n");
- printf("\t --nick \t set a nickname for interface\n");
- printf("\t --cleartop\t clear the top10\n");
- printf("\t --rebuildtotal\t rebuild total transfers from months\n");
+ printf("\t -u, --update\t\t update database\n");
+ printf("\t -r, --reset\t\t reset interface counters\n");
+ printf("\t --enable\t\t enable interface\n");
+ printf("\t --disable\t\t disable interface\n");
+ printf("\t --nick \t\t set a nickname for interface\n");
+ printf("\t --cleartop\t\t clear the top10\n");
+ printf("\t --rebuildtotal\t\t rebuild total transfers from months\n");
printf(" Query:\n");
- printf("\t -q, --query\t query database\n");
- printf("\t -d, --days\t show days\n");
- printf("\t -m, --months\t show months\n");
- printf("\t -w, --weeks\t show weeks\n");
- printf("\t -t, --top10\t show top10\n");
- printf("\t -s, --short\t use short output\n");
- printf("\t --dumpdb\t show database in parseable format\n");
+ printf("\t -q, --query\t\t query database\n");
+ printf("\t -h, --hours\t\t show hours\n");
+ printf("\t -d, --days\t\t show days\n");
+ printf("\t -m, --months\t\t show months\n");
+ printf("\t -w, --weeks\t\t show weeks\n");
+ printf("\t -t, --top10\t\t show top10\n");
+ printf("\t -s, --short\t\t use short output\n");
+ printf("\t --dumpdb\t\t show database in parseable format\n");
printf(" Misc:\n");
- printf("\t -i, --iface\t interface (default: %s)\n", definterface);
- printf("\t -h, --help\t help\n");
- printf("\t -D, --debug\t show some additional debug information\n");
- printf("\t -v, --version\t show version\n");
- printf("\t -tr, --traffic\t calculate traffic\n");
- printf("\t --testkernel\t check if the kernel is broken\n");
+ printf("\t -i, --iface\t\t change interface (default: %s)\n", definterface);
+ printf("\t -?, --help\t\t short help\n");
+ printf("\t -D, --debug\t\t show some additional debug information\n");
+ printf("\t -v, --version\t\t show version\n");
+ printf("\t -tr, --traffic\t\t calculate traffic\n");
+ printf("\t --testkernel\t\t check if the kernel is broken\n");
+ printf("\t --longhelp\t\t display this help\n\n");
+
+ printf("See also \"man vnstat\".\n");
+
+ exit(0);
+
+ } else if ((strcmp(argv[currentarg],"-?")==0) || (strcmp(argv[currentarg],"--help"))==0) {
+
+ printf(" vnStat %s by Teemu Toivola <tst at iki dot fi>\n\n", VNSTATVERSION);
+
+ printf("\t -q, --query\t\t query database\n");
+ printf("\t -h, --hours\t\t show hours\n");
+ printf("\t -d, --days\t\t show days\n");
+ printf("\t -m, --months\t\t show months\n");
+ printf("\t -w, --weeks\t\t show weeks\n");
+ printf("\t -t, --top10\t\t show top10\n");
+ printf("\t -s, --short\t\t use short output\n");
+ printf("\t -u, --update\t\t update database\n");
+ printf("\t -i, --iface\t\t change interface (default: %s)\n", definterface);
+ printf("\t -?, --help\t\t short help\n");
+ printf("\t -v, --version\t\t show version\n");
+ printf("\t -tr, --traffic\t\t calculate traffic\n\n");
+
+ printf("See also \"--longhelp\" for complete options list and \"man vnstat\".\n");
exit(0);
+
} else if ((strcmp(argv[currentarg],"-i")==0) || (strcmp(argv[currentarg],"--iface"))==0) {
if (currentarg+1<argc) {
strncpy(interface,argv[currentarg+1],32);
qmode=5;
} else if ((strcmp(argv[currentarg],"-w")==0) || (strcmp(argv[currentarg],"--weeks"))==0) {
qmode=6;
+ } else if ((strcmp(argv[currentarg],"-h")==0) || (strcmp(argv[currentarg],"--hours"))==0) {
+ qmode=7;
} else if (strcmp(argv[currentarg],"--dumpdb")==0) {
qmode=4;
} else if (strcmp(argv[currentarg],"--enable")==0) {
kerneltest();
exit(0);
} else if ((strcmp(argv[currentarg],"-v")==0) || (strcmp(argv[currentarg],"--version"))==0) {
- printf("vnStat %s by Teemu Toivola <tst@iki.fi>\n", VNSTATVERSION);
+ printf("vnStat %s by Teemu Toivola <tst at iki dot fi>\n", VNSTATVERSION);
#ifndef SINGLE
if (debug)
printf("Root ");
reset=1;
query=0;
} else {
- printf("Unknown arg \"%s\".\n",argv[currentarg]);
+ printf("Unknown arg \"%s\". Use --help for help.\n",argv[currentarg]);
exit(1);
}
/* counter reset */
if (reset) {
- if (!spacecheck(dirname)) {
+ if (!spacecheck(dirname) && !force) {
printf("Error:\nNot enough free diskspace available.\n");
exit(0);
}
if (strcmp(interface, "default")==0)
- strcpy(interface, definterface);
+ strncpy(interface, definterface, 32);
sprintf(filename, "%s/%s", dirname, interface);
readdb(interface, filename);
data.currx=0;
/* clear top10 */
if (cleartop) {
- if (!spacecheck(dirname)) {
+ if (!spacecheck(dirname) && !force) {
printf("Error:\nNot enough free diskspace available.\n");
exit(0);
}
if (strcmp(interface, "default")==0)
- strcpy(interface, definterface);
+ strncpy(interface, definterface, 32);
if (force) {
- sprintf(filename, "%s/%s", dirname, interface);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
readdb(interface, filename);
for (i=0; i<=9; i++) {
data.top10[i].rx=data.top10[i].tx=0;
+ data.top10[i].rxk=data.top10[i].txk=0;
data.top10[i].used=0;
}
exit(0);
}
if (strcmp(interface, "default")==0)
- strcpy(interface, definterface);
+ strncpy(interface, definterface, 32);
if (force) {
- sprintf(filename, "%s/%s", dirname, interface);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
readdb(interface, filename);
data.totalrx=data.totaltx=data.totalrxk=data.totaltxk=0;
for (i=0; i<=29; i++) {
if (data.month[i].used) {
- data.totalrx+=data.month[i].rx;
- data.totaltx+=data.month[i].tx;
+ addtraffic(&data.totalrx, &data.totalrxk, data.month[i].rx, data.month[i].rxk);
+ addtraffic(&data.totaltx, &data.totaltxk, data.month[i].tx, data.month[i].txk);
}
}
/* enable & disable */
if (active==1) {
- if (!spacecheck(dirname)) {
+ if (!spacecheck(dirname) && !force) {
printf("Error:\nNot enough free diskspace available.\n");
exit(0);
}
if (strcmp(interface, "default")==0)
- strcpy(interface, definterface);
- sprintf(filename, "%s/%s", dirname, interface);
+ strncpy(interface, definterface, 32);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
newdb=readdb(interface, filename);
if (!data.active && !newdb) {
data.active=1;
printf("Interface \"%s\" is already enabled.\n", data.interface);
}
} else if (active==0) {
- if (!spacecheck(dirname)) {
+ if (!spacecheck(dirname) && !force) {
printf("Error:\nNot enough free diskspace available.\n");
exit(0);
}
if (strcmp(interface, "default")==0)
- strcpy(interface, definterface);
- sprintf(filename, "%s/%s", dirname, interface);
+ strncpy(interface, definterface, 32);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
newdb=readdb(interface, filename);
if (data.active && !newdb) {
data.active=0;
if (update) {
/* check that there's some free diskspace left */
- if (!spacecheck(dirname)) {
+ if (!spacecheck(dirname) && !force) {
printf("Error:\nNot enough free diskspace available.\n");
exit(0);
}
while ((di=readdir(dir))) {
if (di->d_name[0]!='.') {
files++;
- strcpy(interface, di->d_name);
- sprintf(filename, "%s/%s", dirname, interface);
+ strncpy(interface, di->d_name, 32);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
if (debug)
printf("\nProcessing file \"%s\"...\n", filename);
newdb=readdb(interface, filename);
printf("No database found.\n");
/* reset to default */
- strcpy(interface, "default");
+ strncpy(interface, "default", 32);
/* update only selected file */
} else {
- sprintf(filename, "%s/%s", dirname, interface);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
newdb=readdb(interface, filename);
if (data.active) {
readproc(data.interface);
printf("\n rx / tx / total / estimated\n");
while ((di=readdir(dir))) {
if (di->d_name[0]!='.') {
- strcpy(interface, di->d_name);
- sprintf(filename, "%s/%s", dirname, interface);
+ strncpy(interface, di->d_name, 32);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
if (debug)
printf("\nProcessing file \"%s\"...\n", filename);
readdb(interface, filename);
/* show in qmode if there's only one file or qmode!=0 */
} else {
- sprintf(filename, "%s/%s", dirname, definterface);
+ snprintf(filename, 512, "%s/%s", dirname, definterface);
readdb(definterface, filename);
if (!newdb) {
if (qmode==5)
/* show only specified file */
} else {
- sprintf(filename, "%s/%s", dirname, interface);
+ snprintf(filename, 512, "%s/%s", dirname, interface);
readdb(interface, filename);
if (!newdb) {
if (qmode==5)
/* calculate traffic */
if (traffic) {
if (strcmp(interface, "default")==0)
- strcpy(interface, definterface);
+ strncpy(interface, definterface, 32);
trafficmeter(interface, sampletime);
}
/* if nothing was shown previously */
- if (!query && !update && !reset && active==-1 && !cleartop && !rebuildtotal && !traffic)
- printf("Nothing to do. Use -h for help\n");
+ if (!query && !update && !reset && active==-1 && !cleartop && !rebuildtotal && !traffic) {
+
+ /* give more help if there's no database */
+ if (files==0) {
+ printf("No database found, nothing to do. Use --help for help.\n\n");
+ printf("A new database can be created with the following command:\n");
+ printf(" %s -u -i eth0\n\n", argv[0]);
+ printf("Replace 'eth0' with the interface that should be monitored. A list\n");
+ printf("of available interfaces can be seen with the 'ifconfig' command.\n");
+ } else {
+ printf("Nothing to do. Use --help for help.\n");
+ }
+ }
return 0;
}
#define BVAR "15"
/* database version */
-/* 1 = 1.0, 2 = 1.1-1.2 */
-#define DBVERSION 2
+/* 1 = 1.0, 2 = 1.1-1.2, 3 = 1.3*/
+#define DBVERSION 3
/* version string */
-#define VNSTATVERSION "1.2"
+#define VNSTATVERSION "1.3"
#ifdef BLIMIT
/* 64 bit limit */
typedef struct {
time_t date;
uint64_t rx, tx;
+} HOUR;
+
+typedef struct {
+ time_t date;
+ uint64_t rx, tx;
+ int rxk, txk;
int used;
} DAY;
typedef struct {
time_t month;
uint64_t rx, tx;
+ int rxk, txk;
int used;
} MONTH;
DAY day[30];
MONTH month[12];
DAY top10[10];
+ HOUR hour[24];
uint64_t btime;
} DATA;