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(); }
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); } }
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; }
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" ); }
/* * 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; }
/* * 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 ); }
/* * 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], ¶ms[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; }
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; } } }
/* * 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--; }
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; }
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 ; } }
/* * 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; }
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; }
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); }
/* * 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 */ }
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); }
/* 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() */