=== modified file 'src/com/goldencode/p2j/main/ClientCore.java'
--- src/com/goldencode/p2j/main/ClientCore.java	2022-12-14 16:21:35 +0000
+++ src/com/goldencode/p2j/main/ClientCore.java	2023-01-27 13:53:55 +0000
@@ -2,7 +2,7 @@
 ** Module   : ClientCore.java
 ** Abstract : core client loop which handles init and connects to server
 **
-** Copyright (c) 2005-2022, Golden Code Development Corporation.
+** Copyright (c) 2005-2023, Golden Code Development Corporation.
 **
 ** -#- -I- --Date-- ----------------------------------Description---------------------------------
 ** 001 GES 20110928 Moved core logic here from ClientDriver so that the same
@@ -62,6 +62,7 @@
 **     CA  20220918 Added socket trust store filename and password to the ClientParameters.
 **     GBB 20221209 Path to debug log file to be read from client bootstrap configs.
 **                  Passing arg to spawner for path to stderr log file for background processes.
+**     GBB 20230127 Fixing pid in outputToFile name by replacing it in Java code.
 */
 /*
 ** This program is free software: you can redistribute it and/or modify
@@ -118,6 +119,7 @@
 
 package com.goldencode.p2j.main;
 
+import java.io.*;
 import java.util.*;
 import java.util.function.*;
 import java.util.logging.*;
@@ -186,6 +188,11 @@
    public static void start(BootstrapConfig config, boolean file, boolean single, Supplier<String> diag)
    throws Exception
    {
+      // Load native library
+      loadNativeLibrary();
+      
+      setOutputToFile(config);
+      
       String  uuid     = config.getString("server", "spawner", "uuid", null);
       boolean dbg      = config.getBoolean("logging", "debug", "enable", false);
       String  referrer = config.getString("web", "referrer", "url", null);
@@ -196,9 +203,6 @@
       // iterations of the core loop
       ScreenDriver<?> driver = (uuid == null) ? null : processTemporaryClient(uuid, config);
       
-      // Load native library
-      loadNativeLibrary();
-      
       while (running)
       {
          Object          context = null; 
@@ -434,6 +438,25 @@
       return isStop;
    }
 
+   private static void setOutputToFile(BootstrapConfig config)
+   {
+      String outputToFile = config.getString("server", "clientConfig", "outputToFile", null);
+      if (outputToFile == null)
+      {
+         return;
+      }
+      
+      try
+      {
+         outputToFile = outputToFile.replace("%pid%", String.valueOf(getPid()));
+         System.setOut(new PrintStream(new FileOutputStream(outputToFile), true));
+      }
+      catch (Throwable t)
+      {
+         System.err.println("ClientCore: Unable to redirect stdout to outputToFile " + outputToFile);
+      }
+   }
+
    /**
     * Loads native library and performs required initial steps for P2J library to working.
     */

=== modified file 'src/com/goldencode/p2j/main/ProcessClientBuilder.java'
--- src/com/goldencode/p2j/main/ProcessClientBuilder.java	2017-04-01 23:33:34 +0000
+++ src/com/goldencode/p2j/main/ProcessClientBuilder.java	2023-01-27 13:56:11 +0000
@@ -2,7 +2,7 @@
 ** Module   : ProcessClientBuilder.java
 ** Abstract : build and start a platform process for P2J process.
 **
-** Copyright (c) 2014-2017, Golden Code Development Corporation.
+** Copyright (c) 2014-2023, Golden Code Development Corporation.
 **
 ** -#- -I- --Date-- ---------------------------------Description----------------------------------
 ** 001 CA  20140206 First version.
@@ -10,6 +10,7 @@
 ** 003 MAG 20140722 Implemented the remote launcher.
 ** 004 GES 20160219 Moved code to the parent class allowing reuse of the native secure connection
 **                  setup processing.
