Esempio n. 1
0
streng *os2_beep( tsd_t *TSD, cparamboxptr parms )
{
   int freq=0,dur=1;

   checkparam(  parms,  2,  1 , "BEEP" ) ;

   if (parms && parms->value)
   {
      freq = atopos( TSD, parms->value, "BEEP", 1 ) ;
      if (freq < 37 || freq > 32767)
         exiterror( ERR_INCORRECT_CALL, 0 );
   }
   if (parms->next && parms->next->value)
   {
      dur = atopos( TSD, parms->next->value, "BEEP", 2 ) ;
      if (dur < 1 || freq > 60000)
         exiterror( ERR_INCORRECT_CALL, 0 );
   }

#if defined(WIN32)
   Beep( (DWORD)freq, (DWORD)dur );
#elif defined (__EMX__)
   if (_osmode != DOS_MODE)
      DosBeep( freq, dur );
   else
   {
      int hdl;

      /* stdout and/or stderr may be redirected */
      if ((hdl = open("con", O_WRONLY)) != -1)
      {
         write(hdl, "\x07" /* ^G == bell */, 1);
         close(hdl);
      }
   }
#elif defined(DOS)
   putchar(7);
#elif defined(OS2)
   DosBeep( freq, dur );
#elif defined(__QNX__)
   printf("\a");
#elif defined(__WATCOMC__)
   sound( freq );
   delay( dur );
   nosound( );
#elif defined(__DJGPP__)
   sound( freq );
   delay( dur );
   nosound( );
#elif defined(__WINS__) || defined(__EPOC32__)
   beep( freq, dur );
#endif
   return nullstringptr();
}
Esempio n. 2
0
static void do_signal(int signr, siginfo_t *sinfo, void *unused)
{
	printf("%ld Got signal %d\n", pthread_self(), signr);
	switch (signr) {
		case SIGINT:
		case SIGTERM:
			/* cleanup the hash cache */
			cleanup_hashes();
			/* Cleanup the RPC service */
			cleanup_service(&info);
			/* Clean up the plugins */
			capfsd_plugin_cleanup();
			/* cleanup the client-side stuff */
			clnt_finalize();
			cleanup();
			exiterror("caught SIGTERM. exiting gracefully\n");
			exit(1);
		case SIGHUP:
			PERROR( "caught SIGHUP;  Reinitializing and/or adding new plugins\n");
			/* This should hopefully find out if there are any plugins and initialize them... */
			capfsd_plugin_init();
			break;
		case SIGPIPE:
			PERROR( "caught SIGPIPE; continuing\n");
			break;
		case SIGSEGV:
			/* cleanup the hash cache */
			cleanup_hashes();
			/* Cleanup the RPC service */
			cleanup_service(&info);
			capfs_comm_shutdown();
			close_capfsdev(dev_fd);
			/* Clean up the plugins */
			capfsd_plugin_cleanup();
			/* cleanup the client-side stuff */
			clnt_finalize();
			exiterror("caught SIGSEGV\n");
			exit(1);
		default:
			/* cleanup the hash cache */
			cleanup_hashes();
			/* Cleanup the RPC service */
			cleanup_service(&info);
			capfs_comm_shutdown();
			close_capfsdev(dev_fd);
			/* Clean up the plugins */
			capfsd_plugin_cleanup();
			/* cleanup the client-side stuff */
			clnt_finalize();
			exiterror("caught unexpected signal\n");
			exit(1);
	}
}
Esempio n. 3
0
void set_trace_char( tsd_t *TSD, char ch2 )
{
   ch2 = (char) rx_toupper( ch2 );
   switch ( ch2 )
   {
      case '?':
         TSD->systeminfo->interactive = !TSD->systeminfo->interactive;
         TSD->currlevel->traceint = (char) TSD->systeminfo->interactive;
         if ( TSD->systeminfo->interactive )
            starttrace( TSD );
         break ;

      case 'F':
      case 'A':
      case 'C':
      case 'E':
      case 'I':
      case 'L':
      case 'N':
      case 'O':
      case 'R':
         TSD->currlevel->tracestat = ch2;
         break;

      default:
         exiterror( ERR_INVALID_TRACE, 1, "ACEFILNOR", ch2 );
   }

   if ( ch2 == 'O' )
      TSD->systeminfo->interactive = TSD->currlevel->traceint = 0;
   TSD->trace_stat = TSD->currlevel->tracestat;
}
Esempio n. 4
0
void queue_trace_char( const tsd_t *TSD, char ch2 )
{
   tra_tsd_t *tt;

   tt = (tra_tsd_t *)TSD->tra_tsd;
   if ( tt->bufptr0 < 32 )
      tt->buf0[tt->bufptr0++] = ch2;
   else
      exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__,
                                               "too many tracechars queued" );
}
Esempio n. 5
0
/*
 * execute_file executes a plain text script that has already been assigned
 * as the input file.
 *
 * The arguments must have been assigned, too.
 *
 * The return value is the value that the main routine should return to the OS.
 */
static int execute_file( tsd_t *TSD )
{
   FILE *fptr = TSD->systeminfo->input_fp;
   internal_parser_type parsing;
   streng *string;
   int RetCode;

   /*
    * From here we are interpreting...
    */
   fetch_file( TSD, fptr ? fptr : stdin, &parsing );
   if ( fptr )
      fclose( fptr );
   TSD->systeminfo->input_fp = NULL;

   if ( parsing.result != 0 )
      exiterror( ERR_YACC_SYNTAX, 1, parsing.tline );
   else
      TSD->systeminfo->tree = parsing;

#if !defined(MINIMAL) && !defined(VMS) && !defined(DOS) && !defined(_MSC_VER) && !defined(__IBMC__) && !defined(MAC)
   if ( !fptr )
   {
      struct stat buffer;
      int rc;

      rc = fstat( fileno( stdin ), &buffer );
      if ( ( rc == 0 ) && S_ISCHR( buffer.st_mode ) )
      {
         /*
          * FIXME. MH and FGC.
          * When does this happen. Add debugging code to determine this, because
          * after 2 glasses of rocket fuel it seems silly to have this code!
          * 13-5-2004.
          */
         printf( "  \b\b" );
         fflush( stdout );
         rewind( stdin );
      }
   }
#endif

   flush_trace_chars( TSD );

   string = interpret( TSD, TSD->systeminfo->tree.root );
   RetCode = codeFromString( TSD, string );
   if ( string )
      Free_stringTSD( string );

   return RetCode;
}
Esempio n. 6
0
/*
 * just_compile does a compile step without execution of the assigned input
 * file (TSD->systeminfo's input_file) to the file named outputname.
 *
 * On exit everything has been done.
 */
