3 #define COMPLAINED_READ (1 << 0)
\r
4 #define COMPLAINED_WRITE (1 << 1)
\r
5 #define COMPLAINED_ROTATE (1 << 2)
\r
7 static HANDLE create_logging_thread(TCHAR *service_name, TCHAR *path, unsigned long sharing, unsigned long disposition, unsigned long flags, HANDLE *read_handle_ptr, HANDLE *pipe_handle_ptr, HANDLE *write_handle_ptr, unsigned long rotate_bytes_low, unsigned long rotate_bytes_high, unsigned long *tid_ptr, unsigned long *rotate_online) {
\r
10 /* Pipe between application's stdout/stderr and our logging handle. */
\r
11 if (read_handle_ptr && ! *read_handle_ptr) {
\r
12 if (pipe_handle_ptr && ! *pipe_handle_ptr) {
\r
13 if (CreatePipe(read_handle_ptr, pipe_handle_ptr, 0, 0)) {
\r
14 SetHandleInformation(*pipe_handle_ptr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
\r
17 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service_name, path, error_string(GetLastError()));
\r
23 logger_t *logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
\r
25 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("logger"), _T("create_logging_thread()"), 0);
\r
29 ULARGE_INTEGER size;
\r
30 size.LowPart = rotate_bytes_low;
\r
31 size.HighPart = rotate_bytes_high;
\r
33 logger->service_name = service_name;
\r
34 logger->path = path;
\r
35 logger->sharing = sharing;
\r
36 logger->disposition = disposition;
\r
37 logger->flags = flags;
\r
38 logger->read_handle = *read_handle_ptr;
\r
39 logger->write_handle = *write_handle_ptr;
\r
40 logger->size = (__int64) size.QuadPart;
\r
41 logger->tid_ptr = tid_ptr;
\r
42 logger->rotate_online = rotate_online;
\r
44 HANDLE thread_handle = CreateThread(NULL, 0, log_and_rotate, (void *) logger, 0, logger->tid_ptr);
\r
45 if (! thread_handle) {
\r
46 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0);
\r
47 HeapFree(GetProcessHeap(), 0, logger);
\r
50 return thread_handle;
\r
53 static inline unsigned long guess_charsize(void *address, unsigned long bufsize) {
\r
54 if (IsTextUnicode(address, bufsize, 0)) return (unsigned long) sizeof(wchar_t);
\r
55 else return (unsigned long) sizeof(char);
\r
58 static inline void write_bom(logger_t *logger, unsigned long *out) {
\r
59 wchar_t bom = L'\ufeff';
\r
60 if (! WriteFile(logger->write_handle, (void *) &bom, sizeof(bom), out, 0)) {
\r
61 log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SOMEBODY_SET_UP_US_THE_BOM, logger->service_name, logger->path, error_string(GetLastError()), 0);
\r
65 /* Get path, share mode, creation disposition and flags for a stream. */
\r
66 int get_createfile_parameters(HKEY key, TCHAR *prefix, TCHAR *path, unsigned long *sharing, unsigned long default_sharing, unsigned long *disposition, unsigned long default_disposition, unsigned long *flags, unsigned long default_flags) {
\r
67 TCHAR value[NSSM_STDIO_LENGTH];
\r
70 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s"), prefix) < 0) {
\r
71 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, _T("get_createfile_parameters()"), 0);
\r
74 switch (expand_parameter(key, value, path, PATH_LENGTH, true, false)) {
\r
75 case 0: if (! path[0]) return 0; break; /* OK. */
\r
76 default: return 2; /* Error. */
\r
80 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_SHARING) < 0) {
\r
81 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, _T("get_createfile_parameters()"), 0);
\r
84 switch (get_number(key, value, sharing, false)) {
\r
85 case 0: *sharing = default_sharing; break; /* Missing. */
\r
86 case 1: break; /* Found. */
\r
87 case -2: return 4; break; /* Error. */
\r
90 /* CreationDisposition. */
\r
91 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
\r
92 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, _T("get_createfile_parameters()"), 0);
\r
95 switch (get_number(key, value, disposition, false)) {
\r
96 case 0: *disposition = default_disposition; break; /* Missing. */
\r
97 case 1: break; /* Found. */
\r
98 case -2: return 6; break; /* Error. */
\r
102 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_FLAGS) < 0) {
\r
103 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, _T("get_createfile_parameters()"), 0);
\r
106 switch (get_number(key, value, flags, false)) {
\r
107 case 0: *flags = default_flags; break; /* Missing. */
\r
108 case 1: break; /* Found. */
\r
109 case -2: return 8; break; /* Error. */
\r
115 int set_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix, unsigned long number) {
\r
116 TCHAR value[NSSM_STDIO_LENGTH];
\r
118 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
119 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("set_createfile_parameter()"), 0);
\r
123 return set_number(key, value, number);
\r
126 int delete_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix) {
\r
127 TCHAR value[NSSM_STDIO_LENGTH];
\r
129 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
130 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("delete_createfile_parameter()"), 0);
\r
134 if (RegDeleteValue(key, value)) return 0;
\r
138 HANDLE write_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
\r
139 HANDLE ret = CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);
\r
141 if (SetFilePointer(ret, 0, 0, FILE_END) != INVALID_SET_FILE_POINTER) SetEndOfFile(ret);
\r
145 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(GetLastError()), 0);
\r
149 static void rotated_filename(TCHAR *path, TCHAR *rotated, unsigned long rotated_len, SYSTEMTIME *st) {
\r
156 TCHAR buffer[PATH_LENGTH];
\r
157 memmove(buffer, path, sizeof(buffer));
\r
158 TCHAR *ext = PathFindExtension(buffer);
\r
159 TCHAR extension[PATH_LENGTH];
\r
160 _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
162 _sntprintf_s(rotated, rotated_len, _TRUNCATE, _T("%s%s"), buffer, extension);
\r
165 void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsigned long low, unsigned long high) {
\r
166 unsigned long error;
\r
170 GetSystemTime(&st);
\r
172 BY_HANDLE_FILE_INFORMATION info;
\r
174 /* Try to open the file to check if it exists and to get attributes. */
\r
175 HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
\r
177 /* Get file attributes. */
\r
178 if (! GetFileInformationByHandle(file, &info)) {
\r
179 /* Reuse current time for rotation timestamp. */
\r
180 seconds = low = high = 0;
\r
181 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
187 error = GetLastError();
\r
188 if (error == ERROR_FILE_NOT_FOUND) return;
\r
189 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);
\r
190 /* Reuse current time for rotation timestamp. */
\r
191 seconds = low = high = 0;
\r
192 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
195 /* Check file age. */
\r
198 SystemTimeToFileTime(&st, &ft);
\r
201 s.LowPart = ft.dwLowDateTime;
\r
202 s.HighPart = ft.dwHighDateTime;
\r
203 s.QuadPart -= seconds * 10000000LL;
\r
204 ft.dwLowDateTime = s.LowPart;
\r
205 ft.dwHighDateTime = s.HighPart;
\r
206 if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;
\r
209 /* Check file size. */
\r
211 if (info.nFileSizeHigh < high) return;
\r
212 if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;
\r
215 /* Get new filename. */
\r
216 FileTimeToSystemTime(&info.ftLastWriteTime, &st);
\r
218 TCHAR rotated[PATH_LENGTH];
\r
219 rotated_filename(path, rotated, _countof(rotated), &st);
\r
222 if (MoveFile(path, rotated)) {
\r
223 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, service_name, path, rotated, 0);
\r
226 error = GetLastError();
\r
228 if (error == ERROR_FILE_NOT_FOUND) return;
\r
229 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("MoveFile()"), rotated, error_string(error), 0);
\r
233 int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
\r
234 bool redirect = false;
\r
237 if (get_createfile_parameters(key, NSSM_REG_STDIN, service->stdin_path, &service->stdin_sharing, NSSM_STDIN_SHARING, &service->stdin_disposition, NSSM_STDIN_DISPOSITION, &service->stdin_flags, NSSM_STDIN_FLAGS)) {
\r
238 service->stdin_sharing = service->stdin_disposition = service->stdin_flags = 0;
\r
239 ZeroMemory(service->stdin_path, _countof(service->stdin_path) * sizeof(TCHAR));
\r
242 if (si && service->stdin_path[0]) {
\r
243 si->hStdInput = CreateFile(service->stdin_path, FILE_READ_DATA, service->stdin_sharing, 0, service->stdin_disposition, service->stdin_flags, 0);
\r
244 if (! si->hStdInput) {
\r
245 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
\r
253 if (get_createfile_parameters(key, NSSM_REG_STDOUT, service->stdout_path, &service->stdout_sharing, NSSM_STDOUT_SHARING, &service->stdout_disposition, NSSM_STDOUT_DISPOSITION, &service->stdout_flags, NSSM_STDOUT_FLAGS)) {
\r
254 service->stdout_sharing = service->stdout_disposition = service->stdout_flags = 0;
\r
255 ZeroMemory(service->stdout_path, _countof(service->stdout_path) * sizeof(TCHAR));
\r
258 if (si && service->stdout_path[0]) {
\r
259 if (service->rotate_files) rotate_file(service->name, service->stdout_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
260 HANDLE stdout_handle = write_to_file(service->stdout_path, service->stdout_sharing, 0, service->stdout_disposition, service->stdout_flags);
\r
261 if (! stdout_handle) return 4;
\r
263 if (service->rotate_files && service->rotate_stdout_online) {
\r
264 service->stdout_pipe = si->hStdOutput = 0;
\r
265 service->stdout_thread = create_logging_thread(service->name, service->stdout_path, service->stdout_sharing, service->stdout_disposition, service->stdout_flags, &service->stdout_pipe, &si->hStdOutput, &stdout_handle, service->rotate_bytes_low, service->rotate_bytes_high, &service->stdout_tid, &service->rotate_stdout_online);
\r
266 if (! service->stdout_thread) {
\r
267 CloseHandle(service->stdout_pipe);
\r
268 CloseHandle(si->hStdOutput);
\r
271 else service->stdout_thread = 0;
\r
273 if (! service->stdout_thread) {
\r
274 if (! DuplicateHandle(GetCurrentProcess(), stdout_handle, GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
275 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stdout"), error_string(GetLastError()), 0);
\r
278 service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
\r
285 if (get_createfile_parameters(key, NSSM_REG_STDERR, service->stderr_path, &service->stderr_sharing, NSSM_STDERR_SHARING, &service->stderr_disposition, NSSM_STDERR_DISPOSITION, &service->stderr_flags, NSSM_STDERR_FLAGS)) {
\r
286 service->stderr_sharing = service->stderr_disposition = service->stderr_flags = 0;
\r
287 ZeroMemory(service->stderr_path, _countof(service->stderr_path) * sizeof(TCHAR));
\r
290 if (service->stderr_path[0]) {
\r
291 /* Same as stdout? */
\r
292 if (str_equiv(service->stderr_path, service->stdout_path)) {
\r
293 service->stderr_sharing = service->stdout_sharing;
\r
294 service->stderr_disposition = service->stdout_disposition;
\r
295 service->stderr_flags = service->stdout_flags;
\r
296 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
299 /* Two handles to the same file will create a race. */
\r
300 if (! DuplicateHandle(GetCurrentProcess(), si->hStdOutput, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
301 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDOUT, _T("stderr"), error_string(GetLastError()), 0);
\r
307 if (service->rotate_files) rotate_file(service->name, service->stderr_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high);
\r
308 HANDLE stderr_handle = write_to_file(service->stderr_path, service->stderr_sharing, 0, service->stderr_disposition, service->stderr_flags);
\r
309 if (! stderr_handle) return 7;
\r
311 if (service->rotate_files && service->rotate_stderr_online) {
\r
312 service->stderr_pipe = si->hStdError = 0;
\r
313 service->stderr_thread = create_logging_thread(service->name, service->stderr_path, service->stderr_sharing, service->stderr_disposition, service->stderr_flags, &service->stderr_pipe, &si->hStdError, &stderr_handle, service->rotate_bytes_low, service->rotate_bytes_high, &service->stderr_tid, &service->rotate_stderr_online);
\r
314 if (! service->stderr_thread) {
\r
315 CloseHandle(service->stderr_pipe);
\r
316 CloseHandle(si->hStdError);
\r
319 else service->stderr_thread = 0;
\r
321 if (! service->stderr_thread) {
\r
322 if (! DuplicateHandle(GetCurrentProcess(), stderr_handle, GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
\r
323 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, NSSM_REG_STDERR, _T("stderr"), error_string(GetLastError()), 0);
\r
326 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
333 if (! redirect || ! si) return 0;
\r
335 /* Allocate a new console so we get a fresh stdin, stdout and stderr. */
\r
339 /* Set a title like "[NSSM] Jenkins" */
\r
340 TCHAR displayname[SERVICE_NAME_LENGTH];
\r
341 unsigned long len = _countof(displayname);
\r
342 SC_HANDLE services = open_service_manager();
\r
344 if (! GetServiceDisplayName(services, service->name, displayname, &len)) _sntprintf_s(displayname, _countof(displayname), _TRUNCATE, _T("%s"), service->name);
\r
345 CloseServiceHandle(services);
\r
348 TCHAR title[65535];
\r
349 _sntprintf_s(title, _countof(title), _TRUNCATE, _T("[%s] %s\n"), NSSM, displayname);
\r
350 SetConsoleTitle(title);
\r
353 We need to set the startup_info flags to make the new handles
\r
354 inheritable by the new process.
\r
356 if (si) si->dwFlags |= STARTF_USESTDHANDLES;
\r
358 /* Redirect other handles. */
\r
359 if (! si->hStdInput) {
\r
360 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE), GetCurrentProcess(), &si->hStdInput, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
361 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_INPUT_HANDLE"), _T("stdin"), error_string(GetLastError()), 0);
\r
365 if (! si->hStdOutput) {
\r
366 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE), GetCurrentProcess(), &si->hStdOutput, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
367 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_OUTPUT_HANDLE"), _T("stdout"), error_string(GetLastError()), 0);
\r
371 if (! si->hStdError) {
\r
372 if (! DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE), GetCurrentProcess(), &si->hStdError, 0, true, DUPLICATE_SAME_ACCESS)) {
\r
373 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, _T("STD_ERROR_HANDLE"), _T("stderr"), error_string(GetLastError()), 0);
\r
381 void close_output_handles(STARTUPINFO *si) {
\r
382 if (si->hStdInput) CloseHandle(si->hStdInput);
\r
383 if (si->hStdOutput) CloseHandle(si->hStdOutput);
\r
384 if (si->hStdError) CloseHandle(si->hStdError);
\r
388 Try multiple times to read from a file.
\r
389 Returns: 0 on success.
\r
390 1 on non-fatal error.
\r
393 static int try_read(logger_t *logger, void *address, unsigned long bufsize, unsigned long *in, int *complained) {
\r
395 unsigned long error;
\r
396 for (int tries = 0; tries < 5; tries++) {
\r
397 if (ReadFile(logger->read_handle, address, bufsize, in, 0)) return 0;
\r
399 error = GetLastError();
\r
401 /* Other end closed the pipe. */
\r
402 case ERROR_BROKEN_PIPE:
\r
404 goto complain_read;
\r
406 /* Couldn't lock the buffer. */
\r
407 case ERROR_NOT_ENOUGH_QUOTA:
\r
408 Sleep(2000 + tries * 3000);
\r
412 /* Write was cancelled by the other end. */
\r
413 case ERROR_OPERATION_ABORTED:
\r
415 goto complain_read;
\r
423 /* Ignore the error if we've been requested to exit anyway. */
\r
424 if (*logger->rotate_online != NSSM_ROTATE_ONLINE) return ret;
\r
425 if (! (*complained & COMPLAINED_READ)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_READFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
426 *complained |= COMPLAINED_READ;
\r
431 Try multiple times to write to a file.
\r
432 Returns: 0 on success.
\r
433 1 on non-fatal error.
\r
436 static int try_write(logger_t *logger, void *address, unsigned long bufsize, unsigned long *out, int *complained) {
\r
438 unsigned long error;
\r
439 for (int tries = 0; tries < 5; tries++) {
\r
440 if (WriteFile(logger->write_handle, address, bufsize, out, 0)) return 0;
\r
442 error = GetLastError();
\r
443 if (error == ERROR_IO_PENDING) {
\r
444 /* Operation was successful pending flush to disk. */
\r
449 /* Other end closed the pipe. */
\r
450 case ERROR_BROKEN_PIPE:
\r
452 goto complain_write;
\r
454 /* Couldn't lock the buffer. */
\r
455 case ERROR_NOT_ENOUGH_QUOTA:
\r
456 /* Out of disk space. */
\r
457 case ERROR_DISK_FULL:
\r
458 Sleep(2000 + tries * 3000);
\r
463 /* We'll lose this line but try to read and write subsequent ones. */
\r
469 if (! (*complained & COMPLAINED_WRITE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_WRITEFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
470 *complained |= COMPLAINED_WRITE;
\r
474 /* Wrapper to be called in a new thread for logging. */
\r
475 unsigned long WINAPI log_and_rotate(void *arg) {
\r
476 logger_t *logger = (logger_t *) arg;
\r
477 if (! logger) return 1;
\r
480 BY_HANDLE_FILE_INFORMATION info;
\r
482 /* Find initial file size. */
\r
483 if (! GetFileInformationByHandle(logger->write_handle, &info)) logger->size = 0LL;
\r
486 l.HighPart = info.nFileSizeHigh;
\r
487 l.LowPart = info.nFileSizeLow;
\r
493 unsigned long in, out;
\r
494 unsigned long charsize = 0;
\r
495 unsigned long error;
\r
497 int complained = 0;
\r
500 /* Read data from the pipe. */
\r
502 ret = try_read(logger, address, sizeof(buffer), &in, &complained);
\r
504 CloseHandle(logger->read_handle);
\r
505 CloseHandle(logger->write_handle);
\r
506 HeapFree(GetProcessHeap(), 0, logger);
\r
509 else if (ret) continue;
\r
511 if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
\r
512 /* Look for newline. */
\r
514 for (i = 0; i < in; i++) {
\r
515 if (buffer[i] == '\n') {
\r
516 if (! charsize) charsize = guess_charsize(address, in);
\r
519 /* Write up to the newline. */
\r
520 ret = try_write(logger, address, i, &out, &complained);
\r
522 HeapFree(GetProcessHeap(), 0, logger);
\r
523 CloseHandle(logger->read_handle);
\r
524 CloseHandle(logger->write_handle);
\r
527 size += (__int64) out;
\r
530 *logger->rotate_online = NSSM_ROTATE_ONLINE;
\r
531 TCHAR rotated[PATH_LENGTH];
\r
532 rotated_filename(logger->path, rotated, _countof(rotated), 0);
\r
535 Ideally we'd try the rename first then close the handle but
\r
536 MoveFile() will fail if the handle is still open so we must
\r
537 risk losing everything.
\r
539 CloseHandle(logger->write_handle);
\r
540 if (MoveFile(logger->path, rotated)) {
\r
541 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, logger->service_name, logger->path, rotated, 0);
\r
545 error = GetLastError();
\r
546 if (error != ERROR_FILE_NOT_FOUND) {
\r
547 if (! (complained & COMPLAINED_ROTATE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, logger->service_name, logger->path, _T("MoveFile()"), rotated, error_string(error), 0);
\r
548 complained |= COMPLAINED_ROTATE;
\r
549 /* We can at least try to re-open the existing file. */
\r
550 logger->disposition = OPEN_ALWAYS;
\r
555 logger->write_handle = write_to_file(logger->path, logger->sharing, 0, logger->disposition, logger->flags);
\r
556 if (! logger->write_handle) {
\r
557 error = GetLastError();
\r
558 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, logger->path, error_string(error), 0);
\r
559 /* Oh dear. Now we can't log anything further. */
\r
560 HeapFree(GetProcessHeap(), 0, logger);
\r
561 CloseHandle(logger->read_handle);
\r
562 CloseHandle(logger->write_handle);
\r
566 /* Resume writing after the newline. */
\r
567 address = (void *) ((char *) address + i);
\r
574 /* Write a BOM to the new file. */
\r
575 if (! charsize) charsize = guess_charsize(address, in);
\r
576 if (charsize == sizeof(wchar_t)) write_bom(logger, &out);
\r
577 size += (__int64) out;
\r
580 /* Write the data, if any. */
\r
581 if (! in) continue;
\r
583 ret = try_write(logger, address, in, &out, &complained);
\r
584 size += (__int64) out;
\r
586 HeapFree(GetProcessHeap(), 0, logger);
\r
587 CloseHandle(logger->read_handle);
\r
588 CloseHandle(logger->write_handle);
\r
593 HeapFree(GetProcessHeap(), 0, logger);
\r
594 CloseHandle(logger->read_handle);
\r
595 CloseHandle(logger->write_handle);
\r