<commit_before>//===============================================
// File: system_server.c  
// 
//     use an extra "server" process to handle computing the
//     symbols to insulate the client process from the complexity of this task, 
//     including use of the system command to fork new processes. having the
//     server process enables use to avoid dealing with forking off new processes
//     with system when there might be multiple threads active with sampling  
//     enabled.
//
//  Modification history:
//     2008 April 29 - created <NAME>
//===============================================

//*******************************************************************************
// system includes 
//*******************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for strlen
#include <stdarg.h> // for varargs
#include <unistd.h> // for pipe



//*******************************************************************************
// local includes 
//*******************************************************************************

//-------------
// monitor
//-------------
#include "monitor.h"

#include "pmsg.h"
#include "system_server.h"



//*******************************************************************************
// private data  
//*******************************************************************************

// constant data 
static const int server_done = -1;

static int system_server_pipes[2][2];
static pid_t server_pid;


//*******************************************************************************
// macros 
//*******************************************************************************

#define CLIENT_TO_SERVER 0
#define SERVER_TO_CLIENT 1


#define READ_FD(end) system_server_pipes[end][0]
#define WRITE_FD(end) system_server_pipes[end][1]

#define SS_EXIT_ON_ERROR(r,e,...) system_server_exit_on_error(r,e,__VA_ARGS__)


//*******************************************************************************
// forward declarations 
//*******************************************************************************

void system_server_exit_on_error(int ret, int ret_expected, const char *fmt, ...);



//*******************************************************************************
// interface operations  
//*******************************************************************************

int 
system_server_start()
{
  int ret;
  extern int __libc_system(char *);

  // --------------------------------------------------------------------------------------------------
  // set up pipes for communication between client and server
  // --------------------------------------------------------------------------------------------------
  ret = pipe(system_server_pipes[CLIENT_TO_SERVER]);
  EXIT_ON_ERROR(ret, 0, "system server: failed to create 1st pipe");

  ret = pipe(system_server_pipes[SERVER_TO_CLIENT]);
  EXIT_ON_ERROR(ret, 0, "system server: failed to create 2nd pipe");

  // --------------------------------------------------------------------------------------------------
  // fork server from client
  // --------------------------------------------------------------------------------------------------
  server_pid = monitor_real_fork();
  if (server_pid == 0) { /* child process */
     NMSG(SYSTEM_SERVER,"in child");

     // --------------------------------------------------------------------------------------------------
     // avoid monitoring processes that we spawn with system
     // --------------------------------------------------------------------------------------------------
     unsetenv("LD_PRELOAD");

     // --------------------------------------------------------------------------------------------------
     // server: close unused file descriptor to send data to self 
     // --------------------------------------------------------------------------------------------------
     ret = close(WRITE_FD(CLIENT_TO_SERVER));
     SS_EXIT_ON_ERROR(ret, 0, "system server: failed to close pipe in server");

     for(;;) {
       int nbytes;

       // --------------------------------------------------------------------------------------------------
       // receive command string length from client
       // --------------------------------------------------------------------------------------------------
       ret = read(READ_FD(CLIENT_TO_SERVER), &nbytes, sizeof(nbytes));
       SS_EXIT_ON_ERROR(ret, sizeof(nbytes), "system server fatal error: read failed");

       if (nbytes > 0) {
          TMSG(SYSTEM_SERVER,"system server: expecting command of %d bytes", nbytes);

	  // --------------------------------------------------------------------------------------------------
	  // allocate space for command string 
	  // --------------------------------------------------------------------------------------------------
          char *command = malloc(nbytes);

	  // --------------------------------------------------------------------------------------------------
	  // receive command string from client
	  // --------------------------------------------------------------------------------------------------
          ret = read(READ_FD(CLIENT_TO_SERVER), command, nbytes);
          SS_EXIT_ON_ERROR(ret, nbytes, "system server fatal error: "
	                "read only %d of %d bytes for a command %d", ret, nbytes);

	  // --------------------------------------------------------------------------------------------------
	  // execute command 
	  //
	  // NOTE: must use monitor_real_system to avoid monitor callbacks 
	  //             for fork and exec as part of system because monitor has 
	  //             control of server process 
	  // --------------------------------------------------------------------------------------------------
	  TMSG(SYSTEM_SERVER,"executing command: '%s'\n", command);
          int status = monitor_real_system(command);

	  // --------------------------------------------------------------------------------------------------
	  // send command result to client
	  // --------------------------------------------------------------------------------------------------
          ret = write(WRITE_FD(SERVER_TO_CLIENT), &status, sizeof(status));

	  // --------------------------------------------------------------------------------------------------
	  // free space for command string 
	  // --------------------------------------------------------------------------------------------------
	  free(command);
       } else {
	 if (nbytes != server_done) {
            SS_EXIT_ON_ERROR(nbytes, server_done, "system server fatal error: "
			  "received negative length %d for command string", nbytes);
	 }
	 // --------------------------------------------------------------------------------------------------
	 // received command string length value server_done to terminate 
	 //
	 // NOTE: must use monitor_exit to avoid monitor callbacks on exit
	 //             because monitor has control of server process 
	 // --------------------------------------------------------------------------------------------------
         monitor_real_exit(0); 
       }
     }
  } 

  // --------------------------------------------------------------------------------------------------
  // client: close unused file descriptor to send data to self 
  // --------------------------------------------------------------------------------------------------
  ret = close(WRITE_FD(SERVER_TO_CLIENT));
  EXIT_ON_ERROR(ret, 0, "system server: failed to close pipe in client");

  return (server_pid != -1) ? 0 : -1;
}


