Rotate output files.
authorIain Patterson <me@iain.cx>
Sat, 21 Dec 2013 12:00:53 +0000 (12:00 +0000)
committerIain Patterson <me@iain.cx>
Sat, 21 Dec 2013 13:44:41 +0000 (13:44 +0000)
The files specified by AppStdout and AppStderr can now be rotated prior
to launching the application.  An existing file will be renamed with a
new suffix based on its last write time, to millisecond precision.

Rotation is controlled independently of the CreateFile() arguments used
when opening the files for writing.  It is possible to configure
rotation regardless of whether existing files would be appended or
replaced.

Four new REG_DWORD entries control how rotation happens.

If AppRotateFiles is 0 or missing, rotation is disabled.

If AppRotateSeconds is non-zero, a file will not be rotated if its last
write time is less than the given number of seconds in the past.

If AppRotateBytes is non-zero, a file will not be rotated if it is
smaller than the given number of bytes.

64-bit file sizes can be handled by specifying a high order part in
AppRotateBytesHigh.

Thanks Doug Watson.

ChangeLog.txt
README.txt
gui.cpp
io.cpp
io.h
messages.mc
nssm.rc
registry.cpp
registry.h
resource.h
service.h

index e50c841..b26ab1b 100644 (file)
@@ -1,3 +1,11 @@
+Changes since 2.21
+-----------------
+  * NSSM can now optionally rotate existing files when
+    redirecting I/O.
+
+  * Unqualified path names are now relative to the
+    application startup directory when redirecting I/O.
+
 Changes since 2.20
 -----------------
   * Services installed from the GUI no longer have incorrect
index 3dacf18..366e6f3 100644 (file)
@@ -53,6 +53,8 @@ Since version 2.19, NSSM can add to the service's environment by setting
 AppEnvironmentExtra in place of or in addition to the srvany-compatible\r
 AppEnvironment.\r
 \r
+Since version 2.22, NSSM can rotate existing output files when redirecting I/O.\r
+\r
 \r
 Usage\r
 -----\r
@@ -234,6 +236,32 @@ work.  Remember, however, that the path must be accessible to the user
 running the service.\r
 \r
 \r
+File rotation\r
+-------------\r
+When using I/O redirection, NSSM can rotate existing output files prior to\r
+opening stdout and/or stderr.  An existing file will be renamed with a\r
+suffix based on the file's last write time, to millisecond precision.  For\r
+example, the file nssm.log might be rotated to nssm-20131221T113939.457.log.\r
+\r
+NSSM will look in the registry under\r
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters for REG_DWORD\r
+entries which control how rotation happens.\r
+\r
+If AppRotateFiles is missing or set to 0, rotation is disabled.  Any non-zero\r
+value enables rotation.\r
+\r
+If AppRotateSeconds is non-zero, a file will not be rotated if its last write\r
+time is less than the given number of seconds in the past.\r
+\r
+If AppRotateBytes is non-zero, a file will not be rotated if it is smaller\r
+than the given number of bytes.  64-bit file sizes can be handled by setting\r
+a non-zero value of AppRotateBytesHigh.\r
+\r
+Rotation is independent of the CreateFile() parameters used to open the files.\r
+They will be rotated regardless of whether NSSM would otherwise have appended\r
+or replaced them.\r
+\r
+\r
 Environment variables\r
 ---------------------\r
 NSSM can replace or append to the managed application's environment.  Two\r
@@ -328,6 +356,7 @@ Thanks to Brian Baxter for suggesting how to escape quotes from the command prom
 Thanks to Russ Holmann for suggesting that the shutdown timeout be configurable.\r
 Thanks to Paul Spause for spotting a bug with default registry entries.\r
 Thanks to BUGHUNTER for spotting more GUI bugs.\r
+Thanks to Doug Watson for suggesting file rotation.\r
 \r
 Licence\r
 -------\r
diff --git a/gui.cpp b/gui.cpp
index 67458af..1459d97 100644 (file)
--- a/gui.cpp
+++ b/gui.cpp
@@ -1,6 +1,6 @@
 #include "nssm.h"\r
 \r
