00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "rcs_defs.hh"
00018 #include "filemem.hh"
00019 #include "cms.hh"
00020 #include "rcs_prnt.hh"
00021 #include "timer.hh"
00022
00023 #ifdef EXTERN_C_STD_HEADERS
00024 extern "C"
00025 {
00026 #endif
00027
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <errno.h>
00031
00032
00033 #ifdef USE_FCNTL_FILE_LOCKING
00034 #include <fcntl.h>
00035 #endif
00036
00037 #if defined(USE_FCNTL_FILE_LOCKING) && defined(FILEMEM_USE_SEMAPHORES)
00038 #error Can not compile with both defined(USE_FCNTL_FILE_LOCKING && FILEMEM_USE_SEMAPHORES)
00039 #endif
00040
00041 #if defined(lynxosPC) || defined(sunos4)
00042
00043
00044
00045 #include <stdio.h>
00046 #include <unistd.h>
00047
00048 static int fgetpos (FILE * stream, fpos_t * ptr);
00049 static int fsetpos (FILE * stream, const fpos_t * ptr);
00050
00051
00052
00053 int fgetpos (FILE * stream, fpos_t * ptr)
00054 {
00055 long retval;
00056
00057 retval = ftell (stream);
00058
00059 if (retval == -1L)
00060 {
00061 return -1;
00062 }
00063 else
00064 {
00065 *ptr = (fpos_t) retval;
00066 return 0;
00067 }
00068 }
00069
00070 int fsetpos (FILE * stream, const fpos_t * ptr)
00071 {
00072 return fseek (stream, (long) *ptr, SEEK_SET);
00073 }
00074
00075 #endif
00076
00077 #ifdef EXTERN_C_STD_HEADERS
00078 }
00079 #endif
00080
00081
00082 #ifndef WIN32
00083 #define MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
00084 #else
00085 #define MODE (0)
00086 #endif
00087
00088
00089 #if defined(sunos4) && !defined(SEEK_SET)
00090 #define SEEK_SET 0
00091 #endif
00092
00093
00094 FILEMEM::FILEMEM (char *bufline, char *procline, int set_to_server,
00095 int set_to_master):
00096 CMS (bufline, procline, set_to_server)
00097 {
00098 char *infile_name_string = (char *) NULL;
00099 char *outfile_name_string = (char *) NULL;
00100 char *end_name = (char *) NULL;
00101
00102 int master;
00103 master = is_local_master;
00104 if (1 == set_to_master)
00105 {
00106 master = 1;
00107 }
00108 else if (-1 == set_to_master)
00109 {
00110 master = 0;
00111 }
00112
00113 in = (FILE *) NULL;
00114 out = (FILE *) NULL;
00115 write_time = 0;
00116 last_write_time = 0;
00117 read_time = 0;
00118 last_read_time = 0;
00119 wait_period = 0;
00120 wait_start = 0;
00121 write_count = 0;
00122 write_cycle = 0;
00123 read_cycle = 0;
00124 add_waits = 0;
00125 write_file_length = 0;
00126 input_is_stdin = 0;
00127 output_is_stdout = 0;
00128
00129 if (CMS_DISPLAY_ASCII_ENCODING != neutral_encoding_method || !neutral)
00130 {
00131 rcs_print_error
00132 ("The neutral_encoding_method must be ASCII_DISPLAY_ENCODING and the buffer must be neutral format to use FILEMEM.\n");
00133 status = CMS_CONFIG_ERROR;
00134 }
00135
00136 #ifdef FILEMEM_USE_SEMAPHORES
00137
00138 if (sscanf (bufline, "%*s %*s %*s %*s %*d %*s %*s %*d %d", &key) != 1)
00139 {
00140 rcs_print_error ("FILEMEM: Invalid configuration file format.\n");
00141 return;
00142 }
00143 #endif
00144
00145 if (NULL != strstr (procline, "add_waits")
00146 || NULL != strstr (bufline, "add_waits"))
00147 {
00148 add_waits = 1;
00149 }
00150
00151
00152 outfile_name_string = strstr (procline, "out=");
00153 if (NULL == outfile_name_string)
00154 {
00155 outfile_name_string = strstr (bufline, "out=");
00156 }
00157 if (NULL != outfile_name_string)
00158 {
00159 strcpy (outfile_name, outfile_name_string + 4);
00160 end_name = strpbrk (outfile_name, " \t\n\r,;=");
00161 if (NULL != end_name)
00162 {
00163 *end_name = 0;
00164 }
00165 if (!strcmp (outfile_name, "stdout"))
00166 {
00167 output_is_stdout = 1;
00168 out = stdout;
00169 }
00170 else
00171 {
00172 out = fopen (outfile_name, "w+");
00173 if (out == NULL || ((long) out) == -1)
00174 {
00175 rcs_print_error ("FILEMEM: Can not open %s. (error = %d,%s)\n",
00176 outfile_name, errno, strerror (errno));
00177 status = CMS_CREATE_ERROR;
00178 return;
00179 }
00180 }
00181 }
00182 else
00183 {
00184 strcpy (outfile_name, "stdout");
00185 output_is_stdout = 1;
00186 out = stdout;
00187 }
00188
00189 infile_name_string = strstr (procline, "in=");
00190 if (NULL == infile_name_string)
00191 {
00192 infile_name_string = strstr (bufline, "in=");
00193 }
00194 if (NULL != infile_name_string)
00195 {
00196 strcpy (infile_name, infile_name_string + 3);
00197
00198 end_name = strpbrk (infile_name, " \t\n\r,;=");
00199 if (NULL != end_name)
00200 {
00201 *end_name = 0;
00202 }
00203 if (!strcmp (infile_name, "stdin"))
00204 {
00205 in = stdin;
00206 }
00207 else
00208 {
00209 in = fopen (infile_name, "r");
00210 if (in == NULL || ((long) in) == -1)
00211 {
00212 rcs_print_error ("FILEMEM: Can not open %s. (error = %d,%s)\n",
00213 infile_name, errno, strerror (errno));
00214 status = CMS_CREATE_ERROR;
00215 return;
00216 }
00217 }
00218 }
00219 else
00220 {
00221 strcpy (infile_name, "stdin");
00222 in = stdin;
00223 }
00224
00225 max_output_messages = -1;
00226 char *ptr;
00227 ptr = strstr (procline, "max_out=");
00228 if (NULL == ptr)
00229 {
00230 ptr = strstr (bufline, "max_out=");
00231 }
00232 if (NULL != ptr)
00233 {
00234 max_output_messages = strtol (ptr + 8, (char **) NULL, 0);
00235 }
00236
00237 #ifdef FILEMEM_USE_SEMAPHORES
00238 if (is_local_master)
00239 {
00240 sem = new RCS_SEMAPHORE (key, RCS_SEMAPHORE_CREATE, -1, (int) MODE, 1);
00241 if (NULL == sem)
00242 {
00243 rcs_print_error ("CMS: couldn't create RCS_SEMAPHORE.\n");
00244 rcs_print_error (" Possibly out of memory?\n");
00245 status = CMS_CREATE_ERROR;
00246 return;
00247 }
00248 if (!sem->valid ())
00249 {
00250 rcs_print_error ("CMS: RCS_SEMAPHORE is invalid.\n");
00251 status = CMS_MISC_ERROR;
00252 return;
00253 }
00254 }
00255 else
00256 {
00257 sem = new RCS_SEMAPHORE (key, RCS_SEMAPHORE_NOCREATE, -1);
00258 if (NULL == sem)
00259 {
00260 rcs_print_error ("CMS: couldn't create RCS_SEMAPHORE.\n");
00261 rcs_print_error (" Possibly out of memory?\n");
00262 status = CMS_CREATE_ERROR;
00263 return;
00264 }
00265 if (!sem->valid ())
00266 {
00267 rcs_print_error ("CMS: RCS_SEMAPHORE is invalid.\n");
00268 status = CMS_MISC_ERROR;
00269 return;
00270 }
00271 }
00272 #endif
00273
00274
00275
00276 fgetpos (in, &last_read_pos);
00277 fgetpos (out, &last_write_pos);
00278
00279 }
00280
00281
00282 FILEMEM::~FILEMEM ()
00283 {
00284 if (NULL != in && strcmp (infile_name, "stdin"))
00285 {
00286 fclose (in);
00287 in = (FILE *) NULL;
00288 }
00289 if (NULL != out && strcmp (outfile_name, "stdout"))
00290 {
00291 fclose (out);
00292 out = (FILE *) NULL;
00293 }
00294 #ifdef FILEMEM_USE_SEMAPHORES
00295 if (NULL != sem)
00296 {
00297 if (is_local_master || delete_totally)
00298 {
00299 sem->setflag (RCS_SEMAPHORE_CREATE);
00300 }
00301 else
00302 {
00303 sem->setflag (RCS_SEMAPHORE_NOCREATE);
00304 }
00305 delete sem;
00306 sem = (RCS_SEMAPHORE *) NULL;
00307 }
00308 #endif
00309
00310 }
00311
00312 CMS_STATUS
00313 FILEMEM::clear ()
00314 {
00315 return status;
00316 }
00317
00318 int
00319 FILEMEM::check_if_read ()
00320 {
00321 return 1;
00322 }
00323
00324 CMS_STATUS
00325 FILEMEM::read ()
00326 {
00327 char *ptr;
00328 read_time = etime ();
00329 if (read_time - wait_start < wait_period && last_read_time > 0
00330 && wait_start > 0)
00331 {
00332 return (status = CMS_READ_OLD);
00333 }
00334 wait_period = 0;
00335 if (NULL == in)
00336 {
00337 reopen_input ();
00338 }
00339
00340 if (NULL == in)
00341 {
00342 rcs_print_error ("FILE *in=NULL\n");
00343 return (status = CMS_MISC_ERROR);
00344 }
00345 if (lock_input () < 0)
00346 {
00347 return (status = CMS_MISC_ERROR);
00348 }
00349
00350 while (!feof (in))
00351 {
00352 memset (input_buffer, 0, FILEMEM_INPUT_BUFFER_SIZE);
00353 fgetpos (in, &last_read_pos);
00354 fgets (input_buffer, FILEMEM_INPUT_BUFFER_SIZE, in);
00355 if (!strncmp (input_buffer, "MSG", 3))
00356 {
00357 ptr = strstr (input_buffer, ">");
00358 if (NULL == ptr)
00359 {
00360 rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00361 unlock_input ();
00362 return (status = CMS_MISC_ERROR);
00363 }
00364 if (0 == *ptr)
00365 {
00366 rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00367 unlock_input ();
00368 return (status = CMS_MISC_ERROR);
00369 }
00370 strcpy ((char *) encoded_data, ptr + 1);
00371 last_read_time = read_time;
00372 unlock_input ();
00373 close_input ();
00374 return (status = CMS_READ_OK);
00375 }
00376 if (!strncmp (input_buffer, "WAIT", 4))
00377 {
00378 ptr = strstr (input_buffer, ">");
00379 if (NULL == ptr)
00380 {
00381 rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00382 unlock_input ();
00383 return (status = CMS_MISC_ERROR);
00384 }
00385 if (0 == *ptr)
00386 {
00387 rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00388 return (status = CMS_MISC_ERROR);
00389 }
00390 errno = 0;
00391 wait_period = strtod (ptr + 1, (char **) NULL);
00392 if (errno != 0)
00393 {
00394 rcs_print_error ("FILEMEM: Badly formatted message string.\n");
00395 unlock_input ();
00396 return (status = CMS_MISC_ERROR);
00397 }
00398 wait_start = last_read_time;
00399 if (read_time - wait_start < wait_period && last_read_time > 0
00400 && wait_start > 0)
00401 {
00402 unlock_input ();
00403 close_input ();
00404 return (status = CMS_READ_OLD);
00405 }
00406 last_read_time = read_time;
00407 }
00408 if (!strncmp (input_buffer, "REWIND", 5))
00409 {
00410 fseek (in, 0, SEEK_SET);
00411 }
00412 if (!strncmp (input_buffer, "END", 3))
00413 {
00414 fsetpos (in, &last_read_pos);
00415 unlock_input ();
00416 close_input ();
00417 return (status = CMS_READ_OLD);
00418 }
00419 }
00420 unlock_input ();
00421 close_input ();
00422 last_read_time = read_time;
00423 return (status = CMS_READ_OLD);
00424 }
00425
00426 int
00427 FILEMEM::lock_input ()
00428 {
00429 if (input_is_stdin)
00430 {
00431 return 0;
00432 }
00433 #ifdef FILEMEM_USE_SEMAPHORES
00434 if (NULL == sem)
00435 {
00436 return -1;
00437 }
00438 return sem->wait ();
00439 #endif
00440
00441
00442 #ifdef USE_FCNTL_FILE_LOCKING
00443 input_fd = fileno (in);
00444 read_lock.l_type = F_RDLCK;
00445 read_lock.l_start = 0;
00446 read_lock.l_whence = SEEK_SET;
00447 read_lock.l_len = 0;
00448 while (1)
00449 {
00450 switch (fcntl (input_fd, F_SETLK, &read_lock))
00451 {
00452 case -1:
00453 if (errno == EACCES || errno == EAGAIN)
00454 {
00455 continue;
00456 }
00457 rcs_print_error
00458 ("FILEMEM: Can not lock input file %s. (errno = %d) %s\n",
00459 infile_name, errno, strerror (errno));
00460 return -1;
00461 default:
00462 return 0;
00463 }
00464 }
00465 #endif
00466 return 0;
00467 }
00468
00469 int
00470 FILEMEM::unlock_input ()
00471 {
00472 if (input_is_stdin)
00473 {
00474 return 0;
00475 }
00476 #ifdef FILEMEM_USE_SEMAPHORES
00477 sem->post ();
00478 return 0;
00479 #endif
00480
00481 #ifdef USE_FCNTL_FILE_LOCKING
00482 read_lock.l_type = F_UNLCK;
00483 fcntl (input_fd, F_SETLK, &read_lock);
00484 #endif
00485 return 0;
00486 }
00487
00488 int
00489 FILEMEM::lock_output ()
00490 {
00491 if (output_is_stdout)
00492 {
00493 return 0;
00494 }
00495
00496 #ifdef FILEMEM_USE_SEMAPHORES
00497 if (NULL == sem)
00498 {
00499 return -1;
00500 }
00501 return sem->wait ();
00502 #endif
00503
00504 #ifdef USE_FCNTL_FILE_LOCKING
00505 output_fd = fileno (out);
00506 write_lock.l_type = F_WRLCK;
00507 write_lock.l_start = 0;
00508 write_lock.l_whence = SEEK_SET;
00509 write_lock.l_len = 0;
00510 while (1)
00511 {
00512 switch (fcntl (output_fd, F_SETLK, &write_lock))
00513 {
00514 case -1:
00515 if (errno == EACCES || errno == EAGAIN)
00516 {
00517 continue;
00518 }
00519 rcs_print_error
00520 ("FILEMEM: Can not lock input file %s. (errno = %d) %s\n",
00521 infile_name, errno, strerror (errno));
00522 return -1;
00523 default:
00524 return 0;
00525 }
00526 }
00527 #endif
00528 return 0;
00529 }
00530
00531 int
00532 FILEMEM::unlock_output ()
00533 {
00534 if (output_is_stdout)
00535 {
00536 return 0;
00537 }
00538 #ifdef FILEMEM_USE_SEMAPHORES
00539 sem->post ();
00540 return 0;
00541 #endif
00542
00543 #ifdef USE_FCNTL_FILE_LOCKING
00544 write_lock.l_type = F_UNLCK;
00545 fcntl (output_fd, F_SETLK, &write_lock);
00546 #endif
00547 return 0;
00548 }
00549
00550
00551 CMS_STATUS
00552 FILEMEM::peek ()
00553 {
00554 return read ();
00555 }
00556
00557 void
00558 FILEMEM::close_input ()
00559 {
00560 if (NULL != in && strcmp (infile_name, "stdin"))
00561 {
00562 input_file_pos = ftell (in);
00563 fseek (in, 0, SEEK_SET);
00564 fgets (input_buffer, FILEMEM_INPUT_BUFFER_SIZE, in);
00565 if (!strncmp (input_buffer, "CYCLE", 5))
00566 {
00567 char *ptr;
00568 long file_cycle;
00569 ptr = strstr (input_buffer, ">");
00570 file_cycle = strtol (ptr + 1, (char **) NULL, 0);
00571 if (file_cycle != read_cycle)
00572 {
00573 read_cycle = file_cycle;
00574 fgetpos (in, &last_read_pos);
00575 return;
00576 }
00577 }
00578 fclose (in);
00579 in = (FILE *) NULL;
00580 }
00581 }
00582
00583 void
00584 FILEMEM::reopen_input ()
00585 {
00586 if (NULL == in)
00587 {
00588 if (!strcmp (infile_name, "stdin"))
00589 {
00590 in = stdin;
00591 }
00592 else
00593 {
00594 in = fopen (infile_name, "r");
00595 if ((long) in == -1 || in == NULL)
00596 {
00597 in = (FILE *) NULL;
00598 return;
00599 }
00600 fgets (input_buffer, FILEMEM_INPUT_BUFFER_SIZE, in);
00601 if (!strncmp (input_buffer, "CYCLE", 5))
00602 {
00603 char *ptr;
00604 long file_cycle;
00605 ptr = strstr (input_buffer, ">");
00606 file_cycle = strtol (ptr + 1, (char **) NULL, 0);
00607 if (file_cycle > read_cycle)
00608 {
00609 read_cycle = file_cycle;
00610 fgetpos (in, &last_read_pos);
00611 return;
00612 }
00613 }
00614 fseek (in, input_file_pos, SEEK_SET);
00615 }
00616 }
00617 }
00618
00619 CMS_STATUS
00620 FILEMEM::write (void *user_data)
00621 {
00622 char temp_buffer[2048];
00623 long current_pos;
00624 long dist_to_end;
00625 long output_size;
00626
00627 if (NULL == out)
00628 {
00629 rcs_print_error ("FILE *out=NULL\n");
00630 return (status = CMS_MISC_ERROR);
00631 }
00632 if (lock_output () < 0)
00633 {
00634 return (status = CMS_MISC_ERROR);
00635 }
00636 write_time = etime ();
00637 write_count++;
00638 fsetpos (out, &last_write_pos);
00639 if (write_count > max_output_messages &&
00640 max_output_messages > 0 && strcmp (outfile_name, "stdout") != 0)
00641 {
00642 write_count = 0;
00643 write_cycle++;
00644 fprintf (out, "\nREWIND>%d\n", write_cycle);
00645 current_pos = ftell (out);
00646 if (current_pos > write_file_length)
00647 {
00648 write_file_length = current_pos;
00649 }
00650 dist_to_end = write_file_length - current_pos;
00651 if (dist_to_end > 0)
00652 {
00653 output_size = dist_to_end < 2048 ? dist_to_end : 2048;
00654 if (output_size <= 0)
00655 {
00656 rcs_print_error ("FILEMEM: Bad output size %d.\n", output_size);
00657 unlock_output ();
00658 return (status = CMS_MISC_ERROR);
00659 }
00660 size_t unsigned_output_size = (size_t) output_size;
00661 memset (temp_buffer, '#', output_size);
00662 size_t fwrite_ret = fwrite (temp_buffer, 1, output_size, out);
00663 if (fwrite_ret < unsigned_output_size)
00664 {
00665 rcs_print_error
00666 ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00667 outfile_name, errno, strerror (errno));
00668 unlock_output ();
00669 return (status = CMS_MISC_ERROR);
00670 }
00671 }
00672 fseek (out, 0, SEEK_SET);
00673 if (fprintf
00674 (out,
00675 "CYCLE>%d\n# Returned to the beginning of the file after %d messages.\n",
00676 write_cycle, (int) (write_cycle * max_output_messages)) < 0)
00677 {
00678 rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00679 outfile_name, errno, strerror (errno));
00680 unlock_output ();
00681 return (status = CMS_MISC_ERROR);
00682 }
00683 fgetpos (out, &last_write_pos);
00684
00685 }
00686 if (fprintf (out, "\n# time=%f, count=%d, cycle=%d",
00687 write_time, write_count, write_cycle) < 0)
00688 {
00689 rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00690 outfile_name, errno, strerror (errno));
00691 unlock_output ();
00692 return (status = CMS_MISC_ERROR);
00693 }
00694 if (add_waits)
00695 {
00696 if (fprintf (out, "\nWAIT> %f",
00697 last_write_time > 0 ? write_time - last_write_time : 0.0) <
00698 0)
00699 {
00700 rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00701 outfile_name, errno, strerror (errno));
00702 unlock_output ();
00703 return (status = CMS_MISC_ERROR);
00704 }
00705 }
00706 if (fprintf (out, "\nMSG>%s", (char *) encoded_data) < 0)
00707 {
00708 rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00709 outfile_name, errno, strerror (errno));
00710 unlock_output ();
00711 return (status = CMS_MISC_ERROR);
00712 }
00713 last_write_time = write_time;
00714
00715 fgetpos (out, &last_write_pos);
00716 if (fprintf (out, "\nEND>\n#") < 0)
00717 {
00718 rcs_print_error ("FILEMEM: Can not write to %s. (error = %d,%s)\n",
00719 outfile_name, errno, strerror (errno));
00720 unlock_output ();
00721 return (status = CMS_MISC_ERROR);
00722 }
00723 current_pos = ftell (out);
00724 if (current_pos > write_file_length)
00725 {
00726 write_file_length = current_pos;
00727 }
00728 if (fflush (out))
00729 {
00730 rcs_print_error ("FILEMEM: Error Flushing output buffer.\n",
00731 outfile_name, errno, strerror (errno));
00732 unlock_output ();
00733 return (status = CMS_MISC_ERROR);
00734 }
00735 unlock_output ();
00736 return (status = CMS_WRITE_OK);
00737 }
00738
00739 CMS_STATUS
00740 FILEMEM::write_if_read (void *user_data)
00741 {
00742 return write (user_data);
00743 }