]> granicus.if.org Git - vnstat/commitdiff
Version 1.5 v1.5
authorTeemu Toivola <git@humdi.net>
Mon, 24 Feb 2014 19:47:43 +0000 (21:47 +0200)
committerTeemu Toivola <git@humdi.net>
Mon, 24 Feb 2014 19:47:43 +0000 (21:47 +0200)
22 files changed:
CHANGES
FAQ
INSTALL
Makefile
README
UPGRADE
cfg/vnstat.conf [new file with mode: 0644]
cron/vnstat
man/vnstat.1
pppd/vnstat_ip-down
pppd/vnstat_ip-up
src/Makefile
src/cfg.c [new file with mode: 0644]
src/cfg.h [new file with mode: 0644]
src/db.c
src/db.h
src/misc.c
src/misc.h
src/proc.c
src/proc.h
src/vnstat.c
src/vnstat.h

diff --git a/CHANGES b/CHANGES
index 16805f8ba4c4e200a251aadf5a2ce697036eead9..231ed46918ba09a504acd1c4e91a78629634082a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,20 @@
+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
diff --git a/FAQ b/FAQ
index 8a0855514eb1f4fe4dbf573fb7e3945db06a8a46..4776e133d9921003cfa6ce898f6178d345958332 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -3,4 +3,4 @@ That FAQ is located at
 
    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.
diff --git a/INSTALL b/INSTALL
index 46ed563d67a1bbc1db6d4b9f2f9325386fbe79ef..9cc805d49d9659b918b713686183eeacbaf37971 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-(Updated 26.3.2003 based on version 1.4)
+(Updated 2.12.2007 based on version 1.5)
 
 'I don't read manuals' install
 ::::::::::::::::::::::::::::::
@@ -23,56 +23,56 @@ Installing vnStat
  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
 
@@ -82,7 +82,8 @@ Installing vnStat
  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
 
@@ -91,11 +92,14 @@ Installing vnStat
  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.
+
index 119175fd892abfa399cb6c08afaa4c570f384bef..1de6b270a77f0b346614e464b26728b3dc10bda0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,44 +6,68 @@ CRON = $(DESTDIR)/etc/cron.d
 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
diff --git a/README b/README
index 21a7653605afe34962200aae6c4a2281158652dd..ace467848647373e0e9c99860ce050c35cc60ce9 100644 (file)
--- a/README
+++ b/README
@@ -1,11 +1,13 @@
-(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
@@ -27,36 +29,32 @@ Available options
 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
@@ -64,7 +62,9 @@ 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/
diff --git a/UPGRADE b/UPGRADE
index 6a35c9706bcc414beea9e1e59497b311058d04d5..c34d4f85498f41d74e5dec01c591a2fc8aed7ebd 100644 (file)
--- a/UPGRADE
+++ b/UPGRADE
@@ -1,14 +1,15 @@
-(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?
@@ -34,4 +35,4 @@ 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.
diff --git a/cfg/vnstat.conf b/cfg/vnstat.conf
new file mode 100644 (file)
index 0000000..77b9a0a
--- /dev/null
@@ -0,0 +1,48 @@
+# 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
index ceed136071dbd07930677721cd4a9fb7d1b9f4c0..df971cc2b829b48090523e81d030b8643f3c8f32 100644 (file)
@@ -1 +1 @@
-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
index c7294e7eeaffe9b81eb00e7d7d490694d253e115..e0c6d8890015e507527cccfcb0da5421ce23eebd 100644 (file)
@@ -1,10 +1,10 @@
-.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
@@ -31,6 +31,8 @@ vnStat \- a console-based network traffic monitor
 .B \-\-iface
 .I interface
 ] [
+.B \-\-live
+] [
 .B \-\-longhelp
 ] [
 .B \-\-months
@@ -46,6 +48,8 @@ vnStat \- a console-based network traffic monitor
 ] [
 .B \-\-short
 ] [
+.B \-\-showconfig
+] [
 .B \-\-testkernel
 ] [
 .B \-\-top10
@@ -61,39 +65,22 @@ vnStat \- a console-based network traffic monitor
 ]
 .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.
@@ -101,6 +88,9 @@ 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
@@ -109,25 +99,80 @@ seconds. The
 .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
@@ -157,42 +202,16 @@ vnStat has filled this value and it is in use.
 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
@@ -220,13 +239,16 @@ and disables it from being updated before enabled again with the
 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)