-static enum { NSSM_TAB_APPLICATION, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
+static enum { NSSM_TAB_APPLICATION, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
 static HWND tablist[NSSM_NUM_TABS];\r
 static int selected_tab;\r
 \r
@@ -135,12 +135,24 @@ int install(HWND window) {
     check_io(_T("stdin"), service->stdin_path, sizeof(service->stdin_path), IDC_STDIN);\r
     check_io(_T("stdout"), service->stdout_path, sizeof(service->stdout_path), IDC_STDOUT);\r
     check_io(_T("stderr"), service->stderr_path, sizeof(service->stderr_path), IDC_STDERR);\r
+\r
     /* Override stdout and/or stderr. */\r
-    if (SendDlgItemMessage(tablist[NSSM_TAB_IO], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+    if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
       if (service->stdout_path[0]) service->stdout_disposition = CREATE_ALWAYS;\r
       if (service->stderr_path[0]) service->stderr_disposition = CREATE_ALWAYS;\r
     }\r
 \r
+    /* Get rotation stuff. */\r
+    if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+      service->rotate_files = true;\r
+    }\r
+    if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS_ENABLED, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+      check_method_timeout(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, &service->rotate_seconds);\r
+    }\r
+    if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW_ENABLED, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+      check_method_timeout(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
+    }\r
+\r
     /* Get environment. */\r
     unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);\r
     if (envlen) {\r
@@ -367,6 +379,7 @@ INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {
     case WM_COMMAND:\r
       HWND dlg;\r
       TCHAR buffer[MAX_PATH];\r
+      unsigned long state;\r
 \r
       switch (LOWORD(w)) {\r
         /* Browse for application. */\r
@@ -416,6 +429,17 @@ INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {
           GetDlgItemText(tab, IDC_STDERR, buffer, sizeof(buffer));\r
           browse(dlg, buffer, 0, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
           break;\r
+\r
+        /* Rotation. */\r
+        case IDC_ROTATE:\r
+        case IDC_ROTATE_SECONDS_ENABLED:\r
+        case IDC_ROTATE_BYTES_LOW_ENABLED:\r
+          if (SendDlgItemMessage(tab, LOWORD(w), BM_GETCHECK, 0, 0) & BST_CHECKED) state = BST_CHECKED;\r
+          else state = BST_UNCHECKED;\r
+          SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_SETCHECK, state, 0);\r
+          SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS_ENABLED, BM_SETCHECK, state, 0);\r
+          SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW_ENABLED, BM_SETCHECK, state, 0);\r
+          break;\r
       }\r
       return 1;\r
   }\r
@@ -486,6 +510,17 @@ INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       tablist[NSSM_TAB_IO] = CreateDialog(0, MAKEINTRESOURCE(IDD_IO), window, tab_dlg);\r
       ShowWindow(tablist[NSSM_TAB_IO], SW_HIDE);\r
 \r
+      /* Rotation tab. */\r
+      tab.pszText = message_string(NSSM_GUI_TAB_ROTATION);\r
+      tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
+      SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_ROTATION, (LPARAM) &tab);\r
+      tablist[NSSM_TAB_ROTATION] = CreateDialog(0, MAKEINTRESOURCE(IDD_ROTATION), window, tab_dlg);\r
+      ShowWindow(tablist[NSSM_TAB_ROTATION], SW_HIDE);\r
+\r
+      /* Set defaults. */\r
+      SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, 0, 0);\r
+      SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, 0, 0);\r
+\r
       /* Environment tab. */\r
       tab.pszText = message_string(NSSM_GUI_TAB_ENVIRONMENT);\r
       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
diff --git a/io.cpp b/io.cpp
index 5331188..30deb72 100644 (file)
--- a/io.cpp
+++ b/io.cpp
@@ -81,7 +81,77 @@ HANDLE append_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *a
   return CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);\r
 }\r
 \r
