Changeset 352 in MondoRescue


Ignore:
Timestamp:
Jan 28, 2006, 6:41:40 PM (18 years ago)
Author:
bcornec
Message:

monitas v0.1a

Location:
branches/stable/monitas
Files:
6 added
2 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/monitas/client.c

    r351 r352  
    44
    55
     6
    67FIXME
    7 - fork child process ('daemon', almost) to interact with server
    8 - parent process will interact with keyboard ('logout'=quit)
    9 - if trigger_backup msg arrives then act accordingly
    10 - remember, the client is a 'server' from the minute it logs in
    11   until the minute it logs out of the server: the client listens
    12   on a port between 8800 and 8899, waiting for incoming msgs
    13   from server; all the forked process has to do is take over the
    14   task of watching that port and act on the incoming data
    15 - when trigger_backup is received then send file along connection
    16 
    17 05/19
     8- perror() --- replace with log_it()
     9
     10
     11
     1206/19
     13- fixed bugs in mondoarchive compare code
     14- added track_restore_task_progress()
     15
     1606/16
     17- when calling mondoarchive in bkgd, see if it starts OK; if it
     18  doesn't then say so & return error
     19
     2006/14
     21- added a FIFO to let user request backup/compare/restore
     22- send progress info to server - % done, etc. - when backing up
     23- pipe logs to logfile, not stdout
     24
     2506/11
     26- added call to register_pid()
     27- commented code a bit
     28- implemented compare_archives and restore_archives()
     29
     3006/10
     31- create function to call external executable in background
     32- create function to wait for it to terminate & to grab its result
     33- put them in common.c
     34
     3505/27
     36- fixed watch_port_for_triggers()
     37- turned st_'s into a global and some locals
     38- fork in login thingy becomes a thread
     39- added bind_client_port()
     40- added accept_and_recv_thru_client_port()
     41- changed flag (recv) from DONTWAIT to 0 [no flag]
     42
     4305/21
     44- added back_my_smitch_up(), compare_archives(), restore_archives()
     45- added log_it(); fixed fprintf(stderr,"") and printf() reporting
     46- parallelize/fork the 'watch for triggers from server' process
    1847- added tmsg_to_string()
    1948- forked port-watcher to receive triggers from server in bkgd
     
    3261
    3362#include "structs.h"
     63//#define LOG_THESE_AND_HIGHER debug
     64#define LOGFILE "/var/log/monitas-client.log"
    3465
    3566
     
    3768/* global vars */
    3869
    39 
     70bool g_logged_in_currently=false, g_logging_out=false;
     71int g_sClient=-1, g_client_port=0; /* client port; set by login */
     72struct sockaddr_in g_sinClient; /* client port */
     73char g_server_name[MAX_STR_LEN+1];
     74pthread_t g_mondo_thread=0;
     75char g_command_fifo[MAX_STR_LEN+1];
     76char g_logfile[MAX_STR_LEN+1] = "/var/log/monitas-client.log";
     77
     78/* externs */
     79
     80extern char *call_program_and_get_last_line_of_output(char*);
     81extern int call_program_and_log_output(char*);
     82extern void call_program_in_background(pthread_t*, char*);
     83extern int create_and_watch_fifo_for_commands(char*);
     84extern bool does_file_exist(char*);
     85extern int get_bkgd_prog_result(pthread_t*);
     86extern void log_it_SUB(char*, t_loglevel level, char *sz_message);
     87extern bool program_still_running(char*);
     88extern int receive_file_from_socket(FILE*, int);
     89extern void register_pid(pid_t, char*);
     90extern char *tmsg_to_string(t_msg msg_type);
     91extern int transmit_file_to_socket(FILE*, int);
     92extern void register_pid(pid_t, char*);
     93extern void set_signals(bool);
    4094
    4195/* prototypes */
    4296
     97int accept_and_recv_thru_client_port(int, int*, struct sockaddr_in*, char*, int);
     98int back_my_smitch_up(char*, int);
     99int bind_client_port(struct sockaddr_in*, int);
     100int compare_archives(char*, int);
    43101int find_and_bind_free_server_port(struct sockaddr_in*, int*);
    44102long increment_magic_number(void);
    45103int login_to_server(char*,char*);
     104void logout_and_exit(char*);
    46105int logout_of_server(char*);
     106int process_incoming_command(char*);
     107int restore_archives(char*, char*, int);
     108void restore_archives_SIGPIPE(int);
     109int send_final_progress_report(char*);
    47110int send_msg_to_server(struct s_client2server_msg_record*, char*);
    48111int send_ping_to_server(char*,char*);
    49 char *tmsg_to_string(t_msg);
    50 void watch_port_for_triggers_from_server(struct sockaddr_in *, int, int);
    51 
    52 /* subroutines */
     112int send_progress_rpt_to_server(char*, char*);
     113void terminate_daemon(int);
     114void *track_backup_task_progress(void*);
     115void *track_compare_task_progress(void*);
     116void *track_restore_task_progress(void*);
     117void *watch_port_for_triggers_from_server(void*);
     118
     119
     120
     121
     122/*-----------------------------------------------------------*/
     123
     124
     125
     126int accept_and_recv_thru_client_port(int sClient, int *new_sClient, struct sockaddr_in*sinClient, char*incoming, int expected_length)
     127/*
     128Purpose:Run accept() and recv() to open port and receive
     129    message from server.
     130Params: sClient - file descriptor of port
     131    new_sClient - [returned] file descriptor of the
     132    new connection to port which we open in this func
     133    sinClient - record about port
     134    expected_length - expected length of incoming block
     135Return: length of block received, or <0 if error
     136*/
     137{
     138      int len;
     139
     140      len = sizeof(struct sockaddr_in);
     141      if ((*new_sClient = accept(sClient, (struct sockaddr*)sinClient, (unsigned int*)&len)) < 0) { log_it(error, "[child] Cannot accept"); return(-6); }
     142      if ((len = recv(*new_sClient, incoming, expected_length, /*MSG_DONTWAIT*/0)) <= 0) { log_it(error, "[child] Cannot recv"); return(-7); }
     143      return(len);
     144}
     145
     146
     147
     148/*-----------------------------------------------------------*/
     149
     150
     151
     152char *get_param_from_rcfile(char*fname, char*field)
     153{
     154  char command[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
     155  static char sz_res[MAX_STR_LEN+1];
     156
     157  sz_res[0]='\0';
     158  if (does_file_exist(fname))
     159    {
     160      sprintf(command, "cat %s | grep %s= | cut -d'=' -f2,3,4,5,6,7,8,9", fname, field);
     161      strcpy(tmp, call_program_and_get_last_line_of_output(command));
     162      strcpy(sz_res, tmp);
     163    }
     164  return(sz_res);
     165}
     166
     167
     168
     169int back_my_smitch_up(char*msgbody, int socket_fd)
     170/*
     171Purpose:Backup archives to server.
     172Params: msgbody - char[MSG_BODY_SIZE] containing info
     173    about the archives to be created
     174    socket_fd - file descriptor to which to
     175    write the archives to server.
     176Return: result (0=success; nonzero=failure)
     177*/
     178{
     179  char tmp[MAX_STR_LEN+1], command[MAX_STR_LEN+1], tempdev[MAX_STR_LEN+1];
     180  char temporary_logfile[MAX_STR_LEN+1]; // where mondoarchive writes its stdout,stderr
     181  char mondoparams_str[MAX_STR_LEN+1];
     182  struct s_server2client_msg_record incoming_rec;
     183  int retval=0, len, new_sClient, res=0;
     184  FILE*fin;
     185  pthread_t progress_thread;
     186
     187  sprintf(tmp, "Backup of %s commenced", msgbody);
     188  log_it(info, tmp);
     189  if (send_progress_rpt_to_server(g_server_name, tmp)) { log_it(error, "Unable to send 'yep, got this msg' progress_rpt to server"); }
     190  sprintf(temporary_logfile, "/tmp/monitas-client.templog.%d", (int)random()%32767);
     191  sprintf(tempdev, "/tmp/monitas-client.device.%d", (int)random()%32767);
     192  unlink(tempdev);
     193  if (mkfifo(tempdev, 700))
     194    {
     195      log_it(error, "Unable to create temporary data output fifo in preparation for the call to mondoarchive");
     196      return(1);
     197    }
     198  unlink(temporary_logfile);
     199  if (mkfifo(temporary_logfile, 700))
     200    {
     201      log_it(error, "Unable to create temporary logfile fifo in preparation for the call to mondoarchive");
     202      return(1);
     203    }
     204  strcpy(mondoparams_str, get_param_from_rcfile(CLIENT_RCFILE, "mondoarchive_params"));
     205  sprintf(tmp, "mondoarchive_params --> '%s'", mondoparams_str);
     206  log_it(debug, tmp);
     207  sprintf(command, "mondoarchive -Ou %s -d %s -I %s -F &> %s; rm -f %s %s", mondoparams_str, tempdev, msgbody, temporary_logfile, tempdev, temporary_logfile);
     208  call_program_in_background(&g_mondo_thread, command);
     209  sleep(10);
     210  if (!program_still_running(command))
     211    { res=1; log_it(error, "Unable to start mondoarchive. Please check /var/log/mondo-archive.log"); }
     212  else
     213    {
     214      if (pthread_create(&progress_thread, NULL, track_backup_task_progress, (void*)temporary_logfile))
     215        { log_it(error, "Cannot create pthread to track mondo task progress"); return(1); }
     216      log_it(debug, "Opening fopen() to tempdev");
     217      if (!(fin = fopen(tempdev, "r"))) { log_it(error, "Cannot open FIFO"); return(1); }
     218      log_it(debug, "fopen() OK");
     219      retval = transmit_file_to_socket(fin, socket_fd);
     220      fclose(fin);
     221      res = get_bkgd_prog_result(&g_mondo_thread);
     222      pthread_join(progress_thread, NULL);
     223    }
     224  if (res)
     225    { retval++; log_it(error, "Mondoarchive returned an error. Notifying server..."); }
     226  if (res)
     227    { retval++; log_it(error, "Mondoarchive returned an error."); }
     228  if (retval) { log_it(debug, "Errors have occurred. Notifing server..."); }
     229  else        { log_it(debug, "Everything is OK so far. Notifying server..."); }
     230  if (write(socket_fd, (char*)&retval, sizeof(retval))!=sizeof(retval)) {retval++;}
     231/* receive msg from server; did backup go OK at its end or not? */
     232  unlink(tempdev);
     233  unlink(temporary_logfile);
     234  log_it(debug, "Waiting for progress thread to join us");
     235  log_it(debug, "Groovy. Continuing..");
     236  len = accept_and_recv_thru_client_port(g_sClient, &new_sClient, &g_sinClient, (char*)&incoming_rec, sizeof(incoming_rec));
     237  if (len<0) { log_it(error, "After backup, unable to accept/recv thru client port"); return(-10); }
     238  sprintf(tmp, "After backup, I received %s - %s", tmsg_to_string(incoming_rec.msg_type), incoming_rec.body);
     239  log_it(debug, tmp);
     240  if (incoming_rec.msg_type == backup_fail)
     241    { retval++; log_it(error, "Server reported error(s) during backup, although client didn't."); }
     242  if (retval)
     243    {
     244      sprintf(tmp, "Backup of %s failed", msgbody);
     245      log_it(error, tmp);
     246      call_program_and_log_output("tail -n6 /var/log/mondo-archive.log");
     247    }
     248  else
     249    {
     250      sprintf(tmp, "Server agrees, backup of %s succeeded :-)", msgbody);
     251      log_it(info, tmp);
     252    }
     253  if (send_final_progress_report(tmp) < 0) { retval++; log_it(error, "Unable to send final progress_rpt to server"); }
     254  return(retval);
     255}
     256
     257
     258
     259/*-----------------------------------------------------------*/
     260
     261
     262
     263int bind_client_port(struct sockaddr_in *sinClient, int client_port)
     264/*
     265Purpose:Bind one of my ports so that I may open it later and
     266        write/read data to/from server with it.
     267Params: sinClient - record/structure relating to the socket
     268        client_port - port# to be bound
     269Return: socket handle, to be used by other subroutines, if success
     270        or <0 if failure
     271*/
     272{
     273      int sClient=-1;
     274      char tmp[MAX_STR_LEN+1];
     275
     276      memset((void*)sinClient, 0, sizeof(struct sockaddr_in));
     277      sinClient->sin_family = AF_INET;
     278      sinClient->sin_addr.s_addr = INADDR_ANY;
     279      sinClient->sin_port = htons(client_port);
     280      if ((sClient = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
     281    {
     282      sprintf(tmp, "Unable to open socket on port #%d", g_client_port);
     283      log_it(error, tmp);
     284          return(-1);
     285    }
     286      if (bind(sClient, (struct sockaddr*)sinClient, sizeof(struct sockaddr_in)) < 0)
     287    {
     288      sprintf(tmp, "Cannot bind %d - %s", g_client_port, strerror(errno));
     289      log_it(error, tmp);
     290      return(-2);
     291    }
     292      if (listen(sClient, MAX_PENDING) < 0)
     293    {
     294      sprintf(tmp, "Cannot setup listen (%d) - %sn", g_client_port, strerror(errno));
     295      log_it(error, tmp);
     296      return(-3);
     297    }
     298      log_it(debug, "Successfully bound client port.");
     299      return(sClient);
     300}
     301
     302
     303
     304/*-----------------------------------------------------------*/
     305
     306
     307
     308int compare_archives(char*msgbody, int socket_fd)
     309/*
     310Purpose:Compare archives, sent by server.
     311Params: msgbody - char[MSG_BODY_SIZE] containing info
     312about the archives to be compared
     313socket_fd - file descriptor from which to
     314read the archives sent by server to be compared.
     315Return: result (0=success; nonzero=failure)
     316*/
     317{
     318  char tmp[MAX_STR_LEN+1], command[MAX_STR_LEN+1], tempdev[MAX_STR_LEN+1], *p;
     319  char temporary_logfile[MAX_STR_LEN+1]; // where mondoarchive writes its stdout,stderr
     320  char mondoparams_str[MAX_STR_LEN+1];
     321  struct s_server2client_msg_record incoming_rec;
     322  int retval=0, len, new_sClient, res=0;
     323  FILE*fout, *fin;
     324  long diffs=0;
     325  pthread_t progress_thread;
     326
     327  sprintf(tmp, "Comparison of %s commenced", msgbody);
     328  log_it(info, tmp);
     329  if (send_progress_rpt_to_server(g_server_name, tmp)) { log_it(error, "Unable to send 'yep, got this msg' progress_rpt to server"); }
     330  sprintf(temporary_logfile, "/tmp/monitas-client.templog.%d", (int)random()%32767);
     331  sprintf(tempdev, "/tmp/monitas-client.device.%d", (int)random()%32767);
     332  unlink(tempdev);
     333  if (mkfifo(tempdev, 700))
     334    {
     335      log_it(error, "Unable to create temporary fifo in preparation for the call to mondoarchive");
     336      return(1);
     337    }
     338  unlink(temporary_logfile);
     339  if (mkfifo(temporary_logfile, 700))
     340    {
     341      log_it(error, "Unable to create temporary logfile fifo in preparation for the call to mondoarchive");
     342      return(1);
     343    }
     344  strcpy(mondoparams_str, get_param_from_rcfile(CLIENT_RCFILE, "mondoarchive_params"));
     345  sprintf(tmp, "mondoarchive_params --> '%s'", mondoparams_str);
     346  log_it(debug, tmp);
     347  sprintf(command, "mondoarchive -Vu -F %s -d %s -I %s > %s"/*; rm -f %s %s"*/, mondoparams_str, tempdev, msgbody, temporary_logfile/*, tempdev, temporary_logfile*/);
     348  call_program_in_background(&g_mondo_thread, command);
     349  sleep(5);
     350  if (!program_still_running(command))
     351    { res=1; log_it(error, "Unable to start mondoarchive. Please check /var/log/mondo-archive.log"); }
     352  else
     353    {
     354      if (pthread_create(&progress_thread, NULL, track_compare_task_progress, (void*)temporary_logfile))
     355        { log_it(error, "Cannot create pthread to track mondo task progress"); return(1); }
     356      fout = fopen(tempdev, "w");
     357      log_it(debug, "Opened fopen() to tempdev");
     358      retval = receive_file_from_socket(fout, socket_fd);
     359      log_it(debug, "Calling get_bkgd_prog_result");
     360      fclose(fout);
     361      res = get_bkgd_prog_result(&g_mondo_thread);
     362      res = 0; // *shrug* Seems to help :)
     363      pthread_join(progress_thread, NULL);
     364    }
     365  if (res)
     366    { retval++; log_it(error, "Mondoarchive returned an error."); }
     367  if (retval) { log_it(debug, "Errors have occurred. Notifing server..."); }
     368  else        { log_it(debug, "Everything is OK so far. Notifying server..."); }
     369  if (write(socket_fd, (char*)&retval, sizeof(retval))!=sizeof(retval)) {retval++;}
     370/* receive msg from server; did comparison go OK at its end or not? */
     371  unlink(tempdev);
     372  unlink(temporary_logfile);
     373  len = accept_and_recv_thru_client_port(g_sClient, &new_sClient, &g_sinClient, (char*)&incoming_rec, sizeof(incoming_rec));
     374  if (len<0) { log_it(error, "After comparison, unable to accept/recv thru client port"); return(-10); }
     375  sprintf(tmp, "After comparison, I received %s - %s", tmsg_to_string(incoming_rec.msg_type), incoming_rec.body);
     376  log_it(debug, tmp);
     377  if (incoming_rec.msg_type == compare_fail)
     378    { retval++; log_it(error, "Server reported error(s) during comparison, although client didn't."); }
     379  if (retval)
     380    {
     381      sprintf(tmp, "Errors occurred during comparison of %s", msgbody);
     382      strcpy(command, call_program_and_get_last_line_of_output("tail -n20 /var/log/mondo-archive.log | grep /tmp/changed | head -n1"));
     383      p = strstr(command, "/tmp/changed");
     384      if (p)
     385        {
     386          strcat(command, " ");
     387          sprintf(tmp, "command = '%s'", command);
     388          log_it(debug, tmp);
     389          *(strchr(p, ' '))='\0';
     390          sprintf(tmp, "Opening list of changed files ('%s')", p);
     391          log_it(debug, tmp);
     392          log_it(info, "---Changed files---");
     393          if ((fin=fopen(p, "r")))
     394            { for(diffs=0; !feof(fin); diffs++) { fgets(tmp, MAX_STR_LEN, fin); if (strlen(tmp)>0) {tmp[strlen(tmp)-1]='\0';} log_it(info, tmp); } fclose(fin); }
     395          log_it(info, "----End of list----");
     396          sprintf(tmp, "%ld differences were found during comparison of %s", diffs, msgbody);
     397          log_it(warn, tmp);
     398          unlink(p);
     399        }
     400      else
     401        {
     402          sprintf(tmp, "Errors occurred during comparison of %s", msgbody);
     403          log_it(error, tmp);
     404          call_program_and_log_output("tail -n6 /var/log/mondo-archive.log");
     405          log_it(info, "Please check /var/log/mondo-archive.log for more information");
     406        }
     407    }
     408  else
     409    {
     410      sprintf(tmp, "Server agrees, comparison of %s succeeded :-)", msgbody);
     411      log_it(info, tmp);
     412    }
     413  if (send_final_progress_report(tmp)) { retval++; log_it(error, "Unable to send final progress_rpt to server"); }
     414  return(retval);
     415}
     416
     417
     418
     419/*-----------------------------------------------------------*/
     420
     421
    53422
    54423int find_and_bind_free_server_port(struct sockaddr_in *sin, int *p_s)
     
    59428Params: sin - server's IP address in a structure
    60429    p_s - [return] file descriptor of port binding
    61 Return: result (0=success, nonzero=failure)
     430Return: result (>0=success, -1=failure)
    62431*/
    63432{
    64433  int server_port;
     434  char tmp[MAX_STR_LEN+1];
    65435
    66436  for(server_port = 8700; server_port < 8710; server_port++)
     
    70440    {
    71441      perror("socket");
    72       return(1);
     442      return(-1);
    73443    }
    74444      if (connect(*p_s, (struct sockaddr*)sin, sizeof(struct sockaddr_in)) < 0)
    75445    {
    76       printf("Not connecting at %d\r", server_port);
     446      sprintf(tmp, "Not connecting at %d", server_port);
     447      log_it(debug, tmp);
    77448      continue;
    78449    }
    79450      return(server_port);
    80451    }
    81   fprintf(stderr, "Cannot find free server port\nIs server actually running?\n");
    82   return(1);
    83 }
     452  return(-1);
     453}
     454
     455
     456
     457/*-----------------------------------------------------------*/
    84458
    85459
     
    98472  return(magic);
    99473}
     474
     475
     476
     477/*-----------------------------------------------------------*/
    100478
    101479
     
    113491{
    114492  struct s_client2server_msg_record orig_rec;
    115   int i;
    116493
    117494  orig_rec.msg_type = login;
    118495  strncpy(orig_rec.body, hostname, sizeof(orig_rec.body));
    119   for(i=0; i<3; i++)
    120     {
    121       if (send_msg_to_server(&orig_rec, servername) > 0)
    122         { return(orig_rec.port); }
    123       printf("Attempt #%d to login failed. Retrying...\n", i+1);
    124     }
    125   printf("Failed to login\n");
    126   return(-1);
    127 }
     496  if (send_msg_to_server(&orig_rec, servername) < 0)
     497    { return(-1); }
     498  else
     499    { return(orig_rec.port); }
     500}
     501
     502
     503
     504/*-----------------------------------------------------------*/
     505
     506
     507
     508
     509void logout_and_exit(char*servername)
     510/*
     511Purpose:Logout of server. Terminate.
     512Params: servername - ip address of server
     513Return: none
     514*/
     515{
     516  if (g_logged_in_currently)
     517    {
     518      if (logout_of_server(servername))
     519        { log_it(warn, "Failed to logout of server."); }
     520    }
     521  call_program_and_log_output("rm -Rf /tmp/monitas-client.*");
     522  register_pid(0, "client");
     523//  chmod(g_command_fifo, 0);
     524  unlink(g_command_fifo);
     525  log_it(info, "---------- Monitas (client) has terminated ----------");
     526  exit(0);
     527}
     528
     529
     530
     531/*-----------------------------------------------------------*/
    128532
    129533
     
    138542  struct s_client2server_msg_record orig_rec;
    139543
     544  g_logging_out = true;
     545  log_it(debug, "Logging out of server");
    140546  orig_rec.msg_type = logout;
    141547  strncpy(orig_rec.body, "Bye bye!", sizeof(orig_rec.body));
    142   if (send_msg_to_server(&orig_rec, servername) <= 0)
     548  if (send_msg_to_server(&orig_rec, servername) < 0)
    143549    { return(1); }
    144550  else
     
    148554
    149555
    150 // FIXME -
    151 // Are the threads trampling on one another's st_sClient, st_new_sClient's?
    152 // I don't see how. After all, there's only one thread... :-)
     556/*-----------------------------------------------------------*/
     557
     558
     559
     560int process_incoming_command(char*incoming)
     561/*
     562Purpose:Process incoming command, presumably
     563        read from FIFO and sent there by sysadm/user.
     564Params: incoming - raw command string itself
     565Return: result (0=success; nonzero=failure)
     566*/
     567{
     568  int res=0;
     569  char tmp[MAX_STR_LEN+1];
     570  int pos, i;
     571  char command[MAX_STR_LEN+1], path[MAX_STR_LEN+1], aux[MAX_STR_LEN+1];
     572  struct s_client2server_msg_record orig_rec;
     573
     574  pos=0;
     575  sscanf(incoming, "%s %s", command, path);
     576  for(i=0; i<strlen(command); i++) { command[i]=command[i]|0x60; }
     577  if (!strcmp(command, "restore"))
     578    { sscanf(incoming, "%s %s %s", command, path, aux); }
     579  else
     580    { aux[0] = '\0'; }
     581  sprintf(tmp, "cmd=%s path=%s aux=%s", command, path, aux);
     582  log_it(debug, tmp);
     583  sprintf(tmp, "%s of %s [aux='%s'] <-- command received", command, path, aux);
     584  log_it(info, tmp);
     585  if (strcmp(command, "restore") && aux[0]!='\0')
     586    { log_it(warn, "Ignoring auxiliary parameter: it is superfluous."); }
     587  if (strcmp(command, "backup") && strcmp(command, "compare") && strcmp(command, "restore"))
     588    {
     589      sprintf(tmp, "%s - command unknown.", command);
     590      log_it(error, tmp);
     591      res=1;
     592    }
     593  else
     594    {
     595      sprintf(tmp, "'%s' sent to server as a formal request", incoming);
     596      orig_rec.msg_type = user_req;
     597      strncpy(orig_rec.body, incoming, sizeof(orig_rec.body));
     598      if (send_msg_to_server(&orig_rec, g_server_name) < 0)
     599        { res++; log_it(error, "Unable to send user req to server"); }
     600      else
     601        { log_it(debug, tmp); }
     602    }
     603  return(res);
     604}
     605
     606
     607
     608/*-----------------------------------------------------------*/
     609
     610
     611
     612int restore_archives(char*msgbody, char*msgbodyAux, int socket_fd)
     613/*
     614Purpose:Restore archives, sent by server.
     615Params: msgbody - char[MSG_BODY_SIZE] containing info
     616about the archives to be restored
     617socket_fd - file descriptor from which to
     618read the archives sent by server.
     619Return: result (0=success; nonzero=failure)
     620*/
     621{
     622  char tmp[MAX_STR_LEN+1], command[MAX_STR_LEN+1], tempdev[MAX_STR_LEN+1], *p;
     623  char temporary_logfile[MAX_STR_LEN+1]; // where mondorestore writes its stdout,stderr
     624  struct s_server2client_msg_record incoming_rec;
     625  int retval=0, len, new_sClient, res=0;
     626  FILE*fout, *fin;
     627  long diffs=0;
     628  pthread_t progress_thread;
     629 
     630  sprintf(tmp, "Restoration of %s commenced", msgbody);
     631  log_it(info, tmp);
     632  if (send_progress_rpt_to_server(g_server_name, tmp)) { log_it(error, "Unable to send 'yep, got this msg' progress_rpt to server"); }
     633  sprintf(temporary_logfile, "/tmp/monitas-client.templog.%d", (int)random()%32767);
     634  sprintf(tempdev, "/tmp/monitas-client.device.%d", (int)random()%32767);
     635  unlink(tempdev);
     636  if (mkfifo(tempdev, 700))
     637    {
     638      log_it(error, "Unable to create temporary fifo in preparation for the call to mondorestore");
     639      return(1);
     640    }
     641  unlink(temporary_logfile);
     642  if (mkfifo(temporary_logfile, 700))
     643    {
     644      log_it(error, "Unable to create temporary logfile in preparation for the call to mondorestore");
     645      return(1);
     646    }
     647  sprintf(command, "mondorestore --monitas-live %s %s %s &> %s", tempdev, msgbody, msgbodyAux, temporary_logfile);
     648//  sprintf(command, "cat %s > %s", tempdev, "/tmp/out.dat");
     649  call_program_in_background(&g_mondo_thread, command);
     650  sleep(5);
     651  if (!program_still_running(command))
     652    {
     653      res=1; log_it(error, "mondorestore could not be started. Please check /tmp/mondo-restore.log");
     654    }
     655  else
     656    {
     657      if (pthread_create(&progress_thread, NULL, track_restore_task_progress, (void*)temporary_logfile))
     658        { log_it(error, "Cannot create pthread to track mondo task progress"); return(1); }
     659      fout = fopen(tempdev, "w");
     660      log_it(debug, "Opened fopen() to tempdev");
     661      retval = receive_file_from_socket(fout, socket_fd);
     662      if (retval && !system("cat /tmp/mondo-restore.log | grep -i \"End of restore_live_from_monitas_server\" &> /dev/null"))
     663        {
     664          retval=0;
     665          log_it(debug, "SIGPIPE caught but that's OK, it was anticipated.");
     666          res=0;
     667        }
     668      log_it(debug, "Calling get_bkgd_prog_result");
     669      fclose(fout);
     670      res = get_bkgd_prog_result(&g_mondo_thread);
     671      pthread_join(progress_thread, NULL);
     672    }
     673  unlink(tempdev);
     674  unlink(temporary_logfile);
     675  if (res)
     676    { retval++; log_it(error, "mondorestore returned an error."); }
     677  if (retval) { log_it(debug, "Errors have occurred. Notifing server..."); }
     678  else        { log_it(debug, "Everything is OK so far. Notifying server..."); }
     679  sleep(1); // probably unnecessary
     680/* I do this thrice because mondorestore often causes a SIGPIPE, which means... I have to do this thrice :-) */
     681  if (write(socket_fd, (char*)&retval, sizeof(retval))!=sizeof(retval)) {log_it(debug, "Failed to write wtf-info"); retval++;}
     682  if (write(socket_fd, (char*)&retval, sizeof(retval))!=sizeof(retval)) {log_it(debug, "Failed to write wtf-info"); retval++;}
     683  if (write(socket_fd, (char*)&retval, sizeof(retval))!=sizeof(retval)) {log_it(debug, "Failed to write wtf-info"); retval++;}
     684/* receive msg from server; did restoration go OK at its end or not? */
     685  unlink(tempdev);
     686  unlink(temporary_logfile);
     687  len = accept_and_recv_thru_client_port(g_sClient, &new_sClient, &g_sinClient, (char*)&incoming_rec, sizeof(incoming_rec));
     688  if (len<0) { log_it(error, "After restoration, unable to accept/recv thru client port"); return(-10); }
     689  sprintf(tmp, "After restoration, I received %s - %s", tmsg_to_string(incoming_rec.msg_type), incoming_rec.body);
     690  log_it(debug, tmp);
     691  if (incoming_rec.msg_type == restore_fail)
     692    { retval++; log_it(error, "Server reported error(s) during restoration, although client didn't."); }
     693  if (retval)
     694    {
     695      sprintf(tmp, "Errors occurred during restoration of %s", msgbody);
     696      strcpy(command, call_program_and_get_last_line_of_output("tail -n20 /var/log/mondo-archive.log | grep /tmp/changed | head -n1"));
     697      p = strstr(command, "/tmp/changed");
     698      if (p)
     699        {
     700          strcat(command, " ");
     701          sprintf(tmp, "command = '%s'", command);
     702          log_it(debug, tmp);
     703          *(strchr(p, ' '))='\0';
     704          sprintf(tmp, "Opening list of changed files ('%s')", p);
     705          log_it(debug, tmp);
     706          log_it(info, "---Changed files---");
     707          if ((fin=fopen(p, "r")))
     708            { for(diffs=0; !feof(fin); diffs++) { fgets(tmp, MAX_STR_LEN, fin); if (strlen(tmp)>0) {tmp[strlen(tmp)-1]='\0';} log_it(info, tmp); } fclose(fin); }
     709          log_it(info, "----End of list----");
     710          sprintf(tmp, "%ld differences were found during restoration of %s", diffs, msgbody);
     711          log_it(warn, tmp);
     712        }
     713      else
     714        {
     715          sprintf(tmp, "Errors occurred during restoration of %s", msgbody);
     716          log_it(error, tmp);
     717          call_program_and_log_output("tail -n6 /var/log/mondo-archive.log");
     718          log_it(info, "Please check /var/log/mondo-archive.log for more information");
     719        }
     720    }
     721  else
     722    {
     723      sprintf(tmp, "Server agrees, restoration of %s succeeded :-)", msgbody);
     724      log_it(info, tmp);
     725    }
     726  if (send_final_progress_report(tmp)) { retval++; log_it(error, "Unable to send final progress_rpt to server"); }
     727  return(retval);
     728}
     729
     730
     731
     732/*-----------------------------------------------------------*/
     733
     734
     735
     736void *send_final_progress_report_SUB(void*inp)
     737{
     738  char message[MAX_STR_LEN+1];
     739
     740  strncpy(message, (char*)inp, MAX_STR_LEN);
     741  sleep(10);
     742  send_progress_rpt_to_server(g_server_name, message);
     743  pthread_exit(NULL);
     744}
     745
     746
     747
     748int send_final_progress_report(char*final_string)
     749{
     750  pthread_t thread;
     751
     752  if (send_progress_rpt_to_server(g_server_name, final_string)) { return(1); }
     753  if (pthread_create(&thread, NULL, send_final_progress_report_SUB, (void*)"Idle")) { log_it(error, "Unable to create pthread"); return(1); }
     754  return(0);
     755}
     756
     757
     758
     759/*-----------------------------------------------------------*/
     760
     761
     762
    153763int send_msg_to_server(struct s_client2server_msg_record *rec, char *servername)
    154764/*
    155765Purpose:Send message to server - a login/logout/ping request
    156     or perhaps a request for data to be restored.
     766        or perhaps a request for data to be restored.
    157767Params: rec - the message to be sent to server
    158     servername - the hostname of server
    159 Return: result (-1=failure, >0=success)
     768        servername - the hostname of server
     769Return: result (<0=failure, 0+=success)
    160770*/
    161771{
    162772  struct hostent *hp;
    163773  struct sockaddr_in sin;
    164   static struct sockaddr_in st_sinClient; /* client port; connected by login; closed by logout */
    165   static int st_sClient; /* client connection */
    166   static int st_new_sClient;
    167   int server_port, s, len;
    168   static int  st_client_port=0; /* client port; set by login */
     774  int server_port, new_sClient, s, len, res;
    169775  struct s_server2client_msg_record incoming_rec;
    170776  struct pollfd ufds;
    171   static t_pid st_pid=-1;
     777  char tmp[MAX_STR_LEN+1];
     778  void *thread_result;
     779  pthread_t a_thread;
    172780
    173781/* If logging out then kill the trigger-watcher before trying;
    174    otherwise, the trigger-watcher will probably catch the
    175    'logout_ok' packet and go nutty on us :-)
    176 */
    177   if (rec->msg_type == logout)
    178     {
    179       sprintf(tmp, "kill %d &> /dev/null", st_pid);
    180     system(tmp);
    181 //      kill(st_pid);
    182     st_pid = -1;
    183     }
    184 
    185 /* st_sinClient, st_new_sClient and st_sClient contain info
    186    relating to the permanent socket which this subroutine
    187    opens at login-time so that it can listen for messages
    188    from the server. This subroutine doesn't watch the
    189    socket all the time (yet) but it leaves it open until
    190    logout-time, for neatness' sake.
    191 */
    192   if ((hp = gethostbyname(servername)) == NULL) { fprintf(stderr, "%s: unknown host\n", servername); return(1); }
    193   if (st_client_port > 0 && rec->msg_type == login) { fprintf(stderr, "Already logged in. Why try again?\n"); return(1); }
    194   if (st_client_port <= 0 && rec->msg_type != login) { fprintf(stderr, "Don't try to send msgs before logging in.\n"); return(1); }
     782otherwise, the trigger-watcher will probably catch the
     783'logout_ok' packet and go nutty on us :-)
     784*/
     785  if ((hp = gethostbyname(servername)) == NULL)
     786    {
     787      sprintf(tmp, "%s: unknown host", servername);
     788      log_it(error, tmp);
     789      return(-1);
     790    }
     791  if (g_logged_in_currently && rec->msg_type == login) { log_it(error, "Already logged in. Why try again?"); return(-1); }
     792  if (!g_logged_in_currently && rec->msg_type != login)
     793    {
     794      log_it(fatal, "Server has forcibly logged you out.");
     795    } /* or you never logged in to begin which, which suggests the programmer screwed up */
    195796  /* open client port if login */
    196 
    197797  if (rec->msg_type == login)
    198798    {
    199       printf("Logging in\n");
    200       st_client_port = 8800 + rand()%100; // FIXME: retry if I can't use this port
    201       memset((void*)&st_sinClient, 0, sizeof(st_sinClient));
    202       st_sinClient.sin_family = AF_INET;
    203       st_sinClient.sin_addr.s_addr = INADDR_ANY;
    204       st_sinClient.sin_port = htons(st_client_port);
    205       if ((st_sClient = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { fprintf(stderr, "Unable to open socket on port #%d\n", st_client_port); return(1); }
    206       if (bind(st_sClient, (struct sockaddr*)&st_sinClient, sizeof(st_sinClient)) < 0) { fprintf(stderr, "Cannot bind %d - %s\n", st_client_port, strerror(errno)); return(2); }
    207       if (listen(st_sClient, MAX_PENDING) < 0) { fprintf(stderr, "Cannot setup listen (%d) - %s\n", st_client_port, strerror(errno)); return(3); }
    208     }
    209 
     799      log_it(info, "Trying to login");
     800      g_client_port = 8800 + rand()%100; // FIXME: retry if I can't use this port
     801      g_sClient = bind_client_port(&g_sinClient, g_client_port);
     802      if (g_sClient<0) { log_it(error, "Cannot bind client port"); return(-1); }
     803    }
    210804  /* send msg to server */
    211   rec->port = st_client_port;
     805  rec->port = g_client_port;
    212806  memset((void*)&sin, 0, sizeof(sin));
    213807  sin.sin_family = AF_INET;
    214808  memcpy((void*)&sin.sin_addr, hp->h_addr, hp->h_length);
    215809  server_port = find_and_bind_free_server_port(&sin, &s);
    216   if (server_port<=0) { fprintf(stderr, "Cannot find free server port\nIs server running?\n"); return(1); }
     810  if (server_port<=0)
     811    {
     812      sprintf(tmp, "Cannot find+bind free server port. Is server running?");
     813      log_it(error, tmp);
     814      return(-3);
     815    }
    217816  rec->magic = increment_magic_number();
    218817  send (s, (char*)rec, sizeof(struct s_client2server_msg_record), 0);
    219818  close(s);
    220 
    221   /* wait for ack/pong/feedback */
    222   ufds.fd = st_sClient;
    223   ufds.events = POLLIN|POLLPRI;
    224   poll(&ufds, 1, 1000);
    225   if (!ufds.revents) { fprintf(stderr,"Failed to poll\n"); return(-1); }
    226   len = sizeof(st_sinClient);
    227   if ((st_new_sClient = accept(st_sClient, (struct sockaddr*)&st_sinClient, &len)) < 0) { fprintf(stderr,"[child] Cannot accept\n"); return(1); }
    228   if ((len = recv(st_new_sClient, (char*)&incoming_rec, sizeof(incoming_rec), MSG_DONTWAIT)) <= 0) { fprintf(stderr, "[child] Cannot recv\n"); return(2); }
    229 
    230   printf("Received %s - %s\n", tmsg_to_string(incoming_rec.msg_Type, incoming_rec.body);
    231   if (rec->msg_type != login && incoming_rec.msg_type == login_ok) { fprintf(stderr, "WTF? login_ok but I wasn't logging in\n"); }
    232   if (rec->msg_type != logout&& incoming_rec.msg_type == logout_ok){ fprintf(stderr, "WTF? logout_ok but I wasn't logging out\n"); }
    233 // FIXME - should I close() after accepting and recving? Or should I wait until logging out?
    234 
    235   /* close client port if logout */
     819  /* wait for ack/pong/feedback (if logging in/out) */
     820  if (rec->msg_type == login /* || rec->msg_type == logout */)
     821    {
     822      ufds.fd = g_sClient;
     823      ufds.events = POLLIN|POLLPRI;
     824      poll(&ufds, 1, 1000);
     825      if (!ufds.revents) { log_it(error, "Failed to poll"); return(-5); }
     826      len = accept_and_recv_thru_client_port(g_sClient, &new_sClient, &g_sinClient, (char*)&incoming_rec, sizeof(incoming_rec));
     827      if (len<0) { log_it(error, "Unable to accept/recv thru client port"); return(-10); }
     828      sprintf(tmp, "Received %s - %s", tmsg_to_string(incoming_rec.msg_type), incoming_rec.body);
     829      log_it(info, tmp);
     830      if (rec->msg_type != login && incoming_rec.msg_type == login_ok) { log_it(error, "WTF? login_ok but I wasn't logging in"); }
     831      if (rec->msg_type != logout&& incoming_rec.msg_type == logout_ok){ log_it(error, "WTF? logout_ok but I wasn't logging out"); }
     832      close(new_sClient);
     833      new_sClient=-1;
     834    }
     835  if (incoming_rec.msg_type == backup_fail) { log_it(error, "Failed, says server"); return(-8); }
     836  /* fork the process which watches in the background for pings/requests/etc. */
     837  if (rec->msg_type == login)
     838    {
     839      g_logged_in_currently = true;
     840      strcpy(tmp, "Hello world!");
     841      res = pthread_create(&a_thread, NULL, watch_port_for_triggers_from_server, (void*)tmp);
     842      log_it(debug, "Returning from login + call to pthread_create");
     843      return(server_port);
     844    }
    236845  if (rec->msg_type == logout)
    237846    {
    238       close(st_new_sClient);
    239       st_new_sClient = st_sClient = st_client_port = 0;
    240     }
    241 
    242   if (incoming_rec.msg_type == fail) { return(-1); }
    243 
    244 /* fork the process which watches in the background for pings/requests/etc. */
    245   if (rec->msg_type == login)
    246     {
    247       st_pid = fork();
    248       switch(st_pid)
    249         {
    250           case -1:
    251             fprintf(stderr, "Failed to fork\n"); exit(1);
    252           case 0: /* child */
    253             watch_port_for_triggers_from_server(&st_sinClient, st_new_sClient, st_sClient);
    254             exit(0);
    255           default:/* parent */
    256             return(server_port);
    257         }
    258     }
    259 }
    260 
    261 
    262 
    263 int send_ping_to_server(char*msg, char*servername)
    264 /*
    265 Purpose:Send a 'ping' to server. Wait for 'pong!'.
     847      log_it(debug, "Calling pthread_join to reunite trigger-watcher and main loop");
     848      res = pthread_join(a_thread, &thread_result);
     849      if (res) { /*perror("Thread join failed");*/ log_it(debug, "Thread join failed in send_msg_to_server()"); }
     850      else { sprintf(tmp, "Thread join succeeded. Result: %s", (char*)thread_result); log_it(debug, tmp); }
     851    }
     852  return(0);
     853}
     854
     855
     856
     857/*-----------------------------------------------------------*/
     858
     859
     860
     861int send_ping_to_server(char*servername, char*msg)
     862/*
     863Purpose:Send a 'ping' to server.
    266864Params: msg - string to send ("Hello world"?)
    267865    servername - server's hostname
     
    272870  orig_rec.msg_type = ping;
    273871  strncpy(orig_rec.body, msg, sizeof(orig_rec.body));
    274   if (send_msg_to_server(&orig_rec, servername) <= 0)
     872  if (send_msg_to_server(&orig_rec, servername) < 0)
    275873    { return(1); }
    276874  else
     
    280878
    281879
    282 char *tmsg_to_string(t_msg msg_type)
    283 /*
    284 Purpose:Return a string/name of the msg of type msg_type
    285 Params: msg_type - type of message (enum typedef)
    286 Return: pointer to static string {name of msg)
    287 */
    288 {
    289   static char sz_msg[MAX_STR_LEN];
    290   switch(msg_type)
    291     {
    292       case unused : strcpy(sz_msg, "unused"); break;
    293       case login  : strcpy(sz_msg, "login"); break;
    294       case logout : strcpy(sz_msg, "logout"); break;
    295       case login_ok:strcpy(sz_msg, "login_ok"); break;
    296       case logout_ok:strcpy(sz_msg, "logout_ok"); break;
    297       case ping   : strcpy(sz_msg, "ping"); break;
    298       case pong   : strcpy(sz_msg, "pong"); break;
    299       case fail   : strcpy(sz_msg, "fail"); break;
    300       case trigger_backup: strcpy(sz_msg, "trigger_backup"); break;
    301       case trigger_restore: strcpy(sz_msg, "trigger_restore"); break;
    302       case begin_stream: strcpy(sz_msg, "begin_stream"); break;
    303       case end_stream: strcpy(sz_msg, "end_stream"); break;
    304       default: strcpy(sz_msg, "(Fix tmsg_to_string please)"); break;
    305     }
    306   return(sz_msg);
    307 }
    308 
    309 
    310 void watch_port_for_triggers_from_server(struct sockaddr_in *sin, int new_s, int s)
     880/*-----------------------------------------------------------*/
     881
     882
     883
     884int send_progress_rpt_to_server(char*servername, char*msg)
     885/*
     886Purpose:Send a 'progress_rpt' string to server.
     887Params: msg - string to send ("Hello world"?)
     888    servername - server's hostname
     889Return: result (0=success, nonzero=failure)
     890*/
     891{
     892  struct s_client2server_msg_record orig_rec;
     893  orig_rec.msg_type = progress_rpt;
     894  strncpy(orig_rec.body, msg, sizeof(orig_rec.body));
     895  if (send_msg_to_server(&orig_rec, servername) < 0)
     896    { return(1); }
     897  else
     898    { return(0); }
     899}
     900
     901
     902
     903/*-----------------------------------------------------------*/
     904
     905
     906
     907void terminate_daemon(int sig)
     908/*
     909Purpose: Shut down the server in response to interrupt.
     910Params:  Signal received.
     911Returns: None
     912*/
     913{
     914  int res;
     915
     916// FIXME - takes server 1-2 mins to realize I've aborted. I want that to be 5-10 seconds :)
     917  set_signals(false); // termination in progress
     918  log_it(info, "Abort signal caught by interrupt handler");
     919  call_program_and_log_output("kill `ps ax | grep mondo | grep -v \"ps ax\" | grep -v \"grep mondo\" | grep monitas | cut -d' ' -f1`");
     920  if (send_ping_to_server(g_server_name, "I'm pinging you before I logout"))
     921    { log_it(error, "Server has shut down without warning."); }
     922  if (g_mondo_thread)
     923    {
     924      res = get_bkgd_prog_result(&g_mondo_thread);
     925    }
     926  logout_and_exit(g_server_name);
     927}
     928
     929
     930
     931/*-----------------------------------------------------------*/
     932
     933
     934
     935void *track_backup_task_progress(void*inp)
     936{
     937  char fname[MAX_STR_LEN+1],
     938    tmp[MAX_STR_LEN+1],
     939    progress_str[MAX_STR_LEN+1],
     940    old_progstr[MAX_STR_LEN+1],
     941    *p;
     942  struct s_client2server_msg_record rec;
     943  FILE*fin;
     944  bool biggies=false, regulars=false;
     945  int prev_percentage=0, i;
     946
     947  rec.msg_type = progress_rpt;
     948  strcpy(fname, (char*)inp);
     949  log_it(debug, "track_backup_task_progres() --- entering");
     950  fin = fopen(fname, "r");
     951  old_progstr[0]='\0';
     952  sprintf(tmp, "fname = %s", fname);
     953  log_it(debug, tmp);
     954  sleep(2);
     955  if (!does_file_exist(fname)) { log_it(fatal, "track_backup_task_progress() -- fname not found"); }
     956  strcpy(rec.body, "Working");
     957  if (send_msg_to_server(&rec, g_server_name) < 0) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     958  log_it(debug, rec.body);
     959/* skip initial stuff */
     960  while(!feof(fin))
     961    {
     962      fgets(progress_str, MAX_STR_LEN, fin);
     963      progress_str[MAX_STR_LEN]='\0';
     964      if (strlen(progress_str)<2) { continue; }
     965      if (strstr(progress_str, "TASK")) { break; }
     966    }
     967/* skip more stuff */
     968  while(!feof(fin))
     969    {
     970      fgets(progress_str, MAX_STR_LEN, fin);
     971      progress_str[MAX_STR_LEN]='\0';
     972      if (strlen(progress_str)<2) { continue; }
     973      if (!strstr(progress_str, "TASK")) { break; }
     974    }
     975/* report on regular+biggie files */
     976  while(!feof(fin))
     977    {
     978      fgets(progress_str, MAX_STR_LEN, fin);
     979      progress_str[MAX_STR_LEN]='\0';
     980      if (strstr(progress_str, "rchiving set 0"))
     981        { prev_percentage = 0; regulars = true; }
     982      if (strstr(progress_str, "acking up all large files"))
     983        { prev_percentage = 0; regulars = false; biggies = true; }
     984      if (strlen(progress_str)<2) { continue; }
     985      if (!strstr(progress_str, "TASK")) { continue; }
     986      progress_str[strlen(progress_str)-1] = '\0';
     987      log_it(debug, progress_str);
     988      if (!biggies && !regulars)
     989        { strcpy(progress_str, "Still working..."); }
     990      if (strcmp(progress_str, old_progstr))
     991        {
     992          strcpy(old_progstr, progress_str);
     993          if (biggies)
     994            { sprintf(rec.body, "Large files: %s", progress_str+6); }
     995          else if (regulars)
     996            { sprintf(rec.body, "Regular files: %s", progress_str+6); }
     997      if (!(p=strstr(progress_str, "% done"))) { continue; }
     998
     999          log_it(info, rec.body);
     1000          if (send_progress_rpt_to_server(g_server_name, rec.body)) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1001          continue;
     1002
     1003          while(!isdigit(*(p-1))) { p--; }
     1004          strcpy(tmp, p);
     1005          *(strchr(tmp, '%')) = '\0';
     1006          i = atoi(tmp);
     1007          if (i > prev_percentage)
     1008            {
     1009              prev_percentage = i;
     1010              log_it(info, rec.body);
     1011// FIXME - could simply call send_progress_rpt_to_server()
     1012              if (send_msg_to_server(&rec, g_server_name) < 0) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1013            }
     1014        }
     1015    }
     1016  log_it(debug, "track_backup_task_progress() --- leaving");
     1017  pthread_exit(NULL);
     1018}
     1019
     1020
     1021
     1022/*-----------------------------------------------------------*/
     1023
     1024
     1025
     1026void *track_compare_task_progress(void*inp)
     1027{
     1028  char fname[MAX_STR_LEN+1],
     1029    tmp[MAX_STR_LEN+1],
     1030    progress_str[MAX_STR_LEN+1],
     1031    old_progstr[MAX_STR_LEN+1],
     1032    *p;
     1033//  struct s_client2server_msg_record rec;
     1034  FILE*fin;
     1035  bool biggies=false, regulars=false;
     1036  int prev_percentage=0, i;
     1037
     1038  strcpy(fname, (char*)inp);
     1039  log_it(debug, "track_compare_task_progress() --- entering");
     1040  if (!(fin = fopen(fname, "r"))) { log_it(fatal, "Unable to openin tempdev while comparing"); }
     1041  old_progstr[0]='\0';
     1042  sprintf(tmp, "fname = %s", fname);
     1043  log_it(debug, tmp);
     1044  sleep(2);
     1045  if (!does_file_exist(fname)) { log_it(fatal, "track_compare_task_progress() -- fname not found"); }
     1046  log_it(debug, "Working");
     1047  if (send_progress_rpt_to_server(g_server_name, "Working")) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1048
     1049/* report on regular+biggie files */
     1050  while(!feof(fin))
     1051    {
     1052      fgets(progress_str, MAX_STR_LEN, fin);
     1053      progress_str[MAX_STR_LEN]='\0';
     1054      log_it(debug, progress_str);
     1055      if (strstr(progress_str, "erifying fileset #0"))
     1056        { prev_percentage = 0; regulars = true; }
     1057      if (strstr(progress_str, "erifying all bigfiles"))
     1058        { prev_percentage = 0; regulars = false; biggies = true; }
     1059      if (strlen(progress_str)<2) { continue; }
     1060      if (!strstr(progress_str, "TASK")) { continue; }
     1061      progress_str[strlen(progress_str)-1] = '\0';
     1062      if (!biggies && !regulars)
     1063        { strcpy(progress_str, "Still working..."); }
     1064      if (strcmp(progress_str, old_progstr))
     1065        {
     1066          strcpy(old_progstr, progress_str);
     1067          if (biggies)
     1068            { sprintf(tmp, "Large files: %s", progress_str+6); }
     1069          else if (regulars)
     1070            { sprintf(tmp, "Regular files: %s", progress_str+6); }
     1071      if (!(p=strstr(progress_str, "% done"))) { continue; }
     1072
     1073          log_it(info, tmp);
     1074          if (send_progress_rpt_to_server(g_server_name, tmp)) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1075          continue;
     1076
     1077          while(!isdigit(*(p-1))) { p--; }
     1078          strcpy(tmp, p);
     1079          *(strchr(tmp, '%')) = '\0';
     1080          i = atoi(tmp);
     1081          if (i > prev_percentage)
     1082            {
     1083              prev_percentage = i;
     1084              log_it(info, tmp);
     1085// FIXME - could simply call send_progress_rpt_to_server()
     1086              if (send_progress_rpt_to_server(g_server_name, tmp)) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1087            }
     1088        }
     1089    }
     1090  log_it(debug, "track_compare_task_progress() --- leaving");
     1091  pthread_exit(NULL);
     1092}
     1093
     1094
     1095
     1096/*-----------------------------------------------------------*/
     1097
     1098
     1099
     1100void *track_restore_task_progress(void*inp)
     1101{
     1102  char fname[MAX_STR_LEN+1],
     1103    tmp[MAX_STR_LEN+1],
     1104    progress_str[MAX_STR_LEN+1],
     1105    old_progstr[MAX_STR_LEN+1],
     1106    *p;
     1107//  struct s_client2server_msg_record rec;
     1108  FILE*fin;
     1109  bool biggies=false, regulars=false;
     1110  int prev_percentage=0, i;
     1111
     1112  strcpy(fname, (char*)inp);
     1113  log_it(debug, "track_restore_task_progress() --- entering");
     1114  if (!(fin = fopen(fname, "r"))) { log_it(fatal, "Unable to openin tempdev while restoring"); }
     1115  old_progstr[0]='\0';
     1116  sprintf(tmp, "fname = %s", fname);
     1117  log_it(debug, tmp);
     1118  sleep(2);
     1119  if (!does_file_exist(fname)) { log_it(fatal, "track_restore_task_progress() -- fname not found"); }
     1120  log_it(debug, "Working");
     1121  if (send_progress_rpt_to_server(g_server_name, "Working")) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1122
     1123// FIXME --- mondorestore does not yet spit out its progress in
     1124// a user-friendly format; so, most of the following code won't
     1125// work. The server will know we're working but it won't know
     1126// how far along we've gotten.
     1127
     1128/* report on regular+biggie files */
     1129  while(!feof(fin))
     1130    {
     1131      fgets(progress_str, MAX_STR_LEN, fin);
     1132      progress_str[MAX_STR_LEN]='\0';
     1133      continue;
     1134
     1135      log_it(debug, progress_str);
     1136      if (strstr(progress_str, "estoring fileset #0"))
     1137        { prev_percentage = 0; regulars = true; }
     1138      if (strstr(progress_str, "erifying all bigfiles"))
     1139        { prev_percentage = 0; regulars = false; biggies = true; }
     1140      if (strlen(progress_str)<2) { continue; }
     1141      if (!strstr(progress_str, "TASK")) { continue; }
     1142      progress_str[strlen(progress_str)-1] = '\0';
     1143      if (!biggies && !regulars)
     1144        { strcpy(progress_str, "Still working..."); }
     1145      if (strcmp(progress_str, old_progstr))
     1146        {
     1147          strcpy(old_progstr, progress_str);
     1148          if (biggies)
     1149            { sprintf(tmp, "Large files: %s", progress_str+6); }
     1150          else if (regulars)
     1151            { sprintf(tmp, "Regular files: %s", progress_str+6); }
     1152      if (!(p=strstr(progress_str, "% done"))) { continue; }
     1153
     1154          log_it(info, tmp);
     1155          if (send_progress_rpt_to_server(g_server_name, tmp)) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1156          continue;
     1157
     1158          while(!isdigit(*(p-1))) { p--; }
     1159          strcpy(tmp, p);
     1160          *(strchr(tmp, '%')) = '\0';
     1161          i = atoi(tmp);
     1162          if (i > prev_percentage)
     1163            {
     1164              prev_percentage = i;
     1165              log_it(info, tmp);
     1166// FIXME - could simply call send_progress_rpt_to_server()
     1167              if (send_progress_rpt_to_server(g_server_name, tmp)) { log_it(error, "Failed to send progress_rpt msg to server."); pthread_exit(NULL); }
     1168            }
     1169        }
     1170    }
     1171  log_it(debug, "track_restore_task_progress() --- leaving");
     1172  pthread_exit(NULL);
     1173}
     1174
     1175
     1176
     1177/*-----------------------------------------------------------*/
     1178
     1179
     1180
     1181void *watch_port_for_triggers_from_server(void*arg)
    3111182/*
    3121183Purpose:Watch client port for incoming trigger
    313 Params: sin - record containing info on the port/socket
    314         new_s - file descriptor of _open_ client socket
    315         s - file descriptor of client socket (not the 'open' side of it)
    316 NB:     I don't really know why new_s and s are what they are or how or why.
     1184Params: none; uses global vars instead
    3171185Return: none
     1186*/
    3181187{
    3191188  struct pollfd ufds;
    320   int len;
    321 
     1189  struct s_server2client_msg_record incoming_rec;
     1190  int len, res, new_s;
     1191  char tmp[MAX_STR_LEN+1];
     1192
     1193  strcpy(tmp,(char*)arg);
     1194  log_it(info, "Awaiting triggers from server");
    3221195  for(;;)
    3231196    {
    324   /* wait for ack/pong/feedback */
    325       ufds.fd = s;
     1197      /* wait for ack/pong/feedback/trigger */
     1198      ufds.fd = g_sClient;
    3261199      ufds.events = POLLIN|POLLPRI;
    3271200      poll(&ufds, 1, 1000);
    3281201      if (!ufds.revents) { continue; } /* wait again */
    329       len = sizeof(struct sockaddr_in);
    330       if ((new_s = accept(s, (struct sockaddr*)sin, &len)) < 0) { fprintf(stderr,"[child] Cannot accept\n"); return(1); }
    331       if ((len = recv(new_s, (char*)&incoming_rec, sizeof(incoming_rec), MSG_DONTWAIT)) <= 0) { fprintf(stderr, "[child] Cannot recv\n"); return(2); }
    332       printf("Received %s - %s\n", tmsg_to_string(incoming_rec.msg_Type, incoming_rec.body);
    333 // FIXME - should I close() after accepting and recving?
    334     }
    335 }
    336 
    337 
    338 
    339 /* main */
     1202      len = accept_and_recv_thru_client_port(g_sClient, &new_s, &g_sinClient, (char*)&incoming_rec, sizeof(incoming_rec));
     1203      if (len<0) { log_it(error, "Unable to receive incoming trigger from server"); continue; }
     1204      switch(incoming_rec.msg_type)
     1205    {
     1206    case trigger_backup:
     1207      res = back_my_smitch_up(incoming_rec.body, new_s); /* no need to multitask: it's the client! :) */
     1208      break;
     1209    case trigger_compare:
     1210      res = compare_archives(incoming_rec.body, new_s);
     1211      break;
     1212    case trigger_restore:
     1213      res = restore_archives(incoming_rec.body, incoming_rec.bodyAux, new_s);
     1214      break;
     1215        case logout_ok:
     1216          if (!g_logging_out)
     1217            { log_it(fatal, "Server has forcibly logged you out. Has server shut down?"); }
     1218          g_logged_in_currently = false;
     1219          g_logging_out = false;
     1220//    exit(0);
     1221          pthread_exit("Thou hast been logged out.");
     1222        case login_fail:
     1223          log_it(fatal, "Failed to login. Server thinks we're logged in already.");
     1224    default:
     1225      sprintf(tmp, "Received %s - '%s'", tmsg_to_string(incoming_rec.msg_type), incoming_rec.body);
     1226      log_it(info, tmp);
     1227    }
     1228      close(new_s);
     1229    }
     1230}
     1231
     1232   
     1233
     1234/*-----------------------------------------------------------*/
     1235
     1236
    3401237
    3411238int main(int argc, char*argv[])
     
    3471244{
    3481245  int client_port;
    349   char hostname[MAX_STR_LEN+1], msg[MAX_STR_LEN+1], servername[MAX_STR_LEN+1];
    350   bool done;
    351 
     1246  char hostname[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
     1247//  char msg[MAX_STR_LEN+1];
     1248//  bool done;
     1249//  pthread_t thread;
     1250
     1251  log_it(info, "---------- Monitas (client) by Hugo Rabson ----------");
     1252  register_pid(getpid(), "client");
     1253  set_signals(true);
    3521254  srandom(time(NULL));
    3531255  /* FIXME - add Ctrl-C / sigterm trapping */
    354   /* FIXME - run login/logout code as a fork and share the logged in/logged out status flag */
    355 
     1256
     1257/*
     1258  call_program_in_background(&thread, "ls aaa");
     1259  if (program_still_running("ls aaa"))
     1260    { printf("Program is still running\n"); }
     1261  else
     1262    { printf("Program is no longer running\n"); }
     1263  exit(0);
     1264*/
    3561265  if (argc == 2)
    3571266    {
    358       strncpy(servername, argv[1], MAX_STR_LEN);
    359       servername[MAX_STR_LEN]='\0';
     1267      strncpy(g_server_name, argv[1], MAX_STR_LEN);
     1268      g_server_name[MAX_STR_LEN]='\0';
    3601269    }
    3611270  else
     
    3651274    }
    3661275  gethostname(hostname, sizeof(hostname));
    367   printf("Logging onto server as client '%s'\n", hostname);
    368   client_port = login_to_server(hostname, servername);
    369   if (client_port <= 0) { fprintf(stderr, "Unable to login to server. Aborting\n"); exit(1); }
    370   for(done=false; !done; )
    371     {
    372       printf("MsgToSend: ");
    373       fgets(msg, sizeof(msg), stdin);
    374       if (!strncmp(msg, "logout", 6)) { done=true; }
    375       else
    376     {
    377       if (send_ping_to_server(msg, servername))
    378         { fprintf(stderr, "Error while waiting for response to ping\n"); exit(1); }
    379     }
    380     }
    381   printf("Logging out of server\n");
    382   if (logout_of_server(servername))
    383     { fprintf(stderr, "Warning - failed to logout of server.\n"); }
     1276  sprintf(tmp, "Logging onto server as client '%s'", hostname);
     1277  log_it(info, tmp);
     1278  client_port = login_to_server(hostname, g_server_name);
     1279  if (client_port <= 0)
     1280    {
     1281      fprintf(stderr, "Unable to login to server.\n");
     1282      log_it(error, "Unable to login to server.");
     1283      exit(1);
     1284    }
     1285
     1286//  set_param_in_rcfile(CLIENT_RCFILE, "mondoarchive_params", "-1 -L");
     1287  log_it(debug, "Awaiting commands from FIFO");
     1288  create_and_watch_fifo_for_commands(CLIENT_COMDEV);
     1289  logout_and_exit(g_server_name);
    3841290  exit(0);
    3851291}
  • branches/stable/monitas/server.c

    r351 r352  
    33
    44
    5 SERVER
    6 
    7 
    8 FIXME
    9 - when sysadm requests it:-
    10   - connect to relevant port of client
    11   - send trigger_backup msg
    12   - receive file(s)
    13   - close client's port
    14 
    15 05/20
    16 - changed 'clientname' to 'clientIP'
     506/19
     6- fixed bugs in mondoarchive compare code
     7
     806/16
     9- every 15 seconds, update /var/spool/monitas/server-status.txt file
     10- added handle_progress_rpt()
     11- modify restore_path() to allow user to restore to another path
     12
     1306/14
     14- added "2> /dev/null" to call to find /var/spool/monitas
     15- improved backup_client(), compare_client(), restore_client()
     16- pipe logs to logfile, not stdout
     17
     1806/11
     19- moved register_pid(), set_signals(), termination_in_progress() to common.c
     20- commented code a bit
     21- improved backup_client(), compare_client(), restore_client()
     22
     2306/10
     24- improved backup_client()
     25- discover whether mondoarchive returned error (ask client)
     26  and act accordingly (i.e. drop archive)
     27
     2806/09
     29- added /var/spool/monitas/input.dev FIFO to
     30  let external programs instruct me to backup
     31  or restore a given computer
     32- added signal trapping
     33
     3406/07
     35- rename transmit_file... and move
     36  to common.c, as transmit_file_to_socket()
     37- rename receive_file... and move to
     38  common.c, as receive_file_from_socket()
     39
     4005/27
     41- save bkps to /var/spool/monitas/123.456.789.012/[time]
     42
     4305/23
     44- added elementary saving/storing of incoming data
     45  from client backing itself up
     46
     4705/21
     48- added backup_client, compare_client, restore_client
     49  templates for triggers
    1750 
    185105/11
     
    3770
    3871
     72/*-----------------------------------------------------------*/
     73
     74
     75
    3976#include "structs.h"
    40 
    41 #define LOG_THESE_AND_HIGHER debug   /* debug, info, warn, error, fatal */
     77//#define LOG_THESE_AND_HIGHER debug
     78
     79
     80
    4281#define NOOF_THREADS 10
    43 
     82#define LOGFILE "/var/log/monitas-server.log"
     83#define log_it(x,y) { log_it_SUB(g_logfile,x,y); }
     84
     85
     86/* externs */
     87
     88extern bool does_file_exist(char*);
     89extern char *call_program_and_get_last_line_of_output(char*);
     90extern int call_program_and_log_output(char*);
     91extern int create_and_watch_fifo_for_commands(char*);
     92extern bool does_file_exist(char*);
     93extern void log_it_SUB(char*, t_loglevel, char *);
     94extern int make_hole_for_file (char *);
     95extern int read_block_from_fd(int socket_fd, char*buf, int len_to_read);
     96extern int receive_file_from_socket(FILE*, int);
     97extern void register_pid(pid_t, char*);
     98extern void set_signals(bool);
     99extern void termination_in_progress(int);
     100extern char *tmsg_to_string(t_msg);
     101extern int transmit_file_to_socket(FILE*,int);
    44102
    45103
     
    48106
    49107struct s_clientlist g_clientlist; /* FIXME - lock during login/logout, using mutexes */
    50 
     108char g_command_fifo[MAX_STR_LEN+1]; // Device which server will monitor for incoming commands
     109pthread_t g_threadinfo[NOOF_THREADS]; // One thread per port, to watch for requests from clients
     110char g_logfile[MAX_STR_LEN+1] = "/var/log/monitas-server.log";
     111char g_server_status_file[MAX_STR_LEN+1];
    51112
    52113
     
    54115/* prototypes */
    55116
    56 int backup_client(int,char*);
     117int backup_client(char*, int, char*);
     118int compare_client(char*, int, char*);
    57119int find_client_in_clientlist(char *);
     120int forcibly_logout_all_clients(void);
     121int forcibly_logout_client(int);
     122void* generate_server_status_file_regularly(void*);
    58123int handle_incoming_message(int, struct sockaddr_in *, struct s_client2server_msg_record *);
    59124int handle_login_request(int, struct s_client2server_msg_record *, char *);
    60125int handle_logout_request(int, struct s_client2server_msg_record *, char *);
    61126int handle_ping_request(int, struct s_client2server_msg_record *, char *);
    62 void log_it(t_loglevel, char *);
    63 int restore_client(int,char*);
    64 int send_msg_to_client(struct s_server2client_msg_record *, char *, int);
     127int handle_progress_rpt(int, struct s_client2server_msg_record *, char *);
     128int handle_user_request(int, struct s_client2server_msg_record *, char *);
     129int process_incoming_command(char*);
     130int read_block_from_fd(int, char*, int);
     131int restore_client(char*, int, char*, char*);
     132int send_msg_to_client(struct s_server2client_msg_record *, char *, int, int*);
    65133void start_threads_to_watch_ports_for_requests(void);
    66 void interact_with_sysadm(void);
     134void terminate_daemon(int);
    67135char *tmsg_to_string(t_msg);
    68136void* watch_port_for_requests_from_clients(void*);
     
    70138
    71139
    72 /* subroutines */
    73 
    74 int backup_client(int clientno, char*path)
     140/*-----------------------------------------------------------*/
     141
     142
     143
     144int backup_client(char*ipaddr, int port, char*clientpath)
    75145/*
    76146Purpose:Backup the path of a specific client. Receive
    77     the archives. Store them locally (on me, the server).
     147the archives. Store them locally (on me, the server).
    78148Params: clientno - client# in g_clientlist[]
    79     path - client's path to be backed up
     149        clientpath - client's path to be backed up
    80150Return: result (0=success, nonzero=failure)
    81151*/
    82152{
    83153  struct s_server2client_msg_record rec_to_client;
    84   int i, res=0;
    85   char tmp[MAX_STR_LEN];
    86 
    87   sprintf(tmp, "Client# = %d", clientno);
     154  int res=0, socket_fd, noof_archives, i, len;
     155  char tmp[MAX_STR_LEN+1], outfile[MAX_STR_LEN+1];
     156  FILE*fout;
     157
     158  sprintf(tmp, "%s - backup of %s commencing", ipaddr, clientpath);
     159  log_it(info, tmp);
     160  sprintf(outfile, "/var/spool/monitas/%s/%s.dat", ipaddr, call_program_and_get_last_line_of_output("date +%s"));
     161  if (does_file_exist(outfile)) { log_it(error, "Backup storage location exists already. That should be impossible."); return(1); }
     162  if (make_hole_for_file(outfile))
     163    { res++; log_it(error, "Cannot write archive to spool dir"); }
     164  else if (!(fout=fopen(outfile, "w")))
     165    { res++; log_it(fatal, "Failed to openout temp data file"); }
     166  else
     167    {
     168      sprintf(tmp, "Backing up %s - archive=%s", ipaddr, outfile);
     169      log_it(debug, tmp);
     170      rec_to_client.msg_type = trigger_backup;
     171      strncpy(rec_to_client.body, clientpath, sizeof(rec_to_client.body));
     172      if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
     173        { log_it(error, "backup_client - failed to send msg to client"); return(1); }
     174      res += receive_file_from_socket(fout, socket_fd);
     175      len=read(socket_fd, (char*)&i, sizeof(i));
     176      if (!len) { res++; log_it(error, "Client hasn't told me the result of its call to mondoarchive"); }
     177      else if (len!=sizeof(i)) { res++; log_it(error, "Client didn't sent _entire_ result of its call to mondoarchive"); }
     178      else if (i) { res++; log_it(error, "Client said, mondoarchive returned an error."); }
     179      else { log_it(debug, "Client said, mondoarchive returned OK"); }
     180      fclose(fout);
     181      close(socket_fd);
     182    }
     183/* Shuffle older backups off the mortal coil. Leave maximum of 4 backup files in /var/spool/monitas/[ipaddr] */
     184  sprintf(tmp, "find /var/spool/monitas/%s -type f 2> /dev/null | grep -n \"\" | tail -n1 | cut -d':' -f1", ipaddr);
     185  noof_archives = atoi(call_program_and_get_last_line_of_output(tmp));
     186  i = noof_archives - 3;
     187  if (i>0)
     188    {
     189      sprintf(tmp, "rm -f `find /var/spool/monitas/%s -type f | sort | head -n%d`", ipaddr, i);
     190      call_program_and_log_output(tmp);
     191    }
     192/* Return success/failure value */
     193  if (res>0)
     194    {
     195      sprintf(tmp, "%s - error(s) occurred while backing up %s", ipaddr, clientpath);
     196      log_it(error, tmp);
     197      rec_to_client.msg_type = backup_fail;
     198      sprintf(rec_to_client.body, "Failed to backup %s", clientpath);
     199      log_it(debug, rec_to_client.body);
     200      unlink(outfile);
     201    }
     202  else
     203    {
     204      sprintf(tmp, "%s - backed up %s ok", ipaddr, clientpath);
     205      log_it(info, tmp);
     206      rec_to_client.msg_type = backup_ok;
     207      sprintf(rec_to_client.body, "%s - backed up ok", clientpath);
     208      log_it(debug, rec_to_client.body);
     209    }
     210  if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
     211    {
     212      res++;
     213      sprintf(tmp, "Unable to notify %s of backup success/failure", ipaddr);
     214      log_it(error, tmp);
     215      i = find_client_in_clientlist(ipaddr);
     216      if (i>=0) { forcibly_logout_client(i); }
     217      log_it(info, "I'm assuming the backup was bad because the client cannot be reached.");
     218      unlink(outfile);
     219    }
     220  return(res);
     221}
     222
     223
     224
     225/*-----------------------------------------------------------*/
     226
     227
     228
     229int compare_client(char*ipaddr, int port, char*clientpath)
     230/*
     231Purpose:Compare the path of a specific client. Transmit
     232the archives from my (the server's) local storage loc.
     233Params: clientno - client# in g_clientlist[]
     234        clientpath - client's path to be compared
     235Return: result (0=success, nonzero=failure)
     236*/
     237{
     238  struct s_server2client_msg_record rec_to_client;
     239  int res=0, socket_fd, len, i;
     240  char tmp[MAX_STR_LEN+1], infile[MAX_STR_LEN+1];
     241  FILE*fin;
     242
     243  sprintf(tmp, "%s - comparison of %s commencing", ipaddr, clientpath);
     244  log_it(info, tmp);
     245// FIXME - don't assume the latest backup contains the files we want ;)
     246  sprintf(tmp, "find /var/spool/monitas/%s -type f | sort | tail -n1", ipaddr);
     247  strcpy(infile, call_program_and_get_last_line_of_output(tmp));
     248  sprintf(tmp, "Comparing to data file '%s'", infile);
    88249  log_it(debug, tmp);
    89   if (clientno >= g_clientlist.items)
    90     { log_it(fatal, "backup_client: clientno>=g_clientlist.items"); }
    91   sprintf(tmp, "Backing up %s - path=%s", g_clientlist.el[clientno].ipaddr, path);
    92   log_it(info, tmp);
    93   rec_to_client.msg_type = trigger_backup;
    94   strncpy(rec_to_client.body, path, sizeof(rec_to_client.body));
    95   if (send_msg_to_client(&rec_to_client, g_clientlist.el[clientno].ipaddr, g_clientlist.el[clientno].port))
    96     { log_it(error, "backup_client - failed to send msg to client"); return(1); }
    97 
    98   if (res)
    99     {
    100       sprintf(tmp, "Error(s) occurred while backing up %s", g_clientlist.el[clientno].ipaddr);
    101       log_it(error, tmp);
    102       return(1);
     250  if (!does_file_exist(infile)) { log_it(error, "Backup not found. That should be impossible."); return(1); }
     251  sprintf(tmp, "Comparing %s - archive=%s", ipaddr, infile);
     252  log_it(debug, tmp);
     253  rec_to_client.msg_type = trigger_compare;
     254  strncpy(rec_to_client.body, clientpath, sizeof(rec_to_client.body));
     255  if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
     256    { log_it(error, "compare_client - failed to send msg to client"); return(1); }
     257  if (!(fin=fopen(infile, "r")))
     258    { log_it(fatal, "Failed to openin temp data file"); }
     259  res += transmit_file_to_socket(fin, socket_fd);
     260  len=read(socket_fd, (char*)&i, sizeof(i));
     261  if (!len) { res++; log_it(error, "Client hasn't told me the result of its call to mondoarchive"); }
     262  else if (len!=sizeof(i)) { res++; log_it(error, "Client didn't sent _entire_ result of its call to mondoarchive"); }
     263  else if (i) { res++; log_it(error, "Client said, mondoarchive returned an error."); }
     264  else { log_it(debug, "Client said, mondoarchive returned OK"); }
     265  fclose(fin);
     266  close(socket_fd);
     267  if (res>0)
     268    {
     269      sprintf(tmp, "%s - error(s) occurred while comparing %s", ipaddr, clientpath);
     270      log_it(error, tmp);
     271      rec_to_client.msg_type = compare_fail;
     272      sprintf(rec_to_client.body, "Failed to compare %s", clientpath);
     273      log_it(debug, rec_to_client.body);
    103274    }
    104275  else
    105276    {
    106       sprintf(tmp, "Backed up %s OK", g_clientlist.el[clientno].ipaddr);
    107       log_it(error, tmp);
    108       return(0);
    109     }
    110 }
     277      sprintf(tmp, "%s - compared %s ok", ipaddr, clientpath);
     278      log_it(info, tmp);
     279      rec_to_client.msg_type = compare_ok;
     280      sprintf(rec_to_client.body, "%s - compared ok", clientpath);
     281      log_it(debug, rec_to_client.body);
     282    }
     283  if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
     284    {
     285      sprintf(tmp, "Unable to notify %s of compare success/failure", ipaddr);
     286      log_it(error, tmp);
     287      i = find_client_in_clientlist(ipaddr);
     288      if (i>=0) { forcibly_logout_client(i); }
     289    }
     290  return(res);
     291}
     292
     293
     294
     295/*-----------------------------------------------------------*/
     296
    111297
    112298
     
    121307{
    122308  int i;
    123   char tmp[MAX_STR_LEN];
     309  char tmp[MAX_STR_LEN+1];
    124310
    125311  for(i = 0; i < g_clientlist.items; i++)
     
    132318  return(-1);
    133319}
     320
     321
     322
     323/*-----------------------------------------------------------*/
     324
     325
     326
     327int forcibly_logout_all_clients()
     328/*
     329Purpose: Tell all clients to disconnect, right now.
     330Params:  None
     331Returns: 0=success
     332*/
     333{
     334// FIXME - lock g_clientlist for duration of this function
     335  while(g_clientlist.items>0)
     336    {
     337      forcibly_logout_client(0);
     338    }
     339  return(0);
     340}
     341
     342
     343
     344/*-----------------------------------------------------------*/
     345
     346
     347
     348int forcibly_logout_client(int clientno)
     349/*
     350Purpose: Logout specific client(#) by force.
     351Params:  Client# in g_clientlist[] array.
     352Returns: 0=success, nonzero=failure to get other end to hear me;)
     353NB:      The client was definitely removed from our login table.
     354         If the client got the message, return 0; else, nonzero.
     355*/
     356{
     357  struct s_server2client_msg_record rec_to_client;
     358  char tmp[MAX_STR_LEN+1];
     359  int res=0;
     360
     361  sprintf(tmp, "Forcibly logging %s out", g_clientlist.el[clientno].ipaddr);
     362  log_it(info, tmp);
     363  rec_to_client.msg_type = logout_ok; /* to confirm logout */
     364  strcpy(rec_to_client.body, "Server is shutting down. You are forced to logout");
     365  res=send_msg_to_client(&rec_to_client, g_clientlist.el[clientno].ipaddr, g_clientlist.el[clientno].port, NULL);
     366  if (--g_clientlist.items > 0)
     367    {
     368      sprintf(tmp, "Moving clientlist[%d] to clientlist[%d]", clientno, g_clientlist.items);
     369      log_it(debug, tmp);
     370      sprintf(tmp, "Was ipaddr=%s; now is ipaddr=", g_clientlist.el[clientno].ipaddr);
     371      memcpy((void*)&g_clientlist.el[clientno], (void*)&g_clientlist.el[g_clientlist.items], sizeof(struct s_registered_client_record));
     372      strcat(tmp, g_clientlist.el[clientno].ipaddr);
     373      log_it(debug, tmp);
     374    }
     375  return(res);
     376}
     377
     378
     379
     380/*-----------------------------------------------------------*/
     381
     382
     383void* generate_server_status_file_regularly(void*inp)
     384{
     385  int i;
     386  FILE*fout;
     387
     388  strncpy(g_server_status_file, (char*)inp, MAX_STR_LEN);
     389  for(;;)
     390    {
     391      if ((fout = fopen(g_server_status_file, "w")))
     392        {
     393// FIXME - lock g_clientlist
     394          for(i=0; i<g_clientlist.items; i++)
     395            {
     396              fprintf(fout, "%s [%s] : %s\n", g_clientlist.el[i].ipaddr, g_clientlist.el[i].hostname_pretty, g_clientlist.el[i].last_progress_rpt);
     397            }
     398          fclose(fout);
     399        }
     400      sleep(1);
     401    }
     402  exit(0);
     403}
     404
     405
     406
     407/*-----------------------------------------------------------*/
    134408
    135409
     
    145419*/
    146420{
    147   char clientIP[MAX_STR_LEN], *ptr, tmp[MAX_STR_LEN];
     421  char clientIP[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
     422  unsigned char *ptr;
    148423  int res=0;
    149424
     
    152427  sprintf(clientIP, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);
    153428  sprintf(tmp, "clientIP = %s", clientIP);
     429  log_it(debug, tmp);
     430  sprintf(tmp, "%s message from %s [%s] (port %d)", tmsg_to_string(rec->msg_type), clientIP, rec->body, rec->port);
    154431  log_it(debug, tmp);
    155432  switch(rec->msg_type)
     
    161438      res=handle_ping_request(skt, rec, clientIP);
    162439      break;
     440    case progress_rpt:
     441      res=handle_progress_rpt(skt, rec, clientIP);
     442      break;
    163443    case logout:
    164444      res=handle_logout_request(skt, rec, clientIP);
    165445      break;
     446    case user_req:
     447      res=handle_user_request(skt, rec, clientIP);
     448      break;
    166449    default:
    167       sprintf(tmp, "%s request from %s [%s] (port %d) - how do I handle it?", tmsg_to_string(rec->msg_type), clientIP, rec->body, rec->port);
    168       log_it(error, tmp);
     450      log_it(error, "...How do I handle it?");
    169451    }
    170452  return(res);
    171453}
     454
     455
     456
     457/*-----------------------------------------------------------*/
    172458
    173459
     
    185471  struct s_server2client_msg_record rec_to_client;
    186472  int clientno;
    187   char tmp[MAX_STR_LEN];
    188 
    189   sprintf(tmp, "Login request from %s [%s] (port %d)", clientIP, rec_from_client->body, rec_from_client->port);
    190   log_it(info, tmp);
     473  char tmp[MAX_STR_LEN+1];
     474
     475//FIXME - lock g_clientlist[]
    191476  clientno = find_client_in_clientlist(clientIP);
    192477  if (clientno>=0)
    193478    {
    194       rec_to_client.msg_type = fail;
     479      rec_to_client.msg_type = login_fail;
    195480      sprintf(rec_to_client.body, "Sorry, you're already logged in!");
    196481      sprintf(tmp, "Ignoring login rq from %s: he's already logged in.", clientIP);
     
    210495      strncpy(g_clientlist.el[clientno].ipaddr, clientIP, sizeof(g_clientlist.el[clientno].ipaddr));
    211496      g_clientlist.el[clientno].port = rec_from_client->port;
     497      g_clientlist.el[clientno].busy = false;
    212498      g_clientlist.items ++;
    213499      sprintf(tmp, "Login request from %s ACCEPTED", clientIP);
    214500      log_it(info, tmp);
    215     }
    216   send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port);
     501      strcpy(g_clientlist.el[clientno].last_progress_rpt, "Logged in");
     502    }
     503  send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
    217504  return(0);
    218505}
     506
     507
     508
     509/*-----------------------------------------------------------*/
    219510
    220511
     
    225516    from client.
    226517Params: skt - client's port to talk to
    227     rec_from_client - login rq record received from client
     518    rec_from_client - logout rq record received from client
    228519    clientIP - client's IP address, in string
    229520Return: result (0=success, nonzero=failure)
     
    232523  struct s_server2client_msg_record rec_to_client;
    233524  int i, res=0;
    234   char tmp[MAX_STR_LEN];
    235 
    236   sprintf(tmp, "Logout request from %s [%s] (port %d)", clientIP, rec_from_client->body, rec_from_client->port);
    237   log_it(info, tmp);
     525  char tmp[MAX_STR_LEN+1];
     526
    238527  i = find_client_in_clientlist(clientIP);
    239528  if (i<0)
     
    241530      sprintf(rec_to_client.body, "Client is not logged in yet. How can I log him out?");
    242531      log_it(error, rec_to_client.body);
    243       rec_to_client.msg_type = fail;
     532      rec_to_client.msg_type = logout_fail;
     533      res=1;
     534    }
     535  else if (g_clientlist.el[i].busy)
     536    {
     537      sprintf(rec_to_client.body, "Client is working. I shouldn't log him out.");
     538      log_it(error, rec_to_client.body);
     539      rec_to_client.msg_type = logout_fail;
    244540      res=1;
    245541    }
     
    257553      log_it(info, tmp);
    258554    }
    259   send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port);
     555  send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
    260556  return(res);
    261557}
     558
     559
     560
     561/*-----------------------------------------------------------*/
    262562
    263563
     
    268568    from client.
    269569Params: skt - client's port to talk to
    270     rec_from_client - login rq record received from client
     570    rec_from_client - ping record received from client
    271571    clientIP - client's IP address, in string
    272572Return: result (0=success, nonzero=failure)
     
    275575  struct s_server2client_msg_record rec_to_client;
    276576  int i;
    277   char tmp[MAX_STR_LEN];
    278 
    279   sprintf(tmp, "ping request from port %d --- %s", rec_from_client->port, rec_from_client->body);
    280   log_it(info, tmp);
     577  char tmp[MAX_STR_LEN+1];
     578
    281579  i = find_client_in_clientlist(clientIP);
    282580  if (i < 0)
     
    289587      rec_to_client.msg_type = pong; /* reply to ping */
    290588      sprintf(rec_to_client.body, "Hey, I'm replying to client#%d's ping. Pong! (re: %s", i, rec_from_client->body);
    291       send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port);
     589      send_msg_to_client(&rec_to_client, clientIP, rec_from_client->port, NULL);
    292590      log_it(debug, rec_to_client.body);
    293591    }
     
    297595
    298596
    299 void interact_with_sysadm()
    300 /*
    301 Purpose:Tell sysadm about users logged in, etc. in
    302     response to keypresses (1=users, ENTER=exit)
    303 Params: none
    304 Return: none
    305 NB: Called by main()
    306 */
    307 {
    308   char tmp[MAX_STR_LEN];
    309   int i;
    310   bool done;
    311 
    312   for(done=false; !done; )
    313     {
    314       printf("Type 1 to list clients\n");
    315       printf("Type 2 to backup a client\n");
    316       printf("Type 3 to restore a client\n");
    317       printf("Type ENTER to quit.\n");
    318       fgets(tmp, sizeof(tmp), stdin);
    319       if (!strcmp(tmp, "1\n"))
    320     {
    321       printf("g_clientlist.items is %d\n", g_clientlist.items);
    322       printf("List of %d clients:-\n", g_clientlist.items);
    323       printf("\tClient# Port#  IP address       Client name\n");
    324       for(i=0; i<g_clientlist.items; i++)
    325         {
    326           printf("\t%d\t%4d   %-16s %-20s \n", i, g_clientlist.el[i].port, g_clientlist.el[i].ipaddr, g_clientlist.el[i].hostname_pretty);
    327         }
    328           printf("<End of list>\n\n");
    329         }
    330       else if (!strcmp(tmp, "2\n"))
    331         {
    332       if (g_clientlist.items!=1) { printf("Forget it\n"); }
    333       else
    334         {
    335           backup_client(0, "/usr/local");
    336         }
    337     }
    338       else if (!strcmp(tmp, "3\n"))
    339         {
    340       if (g_clientlist.items!=1) { printf("Forget it\n"); }
    341       else
    342         {
    343           restore_client(0, "/usr/local");
    344         }
    345     }
    346       else if (!strcmp(tmp, "\n"))
    347         {
    348           if (g_clientlist.items > 0)
     597/*-----------------------------------------------------------*/
     598
     599
     600
     601int handle_progress_rpt(int skt, struct s_client2server_msg_record *rec_from_client, char *clientIP)
     602/*
     603Purpose:Handle a progress_rpt which has just been received
     604    from client.
     605Params: skt - client's port to talk to
     606    rec_from_client - user record received from client
     607    clientIP - client's IP address, in string
     608Return: result (0=success, nonzero=failure)
     609*/
     610{
     611//  struct s_server2client_msg_record rec_to_client;
     612  int i, res=0;
     613  char tmp[MAX_STR_LEN+1];
     614
     615  i = find_client_in_clientlist(clientIP);
     616  if (i < 0)
     617    {
     618      sprintf(tmp, "Hey, %s isn't logged in. I'm not going to deal with his progress_rpt.", clientIP);
     619      log_it(error, tmp);
     620      res++;
     621    }
     622  else
     623    {
     624      strcpy(g_clientlist.el[i].last_progress_rpt, rec_from_client->body);
     625    }
     626  return(res);
     627}
     628
     629
     630
     631/*-----------------------------------------------------------*/
     632
     633
     634
     635int handle_user_request(int skt, struct s_client2server_msg_record *rec_from_client, char *clientIP)
     636/*
     637Purpose:Handle a user request which has just been received
     638    from client.
     639Params: skt - client's port to talk to
     640    rec_from_client - user record received from client
     641    clientIP - client's IP address, in string
     642Return: result (0=success, nonzero=failure)
     643*/
     644{
     645//  struct s_server2client_msg_record rec_to_client;
     646  int i, res=0;
     647  char tmp[MAX_STR_LEN+1], command[MAX_STR_LEN+1], first_half[MAX_STR_LEN+1], second_half[MAX_STR_LEN+1], *p;
     648
     649  i = find_client_in_clientlist(clientIP);
     650  if (i < 0)
     651    {
     652      sprintf(tmp, "Hey, %s isn't logged in. I'm not going to deal with his request.", clientIP);
     653      log_it(error, tmp);
     654      res++;
     655    }
     656  else
     657    {
     658      strcpy(first_half, rec_from_client->body);
     659      p = strchr(first_half, ' ');
     660      if (!p) { second_half[0]='\0'; } else { strcpy(second_half, p); *p='\0'; }
     661      sprintf(command, "echo \"%s %s%s\" > %s", first_half, clientIP, second_half, SERVER_COMDEV);
     662      log_it(debug, command);
     663      i = system(command);
     664      if (i) { res++; log_it(error, "Failed to echo command to FIFO"); }
     665    }
     666  return(res);
     667}
     668
     669
     670
     671/*-----------------------------------------------------------*/
     672
     673
     674
     675int process_incoming_command(char*incoming)
     676/*
     677Purpose:Process incoming command, presumably
     678        read from FIFO and sent there by sysadm/user.
     679Params: incoming - raw command string itself
     680Return: result (0=success; nonzero=failure)
     681*/
     682{
     683int res=0, port;
     684int clientno;
     685char tmp[MAX_STR_LEN+1];
     686int pos;
     687char command[MAX_STR_LEN+1], ipaddr[MAX_STR_LEN+1],
     688    path[MAX_STR_LEN+1], aux[MAX_STR_LEN+1];
     689
     690//  sprintf(tmp, "incoming = '%s'", incoming);
     691//  log_it(debug, tmp);
     692          pos=0;
     693          sscanf(incoming, "%s %s %s", command, ipaddr, path);
     694          if (!strcmp(command, "restore"))
     695            { sscanf(incoming, "%s %s %s %s", command, ipaddr, path, aux); }
     696          else
     697            { aux[0] = '\0'; }
     698
     699//          for(i=0; i<strlen(command); i++) { command[i]=command[i]|0x60; }
     700          sprintf(tmp, "cmd=%s ipaddr=%s path=%s", command, ipaddr, path);
     701          log_it(debug, tmp);
     702          sprintf(tmp, "%s of %s on %s <-- command received", command, path, ipaddr);
     703          log_it(info, tmp);
     704          if ((clientno = find_client_in_clientlist(ipaddr)) < 0)
    349705            {
    350               printf("There are %d users logged in. Are you sure you want to quit? ", g_clientlist.items);
    351               fgets(tmp, sizeof(tmp), stdin);
    352               if (tmp[0]=='Y' || tmp[0]=='y')
    353                 { done=true; }
     706              sprintf(tmp, "%s not found in clientlist; so, %s failed.", ipaddr, command);
     707              log_it(error, tmp);
     708            }
     709          else if (g_clientlist.el[clientno].busy == true)
     710            {
     711              sprintf(tmp, "%s is busy; so, %s failed.", ipaddr, command);
     712              log_it(error, tmp);
    354713            }
    355714          else
    356             { done=true; }
    357           if (done)
    358             { log_it(info, "OK, you've chosen to shutdown server."); }
    359           else
    360             { log_it(info, "Shutdown canceled."); }
    361         }
    362     }
    363 }
    364 
    365 
    366 
    367 void log_it(t_loglevel level, char *sz_message)
    368 {
    369   char sz_outstr[MAX_STR_LEN], sz_level[MAX_STR_LEN], sz_time[MAX_STR_LEN];
    370   time_t time_rec;
    371 
    372   time(&time_rec);
    373   switch(level)
    374     {
    375       case debug: strcpy(sz_level, "DEBUG"); break;
    376       case info:  strcpy(sz_level, "INFO "); break;
    377       case warn:  strcpy(sz_level, "WARN "); break;
    378       case error: strcpy(sz_level, "ERROR"); break;
    379       case fatal: strcpy(sz_level, "FATAL"); break;
    380       default:    strcpy(sz_level, "UNKWN"); break;
    381     }
    382   sprintf(sz_time, ctime(&time_rec));
    383   sz_time[strlen(sz_time)-6] = '\0';
    384   sprintf(sz_outstr, "%s %s: %s", sz_time+11, sz_level, sz_message);
    385   if ((int)level >= LOG_THESE_AND_HIGHER)
    386     {
    387       fprintf(stderr, "%s\n",sz_outstr);
    388     }
    389   if (level==fatal) { fprintf(stderr,"Aborting now."); exit(1); }
    390 }
    391 
    392 
    393 
    394 
    395 int restore_client(int clientno, char*path)
    396 {
    397 }
    398 
    399 
    400 int send_msg_to_client(struct s_server2client_msg_record *rec, char *clientIP, int port)
     715            {
     716              g_clientlist.el[clientno].busy = true;
     717              port = g_clientlist.el[clientno].port;
     718              if (!strcmp(command, "backup"))
     719                { res = backup_client(ipaddr, port, path); }
     720              else if (!strcmp(command, "compare"))
     721                { res = compare_client(ipaddr, port, path); }
     722              else if (!strcmp(command, "restore"))
     723                { res = restore_client(ipaddr, port, path, aux); }
     724              else
     725                {
     726                  sprintf(tmp, "%s - cannot '%s'. Command unknown.", ipaddr, command);
     727                  log_it(error, tmp);
     728                  res=1;
     729                }
     730              g_clientlist.el[clientno].busy = false;
     731            }
     732  return(res);
     733}
     734
     735
     736
     737/*-----------------------------------------------------------*/
     738
     739
     740
     741int restore_client(char*ipaddr, int port, char*clientpath, char*auxpath)
     742/*
     743Purpose:Restore the path of a specific client. Transmit
     744the archives from my (the server's) local storage loc.
     745Params: clientno - client# in g_clientlist[]
     746        clientpath - client's path to be restored
     747Return: result (0=success, nonzero=failure)
     748*/
     749{
     750  struct s_server2client_msg_record rec_to_client;
     751  int res=0, socket_fd, len, i;
     752  char tmp[MAX_STR_LEN+1], infile[MAX_STR_LEN+1];
     753  FILE*fin;
     754
     755  sprintf(tmp, "%s - restoration of %s commencing", ipaddr, clientpath);
     756  log_it(info, tmp);
     757// FIXME - don't assume the latest backup contains the files we want ;)
     758  sprintf(tmp, "find /var/spool/monitas/%s -type f | sort | tail -n1", ipaddr);
     759  strcpy(infile, call_program_and_get_last_line_of_output(tmp));
     760  sprintf(tmp, "Restoring from data file '%s'", infile);
     761  log_it(debug, tmp);
     762  if (!does_file_exist(infile)) { log_it(error, "Backup not found. That should be impossible."); return(1); }
     763  sprintf(tmp, "Restoring %s - archive=%s", ipaddr, infile);
     764  log_it(debug, tmp);
     765  rec_to_client.msg_type = trigger_restore;
     766  strncpy(rec_to_client.body, clientpath, sizeof(rec_to_client.body));
     767  strncpy(rec_to_client.bodyAux, auxpath, sizeof(rec_to_client.bodyAux));
     768  if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
     769    { log_it(error, "restore_client - failed to send msg to client"); return(1); }
     770  if (!(fin=fopen(infile, "r")))
     771    { log_it(fatal, "Failed to openin temp data file"); }
     772  res += transmit_file_to_socket(fin, socket_fd);
     773
     774  len=read(socket_fd, (char*)&i, sizeof(i));
     775  if (!len) { res++; log_it(error, "Client hasn't told me the result of its call to mondorestore"); }
     776  else if (len!=sizeof(i)) { res++; log_it(error, "Client didn't sent _entire_ result of its call to mondorestore"); }
     777  else if (i) { res++; log_it(error, "Client said, mondorestore returned an error."); }
     778  else { log_it(debug, "Client said, mondorestore returned OK"); }
     779
     780  fclose(fin);
     781  close(socket_fd);
     782  if (res>0)
     783    {
     784      sprintf(tmp, "%s - error(s) occurred while restoring %s", ipaddr, clientpath);
     785      log_it(error, tmp);
     786      rec_to_client.msg_type = restore_fail;
     787      sprintf(rec_to_client.body, "Failed to restore %s", clientpath);
     788      log_it(debug, rec_to_client.body);
     789    }
     790  else
     791    {
     792      sprintf(tmp, "%s - restored %s ok", ipaddr, clientpath);
     793      log_it(info, tmp);
     794      rec_to_client.msg_type = restore_ok;
     795      sprintf(rec_to_client.body, "%s - restored ok", clientpath);
     796      log_it(debug, rec_to_client.body);
     797    }
     798  if (send_msg_to_client(&rec_to_client, ipaddr, port, &socket_fd))
     799    {
     800      sprintf(tmp, "Unable to notify %s of restore success/failure", ipaddr);
     801      log_it(error, tmp);
     802      i = find_client_in_clientlist(ipaddr);
     803      if (i>=0) { forcibly_logout_client(i); }
     804    }
     805  return(res);
     806}
     807
     808
     809/*-----------------------------------------------------------*/
     810
     811
     812
     813int send_msg_to_client(struct s_server2client_msg_record *rec, char *clientIP, int port, int *psocket)
    401814/*
    402815Purpose:Send a message from server to client.
    403     A 'message' could be a response to a login/logout/ping
    404     request or perhaps a 'trigger'. (A trigger is a message
    405     from server to client intended to initiate a backup
    406     or similar activity.)
     816A 'message' could be a response to a login/logout/ping
     817request or perhaps a 'trigger'. (A trigger is a message
     818from server to client intended to initiate a backup
     819or similar activity.)
    407820Params: rec - record containing the data to be sent to client
    408     clientIP - the xxx.yyy.zzz.aaa IP address of client
    409     port - the client's port to send data to
    410 Return: result (0=success, nonzero=failure)
    411 */
    412 {
    413   struct hostent *hp;
    414   struct sockaddr_in sin;
    415   int  s;
    416   char tmp[MAX_STR_LEN];
    417 
    418   if ((hp = gethostbyname(clientIP)) == NULL)
    419     {
    420       sprintf(tmp, "send_msg_to_client: %s: unknown host\n", clientIP);
    421       log_it(error, tmp);
    422       return(1);
    423     }
    424   memset((void*)&sin, 0, sizeof(sin));
    425   memcpy((void*)&sin.sin_addr, hp->h_addr, hp->h_length);
    426   sin.sin_family = AF_INET;
    427   sin.sin_addr.s_addr = INADDR_ANY;
    428   sin.sin_port = htons(port);
    429   if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    430     { perror("socket"); log_it(error, "send_msg_to_client: SOCKET error"); return(1); }
    431   if (connect(s, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)) < 0)
    432     { sprintf(tmp, "Failed to connect to client %s on port %d", clientIP, port); log_it(error, tmp); return(1); }
    433   send(s, (char*)rec, sizeof(struct s_server2client_msg_record), 0);
    434   close(s);
    435   sprintf(tmp, "Sent %s msg to %s (port %d)", tmsg_to_string(rec->msg_type), clientIP, port);
    436   log_it(debug, tmp);
    437   return(0);
    438 }
     821clientIP - the xxx.yyy.zzz.aaa IP address of client
     822port - the client's port to send data to
     823psocket - returns the socket's file descriptor, left
     824open by me; or, if psocket==NULL, then socket is closed
     825by me before I return.
     826Return: result (0=success, nonzero=failure)
     827*/
     828{
     829struct hostent *hp;
     830struct sockaddr_in sin;
     831int  s;
     832char tmp[MAX_STR_LEN+1];
     833if ((hp = gethostbyname(clientIP)) == NULL)
     834{
     835sprintf(tmp, "send_msg_to_client: %s: unknown host", clientIP);
     836log_it(error, tmp);
     837return(1);
     838}
     839memset((void*)&sin, 0, sizeof(sin));
     840memcpy((void*)&sin.sin_addr, hp->h_addr, hp->h_length);
     841sin.sin_family = AF_INET;
     842sin.sin_addr.s_addr = INADDR_ANY;
     843sin.sin_port = htons(port);
     844if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
     845{ perror("socket"); log_it(error, "send_msg_to_client: SOCKET error"); return(1); }
     846if (connect(s, (struct sockaddr*)&sin, sizeof(struct sockaddr_in)) < 0)
     847{ sprintf(tmp, "Failed to connect to client %s on port %d", clientIP, port); log_it(error, tmp); return(1); }
     848send(s, (char*)rec, sizeof(struct s_server2client_msg_record), 0);
     849if (psocket) { *psocket=s; } else { close(s); }
     850sprintf(tmp, "Sent %s msg [%s] to %s (port %d)", tmsg_to_string(rec->msg_type), rec->body, clientIP, port);
     851log_it(debug, tmp);
     852return(0);
     853}
     854
     855
     856
     857/*-----------------------------------------------------------*/
    439858
    440859
     
    450869{
    451870  int i, port, res;
    452   pthread_t threadinfo[NOOF_THREADS];
    453   char tmp[MAX_STR_LEN];
     871  char tmp[MAX_STR_LEN+1];
    454872
    455873  g_clientlist.items = 0;
     
    458876      port = 8700+i;
    459877      sprintf(tmp,"%d", port);
    460       res = pthread_create(&(threadinfo[i]), NULL, watch_port_for_requests_from_clients, (void*)tmp);
     878      res = pthread_create(&(g_threadinfo[i]), NULL, watch_port_for_requests_from_clients, (void*)tmp);
    461879      if (res != 0)
    462880        {
    463         perror("Thread creation failed");
     881      perror("Thread creation failed");
    464882        }
    465       usleep(80000);
    466     }
    467   sprintf(tmp, "Threads are now running.");
     883      usleep(50000);
     884    }
     885  sprintf(tmp, "Now monitoring ports %d thru %d for requests from clients.", 8700, 8700+NOOF_THREADS-1);
    468886  log_it(info, tmp);
    469887}
     
    471889
    472890
    473 char *tmsg_to_string(t_msg msg_type)
    474 /*
    475 Purpose:Return a string/name of the msg of type msg_type
    476 Params: msg_type - type of message (enum typedef)
    477 Return: pointer to static string {name of msg)
    478 */
    479 {
    480   static char sz_msg[MAX_STR_LEN];
    481   switch(msg_type)
    482     {
    483       case unused : strcpy(sz_msg, "unused"); break;
    484       case login  : strcpy(sz_msg, "login"); break;
    485       case logout : strcpy(sz_msg, "logout"); break;
    486       case login_ok:strcpy(sz_msg, "login_ok"); break;
    487       case logout_ok:strcpy(sz_msg, "logout_ok"); break;
    488       case ping   : strcpy(sz_msg, "ping"); break;
    489       case pong   : strcpy(sz_msg, "pong"); break;
    490       case fail   : strcpy(sz_msg, "fail"); break;
    491       case trigger_backup: strcpy(sz_msg, "trigger_backup"); break;
    492       case trigger_restore: strcpy(sz_msg, "trigger_restore"); break;
    493       case begin_stream: strcpy(sz_msg, "begin_stream"); break;
    494       case end_stream: strcpy(sz_msg, "end_stream"); break;
    495       default: strcpy(sz_msg, "(Fix tmsg_to_string please)"); break;
    496     }
    497   return(sz_msg);
    498 }
     891/*-----------------------------------------------------------*/
     892
     893
     894
     895void terminate_daemon(int sig)
     896/*
     897Purpose: Shut down the server in response to interrupt.
     898Params:  Signal received.
     899Returns: None
     900*/
     901{
     902  char command[MAX_STR_LEN+1];
     903  static bool logged_out_everyone=false;
     904
     905  set_signals(false); // termination in progress
     906  log_it(info, "Abort signal caught by interrupt handler");
     907  if (!logged_out_everyone)
     908    {
     909// FIXME - lock the var w/mutex
     910      logged_out_everyone=true;
     911      forcibly_logout_all_clients();
     912    }
     913/*
     914  for(i=0; i<NOOF_THREADS; i--)
     915    {
     916      sprintf(tmp, "Terminating thread #%d", i);
     917      log_it(debug, tmp);
     918      pthread_join(g_threadinfo[i], NULL);
     919    }
     920*/
     921  forcibly_logout_all_clients();
     922  sprintf(command, "rm -f %s", g_command_fifo);
     923  call_program_and_log_output(command);
     924//  chmod(g_command_fifo, 0);
     925  unlink(g_command_fifo);
     926  unlink(g_server_status_file);
     927  register_pid(0, "server");
     928  log_it(info, "---------- Monitas (server) has terminated ----------");
     929  exit(0);
     930}
     931
     932
     933
     934/*-----------------------------------------------------------*/
    499935
    500936
     
    514950  int watch_port;
    515951  struct sockaddr_in sin;
    516   char buf[MAX_STR_LEN+1], tmp[MAX_STR_LEN];
     952  char buf[MAX_STR_LEN+1], tmp[MAX_STR_LEN+1];
    517953  int len, s, new_s;
    518954  struct s_client2server_msg_record rec;
    519955
    520956  watch_port = atoi((char*)sz_watchport);
    521   sprintf(tmp, "watch_port_for_requests_from_clients(%d) - starting", watch_port);
    522   log_it(debug, tmp);
     957//  sprintf(tmp, "watch_port_for_requests_from_clients(%d) - starting", watch_port); log_it(debug, tmp);
    523958  memset((void*)&sin, 0, sizeof(sin));
    524959  sin.sin_family = AF_INET;
     
    544979    }
    545980  /* service incoming connections */
    546   sprintf(tmp, "Opened socket on port #%d OK", watch_port);
    547   log_it(info, tmp);
     981  sprintf(tmp, "Bound port #%d OK", watch_port);
     982  log_it(debug, tmp);
    548983  while(true)
    549984    {
     
    5681003
    5691004
     1005/*-----------------------------------------------------------*/
     1006
     1007
     1008
    5701009int main(int argc, char*argv[])
    5711010/*
     
    5751014*/
    5761015{
    577   char tmp[MAX_STR_LEN];
    578 
    579 /* FIXME - add Ctrl-C / sigterm trapping */
    580 
     1016  pthread_t server_status_thread;
     1017
     1018  log_it(info, "---------- Monitas (server) by Hugo Rabson ----------");
     1019  register_pid(getpid(), "server");
     1020  set_signals(true);
    5811021  start_threads_to_watch_ports_for_requests();
    582   interact_with_sysadm(); /* report on users logged in, etc.; return after a while... */
    583   if (g_clientlist.items != 0)
    584     { fprintf(stderr, "Ruh-roh! Some users are still logged in. Oh well...\n"); }
    585 /* FIXME - force clients to log off */
    586 /* FIXME - send signal to threads, telling them to terminate */
    587   sprintf(tmp, "Done. Server is exiting now.");
    588   log_it(info, tmp);
    589   return(0);
     1022  pthread_create(&server_status_thread, NULL, generate_server_status_file_regularly, (void*)SERVER_STATUS_FILE);
     1023  create_and_watch_fifo_for_commands(SERVER_COMDEV);
     1024  log_it(warn, "Execution should never reach this point");
     1025  exit(0);
    5901026}
    5911027/* end main() */
Note: See TracChangeset for help on using the changeset viewer.