3 #define COMPLAINED_READ (1 << 0)
\r
4 #define COMPLAINED_WRITE (1 << 1)
\r
5 #define COMPLAINED_ROTATE (1 << 2)
\r
7 static int dup_handle(HANDLE source_handle, HANDLE *dest_handle_ptr, TCHAR *source_description, TCHAR *dest_description, unsigned long flags) {
\r
8 if (! dest_handle_ptr) return 1;
\r
10 if (! DuplicateHandle(GetCurrentProcess(), source_handle, GetCurrentProcess(), dest_handle_ptr, 0, true, flags)) {
\r
11 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_DUPLICATEHANDLE_FAILED, source_description, dest_description, error_string(GetLastError()), 0);
\r
17 static int dup_handle(HANDLE source_handle, HANDLE *dest_handle_ptr, TCHAR *source_description, TCHAR *dest_description) {
\r
18 return dup_handle(source_handle, dest_handle_ptr, source_description, dest_description, DUPLICATE_SAME_ACCESS);
\r
21 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 rotate_delay, unsigned long *tid_ptr, unsigned long *rotate_online, bool copy_and_truncate) {
\r
24 /* Pipe between application's stdout/stderr and our logging handle. */
\r
25 if (read_handle_ptr && ! *read_handle_ptr) {
\r
26 if (pipe_handle_ptr && ! *pipe_handle_ptr) {
\r
27 if (CreatePipe(read_handle_ptr, pipe_handle_ptr, 0, 0)) {
\r
28 SetHandleInformation(*pipe_handle_ptr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
\r
31 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service_name, path, error_string(GetLastError()));
\r
37 logger_t *logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
\r
39 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("logger"), _T("create_logging_thread()"), 0);
\r
43 ULARGE_INTEGER size;
\r
44 size.LowPart = rotate_bytes_low;
\r
45 size.HighPart = rotate_bytes_high;
\r
47 logger->service_name = service_name;
\r
48 logger->path = path;
\r
49 logger->sharing = sharing;
\r
50 logger->disposition = disposition;
\r
51 logger->flags = flags;
\r
52 logger->read_handle = *read_handle_ptr;
\r
53 logger->write_handle = *write_handle_ptr;
\r
54 logger->size = (__int64) size.QuadPart;
\r
55 logger->tid_ptr = tid_ptr;
\r
56 logger->rotate_online = rotate_online;
\r
57 logger->rotate_delay = rotate_delay;
\r
58 logger->copy_and_truncate = copy_and_truncate;
\r
60 HANDLE thread_handle = CreateThread(NULL, 0, log_and_rotate, (void *) logger, 0, logger->tid_ptr);
\r
61 if (! thread_handle) {
\r
62 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0);
\r
63 HeapFree(GetProcessHeap(), 0, logger);
\r
66 return thread_handle;
\r
69 static inline unsigned long guess_charsize(void *address, unsigned long bufsize) {
\r
70 if (IsTextUnicode(address, bufsize, 0)) return (unsigned long) sizeof(wchar_t);
\r
71 else return (unsigned long) sizeof(char);
\r
74 static inline void write_bom(logger_t *logger, unsigned long *out) {
\r
75 wchar_t bom = L'\ufeff';
\r
76 if (! WriteFile(logger->write_handle, (void *) &bom, sizeof(bom), out, 0)) {
\r
77 log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SOMEBODY_SET_UP_US_THE_BOM, logger->service_name, logger->path, error_string(GetLastError()), 0);
\r
81 /* Get path, share mode, creation disposition and flags for a stream. */
\r
82 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, bool *copy_and_truncate) {
\r
83 TCHAR value[NSSM_STDIO_LENGTH];
\r
86 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s"), prefix) < 0) {
\r
87 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, _T("get_createfile_parameters()"), 0);
\r
90 switch (expand_parameter(key, value, path, PATH_LENGTH, true, false)) {
\r
91 case 0: if (! path[0]) return 0; break; /* OK. */
\r
92 default: return 2; /* Error. */
\r
96 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_SHARING) < 0) {
\r
97 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, _T("get_createfile_parameters()"), 0);
\r
100 switch (get_number(key, value, sharing, false)) {
\r
101 case 0: *sharing = default_sharing; break; /* Missing. */
\r
102 case 1: break; /* Found. */
\r
103 case -2: return 4; /* Error. */
\r
106 /* CreationDisposition. */
\r
107 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
\r
108 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, _T("get_createfile_parameters()"), 0);
\r
111 switch (get_number(key, value, disposition, false)) {
\r
112 case 0: *disposition = default_disposition; break; /* Missing. */
\r
113 case 1: break; /* Found. */
\r
114 case -2: return 6; /* Error. */
\r
118 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_FLAGS) < 0) {
\r
119 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, _T("get_createfile_parameters()"), 0);
\r
122 switch (get_number(key, value, flags, false)) {
\r
123 case 0: *flags = default_flags; break; /* Missing. */
\r
124 case 1: break; /* Found. */
\r
125 case -2: return 8; /* Error. */
\r
128 /* Rotate with CopyFile() and SetEndOfFile(). */
\r
129 if (copy_and_truncate) {
\r
130 unsigned long data;
\r
131 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_COPY_AND_TRUNCATE) < 0) {
\r
132 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_COPY_AND_TRUNCATE, _T("get_createfile_parameters()"), 0);
\r
135 switch (get_number(key, value, &data, false)) {
\r
136 case 0: *copy_and_truncate = false; break; /* Missing. */
\r
137 case 1: /* Found. */
\r
138 if (data) *copy_and_truncate = true;
\r
139 else *copy_and_truncate = false;
\r
141 case -2: return 9; /* Error. */
\r
148 int set_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix, unsigned long number) {
\r
149 TCHAR value[NSSM_STDIO_LENGTH];
\r
151 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
152 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("set_createfile_parameter()"), 0);
\r
156 return set_number(key, value, number);
\r
159 int delete_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix) {
\r
160 TCHAR value[NSSM_STDIO_LENGTH];
\r
162 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
163 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("delete_createfile_parameter()"), 0);
\r
167 if (RegDeleteValue(key, value)) return 0;
\r
171 HANDLE write_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
\r
172 HANDLE ret = CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);
\r
173 if (ret!= INVALID_HANDLE_VALUE) {
\r
174 if (SetFilePointer(ret, 0, 0, FILE_END) != INVALID_SET_FILE_POINTER) SetEndOfFile(ret);
\r
178 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(GetLastError()), 0);
\r
182 static void rotated_filename(TCHAR *path, TCHAR *rotated, unsigned long rotated_len, SYSTEMTIME *st) {
\r
189 TCHAR buffer[PATH_LENGTH];
\r
190 memmove(buffer, path, sizeof(buffer));
\r
191 TCHAR *ext = PathFindExtension(buffer);
\r
192 TCHAR extension[PATH_LENGTH];
\r
193 _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
195 _sntprintf_s(rotated, rotated_len, _TRUNCATE, _T("%s%s"), buffer, extension);
\r
198 void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsigned long delay, unsigned long low, unsigned long high, bool copy_and_truncate) {
\r
199 unsigned long error;
\r
203 GetSystemTime(&st);
\r
205 BY_HANDLE_FILE_INFORMATION info;
\r
207 /* Try to open the file to check if it exists and to get attributes. */
\r
208 HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
\r
209 if (file != INVALID_HANDLE_VALUE) {
\r
210 /* Get file attributes. */
\r
211 if (! GetFileInformationByHandle(file, &info)) {
\r
212 /* Reuse current time for rotation timestamp. */
\r
213 seconds = low = high = 0;
\r
214 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
220 error = GetLastError();
\r
221 if (error == ERROR_FILE_NOT_FOUND) return;
\r
222 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);
\r
223 /* Reuse current time for rotation timestamp. */
\r
224 seconds = low = high = 0;
\r
225 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
228 /* Check file age. */
\r
231 SystemTimeToFileTime(&st, &ft);
\r
234 s.LowPart = ft.dwLowDateTime;
\r
235 s.HighPart = ft.dwHighDateTime;
\r
236 s.QuadPart -= seconds * 10000000LL;
\r
237 ft.dwLowDateTime = s.LowPart;
\r
238 ft.dwHighDateTime = s.HighPart;
\r
239 if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;
\r
242 /* Check file size. */
\r
244 if (info.nFileSizeHigh < high) return;
\r
245 if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;
\r
248 /* Get new filename. */
\r
249 FileTimeToSystemTime(&info.ftLastWriteTime, &st);
\r
251 TCHAR rotated[PATH_LENGTH];
\r
252 rotated_filename(path, rotated, _countof(rotated), &st);
\r
257 if (copy_and_truncate) {
\r
258 function = _T("CopyFile()");
\r
259 if (CopyFile(path, rotated, TRUE)) {
\r
260 file = write_to_file(path, NSSM_STDOUT_SHARING, 0, NSSM_STDOUT_DISPOSITION, NSSM_STDOUT_FLAGS);
\r
262 SetFilePointer(file, 0, 0, FILE_BEGIN);
\r
263 SetEndOfFile(file);
\r
269 function = _T("MoveFile()");
\r
270 if (! MoveFile(path, rotated)) ok = false;
\r
273 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, service_name, path, rotated, 0);
\r
276 error = GetLastError();
\r
278 if (error == ERROR_FILE_NOT_FOUND) return;
\r
279 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, function, rotated, error_string(error), 0);
\r
283 int get_output_handles(nssm_service_t *service, STARTUPINFO *si) {
\r
284 if (! si) return 1;
\r
286 /* Allocate a new console so we get a fresh stdin, stdout and stderr. */
\r
287 alloc_console(service);
\r
290 if (service->stdin_path[0]) {
\r
291 si->hStdInput = CreateFile(service->stdin_path, FILE_READ_DATA, service->stdin_sharing, 0, service->stdin_disposition, service->stdin_flags, 0);
\r
292 if (si->hStdInput == INVALID_HANDLE_VALUE) {
\r
293 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
\r
299 if (service->stdout_path[0]) {
\r
300 if (service->rotate_files) rotate_file(service->name, service->stdout_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high, service->rotate_delay, service->stdout_copy_and_truncate);
\r
301 HANDLE stdout_handle = write_to_file(service->stdout_path, service->stdout_sharing, 0, service->stdout_disposition, service->stdout_flags);
\r
302 if (stdout_handle == INVALID_HANDLE_VALUE) return 4;
\r
304 if (service->rotate_files && service->rotate_stdout_online) {
\r
305 service->stdout_pipe = si->hStdOutput = 0;
\r
306 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->rotate_delay, &service->stdout_tid, &service->rotate_stdout_online, service->stdout_copy_and_truncate);
\r
307 if (! service->stdout_thread) {
\r
308 CloseHandle(service->stdout_pipe);
\r
309 CloseHandle(si->hStdOutput);
\r
312 else service->stdout_thread = 0;
\r
314 if (! service->stdout_thread) {
\r
315 if (dup_handle(stdout_handle, &si->hStdOutput, NSSM_REG_STDOUT, _T("stdout"), DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) return 4;
\r
316 service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
\r
321 if (service->stderr_path[0]) {
\r
322 /* Same as stdout? */
\r
323 if (str_equiv(service->stderr_path, service->stdout_path)) {
\r
324 service->stderr_sharing = service->stdout_sharing;
\r
325 service->stderr_disposition = service->stdout_disposition;
\r
326 service->stderr_flags = service->stdout_flags;
\r
327 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
329 /* Two handles to the same file will create a race. */
\r
330 if (dup_handle(si->hStdOutput, &si->hStdError, _T("stdout"), _T("stderr"))) return 6;
\r
333 if (service->rotate_files) rotate_file(service->name, service->stderr_path, service->rotate_seconds, service->rotate_bytes_low, service->rotate_bytes_high, service->rotate_delay, service->stderr_copy_and_truncate);
\r
334 HANDLE stderr_handle = write_to_file(service->stderr_path, service->stderr_sharing, 0, service->stderr_disposition, service->stderr_flags);
\r
335 if (stderr_handle == INVALID_HANDLE_VALUE) return 7;
\r
337 if (service->rotate_files && service->rotate_stderr_online) {
\r
338 service->stderr_pipe = si->hStdError = 0;
\r
339 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->rotate_delay, &service->stderr_tid, &service->rotate_stderr_online, service->stderr_copy_and_truncate);
\r
340 if (! service->stderr_thread) {
\r
341 CloseHandle(service->stderr_pipe);
\r
342 CloseHandle(si->hStdError);
\r
345 else service->stderr_thread = 0;
\r
347 if (! service->stderr_thread) {
\r
348 if (dup_handle(stderr_handle, &si->hStdError, NSSM_REG_STDERR, _T("stderr"), DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) return 7;
\r
349 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
355 We need to set the startup_info flags to make the new handles
\r
356 inheritable by the new process.
\r
358 si->dwFlags |= STARTF_USESTDHANDLES;
\r
360 if (service->no_console) return 0;
\r
362 /* Redirect other handles. */
\r
363 if (! si->hStdInput) {
\r
364 if (dup_handle(GetStdHandle(STD_INPUT_HANDLE), &si->hStdInput, _T("STD_INPUT_HANDLE"), _T("stdin"))) return 8;
\r
366 if (! si->hStdOutput) {
\r
367 if (dup_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si->hStdOutput, _T("STD_OUTPUT_HANDLE"), _T("stdout"))) return 9;
\r
369 if (! si->hStdError) {
\r
370 if (dup_handle(GetStdHandle(STD_ERROR_HANDLE), &si->hStdError, _T("STD_ERROR_HANDLE"), _T("stderr"))) return 10;
\r
377 void close_output_handles(STARTUPINFO *si) {
\r
378 if (si->hStdInput) CloseHandle(si->hStdInput);
\r
379 if (si->hStdOutput) CloseHandle(si->hStdOutput);
\r
380 if (si->hStdError) CloseHandle(si->hStdError);
\r
384 Try multiple times to read from a file.
\r
385 Returns: 0 on success.
\r
386 1 on non-fatal error.
\r
389 static int try_read(logger_t *logger, void *address, unsigned long bufsize, unsigned long *in, int *complained) {
\r
391 unsigned long error;
\r
392 for (int tries = 0; tries < 5; tries++) {
\r
393 if (ReadFile(logger->read_handle, address, bufsize, in, 0)) return 0;
\r
395 error = GetLastError();
\r
397 /* Other end closed the pipe. */
\r
398 case ERROR_BROKEN_PIPE:
\r
400 goto complain_read;
\r
402 /* Couldn't lock the buffer. */
\r
403 case ERROR_NOT_ENOUGH_QUOTA:
\r
404 Sleep(2000 + tries * 3000);
\r
408 /* Write was cancelled by the other end. */
\r
409 case ERROR_OPERATION_ABORTED:
\r
411 goto complain_read;
\r
419 /* Ignore the error if we've been requested to exit anyway. */
\r
420 if (*logger->rotate_online != NSSM_ROTATE_ONLINE) return ret;
\r
421 if (! (*complained & COMPLAINED_READ)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_READFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
422 *complained |= COMPLAINED_READ;
\r
427 Try multiple times to write to a file.
\r
428 Returns: 0 on success.
\r
429 1 on non-fatal error.
\r
432 static int try_write(logger_t *logger, void *address, unsigned long bufsize, unsigned long *out, int *complained) {
\r
434 unsigned long error;
\r
435 for (int tries = 0; tries < 5; tries++) {
\r
436 if (WriteFile(logger->write_handle, address, bufsize, out, 0)) return 0;
\r
438 error = GetLastError();
\r
439 if (error == ERROR_IO_PENDING) {
\r
440 /* Operation was successful pending flush to disk. */
\r
445 /* Other end closed the pipe. */
\r
446 case ERROR_BROKEN_PIPE:
\r
448 goto complain_write;
\r
450 /* Couldn't lock the buffer. */
\r
451 case ERROR_NOT_ENOUGH_QUOTA:
\r
452 /* Out of disk space. */
\r
453 case ERROR_DISK_FULL:
\r
454 Sleep(2000 + tries * 3000);
\r
459 /* We'll lose this line but try to read and write subsequent ones. */
\r
465 if (! (*complained & COMPLAINED_WRITE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_WRITEFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
466 *complained |= COMPLAINED_WRITE;
\r
470 /* Wrapper to be called in a new thread for logging. */
\r
471 unsigned long WINAPI log_and_rotate(void *arg) {
\r
472 logger_t *logger = (logger_t *) arg;
\r
473 if (! logger) return 1;
\r
476 BY_HANDLE_FILE_INFORMATION info;
\r
478 /* Find initial file size. */
\r
479 if (! GetFileInformationByHandle(logger->write_handle, &info)) logger->size = 0LL;
\r
482 l.HighPart = info.nFileSizeHigh;
\r
483 l.LowPart = info.nFileSizeLow;
\r
489 unsigned long in, out;
\r
490 unsigned long charsize = 0;
\r
491 unsigned long error;
\r
493 int complained = 0;
\r
496 /* Read data from the pipe. */
\r
498 ret = try_read(logger, address, sizeof(buffer), &in, &complained);
\r
500 CloseHandle(logger->read_handle);
\r
501 CloseHandle(logger->write_handle);
\r
502 HeapFree(GetProcessHeap(), 0, logger);
\r
505 else if (ret) continue;
\r
507 if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
\r
508 /* Look for newline. */
\r
510 for (i = 0; i < in; i++) {
\r
511 if (buffer[i] == '\n') {
\r
512 if (! charsize) charsize = guess_charsize(address, in);
\r
515 /* Write up to the newline. */
\r
516 ret = try_write(logger, address, i, &out, &complained);
\r
518 CloseHandle(logger->read_handle);
\r
519 CloseHandle(logger->write_handle);
\r
520 HeapFree(GetProcessHeap(), 0, logger);
\r
523 size += (__int64) out;
\r
526 *logger->rotate_online = NSSM_ROTATE_ONLINE;
\r
527 TCHAR rotated[PATH_LENGTH];
\r
528 rotated_filename(logger->path, rotated, _countof(rotated), 0);
\r
531 Ideally we'd try the rename first then close the handle but
\r
532 MoveFile() will fail if the handle is still open so we must
\r
533 risk losing everything.
\r
535 if (logger->copy_and_truncate) FlushFileBuffers(logger->write_handle);
\r
536 CloseHandle(logger->write_handle);
\r
539 if (logger->copy_and_truncate) {
\r
540 function = _T("CopyFile()");
\r
541 if (CopyFile(logger->path, rotated, TRUE)) {
\r
542 HANDLE file = write_to_file(logger->path, NSSM_STDOUT_SHARING, 0, NSSM_STDOUT_DISPOSITION, NSSM_STDOUT_FLAGS);
\r
543 Sleep(logger->rotate_delay);
\r
544 SetFilePointer(file, 0, 0, FILE_BEGIN);
\r
545 SetEndOfFile(file);
\r
551 function = _T("MoveFile()");
\r
552 if (! MoveFile(logger->path, rotated)) ok = false;
\r
555 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, logger->service_name, logger->path, rotated, 0);
\r
559 error = GetLastError();
\r
560 if (error != ERROR_FILE_NOT_FOUND) {
\r
561 if (! (complained & COMPLAINED_ROTATE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, logger->service_name, logger->path, function, rotated, error_string(error), 0);
\r
562 complained |= COMPLAINED_ROTATE;
\r
563 /* We can at least try to re-open the existing file. */
\r
564 logger->disposition = OPEN_ALWAYS;
\r
569 logger->write_handle = write_to_file(logger->path, logger->sharing, 0, logger->disposition, logger->flags);
\r
570 if (logger->write_handle == INVALID_HANDLE_VALUE) {
\r
571 error = GetLastError();
\r
572 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, logger->path, error_string(error), 0);
\r
573 /* Oh dear. Now we can't log anything further. */
\r
574 CloseHandle(logger->read_handle);
\r
575 CloseHandle(logger->write_handle);
\r
576 HeapFree(GetProcessHeap(), 0, logger);
\r
580 /* Resume writing after the newline. */
\r
581 address = (void *) ((char *) address + i);
\r
588 /* Write a BOM to the new file. */
\r
589 if (! charsize) charsize = guess_charsize(address, in);
\r
590 if (charsize == sizeof(wchar_t)) write_bom(logger, &out);
\r
591 size += (__int64) out;
\r
594 /* Write the data, if any. */
\r
595 if (! in) continue;
\r
597 ret = try_write(logger, address, in, &out, &complained);
\r
598 size += (__int64) out;
\r
600 CloseHandle(logger->read_handle);
\r
601 CloseHandle(logger->write_handle);
\r
602 HeapFree(GetProcessHeap(), 0, logger);
\r
607 CloseHandle(logger->read_handle);
\r
608 CloseHandle(logger->write_handle);
\r
609 HeapFree(GetProcessHeap(), 0, logger);
\r