-int get_output_handles(HKEY key, STARTUPINFO *si) {\r
+void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsigned long low, unsigned long high) {\r
+  unsigned long error;\r
+\r
+  /* Now. */\r
+  SYSTEMTIME st;\r
+  GetSystemTime(&st);\r
+\r
+  BY_HANDLE_FILE_INFORMATION info;\r
+\r
+  /* Try to open the file to check if it exists and to get attributes. */\r
+  HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);\r
+  if (file) {\r
+    /* Get file attributes. */\r
+    if (! GetFileInformationByHandle(file, &info)) {\r
+      /* Reuse current time for rotation timestamp. */\r
+      seconds = low = high = 0;\r
+      SystemTimeToFileTime(&st, &info.ftLastWriteTime);\r
+    }\r
+\r
+    CloseHandle(file);\r
+  }\r
+  else {\r
+    error = GetLastError();\r
+    if (error == ERROR_FILE_NOT_FOUND) return;\r
+    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);\r
+    /* Reuse current time for rotation timestamp. */\r
+    seconds = low = high = 0;\r
+    SystemTimeToFileTime(&st, &info.ftLastWriteTime);\r
+  }\r
+\r
+  /* Check file age. */\r
+  if (seconds) {\r
+    FILETIME ft;\r
+    SystemTimeToFileTime(&st, &ft);\r
+\r
+    ULARGE_INTEGER s;\r
+    s.LowPart = ft.dwLowDateTime;\r
+    s.HighPart = ft.dwHighDateTime;\r
+    s.QuadPart -= seconds * 10000000LL;\r
+    ft.dwLowDateTime = s.LowPart;\r
+    ft.dwHighDateTime = s.HighPart;\r
+    if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;\r
+  }\r
+\r
+  /* Check file size. */\r
+  if (low || high) {\r
+    if (info.nFileSizeHigh < high) return;\r
+    if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;\r
+  }\r
+\r
+  /* Get new filename. */\r
+  FileTimeToSystemTime(&info.ftLastWriteTime, &st);\r
+\r
+  TCHAR buffer[MAX_PATH];\r
+  memmove(buffer, path, sizeof(buffer));\r
+  TCHAR *ext = PathFindExtension(buffer);\r
+  TCHAR extension[MAX_PATH];\r
+  _sntprintf_s(extension, _countof(extension), _TRUNCATE, _T("-%04u%02u%02uT%02u%02u%02u.%03u%s"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, ext);\r
+  *ext = _T('\0');\r
+  TCHAR rotated[MAX_PATH];\r
+  _sntprintf_s(rotated, _countof(rotated), _TRUNCATE, _T("%s%s"), buffer, extension);\r
+\r
+  /* Rotate. */\r
+  if (MoveFile(path, rotated)) return;\r
+  error = GetLastError();\r
+\r
+  log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("MoveFile()"), rotated, error_string(error), 0);\r
+  return;\r
+}\r
+\r
+int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {\r
   TCHAR path[MAX_PATH];\r
   TCHAR stdout_path[MAX_PATH];\r
   unsigned long sharing, disposition, flags;\r
@@ -112,6 +182,7 @@ int get_output_handles(HKEY key, STARTUPINFO *si) {
       return 4;\r
     }\r
 \r
+    if (service->rotate_files) rotate_file(service->name, path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);\r
     si->hStdOutput = append_to_file(path, sharing, &attributes, disposition, flags);\r
     if (! si->hStdOutput) return 5;\r
     set_flags = true;\r
@@ -130,6 +201,7 @@ int get_output_handles(HKEY key, STARTUPINFO *si) {
       }\r
     }\r
     else {\r
+      if (service->rotate_files) rotate_file(service->name, path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);\r
       si->hStdError = append_to_file(path, sharing, &attributes, disposition, flags);\r
       if (! si->hStdError) {\r
         log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(GetLastError()));\r
diff --git a/io.h b/io.h
index 5b9e8ca..41cb976 100644 (file)
--- a/io.h
+++ b/io.h
@@ -14,7 +14,8 @@
 int get_createfile_parameters(HKEY, TCHAR *, TCHAR *, unsigned long *, unsigned long, unsigned long *, unsigned long, unsigned long *, unsigned long);\r
 int set_createfile_parameter(HKEY, TCHAR *, TCHAR *, unsigned long);\r
 HANDLE append_to_file(TCHAR *, unsigned long, SECURITY_ATTRIBUTES *, unsigned long, unsigned long);\r
-int get_output_handles(HKEY, STARTUPINFO *);\r
+void rotate_file(TCHAR *, TCHAR *, unsigned long, unsigned long, unsigned long);\r
+int get_output_handles(nssm_service_t *, HKEY, STARTUPINFO *);\r
 void close_output_handles(STARTUPINFO *);\r
 \r
 #endif\r
index 150d6be..62fb9cd 100644 (file)
@@ -510,6 +510,19 @@ Language = Italian
 I/O%0
 .
 
+MessageId = +1
+SymbolicName = NSSM_GUI_TAB_ROTATION
+Severity = Informational
+Language = English
+File rotation%0
+.
+Language = French
+File rotation%0
+.
+Language = Italian
+File rotation%0
+.
+
 MessageId = +1
 SymbolicName = NSSM_GUI_TAB_ENVIRONMENT
 Severity = Informational
@@ -1546,3 +1559,22 @@ SetEnvironmentVariable(%1=%2) a 
 Language = Italian
 Chiamata a SetEnvironmentVariable(%1=%2) fallita:
 .
+
+MessageId = +1
+SymbolicName = NSSM_EVENT_ROTATE_FILE_FAILED
+Severity = Error
+Language = English
+Failed to rotate output file %2 for service %1.
+%3 failed for file %4:
+%5
+.
+Language = French
+Failed to rotate output file %2 for service %1.
+%3 failed for file %4:
+%5
+.
+Language = Italian
+Failed to rotate output file %2 for service %1.
+%3 failed for file %4:
+%5
+.
diff --git a/nssm.rc b/nssm.rc
index 9596674..3b8667a 100644 (file)
--- a/nssm.rc
+++ b/nssm.rc
@@ -154,7 +154,22 @@ FONT 8, "MS Sans Serif"
     LTEXT           "Error (stderr):", IDC_STATIC, 13, 50, 53, 8, SS_LEFT\r
     EDITTEXT        IDC_STDERR, 70, 48, 167, 12, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
     DEFPUSHBUTTON   "...", IDC_BROWSE_STDERR, 239, 47, 15, 14\r
-    AUTOCHECKBOX    "Replace files", IDC_TRUNCATE, 13, 60, 74, 8\r
+}\r
+\r
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
+IDD_ROTATION DIALOG 9, 20, 261, 75\r
+STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
+FONT 8, "MS Sans Serif"\r
+{\r
+    GROUPBOX        "File rotation", IDC_STATIC, 7, 7, 251, 68\r
+    AUTOCHECKBOX    "Replace existing Output and/or Error files", IDC_TRUNCATE, 13, 18, 145, 8\r
+    AUTOCHECKBOX    "Rotate files", IDC_ROTATE, 13, 32, 51, 8\r
+    AUTOCHECKBOX    "Restrict rotation to files older than", IDC_ROTATE_SECONDS_ENABLED, 13, 46, 121, 8\r
+    EDITTEXT        IDC_ROTATE_SECONDS, 140, 44, 29, 12, ES_AUTOHSCROLL | ES_NUMBER\r
+    LTEXT           "s", IDC_STATIC, 171, 46, 8, 8, SS_LEFT\r
+    AUTOCHECKBOX    "Restrict rotation to files bigger than", IDC_ROTATE_BYTES_LOW_ENABLED, 13, 60, 125, 8\r
+    EDITTEXT        IDC_ROTATE_BYTES_LOW, 140, 58, 49, 12, ES_AUTOHSCROLL | ES_NUMBER\r
+    LTEXT           "kB", IDC_STATIC, 191, 60, 8, 8, SS_LEFT\r
 }\r
 \r
 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