static void just_compile( tsd_t *TSD, char *outputname )
{
   int len;
   streng *SrcStr;
   internal_parser_type ipt;
   void *instore_buf;
   unsigned long instore_length;
   FILE *outfp;

   /*
    * Read the file
    */
   fseek( TSD->systeminfo->input_fp, 0, SEEK_END );
   len = (int) ftell( TSD->systeminfo->input_fp );
   rewind( TSD->systeminfo->input_fp );

   SrcStr = Str_makeTSD( len );
   if ( fread( Str_val( SrcStr ), len, 1, TSD->systeminfo->input_fp ) != 1 )
      exiterror( ERR_PROG_UNREADABLE, 1, "Unable to read input file" );
   SrcStr->len = len;

   /*
    * enter_macro() actually does the tokenising...
    */
   ipt = enter_macro( TSD, SrcStr, &instore_buf, &instore_length );
   fclose( TSD->systeminfo->input_fp );

   outfp = fopen( outputname, "wb" );
   if ( outfp == NULL )
      exiterror( ERR_PROG_UNREADABLE, 1, "Unable to open output file for "
                                                                   "writing" );
   if ( instore_buf == NULL )
      exiterror( ERR_PROG_UNREADABLE, 1, "Error tokenising input file" );
   if ( fwrite( instore_buf, instore_length, 1, outfp ) != 1 )
      exiterror( ERR_PROG_UNREADABLE, 1, "Unable to write contents of output "
                                                                      "file" );
   fclose( outfp );
}
Esempio n. 7
0
/*
 * GCI_Dispatcher is the entry point of all GCI registered functions by the
 * user.
 *
 * The function's arguments and return value depend on its usage from case
 * to case.
 */
int GCI_Dispatcher( tsd_t *TSD,
                    PFN func,
                    void *treeinfo,
                    int Params,
                    const PRXSTRING params,
                    PRXSTRING retstr )
{
   GCI_result rc;
   GCI_str disposition, direct_retval;
   GCI_str args[GCI_REXX_ARGS];
   int i, retval;

   /*
    * This trivial test should come first to be sure not to access nonexisting
    * memory. parseTree has fixed this number.
    */
   if ( Params > GCI_REXX_ARGS )
      GCIcode2ReginaFuncCode( TSD, GCI_InternalError, NULL, 1 );

   memset( args, 0, sizeof( args ) );
   for ( i = 0; i < Params; i++ )
      GCI_migrateRxString( &args[i], &params[i] );

   memset( &disposition, 0, sizeof( disposition ) );
   memset( &direct_retval, 0, sizeof( direct_retval ) );

   rc = GCI_execute( TSD,
                     (void (*)()) func,
                     (const GCI_treeinfo *) treeinfo,
                     Params,
                     args,
                     &disposition,
                     &direct_retval,
                     TSD->gci_prefix );

   if ( rc != GCI_OK )
   {
      GCI_strfree( TSD, &direct_retval ); /* not really needed hopefully */
      GCIcode2ReginaFuncCode( TSD, rc, &disposition, 1 );
   }

   retval = assignRxString( TSD, retstr, &direct_retval );
   GCI_strfree( TSD, &direct_retval );

   if ( retval )
      exiterror( ERR_STORAGE_EXHAUSTED, 0 );

   return 0;
}
Esempio n. 8
0
void set_trace( tsd_t *TSD, const streng *setting )
{
   int cptr,error;
   tra_tsd_t *tt;

   if ( myisnumber( TSD, setting ) )
   {
      cptr = streng_to_int( TSD, setting, &error );
      if ( error )
         exiterror( ERR_INVALID_INTEGER, 7, tmpstr_of( TSD, setting ) );

      /*
       * If the number is positive, interactive tracing continues
       * for the supplied number of clauses, but no pausing is done.
       * If the number is negative, no trace output is inhibited
       * (as is the pauses) for the supplied number of clauses.
       * If the number is zero, this is the same as TRACE OFF
       */
      tt = (tra_tsd_t *)TSD->tra_tsd;
      if ( cptr == 0 )
      {
         TSD->currlevel->tracestat = 'O';
         TSD->systeminfo->interactive = 0;
         TSD->currlevel->traceint = 0;
         TSD->trace_stat = TSD->currlevel->tracestat;
      }
      else if ( cptr > 0 )
      {
         tt->quiet = 0;
         tt->intercount = cptr + 1;
      }
      else
      {
         tt->quiet = 1;
         tt->intercount = -cptr + 1;
      }
   }
   else
   {
      for ( cptr = 0; cptr < Str_len( setting ); cptr++ )
      {
         set_trace_char( TSD, setting->value[cptr] );
         if ( rx_isalpha( setting->value[cptr] ) )
            return;
      }
   }
}
Esempio n. 9
0
/*
 * assign_args sets the current argument list to that one in argv. We count
 * from the next_arg element to to excluding argc.
 *
 * The value is put in TSD->currlevel->args which has to be preeassigned to
 * NULL.
 */