+**     GBB 20230127 Fixing pid in outputToFile name by passing it as config to spawned client.
 */
 /*
 ** This program is free software: you can redistribute it and/or modify
@@ -132,9 +133,9 @@
       if (outputToFile != null)
       {
          cmd.add("-O");
-         cmd.add(outputToFile);
+         cmd.add("server:clientConfig:outputToFile=" + outputToFile);
       }
 
       return cmd;
    }
-}
\ No newline at end of file
+}

=== modified file 'src/native/spawn.c'
--- src/native/spawn.c	2021-05-19 21:40:23 +0000
+++ src/native/spawn.c	2023-01-27 13:45:24 +0000
@@ -162,9 +162,6 @@
    #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)/* 07777 */
 #endif
 
-/* prototypes */
-void stdout_redirect();
-
 /* Global data */
 struct passwd *pw;
 int extra_logging = 0;
@@ -175,6 +172,7 @@
 
 /* Output file name */
 char output_file_name[MAX_FILENAME];
+int output_to_file_opt_found = 0;
 
 /**
  * Use syslog to audit the execution of child processes.
@@ -400,12 +398,6 @@
             logMessage(message_buffer);
             exit(audit(ERR_SPAWN_CHDIR_WD, "chdir(workdir)"));
          }
-
-         /* Redirect STDOUT if required */
-         if (output_file_name[0] != 0)
-         {
-            stdout_redirect();
-         }
          
          /* Execute command */
          exit(execvp(command, argv));
@@ -1018,9 +1010,17 @@
    /* make it 1-based, so it follows the structure of the command line arguments 
       (0 is program name); also, one more position is needed for execvp, which requires for the
       arguments to be null-terminated. */
-   char **arguments = (char**) malloc((length + 2) * sizeof(char*));
+   char **arguments = (char**) malloc((length + 2 + output_to_file_opt_found) * sizeof(char*));
    arguments[0] = NULL;
-   arguments[length + 1] = NULL;
+   arguments[length + 1 + output_to_file_opt_found] = NULL;
+
+   if (output_to_file_opt_found == 1)
+   {
+      int len = strlen(output_file_name) + 1;
+      arguments[length + 1] = (char*) malloc(len * sizeof(char));
+      memset(arguments[length + 1], '\0', len);
+      strcpy(arguments[length + 1], output_file_name);
+   }
    
    int i;
    for (i = 0; i < (int) length; i++)
@@ -1151,38 +1151,6 @@
 }
 
 /**
- * Redirect STDOUT to an output file. 
- */
-void stdout_redirect()
-{
-   int output_fd; 
-   char pid[32];
-   
-   /* convert pid to string */
-   sprintf(pid, "%u", getpid()); 
-   
-   /* replace %pid% placeholder */
-   char* filename = replace_str(output_file_name, "%pid%", pid);
-    
-   // Open file
-   output_fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644);
-   
-   if (output_fd == -1)
-   {
-      fprintf(stderr, "Cannot open file %s\n", filename);
-   }
-   else
-   {
-      /* Redirect STDOUT to file */
-      if (dup2(output_fd, STDOUT_FILENO) == -1)
-      {
-         close(output_fd);
-         fprintf(stderr, "Cannot redirect STDOUT to file %s\n", filename);
-      }
-   }
-}
-
-/**
  * Main function which allows both password and P2J server-style authentication.
  * <p>
  * For P2J server-style authentiation, the following files need to exist in current directory:
@@ -1335,6 +1303,7 @@
          if ((strcmp("-O", argv[i]) == 0) && (++i < argc))
          {
             strcpy(output_file_name, argv[i]);
+            output_to_file_opt_found = 1;
          }
       }
 

=== modified file 'src/native/winspawn.c'
--- src/native/winspawn.c	2022-12-09 10:28:29 +0000
+++ src/native/winspawn.c	2023-01-27 13:45:24 +0000
@@ -132,8 +132,7 @@
 
 unsigned char key1[KEY_SIZE + 1], key2[KEY_SIZE + 1], key3[KEY_SIZE + 1];
 
-/* STDOUT redirection flag. Default NO redirection */
-int stdoutRedirect = 0;
+int outputToFileOption = 0;
 WCHAR szOutputFile[MAX_SIZE] = L"";
 
 WCHAR szUserProfile[MAX_SIZE] = L"";