index e192529..048c07d 100644 (file)
@@ -86,6 +86,10 @@ int create_parameters(nssm_service_t *service) {
     if (service->stderr_disposition != NSSM_STDERR_DISPOSITION) set_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_DISPOSITION, service->stderr_disposition);\r
     if (service->stderr_flags != NSSM_STDERR_FLAGS) set_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_FLAGS, service->stderr_flags);\r
   }\r
+  if (service->rotate_files) set_number(key, NSSM_REG_ROTATE, 1);\r
+  if (service->rotate_seconds) set_number(key, NSSM_REG_ROTATE_SECONDS, service->rotate_seconds);\r
+  if (service->rotate_bytes_low) set_number(key, NSSM_REG_ROTATE_BYTES_LOW, service->rotate_bytes_low);\r
+  if (service->rotate_bytes_high) set_number(key, NSSM_REG_ROTATE_BYTES_HIGH, service->rotate_bytes_high);\r
 \r
   /* Environment */\r
   if (service->env) {\r
@@ -387,13 +391,24 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
     }\r
   }\r
 \r
+  /* Try to get file rotation settings - may fail. */\r
+  unsigned long rotate_files;\r
+  if (get_number(key, NSSM_REG_ROTATE, &rotate_files, false) == 1) {\r
+    if (rotate_files) service->rotate_files = true;\r
+    else service->rotate_files = false;\r
+  }\r
+  else service->rotate_files = false;\r
+  if (get_number(key, NSSM_REG_ROTATE_SECONDS, &service->rotate_seconds, false) != 1) service->rotate_seconds = 0;\r
+  if (get_number(key, NSSM_REG_ROTATE_BYTES_LOW, &service->rotate_bytes_low, false) != 1) service->rotate_bytes_low = 0;\r
+  if (get_number(key, NSSM_REG_ROTATE_BYTES_HIGH, &service->rotate_bytes_high, false) != 1) service->rotate_bytes_high = 0;\r
+\r
   /* Change to startup directory in case stdout/stderr are relative paths. */\r
   TCHAR cwd[MAX_PATH];\r
   GetCurrentDirectory(_countof(cwd), cwd);\r
   SetCurrentDirectory(service->dir);\r
 \r
   /* Try to get stdout and stderr */\r