static void assign_args( tsd_t *TSD, int argc, int next_arg, char **argv )
{
   int i, len;
   streng *string;
   paramboxptr args, prev;

   if ( next_arg >= argc )
      return;

   if ( TSD->systeminfo->invoked == INVO_SUBROUTINE )
   {
      prev = NULL;
      for ( i = next_arg; i < argc; i++ )
      {
         args = (paramboxptr)MallocTSD( sizeof( parambox ) );
         memset( args, 0, sizeof( parambox ) );

         if ( i == next_arg )
            TSD->currlevel->args = args;
         else
            prev->next = args;
         args->value = Str_cre_TSD( TSD, argv[i] );
         prev = args;
      }

      return;
   }

   for ( i = next_arg, len = 0; i < argc; i++ )
      len += strlen( argv[i] ) + 1; /* delimiter or terminator */

   TSD->currlevel->args = (paramboxptr)MallocTSD( sizeof( parambox ) );
   if ( TSD->currlevel->args == NULL )
      exiterror( ERR_STORAGE_EXHAUSTED, 0 );
   args = TSD->currlevel->args;
   memset( args, 0, sizeof(parambox) );
   args->value = string = Str_makeTSD( len );

   for ( i = next_arg; i < argc; i++ )
   {
      string = Str_catstrTSD( string, argv[i] );
      string->value[string->len++] = ' ';
   }
   if ( string && string->len )
      string->len--;
}
Esempio n. 10
0
int init_external_queue( const tsd_t *TSD )
{
   int rc=0;
#ifdef WIN32
   WORD wsver = (WORD)MAKEWORD(1,1);
   WSADATA wsaData;
   if ( WSAStartup( wsver, &wsaData ) != 0 )
   {
      /* TSD will be NULL when called from rxqueue or rxstack */
      if ( TSD == NULL )
         showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_NO_WINSOCK, ERR_RXSTACK_NO_WINSOCK_TMPL, WSAGetLastError() );
      else if ( !TSD->called_from_saa )
         exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_NO_WINSOCK, WSAGetLastError() );
      rc = 1;
   }
#else
   TSD = TSD; /* keep compiler happy */
#endif
   return rc;
}
Esempio n. 11
0
void doparse( tsd_t *TSD, const streng *source, cnodeptr thisptr, int caseless )
{
   int start=0,point=0,length=0, end=0, nextstart=0, solid=0 ;
   const streng *pattern=NULL ;
   const streng *xtmp=NULL ;
   char tch=' ' ;

   nextstart = 0 ;  /* too keep gcc from complaining about uninitialized */
   tch = TSD->currlevel->tracestat ;
   TSD->traceparse = ((tch=='I') || (tch=='R')) ;

recurse:
   /*
    * Cache the length of source, to avoid chasing ponters later.
    * Then make pattern default to the nullstring. The nullstring is
    * so muched used, that we don't want to allocate and deallocate
    * that all the time.
    */
   length = source->len ;
   pattern = &nullstring ;

   /*
    * There are two main cases, either this is the last pattern, in
    * which case we use the rest of the string. Or either there is
    * another pattern further out, in which case we have to find it.
    *
    */
   if (thisptr->p[1])
   {
      /*
       * We are not the last pattern, so first find the next pattern.
       * First cache the type, so we don't chase pointers. There are
       * two main choises: either seek for a string of some sort, or
       * use an offset of some sort.
       */
      solid = thisptr->p[1]->type ;
      if ((solid==X_TPL_MVE)||(solid==X_TPL_VAR))
      {
         /*
          * The pattern to search for is either a literal string, or it
          * is the value hold in a variable, set pattern to whatever
          * it might be. Pattern previous points to a statically
          * allocated variable, so don't bother to deallocate.
          */
         if (solid==X_TPL_MVE)
            pattern = thisptr->p[1]->name ;
         else
            pattern = handle_var( TSD, thisptr->p[1]->p[0] ) ;
         /*
          * Then we must find where in the source string pattern occurs.
          * If it don't occur there, we use the rest of the string, else
          * we use the string up to, but not including, the first char
          * that matched pattern. The 'bmstrstr' returns -1 for not
          * found, so correct that to rest-of-string. Also note that if
          * the pattern is the nullstring, it should match the end of
          * the string.
          */
         if (Str_len(pattern))
         {
            end = bmstrstr( source, start, pattern, caseless ) ;
            if (end<0)
            {
               point = end = length ;
               nextstart = end ;
            }
            else
            {
               nextstart = end + Str_len(pattern) ;
               point = end ;
            }
         }
         else
         {
            nextstart = point = end = length ;
         }

         /*
          * While 'end' marks how much to stuff into variables, nextstart
          * marks where to start the search for the next pattern (if
          * any). Remember that patterns "eat" up the part of the
          * parse string that they match.
          */
/*       nextstart = end + Str_len(pattern) ; */
      }
      else
      {
         /*
          * The next pattern to match is not a string to match, but a
          * positional movement, which will always be numeric, and if
          * it contains a sign, that should have been stripped off during
          * parsing. But a variable may be negative, too.
          */
         if (thisptr->p[1]->name)
            xtmp = thisptr->p[1]->name ;
         else
            xtmp = handle_var( TSD, thisptr->p[1]->p[0] ) ;

         end = streng_to_int( TSD, xtmp, &nextstart ) ;
         if (nextstart)
            exiterror( ERR_INVALID_INTEGER, 4, tmpstr_of( TSD, xtmp ) );

         /*
          * Depending on what sort of positional movement, do the right
          * thing.
          */
         if (solid==X_NEG_OFFS)
         {
            /*
             * If it is a movement backwards, the concept goes something
             * like move-it-foreward-to-a-backwards-position. That is,
             * the string to be parsed continues forwards to the end of
             * the sting and stops there, while the nextposition wraps
             * round to the start again.
             *
             * Anyway, parse all the rest of the sting in this parse, and
             * start on the specified position for the next parse.
             */
            start = point ;
            nextstart = point - end ;
            end = length ;
            if (nextstart > length)
               nextstart = length;
            if (nextstart < 0)
               nextstart = 0;

            point = nextstart ;
         }

         else if (solid==X_POS_OFFS)
         {
            /*
             * If the movement is forward, it is simpler, just move the
             * position of both the end of thisptr, and the start of next
             * to the right point.
             */
            start = point ;
            nextstart = point + end ;
            if (nextstart > length)
               nextstart = length;
            if (nextstart < 0)
               nextstart = 0;
            end = nextstart ;
            if (end<=start)
               end = length ;

            point = nextstart ;
         }

         else if (solid==X_ABS_OFFS)
         {
            /*
             * Same applies if the position is absolute, just move it.
             */
            end--;
            if (end > length)
               end = length;
            if (end < 0)        /* fixes bug 1107757 */
               end = 0;

            point = nextstart = end;
            if (end <= start)
               end = length;
         }
      }
   }
   else
      /*
       * We are last pattern to match, set the end of the string to
       * be parsed to the rest of the string available.
       */
      end = nextstart = length ;

   /*
    * Make sure that we didn't do anything illegal when we pushed
    * around on the value of end and nextstart. These should have been
    * set correctly in the statements above.
    */
   assert((0<=nextstart) && (nextstart<=length)) ;

   /*
    * Then handle end. It must be _after_ the last character in
    * the pattern, while it must not be larger than length.
    */
   assert((start <= end) && (end <= length)) ;

   /*
    * Now we have marked off an area to be parsed, so call 'doparse3' to
    * put values into the variables. Note that end is decremented,
    * since doparse3 expects ptr to last char to use, not ptr to char
    * after last char to use.
    */
   if (thisptr->p[0])
   {
      doparse3( TSD, thisptr->p[0], source->value+start, end-start);
      --end;
   }

   /*
    * Then make a tailrecursive call, or rather, simulate one. This
    * operation will take care of the next set of variables to be
    * parsed values into.
    */
   if ((thisptr=thisptr->p[2]) != NULL)
   {
      start = nextstart ;
      goto recurse ;
   }

}
Esempio n. 12
0
/*
 * execute_tokenized executes a tokenized script that has already been assigned
 * as the input file.
 *
 * The arguments must have been assigned, too.
 *
 * The return value is the value that the main routine should return to the OS.
 */