index 7fc2e611fedbd62cbc50b3017ceb1e0bb6d8912a..9fc470d17d4eb4efce7b29b0f327e0743d6baa19 100644 (file)
@@ -1,2 +1,2 @@
 #!/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
index 89899047c765fa6073eba799c6c898bfaabb7a1d..29007a28cd1383946a973dc41bba31d307d665bc 100644 (file)
@@ -1,2 +1,2 @@
 #!/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
index 1468701456155828607cfbde4ad83c599bef03f0..782bbab15f1124938cc8691c510740a3e2f0a817 100644 (file)
@@ -1,33 +1,26 @@
 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
diff --git a/src/cfg.c b/src/cfg.c
new file mode 100644 (file)
index 0000000..56fafcc
--- /dev/null
+++ b/src/cfg.c
@@ -0,0 +1,391 @@
+#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;
+}
diff --git a/src/cfg.h b/src/cfg.h
new file mode 100644 (file)
index 0000000..02d8feb
--- /dev/null
+++ b/src/cfg.h
@@ -0,0 +1,8 @@
+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);
index 4c414618dd511fe430839d221c69db5669639d4f..25e912702fe58e0680aa8853deacef337da2eb2b 100644 (file)
--- a/src/db.c
+++ b/src/db.c
@@ -4,12 +4,20 @@
 
 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);
@@ -17,10 +25,36 @@ int readdb(char iface[32], char file[512])
                /* 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);
@@ -85,19 +119,30 @@ int readdb(char iface[32], char file[512])
                }
                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)
@@ -119,7 +164,7 @@ void showdb(int qmode)
        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;
        
@@ -128,7 +173,7 @@ void showdb(int qmode)
        
        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);
                
@@ -142,8 +187,12 @@ void showdb(int qmode)
                        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))); */
                
@@ -163,11 +212,11 @@ void showdb(int qmode)
                        
                        /* 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) {
@@ -175,37 +224,41 @@ void showdb(int qmode)
                        }
                        
                        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) {
@@ -213,42 +266,74 @@ void showdb(int qmode)
                        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(&current);
-                               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 */
@@ -257,42 +342,74 @@ void showdb(int qmode)
                        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(&current);
-                               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 */
@@ -301,37 +418,59 @@ void showdb(int qmode)
                        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) {
@@ -366,7 +505,7 @@ void showdb(int qmode)
                                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) {
@@ -382,16 +521,20 @@ void showdb(int qmode)
                        }
                        /* time needed for estimates */
                        d=localtime(&current);
-                       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) {
@@ -401,19 +544,21 @@ void showdb(int qmode)
                        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) {
@@ -421,14 +566,14 @@ void showdb(int qmode)
                        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");
@@ -454,11 +599,11 @@ void showdb(int qmode)
                        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++;
                        }
 
@@ -480,11 +625,11 @@ void showdb(int qmode)
                        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++;
                        }
 
@@ -507,15 +652,19 @@ void showdb(int qmode)
                        if (used!=0) {
                                d=localtime(&current);
                                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++;
                        }
                        
@@ -523,8 +672,15 @@ void showdb(int qmode)
                                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) {
@@ -613,11 +769,11 @@ void showhours(void)
 
                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;
        }
