- Improve daemon startup prints
- Add parameters for changing daemon process user and group
- Add example upstart job configuration file (thanks to Cameron Norman)
- - Create database directory during daemon startup if necessary
- - Update ownership of database files if needed during daemon startup
+ - Create database, pid and log dirs during daemon startup if necessary
+ - Update ownership of database, log and pid files if needed during daemon
+ startup if started as root and configured to change process user and group
- Remove cron update related example files and documentation, the cron
update method should be considered as deprecated
# enable / disable logging (0 = disabled, 1 = logfile, 2 = syslog)
UseLogging 2
-# create db directory if missing (1 = enabled, 0 = disabled)
-CreateDBDir 1
+# create dirs if needed (1 = enabled, 0 = disabled)
+CreateDirs 1
-# update ownership of files when needed (1 = enabled, 0 = disabled)
+# update ownership of files if needed (1 = enabled, 0 = disabled)
UpdateFileOwner 1
# file used for logging if UseLogging is set to 1
-LogFile "/var/log/vnstat.log"
+LogFile "/var/log/vnstat/vnstat.log"
# file used as daemon pid / lock file
-PidFile "/var/run/vnstat.pid"
+PidFile "/var/run/vnstat/vnstat.pid"
# vnstati
.SH DAEMON RELATED KEYWORDS
.TP
-.BI CreateDBDir
-Enable or disable the creation of the database directory when the directory
-doesn't exist. The daemon process will try to create the directory using
+.BI CreateDirs
+Enable or disable the creation of directories when a configured path doesn't
+exist. This includes
+.BI DatabaseDir
+,
+.BI LogFile
+and
+.BI PidFile
+directories. The
+.BI LogFile
+directory will be created only when
+.BI UseLogging
+has been set to 1. The daemon process will try to create the directory using
permissions of the user used to start the process.
.TP
.TP
.BI UpdateFileOwner
Enable or disable the update of file ownership during daemon process startup.
-Only database files will be modified if the user or group change feature
-is enabled and the files don't match the requested user or group.
+Only database, log and pid files will be modified if the user or group change
+feature is enabled and the files don't match the requested user or group.
This option can only be used when the process is started as root.
.TP
printf("# enable / disable logging (0 = disabled, 1 = logfile, 2 = syslog)\n");
printf("UseLogging %d\n\n", cfg.uselogging);
- printf("# create db directory if missing (1 = enabled, 0 = disabled)\n");
- printf("CreateDBDir %d\n\n", cfg.createdbdir);
+ printf("# create dirs if needed (1 = enabled, 0 = disabled)\n");
+ printf("CreateDirs %d\n\n", cfg.createdirs);
- printf("# update ownership of files when needed (1 = enabled, 0 = disabled)\n");
+ printf("# update ownership of files if needed (1 = enabled, 0 = disabled)\n");
printf("UpdateFileOwner %d\n\n", cfg.updatefileowner);
printf("# file used for logging if UseLogging is set to 1\n");
{ "OfflineSaveInterval", 0, &cfg.offsaveinterval, 0, 0 },
{ "SaveOnStatusChange", 0, &cfg.savestatus, 0, 0 },
{ "UseLogging", 0, &cfg.uselogging, 0, 0 },
- { "CreateDBDir", 0, &cfg.createdbdir, 0, 0 },
+ { "CreateDirs", 0, &cfg.createdirs, 0, 0 },
{ "UpdateFileOwner", 0, &cfg.updatefileowner, 0, 0 },
{ "LogFile", cfg.logfile, 0, 512, 0 },
{ "PidFile", cfg.pidfile, 0, 512, 0 },
printe(PT_Config);
}
- if (cfg.createdbdir<0 || cfg.createdbdir>2) {
- cfg.createdbdir = CREATEDBDIR;
- snprintf(errorstring, 512, "Invalid value for CreateDBDir, resetting to \"%d\".", cfg.createdbdir);
+ if (cfg.createdirs<0 || cfg.createdirs>2) {
+ cfg.createdirs = CREATEDIRS;
+ snprintf(errorstring, 512, "Invalid value for CreateDirs, resetting to \"%d\".", cfg.createdirs);
printe(PT_Config);
}
cfg.offsaveinterval = OFFSAVEINTERVAL;
cfg.savestatus = SAVESTATUS;
cfg.uselogging = USELOGGING;
- cfg.createdbdir = CREATEDBDIR;
+ cfg.createdirs = CREATEDIRS;
cfg.updatefileowner = UPDATEFILEOWNER;
strncpy_nt(cfg.logfile, LOGFILE, 512);
strncpy_nt(cfg.pidfile, PIDFILE, 512);
#include <sys/statvfs.h>
#include <pwd.h>
#include <grp.h>
+#include <libgen.h>
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__)
#include <sys/param.h>
#define OFFSAVEINTERVAL 30
#define SAVESTATUS 1
#define USELOGGING 2
-#define CREATEDBDIR 1
+#define CREATEDIRS 1
#define UPDATEFILEOWNER 1
-#define LOGFILE "/var/log/vnstat.log"
-#define PIDFILE "/var/run/vnstat.pid"
+#define LOGFILE "/var/log/vnstat/vnstat.log"
+#define PIDFILE "/var/run/vnstat/vnstat.pid"
/* no transparency by default */
#define TRANSBG 0
char logfile[512], pidfile[512];
char daemonuser[33], daemongroup[33];
short updateinterval, pollinterval, saveinterval, offsaveinterval, savestatus, uselogging;
- short createdbdir, updatefileowner;
+ short createdirs, updatefileowner;
} CFG;
/* internal interface information structure */
}
if (direxists(dir)) {
+ if (debug)
+ printf("already exists: %s\n", dir);
return 1;
}
- if (!cfg.createdbdir) {
+ if (!cfg.createdirs) {
return 0;
}
for (; i<len; i++) {
if (tmp[i] == '/') {
tmp[i] = '\0';
- if (debug)
- printf("for: %s\n", tmp);
if (!direxists(tmp)) {
if (mkdir(tmp, mode)!=0) {
if (debug)
ret = 0;
break;
}
- } else if (debug) {
- printf("skip\n");
}
tmp[i] = '/';
}
if (debug)
printf("Error: mkdir() \"%s\": %s\n", tmp, strerror(errno));
ret = 0;
+ } else if (debug) {
+ printf("created: %s\n", tmp);
}
}
intsignal = 0;
}
-void preparedbdir(DSTATE *s)
+void preparedirs(DSTATE *s)
{
+ /* database directory */
if (mkpath(s->dirname, 0775)) {
- updatedbowner(s->dirname, s->user, s->group);
+ updatedirowner(s->dirname, s->user, s->group);
+ }
+
+ if (!cfg.createdirs) {
+ return;
+ }
+
+ /* possible pid/lock and log directory */
+ preparevnstatdir(cfg.pidfile, s->user, s->group);
+ if (cfg.uselogging == 1) {
+ preparevnstatdir(cfg.logfile, s->user, s->group);
+ }
+}
+
+void preparevnstatdir(const char *file, const char *user, const char *group)
+{
+ int len, i, lastslash=0;
+ char *path, *base;
+
+ if (file == NULL) {
+ return;
+ }
+
+ len = strlen(file);
+ if (len<2) {
+ return;
+ }
+
+ if (file[len-1] == '/') {
+ return;
+ }
+
+ path = strdup(file);
+ if (path == NULL) {
+ return;
+ }
+
+ /* verify that path ends with vnstat or vnstatd */
+ base = basename(dirname(path));
+ if (strcmp(base, "vnstat")!=0 && strcmp(base, "vnstatd")!=0) {
+ free(path);
+ return;
+ }
+ free(path);
+
+ path = strdup(file);
+ if (path == NULL) {
+ return;
+ }
+
+ /* extract path */
+ for (i=0; i<len; i++) {
+ if (path[i] == '/') {
+ lastslash = i;
+ }
+ }
+ if (lastslash == 0) {
+ free(path);
+ return;
+ }
+ path[lastslash] = '\0';
+
+ /* create & chmod if needed */
+ if (mkpath(path, 0775)) {
+ updatedirowner(path, user, group);
}
+ free(path);
}
-void updatedbowner(const char *dir, const char *user, const char *group)
+void updatedirowner(const char *dir, const char *user, const char *group)
{
DIR *d;
struct dirent *di;
if (statbuf.st_uid != uid || statbuf.st_gid != gid) {
if (chown(dir, uid, gid) != 0) {
if (debug)
- printf("Error: updatedbowner() chown() \"%s\": %s\n", dir, strerror(errno));
+ printf("Error: updatedirowner() chown() \"%s\": %s\n", dir, strerror(errno));
return;
} else {
if (debug)
if ((d=opendir(dir))==NULL) {
if (debug)
- printf("Error: updatedbowner() diropen() \"%s\": %s\n", dir, strerror(errno));
+ printf("Error: updatedirowner() diropen() \"%s\": %s\n", dir, strerror(errno));
return;
}
int datalist_timevalidation(DSTATE *s);
int datalist_writedb(DSTATE *s);
void handleintsignals(DSTATE *s);
-void preparedbdir(DSTATE *s);
-void updatedbowner(const char *dir, const char *user, const char *group);
+void preparedirs(DSTATE *s);
+void preparevnstatdir(const char *dir, const char *user, const char *group);
+void updatedirowner(const char *dir, const char *user, const char *group);
#endif
return 0;
}
- preparedbdir(&s);
+ preparedirs(&s);
/* set user and/or group if requested */
setgroup(s.group);
}
END_TEST
-START_TEST(preparedbdir_with_no_dir)
+START_TEST(preparedirs_with_no_dir)
{
+ char logdir[512], piddir[512];
+
DSTATE s;
initdstate(&s);
defaultcfg();
+ cfg.uselogging = 1;
strncpy_nt(s.dirname, TESTDBDIR, 512);
+ snprintf(logdir, 512, "%s/log/vnstat", TESTDIR);
+ snprintf(piddir, 512, "%s/pid/vnstat", TESTDIR);
+ snprintf(cfg.logfile, 512, "%s/vnstat.log", logdir);
+ snprintf(cfg.pidfile, 512, "%s/vnstat.pid", piddir);
ck_assert_int_eq(remove_directory(TESTDIR), 1);
ck_assert_int_eq(direxists(TESTDBDIR), 0);
- preparedbdir(&s);
+ ck_assert_int_eq(direxists(logdir), 0);
+ ck_assert_int_eq(direxists(piddir), 0);
+ preparedirs(&s);
ck_assert_int_eq(direxists(TESTDBDIR), 1);
+ ck_assert_int_eq(direxists(logdir), 1);
+ ck_assert_int_eq(direxists(piddir), 1);
}
END_TEST
-START_TEST(preparedbdir_with_dir)
+START_TEST(preparedirs_with_dir)
{
+ char logdir[512], piddir[512];
+
DSTATE s;
initdstate(&s);
defaultcfg();
+ cfg.uselogging = 1;
strncpy_nt(s.dirname, TESTDBDIR, 512);
+ snprintf(logdir, 512, "%s/log/vnstat", TESTDIR);
+ snprintf(piddir, 512, "%s/pid/vnstat", TESTDIR);
+ snprintf(cfg.logfile, 512, "%s/vnstat.log", logdir);
+ snprintf(cfg.pidfile, 512, "%s/vnstat.pid", piddir);
ck_assert_int_eq(remove_directory(TESTDIR), 1);
ck_assert_int_eq(direxists(TESTDBDIR), 0);
ck_assert_int_eq(mkpath(TESTDBDIR, 0775), 1);
ck_assert_int_eq(direxists(TESTDBDIR), 1);
- preparedbdir(&s);
+ ck_assert_int_eq(direxists(logdir), 0);
+ ck_assert_int_eq(direxists(piddir), 0);
+ preparedirs(&s);
ck_assert_int_eq(direxists(TESTDBDIR), 1);
+ ck_assert_int_eq(direxists(logdir), 1);
+ ck_assert_int_eq(direxists(piddir), 1);
}
END_TEST
tcase_add_test(tc_daemon, direxists_with_dir);
tcase_add_test(tc_daemon, mkpath_with_no_dir);
tcase_add_test(tc_daemon, mkpath_with_dir);
- tcase_add_test(tc_daemon, preparedbdir_with_no_dir);
- tcase_add_test(tc_daemon, preparedbdir_with_dir);
+ tcase_add_test(tc_daemon, preparedirs_with_no_dir);
+ tcase_add_test(tc_daemon, preparedirs_with_dir);
suite_add_tcase(s, tc_daemon);
}