void 
system_server_shutdown() 
{
  // --------------------------------------------------------------------------------------------------
  // send command string length value of -1 to terminate 
  // --------------------------------------------------------------------------------------------------
  int ret = write(WRITE_FD(CLIENT_TO_SERVER), &server_done, sizeof(server_done));
  EXIT_ON_ERROR(ret, sizeof(server_done), "system server shutdown failed");
}
 

int 
system_server_execute_command(const char *command)  
{
  int ret, status;
  int len = strlen(command) + 1;         // add 1 for terminating null

  // --------------------------------------------------------------------------------------------------
  // send command string length to server
  // --------------------------------------------------------------------------------------------------
  TMSG(SYSTEM_COMMAND,"system server: sending command size = %d bytes", len);<commit_msg>Don't send the shutdown message to the system server (which will fail) if we are the system server.<commit_after>//===============================================
// File: system_server.c  
// 
//     use an extra "server" process to handle computing the
//     symbols to insulate the client process from the complexity of this task, 
//     including use of the system command to fork new processes. having the
//     server process enables use to avoid dealing with forking off new processes
//     with system when there might be multiple threads active with sampling  
//     enabled.
//
//  Modification history:
//     2008 April 29 - created <NAME>
//===============================================

//*******************************************************************************
// system includes 
//*******************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for strlen
#include <stdarg.h> // for varargs
#include <unistd.h> // for pipe



//*******************************************************************************
// local includes 
//*******************************************************************************

//-------------
// monitor
//-------------
#include "monitor.h"

#include "pmsg.h"
#include "system_server.h"



//*******************************************************************************
// private data  
//*******************************************************************************

// constant data 
static const int server_done = -1;

static int system_server_pipes[2][2];
static pid_t server_pid;


//*******************************************************************************
// macros 
//*******************************************************************************

#define CLIENT_TO_SERVER 0
#define SERVER_TO_CLIENT 1


#define READ_FD(end) system_server_pipes[end][0]
#define WRITE_FD(end) system_server_pipes[end][1]

#define SS_EXIT_ON_ERROR(r,e,...) system_server_exit_on_error(r,e,__VA_ARGS__)


//*******************************************************************************
// forward declarations 
//*******************************************************************************

void system_server_exit_on_error(int ret, int ret_expected, const char *fmt, ...);



//*******************************************************************************
// interface operations  
//*******************************************************************************

int 
system_server_start()
{
  int ret;
  extern int __libc_system(char *);

  // --------------------------------------------------------------------------------------------------
  // set up pipes for communication between client and server
  // --------------------------------------------------------------------------------------------------
  ret = pipe(system_server_pipes[CLIENT_TO_SERVER]);
  EXIT_ON_ERROR(ret, 0, "system server: failed to create 1st pipe");

  ret = pipe(system_server_pipes[SERVER_TO_CLIENT]);
  EXIT_ON_ERROR(ret, 0, "system server: failed to create 2nd pipe");

  // --------------------------------------------------------------------------------------------------
  // fork server from client
  // --------------------------------------------------------------------------------------------------
  server_pid = monitor_real_fork();
  if (server_pid == 0) { /* child process */
     NMSG(SYSTEM_SERVER,"in child");

     // --------------------------------------------------------------------------------------------------
     // avoid monitoring processes that we spawn with system
     // --------------------------------------------------------------------------------------------------
     unsetenv("LD_PRELOAD");

     // --------------------------------------------------------------------------------------------------
     // server: close unused file descriptor to send data to self 
     // --------------------------------------------------------------------------------------------------
     ret = close(WRITE_FD(CLIENT_TO_SERVER));
     SS_EXIT_ON_ERROR(ret, 0, "system server: failed to close pipe in server");

     for(;;) {
       int nbytes;

       // --------------------------------------------------------------------------------------------------
       // receive command string length from client
       // --------------------------------------------------------------------------------------------------
       ret = read(READ_FD(CLIENT_TO_SERVER), &nbytes, sizeof(nbytes));
       SS_EXIT_ON_ERROR(ret, sizeof(nbytes), "system server fatal error: read failed");

       if (nbytes > 0) {
          TMSG(SYSTEM_SERVER,"system server: expecting command of %d bytes", nbytes);

	  // --------------------------------------------------------------------------------------------------
	  // allocate space for command string 
	  // --------------------------------------------------------------------------------------------------
          char *command = malloc(nbytes);

	  // --------------------------------------------------------------------------------------------------
	  // receive command string from client
	  // --------------------------------------------------------------------------------------------------
          ret = read(READ_FD(CLIENT_TO_SERVER), command, nbytes);
          SS_EXIT_ON_ERROR(ret, nbytes, "system server fatal error: "
	                "read only %d of %d bytes for a command %d", ret, nbytes);

	  // --------------------------------------------------------------------------------------------------
	  // execute command 
	  //
	  // NOTE: must use monitor_real_system to avoid monitor callbacks 
	  //             for fork and exec as part of system because monitor has 
	  //             control of server process 
	  // --------------------------------------------------------------------------------------------------
	  TMSG(SYSTEM_SERVER,"executing command: '%s'\n", command);
          int status = monitor_real_system(command);

	  // --------------------------------------------------------------------------------------------------
	  // send command result to client
	  // --------------------------------------------------------------------------------------------------
          ret = write(WRITE_FD(SERVER_TO_CLIENT), &status, sizeof(status));

	  // --------------------------------------------------------------------------------------------------
	  // free space for command string 
	  // --------------------------------------------------------------------------------------------------
	  free(command);
       } else {
	 if (nbytes != server_done) {
            SS_EXIT_ON_ERROR(nbytes, server_done, "system server fatal error: "
			  "received negative length %d for command string", nbytes);
	 }
	 // --------------------------------------------------------------------------------------------------
	 // received command string length value server_done to terminate 
	 //
	 // NOTE: must use monitor_exit to avoid monitor callbacks on exit
	 //             because monitor has control of server process 
	 // --------------------------------------------------------------------------------------------------
         monitor_real_exit(0); 
       }
     }
  } 

  // --------------------------------------------------------------------------------------------------
  // client: close unused file descriptor to send data to self 
  // --------------------------------------------------------------------------------------------------
  ret = close(WRITE_FD(SERVER_TO_CLIENT));
  EXIT_ON_ERROR(ret, 0, "system server: failed to close pipe in client");

  return (server_pid != -1) ? 0 : -1;
}


void 
system_server_shutdown() 
{
  // --------------------------------------------------------------------------------------------------
  // send command string length value of -1 to terminate 
  // but not if we're called back in the server (child) itself
  // --------------------------------------------------------------------------------------------------
  if (server_pid != 0) {
    int ret = write(WRITE_FD(CLIENT_TO_SERVER), &server_done, sizeof(server_done));
    EXIT_ON_ERROR(ret, sizeof(server_done), "system server shutdown failed");
  }
}
 

int 
system_server_execute_command(const char *command)  
{
  int ret, status;
  int len = strlen(command) + 1;         // add 1 for terminating null

  // --------------------------------------------------------------------------------------------------
  // send command string length to server
  // --------------------------------------------------------------------------------------------------
  TMSG(SYSTEM_COMMAND,"system server: sending command size = %d bytes", len);
{'fraction_non_alphanumeric': 0.5021881838074398, 'fraction_numerical': 0.0032822757111597373, 'mean_word_length': 1.1022878586127587, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2740090', 'n_tokens_mistral': 3386, 'n_tokens_neox': 3095, 'n_words': 942}