@@ -658,9 +814,10 @@ void cleanhours(void)
        
        /* 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);
                        }
@@ -771,7 +928,7 @@ void rotatemonths(void)
        }
 }
 
-void convertdb(FILE *db)
+int convertdb(FILE *db)
 {
        int i, days, mod;
        DATA10 data10;
@@ -779,8 +936,7 @@ void convertdb(FILE *db)
        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(&current);
@@ -1001,34 +1157,165 @@ void convertdb(FILE *db)
                        
        }
        
-       /* 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++;
+               }
        }
 }
index c3ebf4ef6728e672a932763747aaba622851507f..a2f8b6f822d9ca93e825ea5c0c72dcd46444d983 100644 (file)
--- a/src/db.h
+++ b/src/db.h
@@ -1,12 +1,15 @@
-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 {
index 11532783b3c7779cb52a23c8b4342737e4d56e5a..6fd973b3c328fb31d026f5f671b489b7e9559847 100644 (file)
@@ -1,72 +1,57 @@
 #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)
@@ -82,7 +67,7 @@ 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);
@@ -94,8 +79,49 @@ int spacecheck(char *path)
        /* 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;
 }
index 5db5f569c31f310a9db5b5790e025674e713e556..7c15152adbf7f7d0b8700afafb84a9e1d7dbeef0 100644 (file)
@@ -1,2 +1,4 @@
 void kerneltest(void);
 int spacecheck(char *path);
+void intr(int);
+int getbtime(void);
index e2f3f16987b3eb2c333c23a3392ae54f62b454af..81525fae74a6bb093cde97671370743da951dc6f 100644 (file)
@@ -1,6 +1,8 @@
 #include "vnstat.h"
 #include "proc.h"
+#include "misc.h"
 #include "db.h"
+#include "cfg.h"
 
 void readproc(char iface[32])
 {
@@ -14,9 +16,9 @@ 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;
@@ -37,111 +39,85 @@ void readproc(char iface[32])
                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 */
@@ -181,7 +157,7 @@ void parseproc(int newdb)
 
        /* 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();
 
 }
@@ -190,28 +166,26 @@ void trafficmeter(char iface[32], int sampletime)
 {
        /* 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++;
@@ -238,32 +212,230 @@ void trafficmeter(char iface[32], int sampletime)
        
        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)
@@ -271,8 +443,42 @@ 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);
        }
 }
index b58b2766c8bcd458b528cf48a0a7321d19b54640..cc58a39616b3d671f36ae1afdad58aa5956b1ab1 100644 (file)
@@ -1,4 +1,7 @@
 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);
index fdb7b555294e87a042d27ce5569add0f3b23a57e..9ae53da9f354f1ccd58b3321a86cd974137871dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-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
@@ -19,64 +19,49 @@ vnStat - Copyright (c) 2002-04 Teemu Toivola <tst@iki.fi>
 #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)
@@ -88,6 +73,7 @@ int main(int argc, char *argv[]) {
                        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");
@@ -105,11 +91,13 @@ int main(int argc, char *argv[]) {
                        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");
 
@@ -121,18 +109,19 @@ int main(int argc, char *argv[]) {
 
                        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");
 
@@ -169,28 +158,27 @@ int main(int argc, char *argv[]) {
                        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;
@@ -199,6 +187,9 @@ int main(int argc, char *argv[]) {
                        }
                        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) {
@@ -211,26 +202,25 @@ int main(int argc, char *argv[]) {
                } 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);
@@ -238,6 +228,31 @@ int main(int argc, char *argv[]) {
                
        }
 
+       /* 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) {
@@ -246,15 +261,27 @@ int main(int argc, char *argv[]) {
                }
                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) {
@@ -264,8 +291,7 @@ int main(int argc, char *argv[]) {
                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;
@@ -273,9 +299,9 @@ int main(int argc, char *argv[]) {
                                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");
@@ -292,8 +318,7 @@ int main(int argc, char *argv[]) {
                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++) {
@@ -303,9 +328,9 @@ int main(int argc, char *argv[]) {
                                }
                        }
 
-                       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");
@@ -321,11 +346,10 @@ int main(int argc, char *argv[]) {
                }
                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) {
@@ -338,11 +362,10 @@ int main(int argc, char *argv[]) {
                }
                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) {
@@ -369,17 +392,16 @@ int main(int argc, char *argv[]) {
                                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)));
@@ -395,23 +417,24 @@ int main(int argc, char *argv[]) {
                        }
 
                        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)));
@@ -433,18 +456,18 @@ int main(int argc, char *argv[]) {
                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);
                                                
@@ -454,23 +477,21 @@ int main(int argc, char *argv[]) {
                                
                        /* 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);
                        }
                }
        }
@@ -479,11 +500,19 @@ int main(int argc, char *argv[]) {
        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) {
index 5ccfa2f593de12d1ee9057055c7870a8bcf24d53..84d7249c4191616ed8f5936db45a130b735e82b6 100644 (file)
@@ -9,12 +9,23 @@
 #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;
@@ -71,6 +123,7 @@ typedef struct {
        int used;
 } MONTH;
 
+/* db structure */
 typedef struct {
        int version;
        char interface[32];
@@ -86,6 +139,16 @@ typedef struct {
        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;