@@ -510,58 +509,6 @@
 }
 
 /**
-* Redirect STDOUT to an output file. 
-*
-* @param   szWorkingDir
-*          Working directory.
-* @param   szOutputFile
-*          The name of the file where the STDOUT is redirected.
-*/
-void stdout_redirect(LPWSTR szWorkingDir, LPWSTR szOutputFile)
-{
-   HANDLE hFile;
-   WCHAR pid[32];
-   
-   /* Goto working directory */
-   if (!SetCurrentDirectoryW(szWorkingDir))
-   {
-      DisplayError(L"SetCurrentDirectoryW");
-   }
-   
-   /* convert pid to string */
-   swprintf(pid, sizeof(pid), L"%lu", GetCurrentProcessId()); 
-   
-   /* replace %pid% placeholder */
-   LPWSTR szFileName = replace_str(szOutputFile, L"%pid%", pid);
-    
-   SECURITY_ATTRIBUTES sa;
-   sa.nLength = sizeof(sa);
-   sa.lpSecurityDescriptor = NULL;
-   sa.bInheritHandle = TRUE;   
-    
-   /* create file */
-   hFile = CreateFileW(szFileName,                         // file name 
-                       FILE_APPEND_DATA,                   // open for writing
-                       FILE_SHARE_WRITE | FILE_SHARE_READ, // allow multiple readers
-                       &sa,                                // security
-                       OPEN_ALWAYS,                        // open or create
-                       FILE_ATTRIBUTE_NORMAL,              // normal file
-                       NULL);                              // no template
-   
-   /* check for errors */
-   if (hFile == INVALID_HANDLE_VALUE)
-   {
-      DisplayError(L"CreateFileW");
-   }
-   else
-   {
-      /* redirect */
-      si.hStdOutput = hFile;
-      si.dwFlags |= STARTF_USESTDHANDLES;
-   }
-}
-
-/**
 * Spawn a child process on the current logon account.
 *
 * @param   szWorkingDir
@@ -579,12 +526,6 @@
    si.wShowWindow = SW_HIDE;
    // since Windows Vista we have to specify desktop session explicitly here
    si.lpDesktop = desktopDefault;
-
-   /* Redirect STDOUT if required */
-   if (stdoutRedirect)
-   {
-      stdout_redirect(szWorkingDir, szOutputFile);
-   }
    
    if (!CreateProcessW(NULL,             // application name
                        szCommand,        // command line
@@ -681,12 +622,6 @@
       }
       szWorkingDir = szUserProfile;
    }
-   
-   /* Redirect STDOUT if required */
-   if (stdoutRedirect)
-   {
-      stdout_redirect(szWorkingDir, szOutputFile);
-   }
 
    if (extra_logging > 0)
    {
@@ -916,7 +851,16 @@
       arguments to be null-terminated. */
    char **arguments = (char**) malloc((length + 2) * sizeof(char*));
    arguments[0] = NULL;
-   arguments[length + 1] = NULL;
+   arguments[length + 1 + outputToFileOption] = NULL;
+   
+   if (outputToFileOption == 1)
+   {
+      int len = strlen(szOutputFile) + 1;
+      arguments[length + 1] = (char*) malloc(len * sizeof(char));
+      memset(arguments[length + 1], '\0', len);
+      strcpy(arguments[length + 1], szOutputFile);
+   }
+   
    int debug_option = 0;
    char *dbg_level = NULL;
    
@@ -1121,7 +1065,7 @@
          if ((wcscmp(L"-O", argv[i]) == 0) && (++i < argc))
          {
             wcscpy(szOutputFile, argv[i]);
-            stdoutRedirect = 1; // restored redirection mode
+            outputToFileOption = 1;
          }
       }
             