static int execute_tokenized( tsd_t *TSD )
{
   void *TinnedTree;
   unsigned long TinnedTreeLen;
   streng *command;
   streng *result;
   streng *environment;
   int err,RetCode;

   /*
    * Read the file into TinnedTree.
    */
   fseek( TSD->systeminfo->input_fp, 0, SEEK_END );
   TinnedTreeLen = ftell( TSD->systeminfo->input_fp );
   rewind( TSD->systeminfo->input_fp );
   TinnedTree = MallocTSD( TinnedTreeLen );
   if ( TinnedTree == NULL )
      exiterror( ERR_STORAGE_EXHAUSTED, 0 );
   if ( fread( TinnedTree, TinnedTreeLen, 1, TSD->systeminfo->input_fp ) != 1 )
      exiterror( ERR_PROG_UNREADABLE, 1, "Unable to read input file" );
   /*
    * Don't close the file because the plain text file remains open as well.
    * This inhibits the deletion or modification on most systems.
    */

   /*
    * Check if the file being read is a valid tokenised file.
    */
   if ( !IsValidTin( (const external_parser_type *)TinnedTree, TinnedTreeLen ) )
      exiterror( ERR_PROG_UNREADABLE,
                 1,
                 "The supplied file is not a valid Regina tokenised file" );

   /*
    * Set program file name and environment. The argument have been assigned
    * already.
    */
   command = Str_dupTSD( TSD->systeminfo->input_file );

   /*
    * Changed after 3.3RC1: The environment is set to SYSTEM instead of
    * the externally bound (ENVIR_PIPE) "DEFAULT".
    */
   environment = Str_creTSD( "SYSTEM" );

   flush_trace_chars( TSD );

   /*
    * do_instore() actually does the execution...
    */
   result = do_instore( TSD, command, TSD->currlevel->args, environment,
                        &err,
                        0,
                        TinnedTree, TinnedTreeLen,
                        NULL, 0, /* source file contents */
                        NULL,
                        TSD->systeminfo->invoked );

   FreeTSD( TinnedTree );
   Free_stringTSD( command );
   Free_stringTSD( environment );

   if ( result )
   {
      RetCode = codeFromString( TSD, result );
      Free_stringTSD( result );
   }
   else
      RetCode = err;

   return RetCode;
}
Esempio n. 13
0
int main(int argc,char *argv[])
# define CALL_MAIN main
#endif
{
   tsd_t *TSD;
   int processed;
   int compile_to_tokens=0;
   int execute_from_tokens=0;
   int locale_set=0;
   int stdinput, rcode;
   jmp_buf jbuf;

#ifdef MAC
   InitCursorCtl( nil );
#endif

   if ( argv0 == NULL )
      argv0 = GetArgv0( argv[0] );

   TSD = GLOBAL_ENTRY_POINT();

   setup_system( TSD, 0 );

   if ( setjmp( jbuf ) )
   {
      /*
       * We may either be jumped normally after an EXIT instruction or after
       * an error. The first reason means normal continuation, the other
       * means that we have to do an immediate stop.
       */
      if ( !TSD->instore_is_errorfree )
      {
         if ( TSD->systeminfo->result )
            return atoi( TSD->systeminfo->result->value );
         return -1;
      }
      else
      {
         if ( TSD->systeminfo->result )
            rcode = codeFromString( TSD, TSD->systeminfo->result );
         else
            rcode = EXIT_SUCCESS;
      }
   }
   else
   {
      TSD->systeminfo->script_exit = &jbuf;

      processed = check_args( TSD, argc, argv, &compile_to_tokens,
                              &execute_from_tokens, &locale_set );

      if ( processed == 0 )
         return 0;

      if ( !locale_set )
      {
         /*
          * Check for a comma separated default locale in REGINA_LANG.
          */
         char *ptr = getenv( "REGINA_LANG" );
         if ( ptr )
            ptr = strchr( ptr, ',' );
         if ( ptr )
            set_locale_info( ptr + 1 );
      }

      if ( processed < argc )
      {
         stdinput = 0;
         TSD->systeminfo->input_file = get_external_routine( TSD,
                                argv[processed], &TSD->systeminfo->input_fp );
         if ( !TSD->systeminfo->input_file )
         {
            TSD->systeminfo->input_file = Str_crestrTSD( argv[processed] );
            exiterror( ERR_PROG_UNREADABLE, 1, "Program was not found" );
         }
         processed++;
      }
      else
      {
         stdinput = 1;
         TSD->systeminfo->input_file = Str_crestrTSD( "<stdin>" );
         TSD->systeminfo->input_fp = NULL;
         if ( compile_to_tokens )
            exiterror( ERR_PROG_UNREADABLE, 1, "Too few arguments when "
                                "tokenising. Usage: -c inputfile outputfile" );
         if ( execute_from_tokens )
            exiterror( ERR_PROG_UNREADABLE, 1, "Cannot run tokenised code "
                                                               "from stdin." );
      }


      /*
       * -c switch specified - tokenise the input file before mucking around
       * with parameters etc.
       */
      if ( compile_to_tokens )
      {
         if ( processed >= argc )
            exiterror( ERR_PROG_UNREADABLE, 1, "Too few arguments when "
                                "tokenising. Usage: -c inputfile outputfile" );
         if ( processed + 1 < argc )
            exiterror( ERR_PROG_UNREADABLE, 1, "Too many arguments when "
                                "tokenising. Usage: -c inputfile outputfile" );

         just_compile( TSD, argv[processed] );
         return 0;
      }

      /*
       * Under DJGPP setmode screws up Parse Pull and entering code
       * interactively :-(
       */
#if defined(__EMX__) || (defined(_MSC_VER) && !defined(__WINS__)) || (defined(__WATCOMC__) && !defined(__QNX__))
      setmode( fileno( stdin ), O_BINARY );
      setmode( fileno( stdout ), O_BINARY );
      setmode( fileno( stderr ), O_BINARY );
#endif

      assign_args( TSD, argc, processed, argv );
      signal_setup( TSD );

      /*
       * -e switch specified - execute from tokenised code
       */
      if ( execute_from_tokens )
         rcode = execute_tokenized( TSD );
      else
         rcode = execute_file( TSD );
   }

#if defined(DEBUG) || defined(TRACEMEM)
   /*
    * Now do the cleanup. We don't need in real life, but for a proper cleanup
    * and for debugging aid it is a good idea to track down the whole beast.
    */
   purge_stacks( TSD );
   purge_filetable( TSD );
# if defined(FLISTS) && defined(NEW_FLISTS)
   free_flists();
# endif

# ifdef DYNAMIC
   /*
    * Remove all external function package functions
    * and libraries. Only valid for the DYNAMIC library.
    */
   purge_library( TSD );
# endif

# ifdef TRACEMEM
   if ( TSD->listleakedmemory )
      listleaked( TSD, MEMTRC_LEAKED );
# endif

   TSD->systeminfo->script_exit = NULL; /* cannot be freed, it's on the stack*/
   killsystem( TSD, TSD->systeminfo );
   TSD->systeminfo = NULL;

   /*
    * Remove all memory allocated by the flists internal memory manager.
    */
# ifdef FLISTS
   purge_flists( TSD );
# endif

#endif /* DEBUG */

   return rcode;
}
Esempio n. 14
0
tsd_t *ReginaInitializeProcess(void)
{
   int OK;

   if (__regina_tsd_initialized)
      return(&__regina_tsd);
   __regina_tsd_initialized = 1;

                                        /* Set up the current (single) tsd_t:*/
                                        /* Default all values to zero        */
   memset(&__regina_tsd,0,sizeof(__regina_tsd));
   __regina_tsd.MTMalloc = MTMalloc;
   __regina_tsd.MTFree = MTFree;
   __regina_tsd.MTExit = MTExit;

   /* Since the local data structure contains a memory chain for the memory
    * management we initialize it first.
    */
   if ((__regina_tsd.mt_tsd = malloc(sizeof(mt_tsd_t))) == NULL)
      return(NULL);                     /* This is a catastrophy             */
   memset(__regina_tsd.mt_tsd,0,sizeof(mt_tsd_t));

   OK = init_memory(&__regina_tsd);     /* Initialize the memory module FIRST*/

   /* Without the initial memory we don't have ANY chance! */
   if (!OK)
      return(NULL);

   /*
    * Some systems with an own MT file don't compile in MT mode. But they
    * still are systems of that kind.
    */
#if defined(WIN32) || defined(__WIN32__)
   {
      extern OS_Dep_funcs __regina_OS_Win;
      __regina_tsd.OS = &__regina_OS_Win;
   }
#elif defined(OS2) && !defined(DOS)
   {
      extern OS_Dep_funcs __regina_OS_Os2;
      __regina_tsd.OS = &__regina_OS_Os2;
   }
#elif defined(GO32)
   {
      extern OS_Dep_funcs __regina_OS_Other;
      __regina_tsd.OS = &__regina_OS_Other;
   }
#elif defined(unix) || defined(__unix__) || defined(__unix) || defined(__QNX__) || defined(__BEOS__) || defined(SKYOS) || ( defined( __APPLE_CC__ ) && defined( __MACH__ ) )
   {
      extern OS_Dep_funcs __regina_OS_Unx;
      __regina_tsd.OS = &__regina_OS_Unx;
   }
#else
   {
      extern OS_Dep_funcs __regina_OS_Other;
      __regina_tsd.OS = &__regina_OS_Other;
   }
#endif
   __regina_tsd.OS->init();
   OK |= init_vars(&__regina_tsd);      /* Initialize the variable module    */
   OK |= init_stacks(&__regina_tsd);    /* Initialize the stack module       */
   OK |= init_filetable(&__regina_tsd); /* Initialize the files module       */
   OK |= init_math(&__regina_tsd);      /* Initialize the math module        */
   OK |= init_spec_vars(&__regina_tsd); /* Initialize the interprt module    */
   OK |= init_tracing(&__regina_tsd);   /* Initialize the tracing module     */
   OK |= init_builtin(&__regina_tsd);   /* Initialize the builtin module     */
   OK |= init_client(&__regina_tsd);    /* Initialize the client module      */
   OK |= init_library(&__regina_tsd);   /* Initialize the library module     */
   OK |= init_rexxsaa(&__regina_tsd);   /* Initialize the rexxsaa module     */
   OK |= init_shell(&__regina_tsd);     /* Initialize the shell module       */
   OK |= init_envir(&__regina_tsd);     /* Initialize the envir module       */
   OK |= init_expr(&__regina_tsd);      /* Initialize the expr module        */
   OK |= init_error(&__regina_tsd);     /* Initialize the error module       */
#ifdef VMS
   OK |= init_vms(&__regina_tsd);       /* Initialize the vmscmd module      */
   OK |= init_vmf(&__regina_tsd);       /* Initialize the vmsfuncs module    */
#endif
   OK |= init_arexxf(&__regina_tsd);    /* Initialize the arxfuncs modules */
   __regina_tsd.loopcnt = 1;            /* stupid r2perl-module              */
   __regina_tsd.traceparse = -1;
   __regina_tsd.thread_id = 1;

   if (!OK)
      exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;

   return(&__regina_tsd);
}
Esempio n. 15
0
/*
 * Returns the translated function code from GCI_result to the code that
 * Regina shall return to the caller.
 * This function set the textual representation of an error code to that value
 * that will be accessed by RxFuncErrMsg() and sets the variable GCI_RC to
 * that value, too.
 *
 * dispo is either NULL (or the content is NULL) or contains the position of
 * the error within the structure. dispo's content will be deallocated.
 */