-  if (get_output_handles(key, si)) {\r
+  if (get_output_handles(service, key, si)) {\r
     log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_OUTPUT_HANDLES_FAILED, service->name, 0);\r
     RegCloseKey(key);\r
     SetCurrentDirectory(cwd);\r
index ffdf3d6..600c188 100644 (file)
 #define NSSM_REG_STDIO_SHARING _T("ShareMode")\r
 #define NSSM_REG_STDIO_DISPOSITION _T("CreationDisposition")\r
 #define NSSM_REG_STDIO_FLAGS _T("FlagsAndAttributes")\r
+#define NSSM_REG_ROTATE _T("AppRotateFiles")\r
+#define NSSM_REG_ROTATE_SECONDS _T("AppRotateSeconds")\r
+#define NSSM_REG_ROTATE_BYTES_LOW _T("AppRotateBytes")\r
+#define NSSM_REG_ROTATE_BYTES_HIGH _T("AppRotateBytesHigh")\r
 #define NSSM_STDIO_LENGTH 29\r
 \r
 int create_messages();\r
index d6f2792..ec82a78 100644 (file)
@@ -8,9 +8,10 @@
 #define IDD_REMOVE            103\r
 #define IDD_APPLICATION            104\r
 #define IDD_IO            105\r
-#define IDD_APPEXIT            106\r
-#define IDD_SHUTDOWN            107\r
-#define IDD_ENVIRONMENT            108\r
+#define IDD_ROTATION        106\r
+#define IDD_APPEXIT            107\r
+#define IDD_SHUTDOWN            108\r
+#define IDD_ENVIRONMENT            109\r
 #define IDC_PATH                        1000\r
 #define IDC_TAB1                        1001\r
 #define IDC_CANCEL                      1002\r
 #define IDC_ENVIRONMENT                 1025\r
 #define IDC_ENVIRONMENT_REPLACE         1026\r
 #define IDC_TRUNCATE                    1027\r
+#define IDC_ROTATE                      1028\r
+#define IDC_ROTATE_SECONDS_ENABLED      1029\r
+#define IDC_ROTATE_SECONDS              1030\r
+#define IDC_ROTATE_BYTES_LOW_ENABLED    1031\r
+#define IDC_ROTATE_BYTES_LOW            1032\r
 \r
 // Next default values for new objects\r
 // \r
 #ifdef APSTUDIO_INVOKED\r
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
-#define _APS_NEXT_RESOURCE_VALUE        109\r
+#define _APS_NEXT_RESOURCE_VALUE        110\r
 #define _APS_NEXT_COMMAND_VALUE         40001\r
-#define _APS_NEXT_CONTROL_VALUE         1028\r
+#define _APS_NEXT_CONTROL_VALUE         1033\r
 #define _APS_NEXT_SYMED_VALUE           101\r
 #endif\r
 #endif\r
index c9824d4..04327c3 100644 (file)
--- a/service.h
+++ b/service.h
@@ -37,6 +37,10 @@ typedef struct {
   unsigned long stderr_sharing;\r
   unsigned long stderr_disposition;\r
   unsigned long stderr_flags;\r
+  bool rotate_files;\r
+  unsigned long rotate_seconds;\r
+  unsigned long rotate_bytes_low;\r
+  unsigned long rotate_bytes_high;\r
   unsigned long default_exit_action;\r
   unsigned long throttle_delay;\r
   unsigned long stop_method;\r