source: trunk/athena/bin/olc/server/olcd/log.c @ 2075

Revision 2075, 16.0 KB checked in by tjcoppet, 35 years ago (diff)
no changes
Line 
1/*
2 * This file is part of the OLC On-Line Consulting System.
3 * It contains procedures for logging each conversation.
4 *
5 *      Win Treese
6 *      Dan Morgan
7 *      Bill Saphir
8 *      MIT Project Athena
9 *
10 *      Ken Raeburn
11 *      MIT Information Systems
12 *
13 *      Tom Coppeto
14 *      MIT Project Athena
15 *
16 *      Copyright (c) 1988 by the Massachusetts Institute of Technology
17 *
18 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/olc/server/olcd/log.c,v $
19 *      $Author: tjcoppet $
20 */
21
22#ifndef lint
23static char rcsid[]="$Header: /afs/dev.mit.edu/source/repository/athena/bin/olc/server/olcd/log.c,v 1.3 1989-08-22 14:02:37 tjcoppet Exp $";
24#endif
25
26
27#include <olc/olc.h>
28#include <olcd.h>
29
30#include <sys/time.h>           /* System time definitions. */
31#include <sys/types.h>          /* System type declarations. */
32#include <sys/stat.h>           /* File status definitions. */
33#include <sys/file.h>
34#include <strings.h>            /* Defs. for string functions. */
35#include <syslog.h>             /* syslog do hickies */
36
37static FILE *status_log = (FILE *)NULL;
38static FILE *error_log = (FILE *)NULL;
39
40 /*
41 * Function:    write_line_to_log() writes a single line of text into a
42 *                      log file.
43 * Arguments:   log:    A FILE pointer to the log file.
44 *              line:   A pointer to the text to be written.
45 * Returns:     Nothing.
46 * Notes:
47 *      Write the text into the file, making sure that the line ends with a
48 *      newline character.  If it does not, add one.
49 */
50
51write_line_to_log(log, line)
52        FILE *log;
53        char *line;
54{
55         
56        fprintf(log, "%s", line);
57        if (line[strlen(line) - 1] != '\n')
58                fprintf(log, "\n");
59}
60
61/*
62 * Function:    format_line_to_user_log() writes a single line of text into a
63 *                      log file.
64 * Arguments:   log:    A FILE pointer to the log file.
65 *              line:   A pointer to the text to be written.
66 * Returns:     Nothing.
67 * Notes:
68 *      Write the text into the file, making sure that the line ends with a
69 *      newline character.  If it does not, add one. This function provides
70 *      a hook for better formatting of the user logs.
71 */
72
73format_line_to_user_log(log,line)
74        FILE *log;
75        char *line;
76{
77  fprintf(log,"%s",line);
78}
79       
80/*
81 * Function:    log_message() writes a message into the log of a user's
82 *                       conversation.
83 * Arguments:   user:           Ptr. to current user structure.
84 *              message:        Message to be written into the log.
85 *              from:           Flag indicating who sent the message.
86 * Returns:     SUCCESS if the message is successfully logged, ERROR otherwise.
87 * Notes:
88 *      If we can't open the log file, record the error and return ERROR.
89 *      Otherwise, find out the time, create a header based on the sender,
90 *      and write the time, header, and message into the user's log.
91 *      Finally, update the information about the log length in the user
92 *      structure.
93 */
94
95ERRCODE
96log_log(knuckle, message, header)
97     KNUCKLE *knuckle;
98     char *message;
99     char *header;
100{
101  FILE *log;           
102  char error[DB_LINE];
103
104  if ((log = fopen(knuckle->question->logfile, "a")) == (FILE *)NULL)
105    {
106      (void) sprintf(error, "log_log: can't open log %s\n",
107              knuckle->question->logfile);
108      log_error(error);
109      return(ERROR);
110    }
111  fprintf(log, "\n%s",header);
112  format_line_to_user_log(log,message);
113
114  fclose(log);
115  return(SUCCESS);
116}
117
118
119
120log_daemon(knuckle,message)
121     KNUCKLE *knuckle;
122     char *message;
123{
124  char time[TIME_SIZE];
125  char header[DB_LINE];
126 
127  time_now(time);
128  (void) sprintf(header,"--- %s\n    [%s]\n ",message,time);
129  (void) log_log(knuckle,"",header);
130}
131
132
133log_message(owner,sender,message)
134     KNUCKLE *owner,*sender;
135     char *message;
136{
137  char time[TIME_SIZE];
138  char header[DB_LINE];
139 
140  time_now(time);
141  (void) sprintf(header, "*** Reply from %s %s@%s\n    [%s]\n",
142          sender->title, sender->user->username,
143          sender->user->machine, time);
144  (void) log_log(owner,message,header);
145}
146
147
148log_mail(owner,sender,message)
149     KNUCKLE *owner,*sender;
150     char *message;
151{
152  char time[TIME_SIZE];
153  char header[DB_LINE];
154 
155  time_now(time);
156  (void) sprintf(header, "*** Mail from %s %s@%s\n    [%s]\n",
157          sender->title, sender->user->username,
158          sender->user->machine, time);
159  (void) log_log(owner,message,header);
160}
161
162
163log_comment(owner,sender,message)
164     KNUCKLE *owner, *sender;
165     char *message;
166{
167  char time[TIME_SIZE];
168  char header[DB_LINE];
169
170  time_now(time);
171  (void) sprintf(header, "--- Comment by %s %s@%s\n    [%s]\n",
172                 sender->title,
173                 sender->user->username,
174                 sender->user->machine,time);
175
176  (void) log_log(owner,message,header);
177}
178
179
180/*
181 * Function:    log_error() writes an error message into the daemon's error
182 *                      log file.
183 * Arguments:   message:        Error message to be written.
184 * Returns:     nothing
185 * Notes:
186 *      First, open the error log file, printing an error message and dying
187 *      if an error occurs here.  Then, get the system time and print a
188 *      formatted version in the error log, followed by the error message. 
189 *      Finally, close the file and return.
190 */
191
192log_error(message)
193     char *message;
194{
195  char time_buf[32];
196  char *time_string = &time_buf[0];
197
198
199#ifdef TEST
200 
201  /*
202   * print error to stderr for debugging
203   */
204
205  error_log = stderr;
206  time_now(time_string);
207  fprintf(error_log, "%s ", time_string);
208  write_line_to_log(error_log, message);
209  return;
210#endif TEST
211
212
213#ifdef SYSLOG
214
215  /*
216   * log errors via syslog
217   */
218
219  syslog(LOG_ERR,message);
220  return;
221#endif SYSLOG
222
223#ifndef TEST
224
225  /*
226   * oh well, use homegrown logging mechanism
227   */
228
229  (void) fflush(stderr);
230  if (error_log == (FILE *)NULL)
231    {
232      error_log = fopen(ERROR_LOG, "a");
233      if (error_log == (FILE *)NULL)
234        {
235          printf("OLC log_error: Error occurred trying to log error.\n");
236          printf("Unable to open file %s\n", ERROR_LOG);
237          olc_broadcast_message("syserror", "Unable to open log file (fatal)","system");
238          olc_broadcast_message("syserror", "log errors... exitting!","system");
239          exit(1);
240        }
241    }
242
243  time_now(time_string);
244  fprintf(error_log, "%s ", time_string);
245  write_line_to_log(error_log, message);
246  olc_broadcast_message("syserror",message);
247  (void) fflush(error_log);
248#endif
249
250}
251
252/*
253 * Function:    log_status() writes a message to the olcd status log.
254 * Arguments:   message:        Message to be written.
255 * Returns:     nothing
256 * Notes:
257 *      First, open the status log file, recording an error and exiting
258 *      if one occurs.  Then, write the formatted current time and the
259 *      status message into the status log.  Finally, close the log file
260 *      and return.
261 */
262
263log_status(message)
264     char *message;
265{
266  char time_buf[32];
267
268#ifdef TEST
269
270  /*
271   * print to stderr, for debugging
272   */
273
274  status_log = stderr;
275  time_now(time_buf);
276  fprintf(status_log, "%s ", time_buf);
277  write_line_to_log(status_log, message);
278  return;
279#endif TEST
280
281#ifdef SYSLOG
282
283  /*
284   * log errors via syslog
285   */
286
287  syslog(LOG_INFO,message);
288  return;
289#endif SYSLOG
290
291#ifndef TEST
292
293  /*
294   * oh well, use homegrown logging mechanism
295   */
296
297  if (status_log == (FILE *) NULL)
298    {
299      status_log = fopen(STATUS_LOG, "a");
300      if (status_log == (FILE *)NULL)
301        {
302          log_error("log_status: can't append to status log");
303          exit(1);
304        }
305    }
306
307  time_now(time_buf);
308  fprintf(status_log, "%s ", time_buf);
309  write_line_to_log(status_log, message);
310  (void) fflush(status_log);
311
312  return;
313#endif not TEST
314}
315
316/*
317 * Function:    init_log() initializes a log file for a user.
318 * Arguments:   user:           A pointer to the user's user structure.
319 *              question:       User's initial question.
320 * Returns:     SUCCESS or ERROR.
321 * Notes:
322 *      First, construct the name of the user's log file.  Then attempt to
323 *      open the file for reading.  If the open does not fail, then a file by
324 *      that name already exists.  In this case, record an error message and
325 *      terminate the log appropriately.  Otherwise, open the
326 *      file for writing and print the initial information into the file.
327 *      Finally, close the file, update the length of the log, and return.
328 */
329
330ERRCODE
331init_log(knuckle, question)
332     KNUCKLE *knuckle;
333     char *question;
334{
335  FILE *logfile;                /* Ptr. to user's log file. */
336  char error[ERRSIZE];          /* Error message. */
337  char current_time[32];        /* Current time value. */
338  char topic[TOPIC_SIZE];       /* Real topic. */
339       
340#ifdef TEST
341  printf("init_log: %s (%d) \n %s\n",knuckle->user->username,
342         knuckle->instance, question);
343#endif TEST
344
345  (void) sprintf(knuckle->question->logfile, "%s/%s_%d.log", LOG_DIR,
346          knuckle->user->username,knuckle->instance);
347  if ((logfile = fopen(knuckle->question->logfile, "r")) != (FILE *) NULL)
348    {
349      (void) sprintf(error,
350                     "init_log: already a log file %s, moving it to log.",
351                        knuckle->question->logfile);
352      log_error(error);
353      (void) fclose(logfile);
354      (void) strcpy(topic, knuckle->question->topic);
355      (void) sprintf(knuckle->question->topic, "crash");
356      terminate_log_crash(knuckle);
357      (void) strcpy(knuckle->question->topic, topic);
358    }
359
360  if ((logfile = fopen(knuckle->question->logfile, "w")) == (FILE *)NULL)
361    {
362      (void) sprintf(error, "init_log: can't open log file %s",
363              knuckle->question->logfile);
364      log_error(error);
365      return(ERROR);
366    }
367
368  time_now(current_time);
369  fprintf(logfile, "Log Initiated for %s %s [%d] (%s@%s)\n[%s]\n\n",
370          knuckle->title,
371          knuckle->user->realname,
372          knuckle->instance,
373          knuckle->user->username,
374          knuckle->user->machine,
375          current_time);
376
377  fprintf(logfile, "Topic:\t\t%s\n\n", knuckle->question->topic);
378  fprintf(logfile, "Question:\n");
379  write_line_to_log(logfile, question);
380  write_line_to_log(logfile,"___________________________________________________________\n\n");
381  fprintf(logfile, "\n");
382  (void) fclose(logfile);
383  return(SUCCESS);
384}
385
386/*
387 * Function:    terminate_log_answered() ends an answered question.
388 * Arguments:   user:           Name of the user whose log we are closing.
389 * Returns:     SUCCESS or ERROR.
390 * Notes:
391 *      First, construct the name of the user's log file.  Then attempt to open
392 *      the file, recording an error if one occurs.  If the open is successful,
393 *      note that the conversation is over, dispose of the log, and return.
394 */
395
396ERRCODE
397terminate_log_answered(knuckle)
398     KNUCKLE *knuckle;
399{
400  QUESTION *question;
401  FILE *logfile;                /* Ptr. to user's log file. */
402  char error[ERRSIZE];          /* Error message. */
403  char time_buf[32];            /* Current time. */
404       
405  question = knuckle->question;
406  if ((logfile = fopen(question->logfile, "a")) == (FILE *)NULL)
407    {
408      perror("terminate_log_answered: fopen");
409      perror(question->logfile);
410      (void) sprintf(error,
411                     "terminate_log_answered: can't open temporary log %s",
412                     question->logfile);
413      log_error(error);
414      return(ERROR);
415    }
416
417  time_now(time_buf);
418  fprintf(logfile, "\n--- Conversation terminated at %.24s\n", time_buf);
419  fprintf(logfile, "\n--- Title: %s\n", question->title);
420
421  (void) fclose(logfile);
422  if (dispose_of_log(knuckle, ANSWERED) == ERROR)
423    return(ERROR);
424  return(SUCCESS);
425}
426
427/*
428 * Function:    terminate_log_unanswered() closes a user's log when his
429 *                      question remains unanswered.
430 * Arguments:   user:   Ptr. to current user structure.
431 * Returns:     SUCCESS or ERROR.
432 * Notes:
433 *      First, open the user's log file.  If we can't, log an error message
434 *      and return.  Otherwise, write a message about the termination into
435 *      the log and dispose of it. This should be separate in case we want
436 *      to put these elsewhere.
437 */
438
439ERRCODE
440terminate_log_unanswered(knuckle)
441     KNUCKLE *knuckle;
442{
443  QUESTION *question;
444  FILE *logfile;                /* Ptr. to user's log file. */
445  char error[ERRSIZE];  /* Error message. */
446  char current_time[32];        /* Current time. */
447 
448  question = knuckle->question;
449  if ((logfile = fopen(question->logfile, "a")) == (FILE *)NULL)
450    {
451    perror(question->logfile);
452    (void) sprintf(error,
453                   "terminate_log_unanswered: can't open temp. log %s",
454                   question->logfile);
455    log_error(error);
456    return(ERROR);
457  }
458  time_now(current_time);
459  fprintf(logfile,
460          "\n--- Session terminated without answer at %s\n",
461          current_time);
462  (void) fclose(logfile);
463  sprintf(question->topic, "oga");
464  if (dispose_of_log(knuckle, UNANSWERED) == ERROR)
465    return(ERROR);
466  return(SUCCESS);
467}
468
469/*
470 * Function:    terminate_log_crash() closes a user's log if it is left over
471 *                      by the daemon crashing.
472 * Arguments:   user:   Ptr. to current user structure.
473 * Returns:     SUCCESS or ERROR.
474 * Notes:
475 *      First, open the user's log file.  If we can't, log an error message
476 *      and return.  Otherwise, write a message about the termination into
477 *      the log and dispose of it.
478 */
479
480ERRCODE
481terminate_log_crash(knuckle)
482     KNUCKLE *knuckle;
483{
484  QUESTION *question;
485  FILE *logfile;                /* Ptr. to user's log file. */
486  char error[ERRSIZE];          /* Error message. */
487  char current_time[32];        /* Current time. */
488 
489  question = knuckle->question;
490  if ((logfile = fopen(question->logfile, "a")) == (FILE *)NULL)
491    {
492      (void) sprintf(error,
493                     "terminate_log_unanswered: can't open temp log %s",
494                     question->logfile);
495      log_error(error);
496      return(ERROR);
497    }
498  time_now(current_time);
499  fprintf(logfile, "\n--- Log file '%s' saved at after daemon crash\n[%s]",
500          index(question->logfile, '/')+1, current_time);
501  (void) fclose(logfile);
502  if (dispose_of_log(knuckle, UNANSWERED) == ERROR)
503    return(ERROR);
504  return(SUCCESS);
505}
506
507/*
508 * Function:    dispose_of_log() sends a user's log to the appropriate
509 *                      notesfile after it has been closed.
510 * Arguments:   user:           Ptr. to current user structure.
511 *              answered:       Flag indicating whether or not the question
512 *                              has been answered.
513 * Returns:     SUCCESS or ERROR.
514 * Notes:
515 *      First, construct the name of the user's log file.  Then use stat() to
516 *      find out how big it is, allocate some memory for it (plus a byte for a
517 *      NULL character at the end), and read it in, checking for errors.
518 *      Next, put a NULL at the end of the string and write the buffer to the
519 *      notesfile with the specified title.   Finally, close the file, delete
520 *      it, free the memory space, and return.
521 */
522
523ERRCODE
524dispose_of_log(knuckle, answered)
525     KNUCKLE *knuckle;
526     int answered;
527{
528  QUESTION *question;
529  char error[ERRSIZE];          /* Error message. */
530  char notesfile[NAME_LENGTH];  /* Name of notesfile. */
531  char newfile[NAME_LENGTH];    /* New file name. */
532  int fd;                       /* File descriptor of log. */
533  int pid, pid2;                /* Process ID for fork. */
534  char msgbuf[BUFSIZ];
535 
536#ifdef TEST
537  printf("dispose title: %s\n",knuckle->question->title);
538#endif TEST
539
540  question = knuckle->question;
541  (void) strcpy(newfile, question->logfile);
542  *(rindex(newfile, '/') + 1) = '\0';
543  (void) strcat(newfile, "#");
544  (void) strcat(newfile, rindex(question->logfile, '/') + 1);
545  if (rename(question->logfile, newfile) == -1)
546    {
547      perror("dispose_of_log: rename");
548      log_error("Can't rename user log.");
549      return(ERROR);
550    }
551  if ((pid = fork()) == -1)
552    {
553      perror("dispose_of_log: fork");
554      log_error("Can't fork to write to notesfile.");
555      return(ERROR);
556    }
557  else if (pid == 0)
558    {
559      (void) sprintf(notesfile, "%s%s", NF_PREFIX, question->topic);
560      (void) sprintf(msgbuf, "%s to crash",
561                     question->logfile);
562      log_status(msgbuf);
563      if ((fd = open(newfile, O_RDONLY, 0)) == -1)
564        {
565          perror("dispose_of_log: open");
566          (void) sprintf(error,
567                         "dispose_of_log: unable to open %s",
568                         question->logfile);
569          log_error(error);
570          exit(ERROR);
571        }
572      if (dup2(fd, 0) == -1) {
573        perror("dispose_of_log: dup2");
574        log_error("dispose_of_log: unable to duplicate file descriptor");
575        exit(ERROR);
576      }
577      execl("/usr/sipb/bin/dspipe", "dspipe", notesfile, "-t",question->title, 0);
578      perror("dispose_of_log: /usr/sipb/bin/dspipe");
579      (void) sprintf(error,
580                     "dispose_of_log: cannot exec /usr/sipb/bin/dspipe.\n");
581      log_error(error);
582      execl("/usr/local/dspipe", "dspipe", notesfile, "-t",question->title, 0);
583      perror("dispose_of_log: /usr/local/dspipe");
584      (void) sprintf(error,
585                     "dispose_of_log: cannot exec /usr/local/dspipe, giving up.\n");
586      log_error(error);
587      exit(0);
588    }
589  while ((pid2 = wait(0)) != pid)
590    {
591      if (pid2 == -1)
592        {
593          perror("dispose_of_log: wait");
594          return(ERROR);
595        }
596    }
597  if (unlink(newfile) == -1)
598    {
599      perror("dispose_of_log: unlink");
600      (void) sprintf(error, "dispose_of_log: Unable to remove %s",newfile);
601      log_error(error);
602    }
603  return(SUCCESS);
604}
605
606
607               
608             
Note: See TracBrowser for help on using the repository browser.