Exemple #1
0
int fputs ( const char * str, FILE * stream )
{
    //printf("INTERCEPTED fputs\n");

    clock_t start = clock();

    int ret = _fputs(str,stream);

    clock_t end = clock();

    double called_time = (double)(start-program_start)/(double)(CLOCKS_PER_SEC);

    double exec_time = (double)(end-start)/(double)(CLOCKS_PER_SEC);

    fprintf(logFile,"%lf %lf fputs %s %p = %d\n",called_time,exec_time,str,stream,ret);

    return ret;

}
Exemple #2
0
int fputs(const char *s, FILE *stream) {
  // Get libc syscall function pointer & offset in image
  libc_func(fputs, int, const char *, FILE *);
    
  if (plr_checkInsidePLR()) {
    // If already inside PLR code, just call original syscall & return
    return _fputs(s, stream);
  } else {
    plr_setInsidePLR();
    int fn = fileno(stream);
    plrlog(LOG_SYSCALL, "[%d:fputs] Write '%s' to fileno %d\n", getpid(), s, fn);
    
    syscallArgs_t args = {
      .addr = _off_fputs,
      .arg[0] = fn,
      .arg[1] = crc32(0, s, strlen(s)),
    };
    plr_checkSyscallArgs(&args);
    
    // Nested function actually performed by master process only
    int ret;
    fputsShmData_t shmDat;
    int masterAct() {
      // Call original libc function
      ret = _fputs(s, stream);
      
      // Flush/sync data to disk to help other processes see it
      fflush(stream);
      fsync(fn);
      
      // Use ftell to get new file offset
      shmDat.err = errno;
      shmDat.ret = ret;
      shmDat.offs = ftell(stream);
      shmDat.eof = feof(stream);
      shmDat.ferr = ferror(stream);
      
      // Store return value in shared memory for slave processes
      plr_copyToShm(&shmDat, sizeof(shmDat), 0);
      
      if (shmDat.ferr) {
        // Not sure how to handle passing ferror's to slaves yet, no way 
        // to manually set error state
        plrlog(LOG_ERROR, "[%d:fputs] ERROR: ferror (%d) occurred (%d)\n", getpid(), shmDat.ferr, fn);
        exit(1);
      }
      
      return 0;
    }
    // All processes call plr_masterAction() to synchronize at this point
    plr_masterAction(masterAct);
    
    if (!plr_isMasterProcess()) {
      // Slaves copy return values from shared memory
      plr_copyFromShm(&shmDat, sizeof(shmDat), 0);
      
      // Slaves seek to new fd offset
      // Can't use SEEK_CUR and advance by ret because the slave processes
      // may have been forked from each other after the fd was opened, in which
      // case the fd & its offset are shared, and that would advance more than needed
      fseek(stream, shmDat.offs, SEEK_SET);
      
      // Necessary to manually reset EOF flag because fseek clears it
      if (shmDat.eof) {
        // fgetc at EOF to set feof indicator
        int c;
        if ((c = fgetc(stream)) != EOF) {
          const char *fmt = "[%d:fputs] ERROR: fgetc to cause EOF actually got data (%c %d), ftell = %d, feof = %d\n";
          plrlog(LOG_ERROR, fmt, getpid(), c, c, ftell(stream), feof(stream));
          exit(1);
        }
      }
      if (shmDat.ferr) {
        plrlog(LOG_ERROR, "[%d:fputs] ERROR: ferror (%d) from master (%d)\n", getpid(), shmDat.ferr, fn);
        exit(1);
      }
    }
    
    // TEMPORARY
    // Slave processes sometimes end up with the wrong file offset, even after SEEK_SET
    // Compare file state at exit to make sure everything is consistent
    // Piggybacking off checkSyscallArgs mechanism to do this
    syscallArgs_t exitState = {
      .arg[0] = ftell(stream),
      .arg[1] = feof(stream),
      .arg[2] = ferror(stream),
    };
    plr_checkSyscallArgs(&exitState);
    
    // All procs return same value & errno
    ret = shmDat.ret;
    errno = shmDat.err;
    
    plr_clearInsidePLR();
    return ret;
  }
}