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
22 read_handle: read from application
\r
23 pipe_handle: stdout of application
\r
24 write_handle: to file
\r
26 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
29 /* Pipe between application's stdout/stderr and our logging handle. */
\r
30 if (read_handle_ptr && ! *read_handle_ptr) {
\r
31 if (pipe_handle_ptr && ! *pipe_handle_ptr) {
\r
32 if (CreatePipe(read_handle_ptr, pipe_handle_ptr, 0, 0)) {
\r
33 SetHandleInformation(*pipe_handle_ptr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
\r
36 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPIPE_FAILED, service_name, path, error_string(GetLastError()));
\r
42 logger_t *logger = (logger_t *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(logger_t));
\r
44 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("logger"), _T("create_logging_thread()"), 0);
\r
48 ULARGE_INTEGER size;
\r
49 size.LowPart = rotate_bytes_low;
\r
50 size.HighPart = rotate_bytes_high;
\r
52 logger->service_name = service_name;
\r
53 logger->path = path;
\r
54 logger->sharing = sharing;
\r
55 logger->disposition = disposition;
\r
56 logger->flags = flags;
\r
57 logger->read_handle = *read_handle_ptr;
\r
58 logger->write_handle = *write_handle_ptr;
\r
59 logger->size = (__int64) size.QuadPart;
\r
60 logger->tid_ptr = tid_ptr;
\r
61 logger->rotate_online = rotate_online;
\r
62 logger->rotate_delay = rotate_delay;
\r
63 logger->copy_and_truncate = copy_and_truncate;
\r
65 HANDLE thread_handle = CreateThread(NULL, 0, log_and_rotate, (void *) logger, 0, logger->tid_ptr);
\r
66 if (! thread_handle) {
\r
67 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATETHREAD_FAILED, error_string(GetLastError()), 0);
\r
68 HeapFree(GetProcessHeap(), 0, logger);
\r
71 return thread_handle;
\r
74 static inline unsigned long guess_charsize(void *address, unsigned long bufsize) {
\r
75 if (IsTextUnicode(address, bufsize, 0)) return (unsigned long) sizeof(wchar_t);
\r
76 else return (unsigned long) sizeof(char);
\r
79 static inline void write_bom(logger_t *logger, unsigned long *out) {
\r
80 wchar_t bom = L'\ufeff';
\r
81 if (! WriteFile(logger->write_handle, (void *) &bom, sizeof(bom), out, 0)) {
\r
82 log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SOMEBODY_SET_UP_US_THE_BOM, logger->service_name, logger->path, error_string(GetLastError()), 0);
\r
86 /* Get path, share mode, creation disposition and flags for a stream. */
\r
87 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
88 TCHAR value[NSSM_STDIO_LENGTH];
\r
91 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s"), prefix) < 0) {
\r
92 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, prefix, _T("get_createfile_parameters()"), 0);
\r
95 switch (expand_parameter(key, value, path, PATH_LENGTH, true, false)) {
\r
96 case 0: if (! path[0]) return 0; break; /* OK. */
\r
97 default: return 2; /* Error. */
\r
101 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_SHARING) < 0) {
\r
102 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_SHARING, _T("get_createfile_parameters()"), 0);
\r
105 switch (get_number(key, value, sharing, false)) {
\r
106 case 0: *sharing = default_sharing; break; /* Missing. */
\r
107 case 1: break; /* Found. */
\r
108 case -2: return 4; /* Error. */
\r
111 /* CreationDisposition. */
\r
112 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_DISPOSITION) < 0) {
\r
113 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_DISPOSITION, _T("get_createfile_parameters()"), 0);
\r
116 switch (get_number(key, value, disposition, false)) {
\r
117 case 0: *disposition = default_disposition; break; /* Missing. */
\r
118 case 1: break; /* Found. */
\r
119 case -2: return 6; /* Error. */
\r
123 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_FLAGS) < 0) {
\r
124 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_FLAGS, _T("get_createfile_parameters()"), 0);
\r
127 switch (get_number(key, value, flags, false)) {
\r
128 case 0: *flags = default_flags; break; /* Missing. */
\r
129 case 1: break; /* Found. */
\r
130 case -2: return 8; /* Error. */
\r
133 /* Rotate with CopyFile() and SetEndOfFile(). */
\r
134 if (copy_and_truncate) {
\r
135 unsigned long data;
\r
136 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, NSSM_REG_STDIO_COPY_AND_TRUNCATE) < 0) {
\r
137 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, NSSM_REG_STDIO_COPY_AND_TRUNCATE, _T("get_createfile_parameters()"), 0);
\r
140 switch (get_number(key, value, &data, false)) {
\r
141 case 0: *copy_and_truncate = false; break; /* Missing. */
\r
142 case 1: /* Found. */
\r
143 if (data) *copy_and_truncate = true;
\r
144 else *copy_and_truncate = false;
\r
146 case -2: return 9; /* Error. */
\r
153 int set_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix, unsigned long number) {
\r
154 TCHAR value[NSSM_STDIO_LENGTH];
\r
156 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
157 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("set_createfile_parameter()"), 0);
\r
161 return set_number(key, value, number);
\r
164 int delete_createfile_parameter(HKEY key, TCHAR *prefix, TCHAR *suffix) {
\r
165 TCHAR value[NSSM_STDIO_LENGTH];
\r
167 if (_sntprintf_s(value, _countof(value), _TRUNCATE, _T("%s%s"), prefix, suffix) < 0) {
\r
168 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, suffix, _T("delete_createfile_parameter()"), 0);
\r
172 if (RegDeleteValue(key, value)) return 0;
\r
176 HANDLE write_to_file(TCHAR *path, unsigned long sharing, SECURITY_ATTRIBUTES *attributes, unsigned long disposition, unsigned long flags) {
\r
177 HANDLE ret = CreateFile(path, FILE_WRITE_DATA, sharing, attributes, disposition, flags, 0);
\r
178 if (ret!= INVALID_HANDLE_VALUE) {
\r
179 if (SetFilePointer(ret, 0, 0, FILE_END) != INVALID_SET_FILE_POINTER) SetEndOfFile(ret);
\r
183 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, path, error_string(GetLastError()), 0);
\r
187 static void rotated_filename(TCHAR *path, TCHAR *rotated, unsigned long rotated_len, SYSTEMTIME *st) {
\r
194 TCHAR buffer[PATH_LENGTH];
\r
195 memmove(buffer, path, sizeof(buffer));
\r
196 TCHAR *ext = PathFindExtension(buffer);
\r
197 TCHAR extension[PATH_LENGTH];
\r
198 _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
200 _sntprintf_s(rotated, rotated_len, _TRUNCATE, _T("%s%s"), buffer, extension);
\r
203 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
204 unsigned long error;
\r
208 GetSystemTime(&st);
\r
210 BY_HANDLE_FILE_INFORMATION info;
\r
212 /* Try to open the file to check if it exists and to get attributes. */
\r
213 HANDLE file = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
\r
214 if (file != INVALID_HANDLE_VALUE) {
\r
215 /* Get file attributes. */
\r
216 if (! GetFileInformationByHandle(file, &info)) {
\r
217 /* Reuse current time for rotation timestamp. */
\r
218 seconds = low = high = 0;
\r
219 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
225 error = GetLastError();
\r
226 if (error == ERROR_FILE_NOT_FOUND) return;
\r
227 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, _T("CreateFile()"), path, error_string(error), 0);
\r
228 /* Reuse current time for rotation timestamp. */
\r
229 seconds = low = high = 0;
\r
230 SystemTimeToFileTime(&st, &info.ftLastWriteTime);
\r
233 /* Check file age. */
\r
236 SystemTimeToFileTime(&st, &ft);
\r
239 s.LowPart = ft.dwLowDateTime;
\r
240 s.HighPart = ft.dwHighDateTime;
\r
241 s.QuadPart -= seconds * 10000000LL;
\r
242 ft.dwLowDateTime = s.LowPart;
\r
243 ft.dwHighDateTime = s.HighPart;
\r
244 if (CompareFileTime(&info.ftLastWriteTime, &ft) > 0) return;
\r
247 /* Check file size. */
\r
249 if (info.nFileSizeHigh < high) return;
\r
250 if (info.nFileSizeHigh == high && info.nFileSizeLow < low) return;
\r
253 /* Get new filename. */
\r
254 FileTimeToSystemTime(&info.ftLastWriteTime, &st);
\r
256 TCHAR rotated[PATH_LENGTH];
\r
257 rotated_filename(path, rotated, _countof(rotated), &st);
\r
262 if (copy_and_truncate) {
\r
263 function = _T("CopyFile()");
\r
264 if (CopyFile(path, rotated, TRUE)) {
\r
265 file = write_to_file(path, NSSM_STDOUT_SHARING, 0, NSSM_STDOUT_DISPOSITION, NSSM_STDOUT_FLAGS);
\r
267 SetFilePointer(file, 0, 0, FILE_BEGIN);
\r
268 SetEndOfFile(file);
\r
274 function = _T("MoveFile()");
\r
275 if (! MoveFile(path, rotated)) ok = false;
\r
278 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, service_name, path, rotated, 0);
\r
281 error = GetLastError();
\r
283 if (error == ERROR_FILE_NOT_FOUND) return;
\r
284 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ROTATE_FILE_FAILED, service_name, path, function, rotated, error_string(error), 0);
\r
288 int get_output_handles(nssm_service_t *service, STARTUPINFO *si) {
\r
289 if (! si) return 1;
\r
291 /* Allocate a new console so we get a fresh stdin, stdout and stderr. */
\r
292 alloc_console(service);
\r
295 if (service->stdin_path[0]) {
\r
296 si->hStdInput = CreateFile(service->stdin_path, FILE_READ_DATA, service->stdin_sharing, 0, service->stdin_disposition, service->stdin_flags, 0);
\r
297 if (si->hStdInput == INVALID_HANDLE_VALUE) {
\r
298 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);
\r
304 if (service->stdout_path[0]) {
\r
305 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
306 HANDLE stdout_handle = write_to_file(service->stdout_path, service->stdout_sharing, 0, service->stdout_disposition, service->stdout_flags);
\r
307 if (stdout_handle == INVALID_HANDLE_VALUE) return 4;
\r
308 service->stdout_si = 0;
\r
310 if (service->use_stdout_pipe) {
\r
311 service->stdout_pipe = si->hStdOutput = 0;
\r
312 service->stdout_thread = create_logging_thread(service->name, service->stdout_path, service->stdout_sharing, service->stdout_disposition, service->stdout_flags, &service->stdout_pipe, &service->stdout_si, &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
313 if (! service->stdout_thread) {
\r
314 CloseHandle(service->stdout_pipe);
\r
315 CloseHandle(service->stdout_si);
\r
318 else service->stdout_thread = 0;
\r
320 if (! service->stdout_thread) {
\r
321 if (dup_handle(stdout_handle, &service->stdout_si, NSSM_REG_STDOUT, _T("stdout"), DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) return 4;
\r
322 service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;
\r
325 if (dup_handle(service->stdout_si, &si->hStdOutput, _T("stdout_si"), _T("stdout"))) {
\r
326 if (service->stdout_thread) {
\r
327 CloseHandle(service->stdout_thread);
\r
328 service->stdout_thread = 0;
\r
334 if (service->stderr_path[0]) {
\r
335 /* Same as stdout? */
\r
336 if (str_equiv(service->stderr_path, service->stdout_path)) {
\r
337 service->stderr_sharing = service->stdout_sharing;
\r
338 service->stderr_disposition = service->stdout_disposition;
\r
339 service->stderr_flags = service->stdout_flags;
\r
340 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
342 /* Two handles to the same file will create a race. */
\r
343 /* XXX: Here we assume that either both or neither handle must be a pipe. */
\r
344 if (dup_handle(service->stdout_si, &service->stderr_si, _T("stdout"), _T("stderr"))) return 6;
\r
347 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
348 HANDLE stderr_handle = write_to_file(service->stderr_path, service->stderr_sharing, 0, service->stderr_disposition, service->stderr_flags);
\r
349 if (stderr_handle == INVALID_HANDLE_VALUE) return 7;
\r
350 service->stderr_si = 0;
\r
352 if (service->use_stderr_pipe) {
\r
353 service->stderr_pipe = si->hStdError = 0;
\r
354 service->stderr_thread = create_logging_thread(service->name, service->stderr_path, service->stderr_sharing, service->stderr_disposition, service->stderr_flags, &service->stderr_pipe, &service->stderr_si, &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
355 if (! service->stderr_thread) {
\r
356 CloseHandle(service->stderr_pipe);
\r
357 CloseHandle(service->stderr_si);
\r
360 else service->stderr_thread = 0;
\r
362 if (! service->stderr_thread) {
\r
363 if (dup_handle(stderr_handle, &service->stderr_si, NSSM_REG_STDERR, _T("stderr"), DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) return 7;
\r
364 service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;
\r
368 if (dup_handle(service->stderr_si, &si->hStdError, _T("stderr_si"), _T("stderr"))) {
\r
369 if (service->stderr_thread) {
\r
370 CloseHandle(service->stderr_thread);
\r
371 service->stderr_thread = 0;
\r
377 We need to set the startup_info flags to make the new handles
\r
378 inheritable by the new process.
\r
380 si->dwFlags |= STARTF_USESTDHANDLES;
\r
382 if (service->no_console) return 0;
\r
384 /* Redirect other handles. */
\r
385 if (! si->hStdInput) {
\r
386 if (dup_handle(GetStdHandle(STD_INPUT_HANDLE), &si->hStdInput, _T("STD_INPUT_HANDLE"), _T("stdin"))) return 8;
\r
388 if (! si->hStdOutput) {
\r
389 if (dup_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si->hStdOutput, _T("STD_OUTPUT_HANDLE"), _T("stdout"))) return 9;
\r
391 if (! si->hStdError) {
\r
392 if (dup_handle(GetStdHandle(STD_ERROR_HANDLE), &si->hStdError, _T("STD_ERROR_HANDLE"), _T("stderr"))) return 10;
\r
398 /* Reuse output handles for a hook. */
\r
399 int use_output_handles(nssm_service_t *service, STARTUPINFO *si) {
\r
400 si->dwFlags &= ~STARTF_USESTDHANDLES;
\r
402 if (service->stdout_si) {
\r
403 if (dup_handle(service->stdout_si, &si->hStdOutput, _T("stdout_pipe"), _T("hStdOutput"))) return 1;
\r
404 si->dwFlags |= STARTF_USESTDHANDLES;
\r
407 if (service->stderr_si) {
\r
408 if (dup_handle(service->stderr_si, &si->hStdError, _T("stderr_pipe"), _T("hStdError"))) {
\r
409 if (si->hStdOutput) {
\r
410 si->dwFlags &= ~STARTF_USESTDHANDLES;
\r
411 CloseHandle(si->hStdOutput);
\r
415 si->dwFlags |= STARTF_USESTDHANDLES;
\r
421 void close_output_handles(STARTUPINFO *si) {
\r
422 if (si->hStdInput) CloseHandle(si->hStdInput);
\r
423 if (si->hStdOutput) CloseHandle(si->hStdOutput);
\r
424 if (si->hStdError) CloseHandle(si->hStdError);
\r
428 Try multiple times to read from a file.
\r
429 Returns: 0 on success.
\r
430 1 on non-fatal error.
\r
433 static int try_read(logger_t *logger, void *address, unsigned long bufsize, unsigned long *in, int *complained) {
\r
435 unsigned long error;
\r
436 for (int tries = 0; tries < 5; tries++) {
\r
437 if (ReadFile(logger->read_handle, address, bufsize, in, 0)) return 0;
\r
439 error = GetLastError();
\r
441 /* Other end closed the pipe. */
\r
442 case ERROR_BROKEN_PIPE:
\r
444 goto complain_read;
\r
446 /* Couldn't lock the buffer. */
\r
447 case ERROR_NOT_ENOUGH_QUOTA:
\r
448 Sleep(2000 + tries * 3000);
\r
452 /* Write was cancelled by the other end. */
\r
453 case ERROR_OPERATION_ABORTED:
\r
455 goto complain_read;
\r
463 /* Ignore the error if we've been requested to exit anyway. */
\r
464 if (*logger->rotate_online != NSSM_ROTATE_ONLINE) return ret;
\r
465 if (! (*complained & COMPLAINED_READ)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_READFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
466 *complained |= COMPLAINED_READ;
\r
471 Try multiple times to write to a file.
\r
472 Returns: 0 on success.
\r
473 1 on non-fatal error.
\r
476 static int try_write(logger_t *logger, void *address, unsigned long bufsize, unsigned long *out, int *complained) {
\r
478 unsigned long error;
\r
479 for (int tries = 0; tries < 5; tries++) {
\r
480 if (WriteFile(logger->write_handle, address, bufsize, out, 0)) return 0;
\r
482 error = GetLastError();
\r
483 if (error == ERROR_IO_PENDING) {
\r
484 /* Operation was successful pending flush to disk. */
\r
489 /* Other end closed the pipe. */
\r
490 case ERROR_BROKEN_PIPE:
\r
492 goto complain_write;
\r
494 /* Couldn't lock the buffer. */
\r
495 case ERROR_NOT_ENOUGH_QUOTA:
\r
496 /* Out of disk space. */
\r
497 case ERROR_DISK_FULL:
\r
498 Sleep(2000 + tries * 3000);
\r
503 /* We'll lose this line but try to read and write subsequent ones. */
\r
509 if (! (*complained & COMPLAINED_WRITE)) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_WRITEFILE_FAILED, logger->service_name, logger->path, error_string(error), 0);
\r
510 *complained |= COMPLAINED_WRITE;
\r
514 /* Wrapper to be called in a new thread for logging. */
\r
515 unsigned long WINAPI log_and_rotate(void *arg) {
\r
516 logger_t *logger = (logger_t *) arg;
\r
517 if (! logger) return 1;
\r
520 BY_HANDLE_FILE_INFORMATION info;
\r
522 /* Find initial file size. */
\r
523 if (! GetFileInformationByHandle(logger->write_handle, &info)) logger->size = 0LL;
\r
526 l.HighPart = info.nFileSizeHigh;
\r
527 l.LowPart = info.nFileSizeLow;
\r
533 unsigned long in, out;
\r
534 unsigned long charsize = 0;
\r
535 unsigned long error;
\r
537 int complained = 0;
\r
540 /* Read data from the pipe. */
\r
542 ret = try_read(logger, address, sizeof(buffer), &in, &complained);
\r
544 CloseHandle(logger->read_handle);
\r
545 CloseHandle(logger->write_handle);
\r
546 HeapFree(GetProcessHeap(), 0, logger);
\r
549 else if (ret) continue;
\r
551 if (*logger->rotate_online == NSSM_ROTATE_ONLINE_ASAP || (logger->size && size + (__int64) in >= logger->size)) {
\r
552 /* Look for newline. */
\r
554 for (i = 0; i < in; i++) {
\r
555 if (buffer[i] == '\n') {
\r
556 if (! charsize) charsize = guess_charsize(address, in);
\r
559 /* Write up to the newline. */
\r
560 ret = try_write(logger, address, i, &out, &complained);
\r
562 CloseHandle(logger->read_handle);
\r
563 CloseHandle(logger->write_handle);
\r
564 HeapFree(GetProcessHeap(), 0, logger);
\r
567 size += (__int64) out;
\r
570 *logger->rotate_online = NSSM_ROTATE_ONLINE;
\r
571 TCHAR rotated[PATH_LENGTH];
\r
572 rotated_filename(logger->path, rotated, _countof(rotated), 0);
\r
575 Ideally we'd try the rename first then close the handle but
\r
576 MoveFile() will fail if the handle is still open so we must
\r
577 risk losing everything.
\r
579 if (logger->copy_and_truncate) FlushFileBuffers(logger->write_handle);
\r
580 CloseHandle(logger->write_handle);
\r
583 if (logger->copy_and_truncate) {
\r
584 function = _T("CopyFile()");
\r
585 if (CopyFile(logger->path, rotated, TRUE)) {
\r
586 HANDLE file = write_to_file(logger->path, NSSM_STDOUT_SHARING, 0, NSSM_STDOUT_DISPOSITION, NSSM_STDOUT_FLAGS);
\r
587 Sleep(logger->rotate_delay);
\r
588 SetFilePointer(file, 0, 0, FILE_BEGIN);
\r
589 SetEndOfFile(file);
\r
595 function = _T("MoveFile()");
\r
596 if (! MoveFile(logger->path, rotated)) ok = false;
\r
599 log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_ROTATED, logger->service_name, logger->path, rotated, 0);
\r
603 error = GetLastError();
\r
604 if (error != ERROR_FILE_NOT_FOUND) {
\r
605 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
606 complained |= COMPLAINED_ROTATE;
\r
607 /* We can at least try to re-open the existing file. */
\r
608 logger->disposition = OPEN_ALWAYS;
\r
613 logger->write_handle = write_to_file(logger->path, logger->sharing, 0, logger->disposition, logger->flags);
\r
614 if (logger->write_handle == INVALID_HANDLE_VALUE) {
\r
615 error = GetLastError();
\r
616 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, logger->path, error_string(error), 0);
\r
617 /* Oh dear. Now we can't log anything further. */
\r
618 CloseHandle(logger->read_handle);
\r
619 CloseHandle(logger->write_handle);
\r
620 HeapFree(GetProcessHeap(), 0, logger);
\r
624 /* Resume writing after the newline. */
\r
625 address = (void *) ((char *) address + i);
\r
632 /* Write a BOM to the new file. */
\r
633 if (! charsize) charsize = guess_charsize(address, in);
\r
634 if (charsize == sizeof(wchar_t)) write_bom(logger, &out);
\r
635 size += (__int64) out;
\r
638 /* Write the data, if any. */
\r
639 if (! in) continue;
\r
641 ret = try_write(logger, address, in, &out, &complained);
\r
642 size += (__int64) out;
\r
644 CloseHandle(logger->read_handle);
\r
645 CloseHandle(logger->write_handle);
\r
646 HeapFree(GetProcessHeap(), 0, logger);
\r
651 CloseHandle(logger->read_handle);
\r
652 CloseHandle(logger->write_handle);
\r
653 HeapFree(GetProcessHeap(), 0, logger);
\r