static int GCIcode2ReginaFuncCode( tsd_t *TSD,
                                   GCI_result rc,
                                   GCI_str *dispo,
                                   int forceError )
{
   GCI_str description, fullinfo, *fi = NULL, *out;
   volatile char *tmpDispo, *tmpFull = NULL, *tmpBest;
   streng *h;
   char GCI_RC[7];
   GCI_strOfCharBuffer(GCI_RC);

   GCI_strcats( &str_GCI_RC, "GCI_RC" );
   GCI_describe( &description, rc );

   if ( ( dispo != NULL ) && ( GCI_content( dispo ) == NULL ) )
      dispo = NULL;

   if ( ( dispo != NULL ) && ( rc != GCI_OK ) )
   {
      if ( GCI_stralloc( TSD, &fullinfo, GCI_strlen( dispo ) +
                                         GCI_strlen( &description ) +
                                         3 ) == GCI_OK )
      {
         fi = &fullinfo;
         GCI_strcpy( fi, &description );
         GCI_strcats( fi, ": " );
         GCI_strcat( fi, dispo );
      }
   }

   out = ( fi != NULL ) ? fi : &description;
   GCI_writeRexx( TSD, &str_GCI_RC, out, 0 );

   if ( ( rc == GCI_OK ) && !forceError )
   {
      if ( dispo != NULL )
         GCI_strfree( TSD, dispo );
      if ( fi != NULL )
         GCI_strfree( TSD, fi );
      return 0;
   }

   h = streng_of( TSD, &description );
   tmpDispo = tmpstr_of( TSD, h );
   Free_stringTSD( h );

   if ( fi != NULL )
   {
      h = streng_of( TSD, fi );
      tmpFull = tmpstr_of( TSD, h );
      Free_stringTSD( h );
   }

   if ( dispo != NULL )
      GCI_strfree( TSD, dispo );
   if ( fi != NULL )
      GCI_strfree( TSD, fi );

   /*
    * We have two temporary strings describing the error condition.
    * All stuff we have to deallocate is deallocated. Let's go.
    */
   tmpBest = ( tmpFull != NULL ) ? tmpFull : tmpDispo;
   set_err_message( TSD, (char *) tmpBest, "" );

   switch ( rc )
   {
      case GCI_NoMemory:
         exiterror( ERR_STORAGE_EXHAUSTED, 0 );

      case GCI_WrongInput:
         exiterror( ERR_INCORRECT_CALL, 980, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_NumberRange:
         exiterror( ERR_INCORRECT_CALL, 981, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_StringRange:
         exiterror( ERR_INCORRECT_CALL, 982, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_UnsupportedType:
         if ( !forceError )
            return 71; /* RXFUNC_BADTYPE + 1 */
         exiterror( ERR_INCORRECT_CALL, 983, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_UnsupportedNumber:
         exiterror( ERR_INCORRECT_CALL, 984, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_BufferTooSmall:
         exiterror( ERR_INCORRECT_CALL, 985, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_MissingName:
         exiterror( ERR_INCORRECT_CALL, 986, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_MissingValue:
         exiterror( ERR_INCORRECT_CALL, 987, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_IllegalName:
         exiterror( ERR_INCORRECT_CALL, 988, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_RexxError:
         exiterror( ERR_INCORRECT_CALL, 989, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_NoBaseType:
         exiterror( ERR_INCORRECT_CALL, 990, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_SyntaxError:
         exiterror( ERR_INCORRECT_CALL, 991, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_ArgStackOverflow:
         exiterror( ERR_INCORRECT_CALL, 992, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      case GCI_NestingOverflow:
         exiterror( ERR_INCORRECT_CALL, 993, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );

      default:
         break;
   }
   exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, tmpBest );
   return 0; /* Keep the compiler happy */
}
Esempio n. 16
0
int main(int argc, char **argv)
{
	int err;
	struct capfs_upcall up;
	struct capfs_downcall down;
	struct capfs_dirent *dent = NULL;
	char *link_name = NULL;
	int opt = 0;
	int capfsd_log_level = CRITICAL_MSG | WARNING_MSG;
	char options[256];
	struct cas_options cas_options = {
doInstrumentation:0,
use_sockets:0,
	};

#ifdef DEBUG
	capfsd_log_level |= INFO_MSG;
	capfsd_log_level |= DEBUG_MSG;
#endif
	set_log_level(capfsd_log_level);
	/* capfsd must register a callback with the meta-data server at the time of mount */
	check_for_registration = 1;
	while((opt = getopt(argc, argv, "dhsn:p:")) != EOF) {
		switch(opt){
			case 's':
				cas_options.use_sockets = 1;
				break;
			case  'd':
				is_daemon = 0;
				break;
			case 'p':
				err = sscanf(optarg, "%x", &capfs_debug);
				if(err != 1){
					usage();
					exiterror("bad arguments");
					exit(1);
				}
				break;
			case 'n':
				num_threads = atoi(optarg);
				break;
			case 'h':
				usage();
				exit(0);
			case '?':
			default:
				usage();
				exiterror("bad arguments");
				exit(1);
		}
	}
		
	if (getuid() != 0 && geteuid() != 0) {
		exiterror("must be run as root");
		exit(1);
	}

	if (setup_capfsdev() < 0) {
		exiterror("setup_capfsdev() failed");
		exit(1);
	}

	if ((dev_fd = open_capfsdev()) < 0) {
		exiterror("open_capfsdev() failed");
		exit(1);
	}
	
	startup(argc, argv);
	/* Initialize the plugin interface */
	capfsd_plugin_init();

	capfs_comm_init();


	/* allocate a 64K, page-aligned buffer for small operations */
	capfs_opt_io_size = ROUND_UP(CAPFS_OPT_IO_SIZE);
	if ((orig_iobuf = (char *) valloc(capfs_opt_io_size)) == NULL) {
		exiterror("calloc failed");
		capfsd_plugin_cleanup();
		exit(1);
	}
	memset(orig_iobuf, 0, capfs_opt_io_size);
	capfs_dent_size = ROUND_UP((FETCH_DENTRY_COUNT * sizeof(struct capfs_dirent)));
	/* allocate a suitably large dent buffer for getdents speed up */
	if ((dent = (struct capfs_dirent *) valloc(capfs_dent_size)) == NULL) {
		exiterror("calloc failed");
		capfsd_plugin_cleanup();
		exit(1);
	}
	memset(dent, 0, capfs_dent_size);
	/* maximum size of a link target cannot be > 4096 */
	capfs_link_size = ROUND_UP(4096);
	link_name = (char *) valloc(capfs_link_size);
	if(!link_name) {
		exiterror("calloc failed");
		capfsd_plugin_cleanup();
		exit(1);
	}
	memset(link_name, 0, capfs_link_size);
	
	fprintf(stderr, "------------ Starting client daemon servicing VFS requests using a thread pool [%d threads] ----------\n",
			num_threads);
	/*
	 * Start up the local RPC service on both TCP/UDP 
	 * for callbacks.
	 */
	pmap_unset(CAPFS_CAPFSD, clientv1);
	if (setup_service(CAPFS_CAPFSD /* program number */,
				clientv1 /* version */,
				-1 /* both tcp/udp */,
				-1 /* any available port */,
				CAPFS_DISPATCH_FN(clientv1) /* dispatch routine */,
				&info) < 0) {
		exiterror("Could not setup local RPC service!\n");
		capfsd_plugin_cleanup();
		exit(1);
	}
	/*
	 * Initialize the hash cache.
	 * Note that we are using default values of cache sizes,
	 * and this should probably be an exposed knob to the user.
	 * CMGR_BSIZE is == CAPFS_MAXHASHLENGTH for SHA1-hash. So we dont need to set
	 * that. We use environment variables to communicate the parameters
	 * to the caches.
	 */
	snprintf(options, 256, "%d", CAPFS_CHUNK_SIZE);
	setenv("CMGR_CHUNK_SIZE", options, 1);
	snprintf(options, 256, "%d", CAPFS_HCACHE_COUNT);
	setenv("CMGR_BCOUNT", options, 1);
	init_hashes();
#if 0
	/*
	 * Initialize the client-side data cache.
	 * Note that we are not using this layer
	 * right now. It is getting fairly complicated already.
	 */
	snprintf(options, 256, "%d", CAPFS_DCACHE_BSIZE);
	setenv("CMGR_BSIZE", options, 1);
	snprintf(options, 256, "%d", CAPFS_DCACHE_COUNT);
	setenv("CMGR_BCOUNT", options, 1);
#endif
	/*
	 * Initialize the client-side data server communication
	 * stuff.
	 */
	clnt_init(&cas_options, num_threads, CAPFS_CHUNK_SIZE);
	
	/* loop forever, doing:
	 * - read from device
	 * - service request
	 * - write back response
	 */
	for (;;) {
		struct timeval begin, end;

		err = read_capfsdev(dev_fd, &up, 30);
		if (err < 0) {
			/* cleanup the hash cache */
			cleanup_hashes();
			/* Cleanup the RPC service */
			cleanup_service(&info);
			capfs_comm_shutdown();
			close_capfsdev(dev_fd);
			/* cleanup the plugins */
			capfsd_plugin_cleanup();
			/* cleanup the client-side stuff */
			clnt_finalize();
			exiterror("read failed\n");
			exit(1);
		}
		if (err == 0) {
			/* timed out */
			capfs_comm_idle();
			continue;
		}
		gettimeofday(&begin, NULL);
		/* the do_capfs_op() call does this already; can probably remove */
		init_downcall(&down, &up);

		err = 0;
		switch (up.type) {
			/* all the easy operations */
		case GETMETA_OP:
		case SETMETA_OP:
		case LOOKUP_OP:
		case CREATE_OP:
		case REMOVE_OP:
		case RENAME_OP:
		case SYMLINK_OP:
		case MKDIR_OP:
		case RMDIR_OP:
		case STATFS_OP:
		case HINT_OP:
		case FSYNC_OP:
		case LINK_OP:
		{
			PDEBUG(D_UPCALL, "read upcall; type = %d, name = %s\n", up.type,
					 up.v1.fhname);
			err = do_capfs_op(&up, &down);
			if (err < 0) {
				PDEBUG(D_LIB, "do_capfs_op failed for type %d\n", up.type);
			}
			break;
			/* the more interesting ones */
		}
		case GETDENTS_OP:
			/* need to pass location and size of buffer to do_capfs_op() */
			up.xfer.ptr = dent;
			up.xfer.size = capfs_dent_size;
			err = do_capfs_op(&up, &down);
			if (err < 0) {
				PDEBUG(D_LIB, "do_capfs_op failed for getdents\n");
			}
			break;
		case READLINK_OP:
			/* need to pass location and size of buffer to hold the target name */
			up.xfer.ptr = link_name;
			up.xfer.size = capfs_link_size;
			err = do_capfs_op(&up, &down);
			if(err < 0) {
				PDEBUG(D_LIB, "do_capfs_op failed for readlink\n");
			}
			break;
		case READ_OP:
			err = read_op(&up, &down);
			if (err < 0) {
				PDEBUG(D_LIB, "read_op failed\n");
			}
			break;
		case WRITE_OP:
			err = write_op(&up, &down);
			if (err < 0) {
				PDEBUG(D_LIB, "do_capfs_op failed\n");
			}
			break;
			/* things that aren't done yet */
		default:
			err = -ENOSYS;
			break;
		}
		gettimeofday(&end, NULL);
		/* calculate the total time spent servicing this call */
		if (end.tv_usec < begin.tv_usec) {
			end.tv_usec += 1000000;
			end.tv_sec--;
		}
		end.tv_sec -= begin.tv_sec;
		end.tv_usec -= begin.tv_usec;
		down.total_time = (end.tv_sec * 1000000 + end.tv_usec);
		down.error = err;

		switch(up.type)
		{
		case HINT_OP:
			/* this is a one shot hint, we don't want a response in case of HINT_OPEN/HINT_CLOSE */
			if (up.u.hint.hint == HINT_CLOSE || up.u.hint.hint == HINT_OPEN) {
				err = 0;
				break;
			}
			/* fall through */
		default:
			/* the default behavior is to write a response to the device */
			err = write_capfsdev(dev_fd, &down, -1);
			if (err < 0) {
				/* cleanup the hash cache */
				cleanup_hashes();
				/* Cleanup the RPC service */
				cleanup_service(&info);
				capfs_comm_shutdown();
				close_capfsdev(dev_fd);
				/* Cleanup the plugins */
				capfsd_plugin_cleanup();
				/* cleanup the client-side stuff */
				clnt_finalize();
				exiterror("write failed");
				exit(1);
			}
			break;
		}

		/* If we used a big I/O buffer, free it after we have successfully
		 * returned the downcall.
		 */
		if (big_iobuf != NULL) {
			free(big_iobuf);
			big_iobuf = NULL;
		}
	}
	/* Not reached */
	/* cleanup the hash cache */
	cleanup_hashes();
	/* Cleanup the RPC service */
	cleanup_service(&info);
	capfs_comm_shutdown();
	close_capfsdev(dev_fd);
	/* cleanup the plugins */
	capfsd_plugin_cleanup();
	/* cleanup the client-side stuff */
	clnt_finalize();
	exit(1);
}
Esempio n. 17
0
/* startup()
 *
 * Handles mundane tasks of setting up logging, becoming a daemon, and
 * initializing signal handlers.
 */
static int startup(int argc, char **argv)
{
	struct sigaction handler;
#ifdef MORE_FDS
	int filemax;
	struct rlimit lim;
#endif

	if (is_daemon) {
		int logfd;
#ifndef CAPFS_LOG_DIR
		/* old behavior */
		char logname[] = "/tmp/capfsdlog.XXXXXX";

		if ((logfd = mkstemp(logname)) == -1) 
#else
		/* new, less obtuse behavior */
		char logname[4096];

		snprintf(logname, 4095, "%s/capfsd", CAPFS_LOG_DIR);
		if ((logfd = open(logname, O_APPEND|O_CREAT|O_RDWR, 0700)) == -1) 
#endif
		{
			PDEBUG(D_SPECIAL, "couldn't create logfile...continuing...\n");
			close(0); close(1); close(2);
		}
		else {
			fchmod(logfd, 0755);
			dup2(logfd, 2);
			dup2(logfd, 1);
			close(0);
		}
		if (fork()) {
			exit(0); /* fork() and kill parent */
		}
		setsid();
	}	

#ifdef MORE_FDS
	/* Try to increase number of open FDs.
	 *
	 * NOTE:
	 * The system maximum must be increased in order for us to be able to
	 * take advantage of an increase for this process.  This value is
	 * stored in /proc/sys/fs/file-max and is manipulated here with the
	 * get_filemax() and set_filemax() functions.
	 *
	 * NONE OF THIS CODE IS ANY GOOD UNTIL THE UNDERLYING TRANSPORT IS
	 * BETTER.  Specifically the sockset code needs to utilize larger
	 * numbers of FDs, as well as the code that associates sockets with
	 * files in the job code.  I'm going to leave this code here, but
	 * it's useless for the moment.
	 */
	if ((filemax = get_filemax()) < 0) {
		PERROR( "warning: get_filemax failed\n");
	}
	/* let's make sure there are plenty of FDs to go around */
	else if (filemax < 2*CAPFSD_NOFILE) {
		if ((filemax = set_filemax(2*CAPFSD_NOFILE)) < 0) {
			PERROR( "warning: set_filemax failed\n");
		}
	}
	/* now we take care of the per-process limits */
	if (getrlimit(RLIMIT_NOFILE, &lim) < 0) {
		PERROR( "warning: getrlimit failed\n");
	}
	else {
		lim.rlim_cur=(lim.rlim_cur<CAPFSD_NOFILE) ? CAPFSD_NOFILE : lim.rlim_cur;
		lim.rlim_max=(lim.rlim_max<CAPFSD_NOFILE) ? CAPFSD_NOFILE : lim.rlim_max;
		if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
			PERROR( "warning: setrlimit failed\n");
		}
	}
#endif

	/* change working dir to avoid unnecessary busy file systems */
	if (chdir("/") != 0) {
		exiterror("could not change working directory to /\n");
		exit(1);
	}

	memset(&handler, 0, sizeof(struct sigaction));
	handler.sa_sigaction = (void *) do_signal;
	handler.sa_flags = SA_SIGINFO;
	/* set up SIGINT handler to shut things down */
	if (sigaction(SIGINT, &handler, NULL) != 0) {
		exiterror("Could not setup signal handler for SIGINT");
		exit(1);
	}
	/* set up SIGTERM handler to shut things down */
	if (sigaction(SIGTERM, &handler, NULL) != 0) {
		exiterror("Could not setup signal handler for SIGTERM");
		exit(1);
	}
	/* set up SIGHUP handler to restart the daemon */
	if (sigaction(SIGHUP, &handler, NULL) != 0) {
		exiterror("Could not setup signal handler for SIGHUP");
		exit(1);
	}
	/* catch SIGPIPE and SIGSEGV signals and log them, on SEGV we die */
	if (sigaction(SIGPIPE, &handler, NULL) != 0) {
		exiterror("Could not setup signal handler for SIGPIPE");
		exit(1);
	}
	if (sigaction(SIGSEGV, &handler, NULL) != 0) {
		exiterror("Could not setup signal handler for SIGSEGV");
		exit(1);
	}

	return 0;
} /* end of startup() */