]> granicus.if.org Git - vnstat/commitdiff
Version 1.3 v1.3
authorTeemu Toivola <git@humdi.net>
Mon, 24 Feb 2014 19:44:05 +0000 (21:44 +0200)
committerTeemu Toivola <git@humdi.net>
Mon, 24 Feb 2014 19:44:05 +0000 (21:44 +0200)
15 files changed:
CHANGES
FAQ
INSTALL
Makefile
README
UPGRADE
man/vnstat.1 [new file with mode: 0644]
src/Makefile
src/db.c
src/db.h
src/misc.c
src/proc.c
src/proc.h
src/vnstat.c
src/vnstat.h

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