+1.5 / 3-Dec-07
+
+ - Fix: compile time warnings solved
+ - Fix: kernel test is now more verbose
+ - Fix: more informative error messages
+ - Fix: possible division by zero for traffic estimates right after midnight
+ - Fix: interface names longer than 6 chars (patch by Jan Schmidle)
+ - Realtime transfer rate mode
+ - Automatic 32bit/64bit counter detection
+ - Config file support
+ - Internal database backups and locking
+ - More visuals in outputs
+ - Adaptive units (kB, MB, GB, TB)
+ - Possibility to sync counters without counting traffic
+ - Maximum bandwidth of interfaces can be set
+
+
1.4 / 26-Mar-04
- Fix: major output problems when compiled with some compilers
http://humdi.net/vnstat/FAQ
-since that's the easiest way to keep it always updated.
+since that's the easiest way to keep it updated.
-(Updated 26.3.2003 based on version 1.4)
+(Updated 2.12.2007 based on version 1.5)
'I don't read manuals' install
::::::::::::::::::::::::::::::
proceeding.
-'root' install
-::::::::::::::
+Installing as root
+::::::::::::::::::
First login as root and run the following two commands:
make
make install
- Those having 64bit counters in /proc/net/dev should use 'make 64bit'
- instead of 'make'. If there was no errors, vnStat should now be installed
- (warnings aren't aren't considered as errors). During version 1.0 it
- became clear that some kernels are broken and don't provide to correct
- boot time for the system. vnStat requires this information so there's a
- test to see if the kernel if working right.
+ If there was no errors, vnStat should now be installed (warnings aren't
+ aren't considered as errors). During version 1.0 it became clear that some
+ kernels are broken and don't provide to correct boot time for the system.
+ vnStat requires this information so there's a test to see if the kernel is
+ working correctly.
vnstat --testkernel
The only way to fix a faulty kernel (afaik) is to compile/install a newer
one. Next every interface that should be monitored needs to be introduced
- to vnStat. Replace eth0 if needed.
+ to vnStat. Replace 'eth0' in the command with any available interface if
+ needed.
vnstat -u -i eth0
Repeat that for every other interface you wish to use. After that wait
- for about 10 kB of network traffic (and 5 min).
+ for about 10 kB of network traffic (and 5 min for the next cron update).
vnstat
- Now you should get some stats about your network usage.
+ Now you should get some stats about your network usage. See the config
+ file /etc/vnstat.conf for interface and other settings.
-'singleuser' install
-::::::::::::::::::::
+Installing without root access
+::::::::::::::::::::::::::::::
This install method is a little bit more complicated but shouldn't be
impossible. :) First compile the binary.
make single
- Those having 64bit counters in /proc/net/dev should use 'make 64bitsingle'
- instead of 'make single'. If there was no errors, copy src/vnstat to some
- directory included in your $PATH (~/bin/ is an example) and make the
- database directory.
+ If there was no errors, copy src/vnstat to some directory included in your
+ $PATH (~/bin/ is an example) and make the database directory.
cp src/vnstat ~/bin/
+ cp cfg/vnstat.conf ~/.vnstatrc
mkdir ~/.vnstat
During version 1.0 it became clear that some kernels are broken and don't
provide to correct boot time for the system. vnStat requires this information
- so there's a test to see if the kernel if working right.
+ so there's a test to see if the kernel is working correctly.
vnstat --testkernel
sysadmin if the kernel is broken.
Next every interface that should be monitored needs to be introduced
- to vnStat. Replace eth0 if needed.
+ to vnStat. Replace 'eth0' in the command with any available interface if
+ needed.
vnstat -u -i eth0
and add the following line (without leading spaces, remember to change the
path):
- 0-55/5 * * * * ~/bin/vnstat -u
+ */5 * * * * ~/bin/vnstat -u
If you found yourself using a strange editor then 'man vi' should help.
- After that wait for about 10 kB of network traffic (and 5 min).
+ After that wait for about 10 kB of network traffic (and 5 min for the
+ next cron update).
vnstat
- Now you should get some stats about your network usage.
+ Now you should get some stats about your network usage. See the config
+ file ~/vnstatrc for interface and other settings.
+
vnstat:
+make -C src vnstat
-64bit:
- +make -C src 64bit
-
single:
+make -C src single
-64bitsingle:
- +make -C src 64bitsingle
-
clean:
make -C src clean
install:
@echo "Installing 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
+# move some really old version database(s) if found
+ @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
+
+# remove some really old version binary if found
+ @if [ -x $(DESTDIR)/usr/local/bin/vnstat ]; \
+ then echo "Removing old binary..."; \
+ rm -f $(DESTDIR)/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
+# install ppp scripts if directory is found
+ @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; \
+ chmod 755 $(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; \
+ chmod 755 $(DESTDIR)/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 default config if such doesn't exist
+ @if [ ! -f $(DESTDIR)/etc/vnstat.conf ]; \
+ then install -m 644 cfg/vnstat.conf $(DESTDIR)/etc; \
+ fi
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 -s -m 755 src/vnstat $(BIN)
+
+# update man page, gzip it if previous version was done so
+ @if [ -f $(MAN)/man1/vnstat.1.gz ]; \
+ then install -m 644 man/vnstat.1 $(MAN)/man1; \
+ gzip -f9 $(MAN)/man1/vnstat.1; \
+ else install -m 644 man/vnstat.1 $(MAN)/man1; \
+ fi
+
install -m 644 cron/vnstat $(CRON)
uninstall:
@echo "Uninstalling vnStat..."
@echo
- @echo "Note: this will remove the database directory"
+ @echo "Note: this will also remove the database directory"
@echo "including any database located there"
@echo
@echo "Press CTRL-C to abort within 10 sec."
@sleep 10
rm -fr $(DESTDIR)/var/lib/vnstat
rm -f $(BIN)/vnstat
- rm -f $(MAN)/man1/vnstat.1
+ rm -f $(MAN)/man1/vnstat.1*
rm -f $(CRON)/vnstat
+ rm -f $(DESTDIR)/etc/vnstat.conf
rm -f $(DESTDIR)/etc/ppp/ip-up.d/vnstat
rm -f $(DESTDIR)/etc/ppp/ip-down.d/vnstat
-(Updated 8.3.2003 based on version 1.3)
+(Updated 27.11.2007 based on version 1.5)
What is vnStat
::::::::::::::
In short, vnStat is a console-based network traffic monitor that uses the
- /proc -filesystem to get the needed information. This means that vnStat wont
- actually be sniffing any traffic. See the webpage for few 'screenshots'.
+ /proc filesystem to get the needed information. This means that vnStat
+ won't actually be sniffing any traffic.
+
+ See the webpage for few 'screenshots'.
Getting started
Usage tips
::::::::::
- vnStat has few settings that can be changed before compiling by editing
- vnstat.h that's included in the src directory. There's comments included
- so see the file with some plain text editor and recompile (and reinstall)
- after any changes.
+ Most vnStat settings can be changed from the config file. The config
+ file is either ~/.vnstatrc or /etc/vnstat.conf depending which one is
+ found first. A new config file can be generated using current settings
+ with the following command:
- However, it's likely that someone will ask anyway how to change the date
- format so here's a short howto about that. First go to the src directory
- and open vnstat.h. Search lines 21-23, those should look like these:
+ vnstat --showconfig >newconfig
-#define DFORMAT "%d.%m."
-#define MFORMAT "%b '%y"
-#define TFORMAT "%d.%m.%y"
+ The config file contains comments before any settings describing with
+ the purpose and usage of each setting is.
- In order to get the date format to look like what's used for example in
- the US change those lines to:
+ By default vnStat will use dd.mm.yy format in timestamps. For example
+ this can be changed from the config file by locating lines
-#define DFORMAT "%m/%d"
-#define MFORMAT "%b '%y"
-#define TFORMAT "%m/%d/%y"
+DayFormat "%d.%m."
+MonthFormat "%b '%y"
+TopFormat "%d.%m.%y"
- and run 'make' (or 'make single') after that in that same src directory or
- continue with the install procedure if you were wise enough to read this
- file before installing. :)
-
- Next, copy the binary over the old one
+ and replacing the parameters:
- cp vnstat /usr/bin/vnstat
+DayFormat "%m/%d"
+MonthFormat "%b '%y"
+TopFormat "%%m/%d/%y"
- or some other path that you've used. Changing the date format wont affect
- the database in any way.
+ Note that some field have space limits and giving too long parameters
+ might affect the readability of the output. Changing date formats won't
+ affect the database(s) in any way.
Contacting the author
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://humdi.net/vnstat/
+
+ Email alerts about new versions are available by subscription at
+ http://freshmeat.net/projects/vnstat/
-(Updated 26.3.2004 based on version 1.4)
+(Updated 27.11.2007 based on version 1.5)
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.4 without user interaction. But for those still using 1.0, please
+to 1.5 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.
+ version 1.0. Any other version can be upgraded using provided install
+ scripts.
What to do before installing?
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.3.
+ installing 1.5.
--- /dev/null
+# vnStat 1.5 config file
+##
+
+# location of the database directory
+DatabaseDir "/var/lib/vnstat"
+
+# locale (LC_ALL)
+Locale "en_US"
+
+# on which day should months change
+MonthRotate 1
+
+# date output formats for -d, -m, -t and -w
+# see 'man date' for control codes
+DayFormat "%d.%m."
+MonthFormat "%b '%y"
+TopFormat "%d.%m.%y"
+
+# characters used for visuals
+RXCharacter "%"
+TXCharacter ":"
+RXHourCharacter "r"
+TXHourCharacter "t"
+
+# default interface
+Interface "eth0"
+
+# maximum bandwidth (Mbit) for all interfaces, 0 = disable feature
+# (unless interface specific limit is given)
+MaxBandwidth 100
+
+# interface specific limits
+# example 8Mbit limit for eth0 (remove # to activate):
+#MaxBWeth0 8
+
+# how many seconds should sampling for -tr take by default
+Sampletime 5
+
+# default query mode
+# 0 = normal, 1 = days, 2 = months, 3 = top10
+# 4 = dumpdb, 5 = short, 6 = weeks, 7 = hours
+QueryMode 0
+
+# database file locking (1 = enabled, 0 = disabled)
+UseFileLocking 1
+
+# how much the boot time can variate between updates (seconds)
+BootVariation 15
-0-55/5 * * * * root if [ -x /usr/bin/vnstat ] && [ `ls /var/lib/vnstat/ | wc -l` -ge 1 ]; then /usr/bin/vnstat -u; fi
+*/5 * * * * root if [ -x /usr/bin/vnstat ] && [ `ls /var/lib/vnstat/ | wc -l` -ge 1 ]; then /usr/bin/vnstat -u; fi
-.TH VNSTAT 1 "MARCH 2004" Linux "User Manuals"
+.TH VNSTAT 1 "DECEMBER 2007" Linux "User Manuals"
.SH NAME
vnStat \- a console-based network traffic monitor
.SH SYNOPSIS
.B vnstat
[
-.B \-Ddhmqrstuvw?
+.B \-Ddhlmqrstuvw?
] [
.B \-i
.I interface
.B \-\-iface
.I interface
] [
+.B \-\-live
+] [
.B \-\-longhelp
] [
.B \-\-months
] [
.B \-\-short
] [
+.B \-\-showconfig
+] [
.B \-\-testkernel
] [
.B \-\-top10
]
.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
+is a console-based network traffic monitor. It keeps a log of hourly,
+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.
+filesystem. That way vnStat can be used even 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.
.BI "-t, --top10"
Show all time top10 traffic days.
.TP
+.BI "-w, --weeks"
+Show traffic for 7 days, current and previous week.
+.TP
.BI "-tr " time
Calculate how much traffic goes through the selected interface during
the given
.I time
will be 5 seconds if a number parameter isn't included.
.TP
+.BI "-l, --live"
+Display current transfer rate for the selected interface in real time
+until interrupted. Statistics will be shown after interruption if runtime
+was more than 10 seconds.
+.TP
+.BI "-i, --iface " interface
+Select one specific
+.I interface
+and apply actions to only it.
+.TP
+.BI "-q, --query"
+Force database query mode.
+.TP
.BI "-u, --update"
Update all enabled databases or only the one specified with
.B -i
parameter.
.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 "--sync"
+Synchronize internal counters in the database with interface
+counters for the selected interface. Use this if the system is
+rebooted but interface counters aren't reseted. Such can occur
+when suspend to ram/disk is used.
+.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 "-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 "-?, --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 boot time information always stays the same like it should or
+if it's shifting.
+.TP
+.BI "-D, --debug"
+Show additional debug output.
+.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.
+script languages. Use this for example with PHP, Perl or Python to make a
+custom webpage. The dump uses ; as field delimeter.
active;1 activity status
interface;eth0 name for the interface
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
+.TP
.I /var/lib/vnstat/
-.RS
This directory contains all databases the program uses. Files are
named according to the monitored interfaces.
+.TP
+.I /etc/vnstat.conf
+Config file that will be used unless
+.I $HOME/.vnstatrc
+exists.
.SH EXAMPLES
.BI "vnstat -u -i"
.I interface
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.
+.PP
+Virtual and aliased interfaces can't be monitored because the kernel doesn't
+provide traffic information for that type of interfaces. Such interfaces are
+usually named eth0:0, eth0:1, eth0:2 etc. where eth0 is the actual interface
+being aliased.
.SH AUTHOR
Teemu Toivola <tst at iki dot fi>
.SH "SEE ALSO"
-.BR proc (5)
+.BR proc (5),
+.BR ifconfig (8)
#!/bin/sh
-if [ -x /usr/bin/vnstat ] && [ -w /var/lib/vnstat/ppp0 ]; then /usr/bin/vnstat --disable -i ppp0; fi
+if [ -x /usr/bin/vnstat ] && [ -w /var/lib/vnstat/$1 ]; then /usr/bin/vnstat -r --disable -i $1; fi
#!/bin/sh
-if [ -x /usr/bin/vnstat ] && [ -w /var/lib/vnstat/ppp0 ]; then /usr/bin/vnstat -r --enable -i ppp0; fi
+if [ -x /usr/bin/vnstat ] && [ -w /var/lib/vnstat/$1 ]; then /usr/bin/vnstat -r --enable -i $1; fi
CC = gcc
CFLAGS = -O2
-OBJS = proc.o db.o misc.o
-OBJS64 = proc64.o db.o misc.o
+OBJS = proc.o db.o misc.o cfg.o
default: vnstat
vnstat: $(OBJS) vnstat.c vnstat.h
- $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS)
-
-64bit: $(OBJS64) vnstat.c vnstat.h
- $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS64) -DBLIMIT
+ $(CC) $(CFLAGS) -lm -o vnstat vnstat.c $(OBJS)
single: $(OBJS) vnstat.c vnstat.h
- $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS) -DSINGLE
-
-64bitsingle: $(OBJS64) vnstat.c vnstat.h
- $(CC) $(CFLAGS) -o vnstat vnstat.c $(OBJS64) -DSINGLE -DBLIMIT
+ $(CC) $(CFLAGS) -lm -o vnstat vnstat.c $(OBJS) -DSINGLE
-proc.o: proc.c proc.h vnstat.h db.h
+proc.o: proc.c proc.h vnstat.h db.h misc.h cfg.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 proc.h vnstat.h
$(CC) $(CFLAGS) -c db.c
misc.o: misc.c misc.h
$(CC) $(CFLAGS) -c misc.c
+cfg.o: cfg.c cfg.h
+ $(CC) $(CFLAGS) -c cfg.c
+
clean:
rm -f *.o *~ core *.i vnstat
--- /dev/null
+#include "vnstat.h"
+#include "cfg.h"
+
+void printcfgfile(void) {
+
+ ibwnode *p = ifacebw;
+
+ printf("# vnStat %s config file\n", VNSTATVERSION);
+ printf("##\n\n");
+
+ printf("# location of the database directory\n");
+ printf("DatabaseDir \"%s\"\n\n", cfg.dbdir);
+
+ printf("# locale (LC_ALL)\n");
+ printf("Locale \"%s\"\n\n", cfg.locale);
+
+ printf("# on which day should months change\n");
+ printf("MonthRotate %d\n\n", cfg.monthrotate);
+
+ printf("# date output formats for -d, -m, -t and -w\n");
+ printf("# see 'man date' for control codes\n");
+ printf("DayFormat \"%s\"\n", cfg.dformat);
+ printf("MonthFormat \"%s\"\n", cfg.mformat);
+ printf("TopFormat \"%s\"\n\n", cfg.tformat);
+
+ printf("# characters used for visuals\n");
+ printf("RXCharacter \"%c\"\n", cfg.rxchar[0]);
+ printf("TXCharacter \"%c\"\n", cfg.txchar[0]);
+ printf("RXHourCharacter \"%c\"\n", cfg.rxhourchar[0]);
+ printf("TXHourCharacter \"%c\"\n\n", cfg.txhourchar[0]);
+
+ printf("# default interface\n");
+ printf("Interface \"%s\"\n\n", cfg.iface);
+
+ printf("# maximum bandwidth (Mbit) for all interfaces, 0 = disable feature\n# (unless interface specific limit is given)\n");
+ printf("MaxBandwidth %d\n\n", cfg.maxbw);
+
+ printf("# interface specific limits\n");
+ printf("# example 8Mbit limit for eth0 (remove # to activate):\n");
+ printf("#MaxBWeth0 8\n");
+
+ while (p != NULL) {
+ printf("MaxBW%s %d\n", p->interface, p->limit);
+ p = p->next;
+ }
+
+ printf("\n");
+
+ printf("# how many seconds should sampling for -tr take by default\n");
+ printf("Sampletime %d\n\n", cfg.sampletime);
+
+ printf("# default query mode\n");
+ printf("# 0 = normal, 1 = days, 2 = months, 3 = top10\n");
+ printf("# 4 = dumpdb, 5 = short, 6 = weeks, 7 = hours\n");
+ printf("QueryMode %d\n\n", cfg.qmode);
+
+ printf("# database file locking (1 = enabled, 0 = disabled)\n");
+ printf("UseFileLocking %d\n\n", cfg.flock);
+
+ printf("# how much the boot time can variate between updates (seconds)\n");
+ printf("BootVariation %d\n", cfg.bvar);
+
+}
+
+int loadcfg(void) {
+
+ FILE *fd;
+ char buffer[512];
+ int i;
+
+ char *cfgname[] = { "DatabaseDir", "Locale", "MonthRotate", "DayFormat", "MonthFormat", "TopFormat", "RXCharacter", "TXCharacter", "RXHourCharacter", "TXHourCharacter", "Interface", "MaxBandwidth", "Sampletime", "QueryMode", "UseFileLocking", "BootVariation", 0 };
+ char *cfglocc[] = { cfg.dbdir, cfg.locale, 0, cfg.dformat, cfg.mformat, cfg.tformat, cfg.rxchar, cfg.txchar, cfg.rxhourchar, cfg.txhourchar, cfg.iface, 0, 0, 0, 0, 0 };
+ int *cfgloci[] = { 0, 0, &cfg.monthrotate, 0, 0, 0, 0, 0, 0, 0, 0, &cfg.maxbw, &cfg.sampletime, &cfg.qmode, &cfg.flock, &cfg.bvar };
+ int cfgnamelen[] = { 512, 32, 0, 64, 64, 64, 1, 1, 1, 1, 32, 0, 0, 0, 0, 0 };
+
+ ifacebw = NULL;
+
+ /* clear buffer */
+ for (i=0; i<512; i++) {
+ buffer[i] = '\0';
+ }
+
+ /* load default config */
+ defaultcfg();
+
+ /* possible config files: 1) $HOME/.vnstatrc 2) /etc/vnstat.conf 3) none */
+
+ strncpy(buffer, getenv("HOME"), 500);
+ strcat(buffer, "/.vnstatrc");
+
+ /* try to open first available config file */
+ if ((fd=fopen(buffer,"r"))!=NULL) {
+ if (debug)
+ printf("Config file: $HOME/.vnstatrc\n");
+ } else if ((fd=fopen("/etc/vnstat.conf","r"))!=NULL) {
+ if (debug)
+ printf("Config file: /etc/vnstat.conf\n");
+/* } else if ((fd=fopen("vnstat.conf","r"))!=NULL) {
+ if (debug)
+ printf("Config file: ./vnstat.conf\n"); */
+ } else {
+ if (debug)
+ printf("Config file: none\n");
+ return 0;
+ }
+
+ rewind(fd);
+
+ /* try to read all config options from file */
+ for (i=0; cfgname[i]!=0; i++) {
+ strcpy(buffer, cfgname[i]);
+ if (getcfgvalue(fd, buffer)) {
+ if (cfgnamelen[i]>0) {
+ strncpy(cfglocc[i], buffer, cfgnamelen[i]);
+
+ } else if (isdigit(buffer[0])) {
+ *cfgloci[i] = atoi(buffer);
+ }
+ }
+ }
+
+ /* search for interface specific limits */
+ ibwcfgread(fd);
+
+ fclose(fd);
+
+ if (debug)
+ ibwlist();
+
+ return 1;
+
+}
+
+void defaultcfg(void) {
+
+ cfg.bvar = BVAR;
+ cfg.qmode = DEFQMODE;
+ cfg.sampletime = DEFSAMPTIME;
+ cfg.monthrotate = MONTHROTATE;
+ cfg.maxbw = DEFMAXBW;
+ cfg.flock = USEFLOCK;
+#ifdef SINGLE
+ strncpy(cfg.dbdir, getenv("HOME"), 500);
+ strcat(cfg.dbdir, "/.vnstat");
+#else
+ strncpy(cfg.dbdir, DATABASEDIR, 512);
+#endif
+ strncpy(cfg.iface, DEFIFACE, 32);
+ strncpy(cfg.locale, LOCALE, 32);
+ strncpy(cfg.dformat, DFORMAT, 64);
+ strncpy(cfg.mformat, MFORMAT, 64);
+ strncpy(cfg.tformat, TFORMAT, 64);
+ strncpy(cfg.rxchar, RXCHAR, 1);
+ strncpy(cfg.txchar, TXCHAR, 1);
+ strncpy(cfg.rxhourchar, RXHOURCHAR, 1);
+ strncpy(cfg.txhourchar, TXHOURCHAR, 1);
+
+}
+
+int getcfgvalue(FILE *fd, char *search) {
+
+ char value[512], cfgline[512];
+ int i, j, linelen, searchlen, rewinds;
+ long startpos;
+
+ rewinds = 0;
+ searchlen = strlen(search);
+
+ /* rewind file if needed */
+ if (feof(fd)) {
+ rewind(fd);
+ rewinds++;
+ }
+
+ /* get current position in file */
+ startpos = ftell(fd);
+
+ if (debug)
+ printf(" search & startpos: '%s' '%ld'\n", search, startpos);
+
+ /* cycle all lines if needed */
+ while (!feof(fd)) {
+
+ cfgline[0] = '\0';
+
+ /* get current line */
+ fgets(cfgline, 512, fd);
+
+ linelen = strlen(cfgline);
+
+ if (linelen>2 && cfgline[0]!='#') {
+
+ if ( (strncasecmp(cfgline, search, searchlen)==0) && (linelen>=searchlen+2) ) {
+
+ /* value buffers */
+ for (j=0; j<512; j++) {
+ value[j]='\0';
+ }
+
+ /* search value */
+ j=0;
+ for (i=searchlen; i<linelen; i++) {
+ if (cfgline[i]=='\n' || cfgline[i]=='\r') {
+ break;
+ } else if (cfgline[i]=='\"') {
+ if (j==0) {
+ continue;
+ } else {
+ break;
+ }
+ } else {
+ if (j==0 && (cfgline[i]==' ' || cfgline[i]=='=' || cfgline[i]=='\t')) {
+ continue;
+ } else {
+ value[j]=cfgline[i];
+ j++;
+ }
+ }
+ }
+
+ /* continue search if found value wasn't suitable */
+ if (strlen(value)==0) {
+ continue;
+ } else {
+
+ if (debug)
+ printf(" %s -> \"%s\"\n", cfgline, value);
+
+ /* fill answer and return to caller */
+ strcpy(search, value);
+ return 1;
+ }
+ }
+ }
+
+ /* rewind file if end of file was reached and
+ reading didn't start from the beginning */
+ if (feof(fd) && startpos && !rewinds) {
+ rewind(fd);
+ rewinds++;
+
+ if (debug)
+ printf(" rewind\n");
+ }
+
+ }
+
+ return 0;
+}
+
+int ibwadd(char *iface, int limit)
+{
+ ibwnode *n = malloc(sizeof(ibwnode));
+
+ if (n == NULL) {
+ return 0;
+ }
+
+ n->next = ifacebw;
+ ifacebw = n;
+ strcpy(n->interface, iface);
+ n->limit = limit;
+
+ return 1;
+}
+
+void ibwlist(void)
+{
+ int i=1;
+ ibwnode *p = ifacebw;
+
+ if (p == NULL) {
+ printf("ibw list is empty.\n");
+
+ } else {
+
+ printf("ibw:\n");
+ while (p != NULL) {
+ printf(" %2d: \"%s\" \"%d\"\n", i, p->interface, p->limit);
+ p = p->next;
+ i++;
+ }
+ }
+}
+
+int ibwget(char *iface)
+{
+ ibwnode *p = ifacebw;
+
+ if (p == NULL) {
+
+ if (cfg.maxbw>0) {
+ return cfg.maxbw;
+ } else {
+ return -1;
+ }
+
+ } else {
+
+ while (p != NULL) {
+ if (strcasecmp(p->interface, iface)==0) {
+ if (p->limit>0) {
+ return p->limit;
+ } else {
+ return -1;
+ }
+ }
+ p = p->next;
+ }
+
+ return -1;
+ }
+}
+
+int ibwcfgread(FILE *fd)
+{
+ char cfgline[512], name[512], value[512];
+ int i, j, linelen, count = 0;
+
+ /* start from value search from first line */
+ rewind(fd);
+
+ /* cycle all lines */
+ while (!feof(fd)) {
+
+ cfgline[0] = '\0';
+
+ /* get current line */
+ fgets(cfgline, 512, fd);
+
+ linelen = strlen(cfgline);
+
+ if (linelen>8 && cfgline[0]!='#') {
+
+ if (strncasecmp(cfgline, "MaxBW", 5)==0) {
+
+ /* clear name and value buffers */
+ for (j=0; j<512; j++) {
+ name[j]=value[j]='\0';
+ }
+
+ /* get interface name */
+ j=0;
+ for (i=5; i<linelen; i++) {
+ if (cfgline[i]==' ' || cfgline[i]=='=' || cfgline[i]=='\t' || cfgline[i]=='\n' || cfgline[i]=='\r') {
+ break;
+ } else {
+ name[j]=cfgline[i];
+ j++;
+ }
+ }
+
+ /* get new line if no usable name was found */
+ if (strlen(name)==0) {
+ continue;
+ }
+
+ /* search value */
+ j=0;
+ for (i++; i<linelen; i++) {
+ if (cfgline[i]=='\n' || cfgline[i]=='\r') {
+ break;
+ } else if (cfgline[i]=='\"') {
+ if (j==0) {
+ continue;
+ } else {
+ break;
+ }
+ } else {
+ if (j==0 && (cfgline[i]==' ' || cfgline[i]=='=' || cfgline[i]=='\t')) {
+ continue;
+ } else {
+ value[j]=cfgline[i];
+ j++;
+ }
+ }
+ }
+
+ /* get new line if no usable value was found */
+ if ((strlen(value)==0) || (!isdigit(value[0])) ) {
+ continue;
+ }
+
+ /* add interface and limit to list */
+ ibwadd(name, atoi(value));
+ }
+ }
+ }
+
+ return count;
+}
--- /dev/null
+void printcfgfile(void);
+int loadcfg(void);
+void defaultcfg(void);
+int getcfgvalue(FILE *fd, char *search);
+int ibwadd(char *iface, int limit);
+void ibwlist(void);
+int ibwget(char *iface);
+int ibwcfgread(FILE *fd);
int dmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-int readdb(char iface[32], char file[512])
+int readdb(char iface[32], char dirname[512])
{
FILE *db;
+ char file[512], backup[512];
int newdb=0, i;
-
+
+ snprintf(file, 512, "%s/%s", dirname, iface);
+ snprintf(backup, 512, "%s/.%s", dirname, iface);
+
if ((db=fopen(file,"r"))!=NULL) {
+
+ /* lock file */
+ lockdb(fileno(db), 0);
+
fread(&data,sizeof(DATA),1,db);
if (debug)
printf("Database loaded for interface \"%s\"...\n",data.interface);
/* convert old database to new format if necessary */
if (data.version!=DBVERSION) {
printf("Trying to convert database \"%s\" (v%d) to current db format\n", file, data.version);
- convertdb(db);
+
+ if (!convertdb(db)) {
+
+ /* close current db and try using backup if database conversion failed */
+ fclose(db);
+ if ((db=fopen(backup,"r"))!=NULL) {
+
+ /* lock file */
+ lockdb(fileno(db), 0);
+
+ fread(&data,sizeof(DATA),1,db);
+ if (debug)
+ printf("Database loaded for interface \"%s\"...\n",data.interface);
+
+ if (data.version!=DBVERSION) {
+ if (!convertdb(db)) {
+ printf("Error:\nUnable to use backup database.\n");
+ exit(0);
+ }
+ }
+ printf("Database possibly corrupted, replacing with backup.\n");
+ } else {
+ printf("Error:\nUnable to open backup database \"%s\".\n", backup);
+ exit(0);
+ }
+ }
}
-
+
fclose(db);
+
if (strcmp(data.interface,iface)) {
printf("Warning:\nThe previous interface for this file was \"%s\".\n",data.interface);
printf("It has now been replaced with \"%s\".\n\n",iface);
}
data.day[0].used=data.month[0].used=1;
data.day[0].date=data.month[0].month=time(NULL);
- data.btime=FPOINT-1;
+ data.btime=FP32;
}
return newdb;
}
-void writedb(char file[512], int newdb)
+void writedb(char iface[32], char dirname[512], int newdb)
{
FILE *db;
+ char file[512], backup[512];
+
+ snprintf(file, 512, "%s/%s", dirname, iface);
+ snprintf(backup, 512, "%s/.%s", dirname, iface);
+
+ /* try to make backup of old file */
+ rename(file, backup);
/* make sure version stays correct */
data.version=DBVERSION;
if ((db=fopen(file,"w"))!=NULL) {
+
+ /* lock file */
+ lockdb(fileno(db), 1);
+
data.lastupdated=time(NULL);
fwrite(&data,sizeof(DATA),1,db);
if (debug)
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, max;
int t_rxk, t_txk;
time_t current, yesterday;
e_rx=e_tx=t_rx=t_tx=t_rxk=t_txk=0;
- if (data.totalrx+data.totaltx==0 && (data.totalrxk/(float)10+data.totaltxk/(float)10)==0) {
+ if (data.totalrx+data.totaltx==0 && data.totalrxk+data.totaltxk==0) {
printf(" %s: Not enough data available yet.\n", data.interface);
rx=(data.totalrx/((float)data.totalrx+data.totaltx))*100;
tx=(data.totaltx/((float)data.totalrx+data.totaltx))*100;
- e_rx=((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440;
- e_tx=((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ if ( data.day[0].rx==0 || data.day[0].tx==0 || (d->tm_hour*60+d->tm_min)==0 ) {
+ e_rx=e_tx=0;
+ } else {
+ e_rx=((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ e_tx=((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ }
/* printf("\nDatabase created: %s",(char*)asctime(localtime(&data.created))); */
/* get formated date for yesterday */
d=localtime(&yesterday);
- strftime(datebuff, 16, DFORMAT, d);
+ strftime(datebuff, 16, cfg.dformat, d);
/* get formated date for previous day in database */
d=localtime(&data.day[1].date);
- strftime(daytemp, 16, DFORMAT, d);
+ strftime(daytemp, 16, cfg.dformat, d);
/* change daytemp to yesterday if formated days match */
if (strcmp(datebuff, daytemp)==0) {
}
printf("\t received: ");
- showint(data.totalrx, data.totalrxk, 14);
- printf(" MB (%.1f%%)\n",rx);
+ showint(data.totalrx, data.totalrxk, 10);
+ printf(" (%.1f%%)\n",rx);
printf("\ttransmitted: ");
- showint(data.totaltx, data.totaltxk, 14);
- printf(" MB (%.1f%%)\n",tx);
+ showint(data.totaltx, data.totaltxk, 10);
+ printf(" (%.1f%%)\n",tx);
printf("\t total: ");
- showint(data.totalrx+data.totaltx, data.totalrxk+data.totaltxk, 14);
- printf(" MB\n\n");
-
-
+ showint(data.totalrx+data.totaltx, data.totalrxk+data.totaltxk, 10);
+ printf("\n\n");
printf("\t rx | tx | total\n");
printf("\t-----------------------+------------+-----------\n");
if (data.day[1].date!=0) {
printf("\t%9s ",daytemp);
showint(data.day[1].rx, data.day[1].rxk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.day[1].tx, data.day[1].txk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.day[1].rx+data.day[1].tx, data.day[1].rxk+data.day[1].txk, 7);
- printf(" MB\n");
+ printf("\n");
}
printf("\t today ");
showint(data.day[0].rx, data.day[0].rxk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.day[0].tx, data.day[0].txk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.day[0].rx+data.day[0].tx, data.day[0].rxk+data.day[0].txk, 7);
- printf(" MB\n");
+ printf("\n");
printf("\t-----------------------+------------+-----------\n");
- printf("\testimated %'7Lu MB | %'7Lu MB | %'7Lu MB\n",e_rx, e_tx, e_rx+e_tx);
+ printf("\testimated ");
+ showint(e_rx, 0, -7);
+ printf(" | ");
+ showint(e_tx, 0, -7);
+ printf(" | ");
+ showint(e_rx+e_tx, 0, -7);
+ printf("\n");
/* days */
} else if (qmode==1) {
printf("\n");
if (strcmp(data.interface, data.nick)==0) {
if (data.active)
- printf("\t%s\n\n", data.interface);
+ printf(" %s / daily\n\n", data.interface);
else
- printf("\t%s [disabled]\n\n", data.interface);
+ printf(" %s [disabled] / daily\n\n", data.interface);
} else {
if (data.active)
- printf("\t%s (%s)\n\n", data.nick, data.interface);
+ printf(" %s (%s) / daily\n\n", data.nick, data.interface);
else
- printf("\t%s (%s) [disabled]\n\n", data.nick, data.interface);
+ printf(" %s (%s) [disabled] / daily\n\n", data.nick, data.interface);
}
- printf("\t day rx | tx | total\n");
- printf("\t------------------------+-------------+--------------\n");
+ printf(" day rx | tx | total\n");
+ printf("------------------------+-------------+----------------------------------------\n");
+
+ /* search maximum */
+ max=0;
+ for (i=29;i>=0;i--) {
+ if (data.day[i].used) {
+
+ t_rx=data.day[i].rx+data.day[i].tx;
+ t_rxk=data.day[i].rxk+data.day[i].txk;
+
+ if (t_rxk>=1024) {
+ t_rx+=t_rxk/1024;
+ t_rxk-=(t_rxk/1024)*1024;
+ }
+
+ t_rx=(t_rx*1024)+t_rxk;
+
+ if (t_rx>max) {
+ max=t_rx;
+ }
+ }
+ }
used=0;
for (i=29;i>=0;i--) {
if (data.day[i].used) {
d=localtime(&data.day[i].date);
- strftime(datebuff, 16, DFORMAT, d);
- printf("\t %6s ",datebuff);
+ strftime(datebuff, 16, cfg.dformat, d);
+ printf(" %8s ",datebuff);
showint(data.day[i].rx, data.day[i].rxk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.day[i].tx, data.day[i].txk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.day[i].rx+data.day[i].tx, data.day[i].rxk+data.day[i].txk, 7);
- printf(" MB\n");
+ showbar(data.day[i].rx, data.day[i].rxk, data.day[i].tx, data.day[i].txk, max, 25);
+ printf("\n");
used++;
}
}
if (used==0)
- printf("\t no data available\n");
- printf("\t------------------------+-------------+--------------\n");
+ printf(" no data available\n");
+ printf("------------------------+-------------+----------------------------------------\n");
if (used!=0) {
d=localtime(¤t);
- e_rx=((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440;
- e_tx=((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440;
- printf("\t estimated %'7Lu MB | %'7Lu MB | %'7Lu MB\n", e_rx, e_tx, e_rx+e_tx);
+ if ( data.day[0].rx==0 || data.day[0].tx==0 || (d->tm_hour*60+d->tm_min)==0 ) {
+ e_rx=e_tx=0;
+ } else {
+ e_rx=((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ e_tx=((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ }
+ printf(" estimated ");
+ showint(e_rx, 0, -7);
+ printf(" | ");
+ showint(e_tx, 0, -7);
+ printf(" | ");
+ showint(e_rx+e_tx, 0, -7);
+ printf("\n");
}
/* months */
printf("\n");
if (strcmp(data.interface, data.nick)==0) {
if (data.active)
- printf("\t%s\n\n", data.interface);
+ printf(" %s / monthly\n\n", data.interface);
else
- printf("\t%s [disabled]\n\n", data.interface);
+ printf(" %s [disabled] / monthly\n\n", data.interface);
} else {
if (data.active)
- printf("\t%s (%s)\n\n", data.nick, data.interface);
+ printf(" %s (%s) / monthly\n\n", data.nick, data.interface);
else
- printf("\t%s (%s) [disabled]\n\n", data.nick, data.interface);
+ printf(" %s (%s) [disabled] / monthly\n\n", data.nick, data.interface);
}
- printf("\t month rx | tx | total\n");
- printf("\t------------------------+---------------+---------------\n");
+ printf(" month rx | tx | total\n");
+ printf("-------------------------+--------------+--------------------------------------\n");
+
+ /* search maximum */
+ max=0;
+ for (i=11;i>=0;i--) {
+ if (data.month[i].used) {
+
+ t_rx=data.month[i].rx+data.month[i].tx;
+ t_rxk=data.month[i].rxk+data.month[i].txk;
+
+ if (t_rxk>=1024) {
+ t_rx+=t_rxk/1024;
+ t_rxk-=(t_rxk/1024)*1024;
+ }
+
+ t_rx=(t_rx*1024)+t_rxk;
+
+ if (t_rx>max) {
+ max=t_rx;
+ }
+ }
+ }
used=0;
for (i=11;i>=0;i--) {
if (data.month[i].used) {
d=localtime(&data.month[i].month);
- strftime(datebuff, 16, MFORMAT, d);
- 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");
+ strftime(datebuff, 16, cfg.mformat, d);
+ printf(" %8s ",datebuff);
+ showint(data.month[i].rx, data.month[i].rxk, 8);
+ printf(" | ");
+ showint(data.month[i].tx, data.month[i].txk, 8);
+ printf(" | ");
+ showint(data.month[i].rx+data.month[i].tx, data.month[i].rxk+data.month[i].txk, 8);
+ showbar(data.month[i].rx, data.month[i].rxk, data.month[i].tx, data.month[i].txk, max, 22);
+ printf("\n");
used++;
}
}
if (used==0)
- printf("\t no data available\n");
- printf("\t------------------------+---------------+---------------\n");
+ printf(" no data available\n");
+ printf("-------------------------+--------------+--------------------------------------\n");
if (used!=0) {
d=localtime(¤t);
- e_rx=((data.month[0].rx)/(float)((d->tm_mday-1)*24+d->tm_hour))*(dmonth[d->tm_mon]*24);
- 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);
+ if ( data.month[0].rx==0 || data.month[0].tx==0 || ((d->tm_mday-1)*24+d->tm_hour)==0 ) {
+ e_rx=e_tx=0;
+ } else {
+ e_rx=((data.month[0].rx)/(float)((d->tm_mday-1)*24+d->tm_hour))*(dmonth[d->tm_mon]*24);
+ e_tx=((data.month[0].tx)/(float)((d->tm_mday-1)*24+d->tm_hour))*(dmonth[d->tm_mon]*24);
+ }
+ printf("estimated ");
+ showint(e_rx, 0, -8);
+ printf(" | ");
+ showint(e_tx, 0, -8);
+ printf(" | ");
+ showint(e_rx+e_tx, 0, -8);
+ printf("\n");
}
/* top10 */
printf("\n");
if (strcmp(data.interface, data.nick)==0) {
if (data.active)
- printf("\t%s\n\n", data.interface);
+ printf(" %s / top 10\n\n", data.interface);
else
- printf("\t%s [disabled]\n\n", data.interface);
+ printf(" %s [disabled] / top 10\n\n", data.interface);
} else {
if (data.active)
- printf("\t%s (%s)\n\n", data.nick, data.interface);
+ printf(" %s (%s) / top 10\n\n", data.nick, data.interface);
else
- printf("\t%s (%s) [disabled]\n\n", data.nick, data.interface);
+ printf(" %s (%s) [disabled] / top 10\n\n", data.nick, data.interface);
}
- printf("\t # day rx | tx | total\n");
- printf("\t--------------------------------+-------------+-------------\n");
+ printf(" # day rx | tx | total\n");
+ printf("-------------------------------+-------------+---------------------------------\n");
+
+ /* search maximum */
+ max=0;
+ for (i=0;i<=9;i++) {
+ if (data.top10[i].used) {
+
+ t_rx=data.top10[i].rx+data.top10[i].tx;
+ t_rxk=data.top10[i].rxk+data.top10[i].txk;
+
+ if (t_rxk>=1024) {
+ t_rx+=t_rxk/1024;
+ t_rxk-=(t_rxk/1024)*1024;
+ }
+
+ t_rx=(t_rx*1024)+t_rxk;
+
+ if (t_rx>max) {
+ max=t_rx;
+ }
+ }
+ }
used=0;
for (i=0;i<=9;i++) {
if (data.top10[i].used) {
d=localtime(&data.top10[i].date);
- strftime(datebuff, 16, TFORMAT, d);
- printf("\t %2d %8s ", i+1, datebuff);
+ strftime(datebuff, 16, cfg.tformat, d);
+ printf(" %2d %10s ", i+1, datebuff);
showint(data.top10[i].rx, data.top10[i].rxk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.top10[i].tx, data.top10[i].txk, 7);
- printf(" MB | ");
+ printf(" | ");
showint(data.top10[i].rx+data.top10[i].tx, data.top10[i].rxk+data.top10[i].txk, 7);
- printf(" MB\n");
+ showbar(data.top10[i].rx, data.top10[i].rxk, data.top10[i].tx, data.top10[i].txk, max, 18);
+ printf("\n");
used++;
}
}
if (used==0)
- printf("\t no data available\n");
- printf("\t--------------------------------+-------------+-------------\n");
+ printf(" no data available\n");
+ printf("-------------------------------+-------------+---------------------------------\n");
/* dumpdb */
} else if (qmode==4) {
printf("h;%d;%d;%Lu;%Lu\n",i,(int)data.hour[i].date, data.hour[i].rx, data.hour[i].tx);
}
- /* multiple dbs at one time */
+ /* multiple dbs in one print */
} else if (qmode==5) {
if (strcmp(data.interface, data.nick)==0) {
}
/* time needed for estimates */
d=localtime(¤t);
- e_rx=((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440;
- e_tx=((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ if ( data.day[0].rx==0 || data.day[0].tx==0 || (d->tm_hour*60+d->tm_min)==0 ) {
+ e_rx=e_tx=0;
+ } else {
+ e_rx=((data.day[0].rx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ e_tx=((data.day[0].tx)/(float)(d->tm_hour*60+d->tm_min))*1440;
+ }
/* get formated date for yesterday */
d=localtime(&yesterday);
- strftime(datebuff, 16, DFORMAT, d);
+ strftime(datebuff, 16, cfg.dformat, d);
/* get formated date for previous day in database */
d=localtime(&data.day[1].date);
- strftime(daytemp, 16, DFORMAT, d);
+ strftime(daytemp, 16, cfg.dformat, d);
/* change daytemp to yesterday if formated days match */
if (strcmp(datebuff, daytemp)==0) {
if (data.day[1].date!=0) {
printf(" %9s ",daytemp);
showint(data.day[1].rx, data.day[1].rxk, 7);
- printf(" MB / ");
+ printf(" / ");
showint(data.day[1].tx, data.day[1].txk, 7);
- printf(" MB / ");
+ printf(" / ");
showint(data.day[1].rx+data.day[1].tx, data.day[1].rxk+data.day[1].txk, 7);
- printf(" MB\n");
+ printf("\n");
}
printf(" today ");
showint(data.day[0].rx, data.day[0].rxk, 7);
- printf(" MB / ");
+ printf(" / ");
showint(data.day[0].tx, data.day[0].txk, 7);
- printf(" MB / ");
+ printf(" / ");
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);
+ printf(" / ");
+ showint(e_rx+e_tx, 0, -7);
+ printf("\n\n");
/* last 7 */
} else if (qmode==6) {
printf("\n");
if (strcmp(data.interface, data.nick)==0) {
if (data.active)
- printf("\t%s\n\n", data.interface);
+ printf("\t%s / weekly\n\n", data.interface);
else
- printf("\t%s [disabled]\n\n", data.interface);
+ printf("\t%s [disabled] / weekly\n\n", data.interface);
} else {
if (data.active)
- printf("\t%s (%s)\n\n", data.nick, data.interface);
+ printf("\t%s (%s) / weekly\n\n", data.nick, data.interface);
else
- printf("\t%s (%s) [disabled]\n\n", data.nick, data.interface);
+ printf("\t%s (%s) [disabled] / weekly\n\n", data.nick, data.interface);
}
printf("\t rx | tx | total\n");
if (used!=0) {
printf("\t last 7 days ");
showint(t_rx, t_rxk, 9);
- printf(" MB | ");
+ printf(" | ");
showint(t_tx, t_txk, 9);
- printf(" MB | ");
+ printf(" | ");
showint(t_rx+t_tx, t_rxk+t_txk, 9);
- printf(" MB\n");
+ printf("\n");
temp++;
}
if (used!=0) {
printf("\t last week ");
showint(t_rx, t_rxk, 9);
- printf(" MB | ");
+ printf(" | ");
showint(t_tx, t_txk, 9);
- printf(" MB | ");
+ printf(" | ");
showint(t_rx+t_tx, t_rxk+t_txk, 9);
- printf(" MB\n");
+ printf("\n");
temp++;
}
if (used!=0) {
d=localtime(¤t);
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);
+ if ( t_rx==0 || t_tx==0 || ((atoi(daytemp)-1)*24+d->tm_hour)==0 ) {
+ e_rx=e_tx=0;
+ } else {
+ 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 ");
showint(t_rx, t_rxk, 9);
- printf(" MB | ");
+ printf(" | ");
showint(t_tx, t_txk, 9);
- printf(" MB | ");
+ printf(" | ");
showint(t_rx+t_tx, t_rxk+t_txk, 9);
- printf(" MB\n");
+ printf("\n");
temp++;
}
printf("\t no data available\n");
printf("\t----------------------------+---------------+--------------\n");
- if (used!=0)
- printf("\t estimated %'9Lu MB | %'9Lu MB | %'9Lu MB\n", e_rx, e_tx, e_rx+e_tx);
+ if (used!=0) {
+ printf("\t estimated ");
+ showint(e_rx, 0, -9);
+ printf(" | ");
+ showint(e_tx, 0, -9);
+ printf(" | ");
+ showint(e_rx+e_tx, 0, -9);
+ printf("\n");
+ }
/* hours */
} else if (qmode==7) {
dots=10*(data.hour[s].rx/(float)max);
for (j=0;j<dots;j++)
- matrix[10-j][k]='r';
+ matrix[10-j][k]=cfg.rxhourchar[0];
dots=10*(data.hour[s].tx/(float)max);
for (j=0;j<dots;j++)
- matrix[10-j][k+1]='t';
+ matrix[10-j][k+1]=cfg.txhourchar[0];
k=k+3;
}
/* remove old data if needed */
for (i=0;i<=23;i++) {
- if (data.hour[i].date<=(current-86400)) { /* 86400 = 24 hours = too old */
+ if ( (data.hour[i].date!=0) && (data.hour[i].date<=(current-86400)) ) { /* 86400 = 24 hours = too old */
data.hour[i].rx=0;
data.hour[i].tx=0;
+ data.hour[i].date=0;
if (debug) {
printf("Hour %d (%d) cleaned.\n",i, (int)data.hour[i].date);
}
}
}
-void convertdb(FILE *db)
+int convertdb(FILE *db)
{
int i, days, mod;
DATA10 data10;
time_t current;
struct tm *d;
int month=0, day;
- int tm_mday, tm_mon, tm_year;
- int converted=0;
+ int tm_mday, tm_mon, tm_year; int converted=0;
current=time(NULL);
d=localtime(¤t);
}
- /* unknown version */
- if (data.version!=DBVERSION) {
+ /* corrupted or unknown version handling */
+ if (data.version==0) {
+ printf("Error:\nUnable to convert corrupted database.\n");
+ return 0;
+ } else if (data.version!=DBVERSION) {
printf("Error:\nUnable to convert database version \"%d\".\n", data.version);
- exit(0);
+ return 0;
}
+
printf("Convertion done.\n");
+
+ return 1;
}
-void showint(uint64_t mb, int kb, int len)
+void showint(uint64_t mb, uint64_t kb, int len)
{
- char format[64];
- int flen, kB;
+ uint64_t kB;
+ int declen=2;
- while (kb>=1024) {
- mb++;
- kb-=1024;
+ /* don't show decimals .00 if len was negative (set that way for estimates) */
+ if (len<0) {
+ declen=0;
+ len=abs(len);
}
- kB=(kb*1000/1024)/10;
+ if (mb!=0) {
+ if (kb>=1024) {
+ mb+=kb/1024;
+ kb-=(kb/1024)*1024;
+ }
+ kB=(mb*1024)+kb;
+ } else {
+ kB=kb;
+ }
- 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);
+ if ( (declen==0) && (kB==0) ){
+ printf("%*s ", len, "--");
} else {
- printf("%'*Lu", len, mb);
+ /* try to figure out what unit to use */
+ if (kB>=(1024*1024*1000)) {
+ printf("%'*.2f TB", len, kB/(float)1024/(float)1024/(float)1024);
+ } else if (kB>=(1024*1000)) {
+ printf("%'*.2f GB", len, kB/(float)1024/(float)1024);
+ } else if (kB>=1000) {
+ printf("%'*.*f MB", len, declen, kB/(float)1024);
+ } else {
+ printf("%'*Lu kB", len, kB);
+ }
+ }
+}
+
+void showbar(uint64_t rx, int rxk, uint64_t tx, int txk, uint64_t max, int len)
+{
+ int i, l;
+
+ if (rxk>=1024) {
+ rx+=rxk/1024;
+ rxk-=(rxk/1024)*1024;
+ }
+
+ if (txk>=1024) {
+ tx+=txk/1024;
+ txk-=(txk/1024)*1024;
+ }
+
+ rx=(rx*1024)+rxk;
+ tx=(tx*1024)+txk;
+
+ if ((rx+tx)!=max) {
+ len=((rx+tx)/(float)max)*len;
+ }
+
+
+ if (len!=0) {
+ printf(" ");
+
+ if (tx>rx) {
+ l=rint((rx/(float)(rx+tx)*len));
+
+ for (i=0;i<l;i++) {
+ printf("%c", cfg.rxchar[0]);
+ }
+ for (i=0;i<(len-l);i++) {
+ printf("%c", cfg.txchar[0]);
+ }
+ } else {
+ l=rint((tx/(float)(rx+tx)*len));
+
+ for (i=0;i<(len-l);i++) {
+ printf("%c", cfg.rxchar[0]);
+ }
+ for (i=0;i<l;i++) {
+ printf("%c", cfg.txchar[0]);
+ }
+ }
+
+ }
+
+}
+
+void synccounters(char iface[32], char dirname[512])
+{
+ char temp[64], temp2[64];
+ char *proclineptr;
+
+ readdb(iface, dirname);
+ readproc(iface);
+
+ /* get rx and tx from procline */
+ proclineptr = strchr(procline, ':');
+ sscanf(proclineptr+1, "%s %*s %*s %*s %*s %*s %*s %*s %s",temp, temp2);
+
+ /* set counters to current without counting traffic */
+ data.currx=strtoull(temp, (char **)NULL, 0);
+ data.curtx=strtoull(temp2, (char **)NULL, 0);
+
+ writedb(iface, dirname, 0);
+}
+
+void lockdb(int fd, int dbwrite)
+{
+ int locktry=1;
+
+ /* lock only if configured to do so */
+ if (cfg.flock) {
+
+ /* try locking file */
+ while (flock(fd, LOCK_EX|LOCK_NB)!=0) {
+
+ if (debug)
+ printf("Database access locked (%d, %d)\n", dbwrite, locktry);
+
+ /* give up if lock can't be obtained */
+ if (locktry>=LOCKTRYLIMIT) {
+ if (dbwrite) {
+ printf("Error:\nLocking database file for write failed for %d tries:\n%s (%d)\n", locktry, strerror(errno), errno);
+ } else {
+ printf("Error:\nLocking database file for read failed for %d tries:\n%s (%d)\n", locktry, strerror(errno), errno);
+ }
+ exit(0);
+ }
+
+ /* someone else has the lock */
+ if (errno==EWOULDBLOCK) {
+ sleep(1);
+
+ /* real error */
+ } else {
+ if (dbwrite) {
+ printf("Error:\nLocking database file for write failed:\n%s (%d)\n", strerror(errno), errno);
+ } else {
+ printf("Error:\nLocking database file for read failed:\n%s (%d)\n", strerror(errno), errno);
+ }
+ exit(0);
+ }
+
+ locktry++;
+ }
}
}
-int readdb(char iface[32], char file[512]);
-void writedb(char file[512], int newdb);
+int readdb(char iface[32], char dirname[512]);
+void writedb(char iface[32], char dirname[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);
+int convertdb(FILE *db);
+void showint(uint64_t mb, uint64_t kb, int len);
+void showbar(uint64_t rx, int rxk, uint64_t tx, int txk, uint64_t max, int len);
+void synccounters(char iface[32], char dirname[512]);
+void lockdb(int fd, int dbwrite);
/* version 1.0 database format aka db v1 */
typedef struct {
#include "vnstat.h"
#include "misc.h"
+
void kerneltest(void)
{
- FILE *fp;
- int i=0, check, b1, b2;
- char temp[64];
+ int i=0, bmax, bmin, btemp;
- if ((fp=fopen("/proc/stat","r"))==NULL) {
- printf("Error:\nUnable to read /proc/net/dev.\n");
- exit(1);
- }
-
- check=0;
- while (fgets(statline,128,fp)!=NULL) {
- sscanf(statline,"%s",temp);
- if (strcmp(temp,"btime")==0) {
- if (debug)
- printf("\n%s\n",statline);
- check=1;
- break;
- }
- }
+ bmax=bmin=getbtime();
- if (check==0) {
- printf("Error:\nbtime missing from /proc/stat.\n");
- exit(1);
+ printf("This test will take about 60 seconds.\n");
+ printf("[ ]");
+ for (i=0; i<=30; i++) {
+ printf("\b");
}
-
- b1=strtoul(statline+6, (char **)NULL, 0);
- fclose(fp);
-
- printf("This test will take about 20 seconds.\n");
- printf("Testing kernel.");
fflush(stdout);
- for (i=1;i<5;i++) {
- sleep(5);
- printf(".");
+ for (i=0;i<30;i++) {
+ sleep(2);
fflush(stdout);
- }
-
- if ((fp=fopen("/proc/stat","r"))==NULL) {
- printf("Error:\nUnable to read /proc/net/dev.\n");
- exit(1);
- }
-
- while (fgets(statline,128,fp)!=NULL) {
- sscanf(statline,"%s",temp);
- if (strcmp(temp,"btime")==0) {
- if (debug)
- printf("\n%s\n",statline);
- break;
+
+ btemp=getbtime();
+
+ if (btemp > bmax) {
+ bmax = btemp;
+ }
+ if (btemp < bmin) {
+ bmin = btemp;
}
+
+ printf("=");
+ fflush(stdout);
}
- b2=strtoul(statline+6, (char **)NULL, 0);
- fclose(fp);
-
- printf(" done\n\n");
- if (b2>b1+5) {
- printf("The current kernel has a broken btime information and vnStat wont work right.\n");
- printf("Upgrading the kernel is likely to solve this problem.\n");
- exit(1);
+ printf("] done.\n\n");
+
+ printf("Detected boot time variation during test: %2d\n", bmax-bmin);
+ printf("Maximum boot time variation set in config: %2d\n\n", cfg.bvar);
+
+ if ((bmax-bmin)>20) {
+ printf("The current kernel has a broken boot time information and\n");
+ printf("vnStat is likely not to work correctly. Upgrading the kernel\n");
+ printf("is likely to solve this problem.\n\n");
+ } else if ((bmax-bmin)>cfg.bvar) {
+ printf("The current kernel has a boot time variation greater than assumed\n");
+ printf("in the vnStat config. That it likely to cause errors in results.\n");
+ printf("Set \"BootVariation\" to something greater than \"%d\" and run this\n", (bmax-bmin));
+ printf("test again.\n\n");
+ } else if ((bmax-bmin)==0) {
+ printf("The current kernel doesn't seem to suffer from boot time variation problems.\n\n");
} else {
- printf("The current kernel is ok.\n");
- exit(0);
+ printf("The current kernel is ok.\n\n");
}
+
}
int spacecheck(char *path)
free=(buf.f_bavail/(float)1024)*buf.f_bsize;
if (debug) {
- printf("bzise %d\n", buf.f_bsize);
+ printf("bsize %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);
/* 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)
+ if (free<=1024) {
return 0;
- else
+ } else {
return 1;
+ }
+}
+
+void intr(int sig)
+{
+ intsignal=1;
+ if (debug)
+ printf("Got signal: %d\n", sig);
+}
+
+int getbtime(void)
+{
+ FILE *fp;
+ int check, result=0;
+ char temp[64];
+
+ if ((fp=fopen("/proc/stat","r"))==NULL) {
+ printf("Error:\nUnable to read /proc/stat.\n");
+ exit(1);
+ }
+
+ check=0;
+ while (fgets(statline,128,fp)!=NULL) {
+ sscanf(statline,"%s",temp);
+ if (strcmp(temp,"btime")==0) {
+ if (debug)
+ printf("\n%s\n",statline);
+ check=1;
+ break;
+ }
+ }
+
+ if (check==0) {
+ printf("Error:\nbtime missing from /proc/stat.\n");
+ exit(1);
+ }
+
+ result = strtoul(statline+6, (char **)NULL, 0);
+ fclose(fp);
+
+ return result;
}
void kerneltest(void);
int spacecheck(char *path);
+void intr(int);
+int getbtime(void);
#include "vnstat.h"
#include "proc.h"
+#include "misc.h"
#include "db.h"
+#include "cfg.h"
void readproc(char iface[32])
{
}
if (strcmp(iface,"default")==0) {
- strncpy(inface,"eth0", 32);
+ strncpy(inface, cfg.iface, 32);
} else {
- strncpy(inface,iface, 32);
+ strncpy(inface, iface, 32);
}
check=0;
exit(1);
}
- if ((fp=fopen("/proc/stat","r"))==NULL) {
- printf("Error:\nUnable to read /proc/net/dev.\n");
- exit(1);
- }
-
- check=0;
- while (fgets(statline,128,fp)!=NULL) {
- sscanf(statline,"%s",temp);
- if (strcmp(temp,"btime")==0) {
- if (debug)
- printf("\n%s\n",statline);
- check=1;
- break;
- }
- }
-
- fclose(fp);
-
- if (check==0) {
- printf("Error:\nbtime missing from /proc/stat.\n");
- exit(1);
- }
}
void parseproc(int newdb)
{
- char temp[64];
+ char temp[64], temp2[64];
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;
+ uint64_t krxchange=0, ktxchange=0, maxtransfer; /* krxchange = rx change in kB */
+ time_t current, interval;
struct tm *d;
- int day, month, year, hour, min, shift;
- int rxkchange=0, txkchange=0; /* changes in the kB counters */
-
- btime=strtoul(statline+6, (char **)NULL, 0);
-
- /* btime in /proc/stat seems to vary ±1 second so we use btime-BVAR just to be safe */
- /* the variation is also slightly different between various kernels... */
- if (data.btime<btime-atoi(BVAR)) {
- data.currx=0;
- data.curtx=0;
- if (debug)
- printf("System has been booted.\n");
- }
-
- data.btime=btime;
+ int day, month, year, hour, min, shift, maxbw;
+ int rxkchange=0, txkchange=0; /* changes in the kB counters */
+ char *proclineptr;
current=time(NULL);
+ interval=current-data.lastupdated;
+ btime=getbtime();
- /* get rx from procline, easy since it's always procline+7 */
+ /* get rx and tx from procline */
+ proclineptr = strchr(procline, ':');
+ sscanf(proclineptr+1, "%s %*s %*s %*s %*s %*s %*s %*s %s",temp, temp2);
-#ifdef BLIMIT
- rx=strtoull(procline+7, (char **)NULL, 0);
-#else
- rx=strtoul(procline+7, (char **)NULL, 0);
-#endif
+ rx=strtoull(temp, (char **)NULL, 0);
+ tx=strtoull(temp2, (char **)NULL, 0);
- if (newdb!=1) {
- if (data.currx<=rx) {
- rxchange=(rx-data.currx)/1024/1024;
- krxchange=(rx-data.currx)/1024;
- rxkchange=((rx-data.currx)/1024)%1024;
- if (debug)
- printf("rx: %Lu - %Lu = %Lu\n",rx,data.currx,rx-data.currx);
- } else {
- rxchange=(FPOINT-data.currx+rx)/1024/1024;
- krxchange=(FPOINT-data.currx+rx)/1024;
- rxkchange=((FPOINT-data.currx+rx)/1024)%1024;
+ /* count traffic only if previous update wasn't too long ago */
+ if ( interval < (60*MAXUPDATEINTERVAL) ) {
+
+ /* btime in /proc/stat seems to vary ±1 second so we use btime-BVAR just to be safe */
+ /* the variation is also slightly different between various kernels... */
+ if (data.btime < (btime-cfg.bvar)) {
+ data.currx=0;
+ data.curtx=0;
if (debug)
- printf("rx: %Lu - %Lu + %Lu = %Lu\n",FPOINT,data.currx,rx,FPOINT-data.currx+rx);
+ printf("System has been booted.\n");
}
- }
-
- data.currx=rx;
- addtraffic(&data.totalrx, &data.totalrxk, rxchange, rxkchange);
-
+ /* process rx & tx */
+ if (newdb!=1) {
+ rxchange = countercalc(data.currx, rx)/1024/1024;
+ krxchange = countercalc(data.currx, rx)/1024;
+ rxkchange = (countercalc(data.currx, rx)/1024)%1024;
+
+ txchange = countercalc(data.curtx, tx)/1024/1024;
+ ktxchange = countercalc(data.curtx, tx)/1024;
+ txkchange = (countercalc(data.curtx, tx)/1024)%1024;
+ }
- /* 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);
+ /* get maximum bandwidth */
+ maxbw = ibwget(data.interface);
-#ifdef BLIMIT
- tx=strtoull(temp, (char **)NULL, 0);
-#else
- tx=strtoul(temp, (char **)NULL, 0);
-#endif
+ if (maxbw > 0) {
+
+ /* calculate maximum possible transfer since last update based on set maximum rate */
+ /* and add 10% in order to be on the safe side */
+ maxtransfer = ceil((maxbw/(float)8)*interval*(float)1.1);
- if (newdb!=1) {
- if (data.curtx<=tx) {
- txchange=(tx-data.curtx)/1024/1024;
- ktxchange=(tx-data.curtx)/1024;
- txkchange=((tx-data.curtx)/1024)%1024;
- if (debug)
- printf("tx: %Lu - %Lu = %Lu\n",tx,data.curtx,tx-data.curtx);
- } else {
- txchange=(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\n",FPOINT,data.curtx,tx,FPOINT-data.curtx+tx);
+ printf("interval: %Lu maxbw: %d maxrate: %Lu rxc: %Lu txc: %Lu\n", (uint64_t)interval, maxbw, maxtransfer, rxchange, txchange);
+
+ /* sync counters if traffic is greater than set maximum */
+ if ( (rxchange > maxtransfer) || (txchange > maxtransfer) ) {
+ rxchange=krxchange=rxkchange=txchange=ktxchange=txkchange=0;
+ if (debug)
+ printf("Traffic is greater than set maximum, counters synced.\n");
+ }
}
+
+ } else {
+ if (debug)
+ printf("Too much time passed since previous update, syncing. (%Lu < %d)\n", (uint64_t)interval, 60*MAXUPDATEINTERVAL);
}
+
+ /* keep btime updated in case it drifts slowly */
+ data.btime=btime;
+
+ data.currx=rx;
data.curtx=tx;
-
+ addtraffic(&data.totalrx, &data.totalrxk, rxchange, rxkchange);
addtraffic(&data.totaltx, &data.totaltxk, txchange, txkchange);
/* update days and months */
/* rotate months in database if needed */
d=localtime(&data.month[0].month);
- if ((d->tm_mon!=month) && (day>=atoi(MONTHROTATE)))
+ if ((d->tm_mon!=month) && (day>=MONTHROTATE))
rotatemonths();
}
{
/* received bytes packets errs drop fifo frame compressed multicast */
/* transmitted bytes packets errs drop fifo colls carrier compressed */
- uint64_t p1[16], p2[16];
+ uint64_t p1[16], p2[16], rx, tx, rxp, txp;
int i, j, len;
char temp[64], buffer[256];
+ char *proclineptr;
- /* less than 5 seconds if probably too inaccurate */
- if (sampletime<5) {
+ /* less than 2 seconds doesn't produce good results */
+ if (sampletime<2) {
printf("Error:\nTime for sampling too short.\n");
exit(1);
}
- /* read /proc/net/dev and get those values to the first list */
+ /* read /proc/net/dev and get values to the first list */
j=0;
readproc(iface);
- for (i=7;i<strlen(procline);i++) {
- if (procline[i]!=' ') {
- sscanf(procline+i,"%s",temp);
+ proclineptr = strchr(procline, ':');
+ for (i=1;i<strlen(proclineptr);i++) {
+ if (proclineptr[i]!=' ') {
+ sscanf(proclineptr+i,"%s",temp);
i+=strlen(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++;
len=strlen(buffer)+3;
- for (i=0;i<len;i++)
+ for (i=0;i<len;i++) {
printf("\b \b");
+ }
- /* read those value again... */
+ /* read those values again... */
j=0;
readproc(iface);
- for (i=7;i<strlen(procline);i++) {
- if (procline[i]!=' ') {
- sscanf(procline+i,"%s",temp);
+ proclineptr = strchr(procline, ':');
+ for (i=1;i<strlen(proclineptr);i++) {
+ if (proclineptr[i]!=' ') {
+ sscanf(proclineptr+i,"%s",temp);
i+=strlen(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("%Lu packets sampled in %d seconds\n", (p2[1]-p1[1])+(p2[9]-p1[9]), sampletime);
+ /* calculate traffic and packets seen between updates */
+ rx = countercalc(p1[0], p2[0]);
+ tx = countercalc(p1[8], p2[8]);
+ rxp = countercalc(p1[1], p2[1]);
+ txp = countercalc(p1[9], p2[9]);
+
+ /* show the difference in a readable format */
+ printf("%Lu packets sampled in %d seconds\n", rxp+txp, 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));
+ printf("\n rx %10.2f kB/s %5Lu packets/s\n", rx/(float)sampletime/(float)1024, (uint64_t)(rxp/sampletime));
+ printf(" tx %10.2f kB/s %5Lu packets/s\n\n", tx/(float)sampletime/(float)1024, (uint64_t)(txp/sampletime));
+
+}
+
+void livetrafficmeter(char iface[32])
+{
+ /* received bytes packets errs drop fifo frame compressed multicast */
+ /* transmitted bytes packets errs drop fifo colls carrier compressed */
+ uint64_t p1[16], p2[16], rx, tx, rxp, txp, rxpc, txpc, timespent;
+ uint64_t rxtotal, txtotal, rxptotal, txptotal;
+ uint64_t rxpmin, txpmin, rxpmax, txpmax;
+ float rxmin, txmin, rxmax, txmax, rxc, txc;
+ int i, j, len;
+ char temp[64], buffer[256];
+ char *proclineptr;
+
+ printf("Monitoring %s... (press CTRL-C to stop)\n\n", iface);
+ printf(" getting traffic...");
+ len=21;
+ fflush(stdout);
+
+ /* enable signal trap */
+ if (signal(SIGINT, intr) == SIG_ERR) {
+ perror("signal");
+ exit(1);
+ }
+
+ /* set some defaults */
+ rxtotal=txtotal=rxptotal=txptotal=rxpmax=txpmax=0;
+ rxpmin=txpmin=-1;
+ rxmax=txmax=0.0;
+ rxmin=txmin=-1.0;
+
+ timespent = (uint64_t)time(NULL);
+
+ /* read /proc/net/dev and get values to the first list */
+ j=0;
+ readproc(iface);
+ proclineptr = strchr(procline, ':');
+ for (i=1;i<strlen(proclineptr);i++) {
+ if (proclineptr[i]!=' ') {
+ sscanf(proclineptr+i,"%s",temp);
+ i+=strlen(temp);
+ p1[j]=strtoull(temp, (char **)NULL, 0);
+ if (debug)
+ printf("%8d '%s' -> '%Lu'\n",j,temp,p1[j]);
+ j++;
+ }
+ }
+
+ /* loop until user gets bored */
+ while (intsignal==0) {
+
+ /* wait 2 seconds for more traffic */
+ sleep(LIVETIME);
+
+ /* break loop without calculations because sleep was probably interrupted */
+ if (intsignal) {
+ break;
+ }
+
+ /* use values from previous loop if this isn't the first time */
+ if (len!=21) {
+ for (i=0;i<16;i++) {
+ p1[i]=p2[i];
+ }
+ }
+
+ /* read those values again... */
+ j=0;
+ readproc(iface);
+ proclineptr = strchr(procline, ':');
+ for (i=1;i<strlen(proclineptr);i++) {
+ if (proclineptr[i]!=' ') {
+ sscanf(proclineptr+i,"%s",temp);
+ i+=strlen(temp);
+ p2[j]=strtoull(temp, (char **)NULL, 0);
+ if (debug)
+ printf("%8d '%s' -> '%Lu'\n",j,temp,p2[j]);
+ j++;
+ }
+ }
+
+ /* calculate traffic and packets seen between updates */
+ rx = countercalc(p1[0], p2[0]);
+ tx = countercalc(p1[8], p2[8]);
+ rxp = countercalc(p1[1], p2[1]);
+ txp = countercalc(p1[9], p2[9]);
+
+ /* update totals */
+ rxtotal += rx;
+ txtotal += tx;
+ rxptotal += rxp;
+ txptotal += txp;
+
+ rxc = rx/(float)LIVETIME/(float)1024;
+ txc = tx/(float)LIVETIME/(float)1024;
+ rxpc = rxp/LIVETIME;
+ txpc = txp/LIVETIME;
+
+ /* update min & max */
+ if ((rxmin==-1.0) || (rxmin>rxc)) {
+ rxmin = rxc;
+ }
+ if ((txmin==-1.0) || (txmin>txc)) {
+ txmin = txc;
+ }
+ if (rxmax<rxc) {
+ rxmax = rxc;
+ }
+ if (txmax<txc) {
+ txmax = txc;
+ }
+
+ if ((rxpmin==-1) || (rxpmin>rxpc)) {
+ rxpmin = rxpc;
+ }
+ if ((txpmin==-1) || (txpmin>txpc)) {
+ txpmin = txpc;
+ }
+ if (rxpmax<rxpc) {
+ rxpmax = rxpc;
+ }
+ if (txpmax<txpc) {
+ txpmax = txpc;
+ }
+
+ /* show the difference in a readable format */
+ snprintf(buffer, 256, " rx: %10.2f kB/s %5Lu p/s tx: %10.2f kB/s %5Lu p/s", rxc, (uint64_t)rxpc, txc, (uint64_t)txpc);
+
+ if (len>1) {
+ if (debug) {
+ printf("\nlinelen: %d\n", len);
+ } else {
+ for (i=0;i<len;i++) {
+ printf("\b \b");
+ }
+ fflush(stdout);
+ }
+ }
+ printf("%s", buffer);
+ fflush(stdout);
+ len=strlen(buffer);
+
+ }
+
+ timespent = (uint64_t)time(NULL) - timespent;
+
+ printf("\n\n");
+
+ /* print some statistics if enough time did pass */
+ if (timespent>10) {
+
+ printf("\n %s / traffic statistics\n\n", iface);
+
+ printf(" rx | tx\n");
+ printf("--------------------------------------+----------------------------------------\n");
+ printf(" bytes ");
+ showint(0, rxtotal/1024, 10);
+ printf(" | ");
+ showint(0, txtotal/1024, 10);
+ printf("\n");
+ printf("--------------------------------------+----------------------------------------\n");
+ printf(" max ");
+ showspeed(rxmax, 8);
+ printf(" | ");
+ showspeed(txmax, 8);
+ printf("\n");
+ printf(" average ");
+ showspeed(rxtotal/(float)timespent/(float)1024, 8);
+ printf(" | ");
+ showspeed(txtotal/(float)timespent/(float)1024, 8);
+ printf("\n");
+ printf(" min ");
+ showspeed(rxmin, 8);
+ printf(" | ");
+ showspeed(txmin, 8);
+ printf("\n");
+ printf("--------------------------------------+----------------------------------------\n");
+ printf(" packets %12Lu | %12Lu\n", rxptotal, txptotal);
+ printf("--------------------------------------+----------------------------------------\n");
+ printf(" max %9Lu p/s | %9Lu p/s\n", rxpmax, txpmax);
+ printf(" average %9Lu p/s | %9Lu p/s\n", rxptotal/timespent, txptotal/timespent);
+ printf(" min %9Lu p/s | %9Lu p/s\n", rxpmin, txpmin);
+ printf("--------------------------------------+----------------------------------------\n");
+
+ if (timespent<=60) {
+ printf(" time %9Lu seconds\n", timespent);
+ } else {
+ printf(" time %7.2f minutes\n", timespent/(float)60);
+ }
+
+ printf("\n");
+ }
+
}
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;
+ if (*destkb>=1024) {
+ *destmb+=*destkb/1024;
+ *destkb-=(*destkb/1024)*1024;
+ }
+}
+
+uint64_t countercalc(uint64_t a, uint64_t b)
+{
+ /* no flip */
+ if (b>=a) {
+ if (debug)
+ printf("cc: %Lu - %Lu = %Lu\n", b, a, b-a);
+ return b-a;
+
+ /* flip exists */
+ } else {
+ /* original counter is 64bit */
+ if (a>FP32) {
+ if (debug)
+ printf("cc64: uint64 - %Lu + %Lu = %Lu\n", a, b, FP64-a+b);
+ return FP64-a+b;
+
+ /* original counter is 32bit */
+ } else {
+ if (debug)
+ printf("cc32: uint32 - %Lu + %Lu = %Lu\n", a, b, FP32-a+b);
+ return FP32-a+b;
+ }
+ }
+}
+
+void showspeed(float xfer, int len)
+{
+ if (xfer>1024) {
+ printf("%'*.2f MB/s", len, xfer/(float)1024);
+ } else {
+ printf("%'*.2f kB/s", len, xfer);
}
}
void readproc(char iface[32]);
void parseproc(int newdb);
void trafficmeter(char iface[32], int sampletime);
+void livetrafficmeter(char iface[32]);
void addtraffic(uint64_t *destmb, int *destkb, uint64_t srcmb, int srckb);
+uint64_t countercalc(uint64_t a, uint64_t b);
+void showspeed(float xfer, int len);
/*
-vnStat - Copyright (c) 2002-04 Teemu Toivola <tst@iki.fi>
+vnStat - Copyright (c) 2002-07 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
#include "proc.h"
#include "db.h"
#include "misc.h"
+#include "cfg.h"
int main(int argc, char *argv[]) {
int i;
- int currentarg, update=0, query=0, newdb=0, qmode=0, reset=0;
+ int currentarg, update=0, query=1, newdb=0, reset=0, sync=0;
int active=-1, files=0, force=0, cleartop=0, rebuildtotal=0, traffic=0;
- int sampletime;
- char interface[32], filename[512], dirname[512], nick[32];
+ int livetraffic=0;
+ char interface[32], dirname[512], nick[32];
char definterface[32];
time_t current;
DIR *dir;
struct dirent *di;
- debug=0; /* debug disabled by default */
+ debug = 0; /* debug disabled by default */
- setlocale(LC_ALL, "en_US");
+ /* early check for debug parameter */
+ if (argc > 1) {
+ for (currentarg=1; currentarg<argc; currentarg++) {
+ if ((strcmp(argv[currentarg],"-D")==0) || (strcmp(argv[currentarg],"--debug"))==0) {
+ debug = 1;
+ }
+ }
+ }
+
+ /* load config if available */
+ loadcfg();
+
+ setlocale(LC_ALL, cfg.locale);
strncpy(interface, "default", 32);
- strncpy(definterface, DEFIFACE, 32);
+ strncpy(definterface, cfg.iface, 32);
strncpy(nick, "none", 32);
- qmode=atoi(DEFQMODE);
- sampletime=atoi(DEFSAMPTIME);
- current=time(NULL);
+ current = time(NULL);
/* init dirname */
#ifdef SINGLE
strncpy(dirname, getenv("HOME"), 500);
strcat(dirname,"/.vnstat");
#else
- strncpy(dirname, DATABASEDIR, 500);
+ strncpy(dirname, cfg.dbdir, 512);
#endif
- /* check if the database dir exists and if it contains files */
- if ((dir=opendir(dirname))!=NULL) {
- if (debug)
- printf("Dir OK\n");
- while ((di=readdir(dir))) {
- if (di->d_name[0]!='.') {
- strncpy(definterface, di->d_name, 32);
- files++;
- }
- }
- if (debug)
- printf("%d files found\n", files);
- if (files) {
- query=1;
- if (files>1)
- strncpy(definterface, DEFIFACE, 32);
- }
- closedir(dir);
- } else {
- printf("Error:\nUnable to open database directory \"%s\".\n", dirname);
- printf("Make sure it exists and is read enabled for this user.\n");
- printf("Exiting...\n");
- exit(0);
- }
-
-
/* parse parameters, maybe not the best way but... */
for (currentarg=1; currentarg<argc; currentarg++) {
if (debug)
printf(" Update:\n");
printf("\t -u, --update\t\t update database\n");
printf("\t -r, --reset\t\t reset interface counters\n");
+ printf("\t --sync \t\t sync 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 --dumpdb\t\t show database in parseable format\n");
printf(" Misc:\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 -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 -l, --live\t\t show transfer rate in real time\n");
+ printf("\t --showconfig\t\t dump config file with current settings\n");
printf("\t --testkernel\t\t check if the kernel is broken\n");
printf("\t --longhelp\t\t display this help\n\n");
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("\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");
+ printf("\t -l, --live\t\t show transfer rate in real time\n\n");
printf("See also \"--longhelp\" for complete options list and \"man vnstat\".\n");
query=1;
} else if ((strcmp(argv[currentarg],"-D")==0) || (strcmp(argv[currentarg],"--debug"))==0) {
debug=1;
- printf("arg %d: \"%s\"\n",currentarg,argv[currentarg]);
} else if ((strcmp(argv[currentarg],"-d")==0) || (strcmp(argv[currentarg],"--days"))==0) {
- qmode=1;
+ cfg.qmode=1;
} else if ((strcmp(argv[currentarg],"-m")==0) || (strcmp(argv[currentarg],"--months"))==0) {
- qmode=2;
+ cfg.qmode=2;
} else if ((strcmp(argv[currentarg],"-t")==0) || (strcmp(argv[currentarg],"--top10"))==0) {
- qmode=3;
+ cfg.qmode=3;
} else if ((strcmp(argv[currentarg],"-s")==0) || (strcmp(argv[currentarg],"--short"))==0) {
- qmode=5;
+ cfg.qmode=5;
} else if ((strcmp(argv[currentarg],"-w")==0) || (strcmp(argv[currentarg],"--weeks"))==0) {
- qmode=6;
+ cfg.qmode=6;
} else if ((strcmp(argv[currentarg],"-h")==0) || (strcmp(argv[currentarg],"--hours"))==0) {
- qmode=7;
+ cfg.qmode=7;
} else if (strcmp(argv[currentarg],"--dumpdb")==0) {
- qmode=4;
+ cfg.qmode=4;
} else if (strcmp(argv[currentarg],"--enable")==0) {
active=1;
query=0;
} else if ((strcmp(argv[currentarg],"-tr")==0) || (strcmp(argv[currentarg],"--traffic"))==0) {
if (currentarg+1<argc) {
if (isdigit(argv[currentarg+1][0])) {
- sampletime=atoi(argv[currentarg+1]);
+ cfg.sampletime=atoi(argv[currentarg+1]);
currentarg++;
traffic=1;
query=0;
}
traffic=1;
query=0;
+ } else if ((strcmp(argv[currentarg],"-l")==0) || (strcmp(argv[currentarg],"--live"))==0) {
+ livetraffic=1;
+ query=0;
} else if (strcmp(argv[currentarg],"--force")==0) {
force=1;
} else if (strcmp(argv[currentarg],"--cleartop")==0) {
} else if (strcmp(argv[currentarg],"--testkernel")==0) {
kerneltest();
exit(0);
+ } else if (strcmp(argv[currentarg],"--showconfig")==0) {
+ printcfgfile();
+ exit(0);
} else if ((strcmp(argv[currentarg],"-v")==0) || (strcmp(argv[currentarg],"--version"))==0) {
- printf("vnStat %s by Teemu Toivola <tst at iki dot fi>\n", VNSTATVERSION);
#ifndef SINGLE
if (debug)
printf("Root ");
#else
if (debug)
- printf("Singleuser ");
-#endif
-#ifndef BLIMIT
- if (debug)
- printf("32bit install\n");
-#else
- if (debug)
- printf("64bit install\n");
+ printf("Single user ");
#endif
+ printf("vnStat %s by Teemu Toivola <tst at iki dot fi>\n", VNSTATVERSION);
exit(0);
} else if ((strcmp(argv[currentarg],"-r")==0) || (strcmp(argv[currentarg],"--reset"))==0) {
reset=1;
query=0;
+ } else if (strcmp(argv[currentarg],"--sync")==0) {
+ sync=1;
+ query=0;
} else {
printf("Unknown arg \"%s\". Use --help for help.\n",argv[currentarg]);
exit(1);
}
+ /* check if the database dir exists and if it contains files */
+ if (!traffic && !livetraffic) {
+ if ((dir=opendir(dirname))!=NULL) {
+ if (debug)
+ printf("Dir OK\n");
+ while ((di=readdir(dir))) {
+ if (di->d_name[0]!='.') {
+ strncpy(definterface, di->d_name, 32);
+ files++;
+ }
+ }
+ if (debug)
+ printf("%d file(s) found\n", files);
+ if (files>1) {
+ strncpy(definterface, cfg.iface, 32);
+ }
+ closedir(dir);
+ } else {
+ printf("Error:\nUnable to open database directory \"%s\".\n", dirname);
+ printf("Make sure it exists and is at least read enabled for current user.\n");
+ printf("Exiting...\n");
+ exit(0);
+ }
+ }
+
/* counter reset */
if (reset) {
if (!spacecheck(dirname) && !force) {
}
if (strcmp(interface, "default")==0)
strncpy(interface, definterface, 32);
- sprintf(filename, "%s/%s", dirname, interface);
- readdb(interface, filename);
+ readdb(interface, dirname);
data.currx=0;
data.curtx=0;
- writedb(filename, 0);
+ writedb(interface, dirname, 0);
if (debug)
printf("Counters reseted for \"%s\"\n", data.interface);
}
+ /* counter sync */
+ if (sync) {
+ if (!spacecheck(dirname) && !force) {
+ printf("Error:\nNot enough free diskspace available.\n");
+ exit(0);
+ }
+ if (strcmp(interface, "default")==0)
+ strncpy(interface, definterface, 32);
+ synccounters(interface, dirname);
+ if (debug)
+ printf("Counters synced for \"%s\"\n", data.interface);
+ }
+
/* clear top10 */
if (cleartop) {
if (!spacecheck(dirname) && !force) {
if (strcmp(interface, "default")==0)
strncpy(interface, definterface, 32);
if (force) {
- snprintf(filename, 512, "%s/%s", dirname, interface);
- readdb(interface, filename);
+ readdb(interface, dirname);
for (i=0; i<=9; i++) {
data.top10[i].rx=data.top10[i].tx=0;
data.top10[i].used=0;
}
- writedb(filename, 0);
- if (debug)
- printf("Top10 reseted for \"%s\"\n", data.interface);
+ writedb(interface, dirname, 0);
+ printf("Top10 cleared for interface \"%s\".\n", data.interface);
+ query=0;
} else {
printf("Warning:\nThe current option would clear the top10 for \"%s\".\n", interface);
printf("Use --force to override this message.\n");
if (strcmp(interface, "default")==0)
strncpy(interface, definterface, 32);
if (force) {
- snprintf(filename, 512, "%s/%s", dirname, interface);
- readdb(interface, filename);
+ readdb(interface, dirname);
data.totalrx=data.totaltx=data.totalrxk=data.totaltxk=0;
for (i=0; i<=29; i++) {
}
}
- writedb(filename, 0);
- if (debug)
- printf("Total transfer rebuild completed for \"%s\"\n", data.interface);
+ writedb(interface, dirname, 0);
+ printf("Total transfer rebuild completed for interface \"%s\".\n", data.interface);
+ query=0;
} else {
printf("Warning:\nThe current option would rebuild total tranfers for \"%s\".\n", interface);
printf("Use --force to override this message.\n");
}
if (strcmp(interface, "default")==0)
strncpy(interface, definterface, 32);
- snprintf(filename, 512, "%s/%s", dirname, interface);
- newdb=readdb(interface, filename);
+ newdb=readdb(interface, dirname);
if (!data.active && !newdb) {
data.active=1;
- writedb(filename, 0);
+ writedb(interface, dirname, 0);
if (debug)
printf("Interface \"%s\" enabled.\n", data.interface);
} else if (!newdb) {
}
if (strcmp(interface, "default")==0)
strncpy(interface, definterface, 32);
- snprintf(filename, 512, "%s/%s", dirname, interface);
- newdb=readdb(interface, filename);
+ newdb=readdb(interface, dirname);
if (data.active && !newdb) {
data.active=0;
- writedb(filename, 0);
+ writedb(interface, dirname, 0);
if (debug)
printf("Interface \"%s\" disabled.\n", data.interface);
} else if (!newdb) {
if (di->d_name[0]!='.') {
files++;
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("\nProcessing file \"%s/%s\"...\n", dirname, interface);
+ newdb=readdb(interface, dirname);
if (data.active) {
readproc(data.interface);
parseproc(newdb);
/* check that the time is correct */
if ((current>=data.lastupdated) || force) {
- writedb(filename, newdb);
+ writedb(interface, dirname, newdb);
} else {
printf("Error:\nThe previous update was after the current date.\n\n");
printf("Previous update: %s", (char*)asctime(localtime(&data.lastupdated)));
}
closedir(dir);
- if (files==0)
- printf("No database found.\n");
+ if (files==0) {
+ // printf("No database found.\n");
+ update=0;
+ }
/* reset to default */
strncpy(interface, "default", 32);
/* update only selected file */
} else {
- snprintf(filename, 512, "%s/%s", dirname, interface);
- newdb=readdb(interface, filename);
+ newdb=readdb(interface, dirname);
if (data.active) {
readproc(data.interface);
parseproc(newdb);
if ((current>=data.lastupdated) || force) {
if (strcmp(nick, "none")!=0)
strncpy(data.nick, nick, 32);
- writedb(filename, newdb);
+ writedb(interface, dirname, newdb);
} else {
printf("Error:\nThe previous update was after the current date.\n\n");
printf("Previous update: %s", (char*)asctime(localtime(&data.lastupdated)));
if (strcmp(interface, "default")==0) {
if (files==0) {
- printf("No database found.\n");
- } else if ((qmode==0) && (files>1)) {
+ // printf("No database found.\n");
+ query=0;
+ } else if ((cfg.qmode==0) && (files>1)) {
dir=opendir(dirname);
printf("\n rx / tx / total / estimated\n");
while ((di=readdir(dir))) {
if (di->d_name[0]!='.') {
strncpy(interface, di->d_name, 32);
- snprintf(filename, 512, "%s/%s", dirname, interface);
if (debug)
- printf("\nProcessing file \"%s\"...\n", filename);
- readdb(interface, filename);
+ printf("\nProcessing file \"%s/%s\"...\n", dirname, interface);
+ readdb(interface, dirname);
if (!newdb)
showdb(5);
/* show in qmode if there's only one file or qmode!=0 */
} else {
- snprintf(filename, 512, "%s/%s", dirname, definterface);
- readdb(definterface, filename);
+ readdb(definterface, dirname);
if (!newdb) {
- if (qmode==5)
+ if (cfg.qmode==5)
printf("\n rx / tx / total / estimated\n");
- showdb(qmode);
+ showdb(cfg.qmode);
}
}
/* show only specified file */
} else {
- snprintf(filename, 512, "%s/%s", dirname, interface);
- readdb(interface, filename);
+ readdb(interface, dirname);
if (!newdb) {
- if (qmode==5)
+ if (cfg.qmode==5)
printf("\n rx / tx / total / estimated\n");
- showdb(qmode);
+ showdb(cfg.qmode);
}
}
}
if (traffic) {
if (strcmp(interface, "default")==0)
strncpy(interface, definterface, 32);
- trafficmeter(interface, sampletime);
+ trafficmeter(interface, cfg.sampletime);
+ }
+
+ /* live traffic */
+ if (livetraffic) {
+ if (strcmp(interface, "default")==0)
+ strncpy(interface, definterface, 32);
+
+ livetrafficmeter(interface);
}
/* if nothing was shown previously */
- if (!query && !update && !reset && active==-1 && !cleartop && !rebuildtotal && !traffic) {
+ if (!query && !update && !reset && !sync && active==-1 && !cleartop && !rebuildtotal && !traffic && !livetraffic) {
/* give more help if there's no database */
if (files==0) {
#include <dirent.h>
#include <sys/vfs.h>
#include <ctype.h>
+#include <signal.h>
+#include <math.h>
+#include <errno.h>
+#include <sys/file.h>
+
+/*
+
+Note! These are only the default values for settings
+and most can be changed later from the config file.
+
+*/
/* location of the database directory */
#define DATABASEDIR "/var/lib/vnstat"
/* on which day should months change */
-#define MONTHROTATE "1"
+#define MONTHROTATE 1
/* date output formats for -d, -m, -t and -w */
/* see 'man date' for control codes */
#define MFORMAT "%b '%y"
#define TFORMAT "%d.%m.%y"
+/* characters used for visuals */
+#define RXCHAR "%"
+#define TXCHAR ":"
+#define RXHOURCHAR "r"
+#define TXHOURCHAR "t"
+
/* default interface */
#define DEFIFACE "eth0"
+/* default locale */
+#define LOCALE "en_US"
+
+/* default maximum bandwidth (Mbit) for all interfaces */
+/* 0 = feature disabled */
+#define DEFMAXBW 100
+
/* how many seconds should sampling take by default */
-#define DEFSAMPTIME "5"
+#define DEFSAMPTIME 5
+
+/* maximum time (minutes) between two updates before traffic */
+/* for that period will be discarded */
+/* set to a little over one hour so that it doesn't break using */
+/* cron.hourly like Gentoo seems to do */
+#define MAXUPDATEINTERVAL 62
/* default query mode */
/* 0 = normal, 1 = days, 2 = months, 3 = top10 */
-/* 4 = dumpdb, 5 = short, 6 = weeks */
-#define DEFQMODE "0"
+/* 4 = dumpdb, 5 = short, 6 = weeks, 7 = hours */
+#define DEFQMODE 0
/* how much the boot time can variate between updates (seconds) */
-#define BVAR "15"
+#define BVAR 15
+
+/* use file locking by default */
+#define USEFLOCK 1
+
+/* how many times try file locking before giving up */
+/* each try takes about a second */
+#define LOCKTRYLIMIT 5
/* database version */
-/* 1 = 1.0, 2 = 1.1-1.2, 3 = 1.3*/
+/* 1 = 1.0, 2 = 1.1-1.2, 3 = 1.3- */
#define DBVERSION 3
/* version string */
-#define VNSTATVERSION "1.4"
+#define VNSTATVERSION "1.5"
-#ifdef BLIMIT
-/* 64 bit limit */
-#define FPOINT 18446744073709551616
+/* integer limits */
+#define FP32 4294967295ULL
+#define FP64 18446744073709551615ULL
+
+/* sampletime in seconds for live traffic */
+/* don't use values below 2 */
+#define LIVETIME 2
+
+/* internal config structure */
+typedef struct {
+ int bvar;
+ int qmode;
+ int sampletime;
+ int monthrotate;
+ int maxbw;
+ int flock;
+ char dformat[64], mformat[64], tformat[64];
+ char iface[32];
+ char locale[32];
+ char dbdir[512];
+ char rxchar[2], txchar[2], rxhourchar[2], txhourchar[2];
+} CFG;
-#else
-/* 32 bit limit */
-#define FPOINT 4294967296
-#endif
typedef struct {
time_t date;
int used;
} MONTH;
+/* db structure */
typedef struct {
int version;
char interface[32];
uint64_t btime;
} DATA;
+typedef struct ibw {
+ char interface[32];
+ int limit;
+ struct ibw *next;
+} ibwnode;
+
+/* global variables */
DATA data;
+CFG cfg;
+ibwnode *ifacebw;
char procline[512], statline[128];
int debug;
+int intsignal;