|
|
1.1 ! root 1: /* jsexec.c */ ! 2: ! 3: /* Execute a Synchronet JavaScript module from the command-line */ ! 4: ! 5: /* $Id: jsexec.c,v 1.109 2006/09/15 21:12:53 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #ifndef JAVASCRIPT ! 39: #define JAVASCRIPT ! 40: #endif ! 41: ! 42: #ifdef __unix__ ! 43: #include <signal.h> ! 44: #endif ! 45: ! 46: #include "ciolib.h" ! 47: ! 48: #include "sbbs.h" ! 49: ! 50: #define DEFAULT_LOG_LEVEL LOG_DEBUG /* Display all LOG levels */ ! 51: #define DEFAULT_ERR_LOG_LVL LOG_WARNING ! 52: ! 53: JSRuntime* js_runtime; ! 54: JSContext* js_cx; ! 55: JSObject* js_glob; ! 56: js_branch_t branch; ! 57: scfg_t scfg; ! 58: ulong js_max_bytes=JAVASCRIPT_MAX_BYTES; ! 59: ulong js_cx_stack=JAVASCRIPT_CONTEXT_STACK; ! 60: ulong stack_limit=JAVASCRIPT_THREAD_STACK; ! 61: FILE* confp; ! 62: FILE* errfp; ! 63: FILE* nulfp; ! 64: FILE* statfp; ! 65: char revision[16]; ! 66: char compiler[32]; ! 67: char* host_name=NULL; ! 68: char host_name_buf[128]; ! 69: BOOL pause_on_exit=FALSE; ! 70: BOOL pause_on_error=FALSE; ! 71: BOOL terminated=FALSE; ! 72: BOOL recycled; ! 73: int log_level=DEFAULT_LOG_LEVEL; ! 74: int err_level=DEFAULT_ERR_LOG_LVL; ! 75: pthread_mutex_t output_mutex; ! 76: #if defined(__unix__) ! 77: BOOL daemonize=FALSE; ! 78: #endif ! 79: ! 80: void banner(FILE* fp) ! 81: { ! 82: fprintf(fp,"\nJSexec v%s%c-%s (rev %s)%s - " ! 83: "Execute Synchronet JavaScript Module\n" ! 84: ,VERSION,REVISION ! 85: ,PLATFORM_DESC ! 86: ,revision ! 87: #ifdef _DEBUG ! 88: ," Debug" ! 89: #else ! 90: ,"" ! 91: #endif ! 92: ); ! 93: ! 94: fprintf(fp, "Compiled %s %s with %s\n" ! 95: ,__DATE__, __TIME__, compiler); ! 96: } ! 97: ! 98: void usage(FILE* fp) ! 99: { ! 100: banner(fp); ! 101: ! 102: fprintf(fp,"\nusage: jsexec [-opts] [path]module[.js] [args]\n" ! 103: "\navailable opts:\n\n" ! 104: "\t-c<ctrl_dir> specify path to Synchronet CTRL directory\n" ! 105: #if defined(__unix__) ! 106: "\t-d run in background (daemonize)\n" ! 107: #endif ! 108: "\t-m<bytes> set maximum heap size (default=%u bytes)\n" ! 109: "\t-s<bytes> set context stack size (default=%u bytes)\n" ! 110: "\t-S<bytes> set thread stack limit (default=%u, 0=unlimited)\n" ! 111: "\t-b<limit> set branch limit (default=%u, 0=unlimited)\n" ! 112: "\t-y<interval> set yield interval (default=%u, 0=never)\n" ! 113: "\t-g<interval> set garbage collection interval (default=%u, 0=never)\n" ! 114: "\t-h[hostname] use local or specified host name (instead of SCFG value)\n" ! 115: "\t-L<level> set log level (default=%u)\n" ! 116: "\t-E<level> set error log level threshold (default=%d)\n" ! 117: "\t-f use non-buffered stream for console messages\n" ! 118: "\t-a append instead of overwriting message output files\n" ! 119: "\t-e<filename> send error messages to file in addition to stderr\n" ! 120: "\t-o<filename> send console messages to file instead of stdout\n" ! 121: "\t-n send status messages to %s instead of stderr\n" ! 122: "\t-q send console messages to %s instead of stdout\n" ! 123: "\t-v display version details and exit\n" ! 124: "\t-x disable auto-termination on local abort signal\n" ! 125: "\t-l loop until intentionally terminated\n" ! 126: "\t-p wait for keypress (pause) on exit\n" ! 127: "\t-! wait for keypress (pause) on error\n" ! 128: ,JAVASCRIPT_MAX_BYTES ! 129: ,JAVASCRIPT_CONTEXT_STACK ! 130: ,JAVASCRIPT_THREAD_STACK ! 131: ,JAVASCRIPT_BRANCH_LIMIT ! 132: ,JAVASCRIPT_YIELD_INTERVAL ! 133: ,JAVASCRIPT_GC_INTERVAL ! 134: ,DEFAULT_LOG_LEVEL ! 135: ,DEFAULT_ERR_LOG_LVL ! 136: ,_PATH_DEVNULL ! 137: ,_PATH_DEVNULL ! 138: ); ! 139: } ! 140: ! 141: int mfprintf(FILE* fp, char *fmt, ...) ! 142: { ! 143: va_list argptr; ! 144: char sbuf[1024]; ! 145: int ret=0; ! 146: ! 147: va_start(argptr,fmt); ! 148: ret=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); ! 149: sbuf[sizeof(sbuf)-1]=0; ! 150: va_end(argptr); ! 151: ! 152: /* Mutex-protect stdout/stderr */ ! 153: pthread_mutex_lock(&output_mutex); ! 154: ! 155: ret = fprintf(fp, "%s\n", sbuf); ! 156: ! 157: pthread_mutex_unlock(&output_mutex); ! 158: return(ret); ! 159: } ! 160: ! 161: /* Log printf */ ! 162: int lprintf(int level, char *fmt, ...) ! 163: { ! 164: va_list argptr; ! 165: char sbuf[1024]; ! 166: int ret=0; ! 167: ! 168: if(level > log_level) ! 169: return(0); ! 170: ! 171: va_start(argptr,fmt); ! 172: ret=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); ! 173: sbuf[sizeof(sbuf)-1]=0; ! 174: va_end(argptr); ! 175: #if defined(__unix__) ! 176: if(daemonize) { ! 177: syslog(level,"%s",sbuf); ! 178: return(ret); ! 179: } ! 180: #endif ! 181: ! 182: /* Mutex-protect stdout/stderr */ ! 183: pthread_mutex_lock(&output_mutex); ! 184: ! 185: if(level<=err_level) { ! 186: ret=fprintf(errfp,"%s\n",sbuf); ! 187: if(errfp!=stderr && confp!=stdout) ! 188: ret=fprintf(statfp,"%s\n",sbuf); ! 189: } ! 190: if(level>err_level || errfp!=stderr) ! 191: ret=fprintf(confp,"%s\n",sbuf); ! 192: ! 193: pthread_mutex_unlock(&output_mutex); ! 194: return(ret); ! 195: } ! 196: ! 197: #if defined(__unix__) && defined(NEEDS_DAEMON) ! 198: /****************************************************************************/ ! 199: /* Daemonizes the process */ ! 200: /****************************************************************************/ ! 201: int ! 202: daemon(int nochdir, int noclose) ! 203: { ! 204: int fd; ! 205: ! 206: switch (fork()) { ! 207: case -1: ! 208: return (-1); ! 209: case 0: ! 210: break; ! 211: default: ! 212: _exit(0); ! 213: } ! 214: ! 215: if (setsid() == -1) ! 216: return (-1); ! 217: ! 218: if (!nochdir) ! 219: (void)chdir("/"); ! 220: ! 221: if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { ! 222: (void)dup2(fd, STDIN_FILENO); ! 223: (void)dup2(fd, STDOUT_FILENO); ! 224: (void)dup2(fd, STDERR_FILENO); ! 225: if (fd > 2) ! 226: (void)close(fd); ! 227: } ! 228: return (0); ! 229: } ! 230: #endif ! 231: ! 232: #if defined(_WINSOCKAPI_) ! 233: ! 234: WSADATA WSAData; ! 235: #define SOCKLIB_DESC WSAData.szDescription ! 236: static BOOL WSAInitialized=FALSE; ! 237: ! 238: static BOOL winsock_startup(void) ! 239: { ! 240: int status; /* Status Code */ ! 241: ! 242: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) { ! 243: /* fprintf(statfp,"%s %s\n",WSAData.szDescription, WSAData.szSystemStatus); */ ! 244: WSAInitialized=TRUE; ! 245: return(TRUE); ! 246: } ! 247: ! 248: lprintf(LOG_ERR,"!WinSock startup ERROR %d", status); ! 249: return(FALSE); ! 250: } ! 251: ! 252: #else /* No WINSOCK */ ! 253: ! 254: #define winsock_startup() (TRUE) ! 255: #define SOCKLIB_DESC NULL ! 256: ! 257: #endif ! 258: ! 259: void bail(int code) ! 260: { ! 261: ! 262: #if defined(_WINSOCKAPI_) ! 263: if(WSAInitialized && WSACleanup()!=0) ! 264: lprintf(LOG_ERR,"!WSACleanup ERROR %d",ERROR_VALUE); ! 265: #endif ! 266: ! 267: if(pause_on_exit || (code && pause_on_error)) { ! 268: fprintf(statfp,"\nHit enter to continue..."); ! 269: getchar(); ! 270: } ! 271: ! 272: if(code) ! 273: fprintf(statfp,"\nReturning error code: %d\n",code); ! 274: exit(code); ! 275: } ! 276: ! 277: static JSBool ! 278: js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 279: { ! 280: uintN i=0; ! 281: int32 level=LOG_INFO; ! 282: JSString* str=NULL; ! 283: ! 284: if(argc > 1 && JSVAL_IS_NUMBER(argv[i])) ! 285: JS_ValueToInt32(cx,argv[i++],&level); ! 286: ! 287: for(; i<argc; i++) { ! 288: if((str=JS_ValueToString(cx, argv[i]))==NULL) ! 289: return(JS_FALSE); ! 290: lprintf(level,"%s",JS_GetStringBytes(str)); ! 291: } ! 292: ! 293: if(str==NULL) ! 294: *rval = JSVAL_VOID; ! 295: else ! 296: *rval = STRING_TO_JSVAL(str); ! 297: ! 298: return(JS_TRUE); ! 299: } ! 300: ! 301: static JSBool ! 302: js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 303: { ! 304: char* buf; ! 305: int rd; ! 306: int32 len=128; ! 307: ! 308: if(argc) ! 309: JS_ValueToInt32(cx,argv[0],&len); ! 310: if((buf=alloca(len))==NULL) ! 311: return(JS_TRUE); ! 312: ! 313: rd=fread(buf,sizeof(char),len,stdin); ! 314: ! 315: if(rd>=0) ! 316: *rval = STRING_TO_JSVAL(JS_NewStringCopyN(cx,buf,rd)); ! 317: ! 318: return(JS_TRUE); ! 319: } ! 320: ! 321: static JSBool ! 322: js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 323: { ! 324: char* buf; ! 325: char* p; ! 326: int32 len=128; ! 327: ! 328: if(argc) ! 329: JS_ValueToInt32(cx,argv[0],&len); ! 330: if((buf=alloca(len+1))==NULL) ! 331: return(JS_TRUE); ! 332: ! 333: p=fgets(buf,len+1,stdin); ! 334: ! 335: if(p!=NULL) ! 336: *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,truncnl(p))); ! 337: ! 338: return(JS_TRUE); ! 339: } ! 340: ! 341: ! 342: static JSBool ! 343: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 344: { ! 345: uintN i; ! 346: JSString* str=NULL; ! 347: ! 348: for (i = 0; i < argc; i++) { ! 349: if((str=JS_ValueToString(cx, argv[i]))==NULL) ! 350: return(JS_FALSE); ! 351: fprintf(confp,"%s",JS_GetStringBytes(str)); ! 352: } ! 353: ! 354: if(str==NULL) ! 355: *rval = JSVAL_VOID; ! 356: else ! 357: *rval = STRING_TO_JSVAL(str); ! 358: return(JS_TRUE); ! 359: } ! 360: ! 361: static JSBool ! 362: js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 363: { ! 364: if(!js_write(cx,obj,argc,argv,rval)) ! 365: return(JS_FALSE); ! 366: ! 367: fprintf(confp,"\n"); ! 368: return(JS_TRUE); ! 369: } ! 370: ! 371: static JSBool ! 372: js_printf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 373: { ! 374: char* p; ! 375: ! 376: if((p = js_sprintf(cx, 0, argc, argv))==NULL) { ! 377: JS_ReportError(cx,"js_sprintf failed"); ! 378: return(JS_FALSE); ! 379: } ! 380: ! 381: fprintf(confp,"%s",p); ! 382: ! 383: *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, p)); ! 384: ! 385: js_sprintf_free(p); ! 386: ! 387: return(JS_TRUE); ! 388: } ! 389: ! 390: static JSBool ! 391: js_alert(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 392: { ! 393: JSString * str; ! 394: ! 395: if((str=JS_ValueToString(cx, argv[0]))==NULL) ! 396: return(JS_FALSE); ! 397: ! 398: fprintf(confp,"!%s\n",JS_GetStringBytes(str)); ! 399: ! 400: *rval = argv[0]; ! 401: ! 402: return(JS_TRUE); ! 403: } ! 404: ! 405: static JSBool ! 406: js_confirm(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 407: { ! 408: JSString * str; ! 409: ! 410: if((str=JS_ValueToString(cx, argv[0]))==NULL) ! 411: return(JS_FALSE); ! 412: ! 413: printf("%s (Y/N)?", JS_GetStringBytes(str)); ! 414: ! 415: *rval = BOOLEAN_TO_JSVAL(FALSE); ! 416: return(JS_TRUE); ! 417: } ! 418: ! 419: static JSBool ! 420: js_prompt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 421: { ! 422: char instr[81]; ! 423: JSString * prompt; ! 424: JSString * str; ! 425: ! 426: if(!JSVAL_IS_VOID(argv[0])) { ! 427: if((prompt=JS_ValueToString(cx, argv[0]))==NULL) ! 428: return(JS_FALSE); ! 429: fprintf(confp,"%s: ",JS_GetStringBytes(prompt)); ! 430: } ! 431: ! 432: if(argc>1) { ! 433: if((str=JS_ValueToString(cx, argv[1]))==NULL) ! 434: return(JS_FALSE); ! 435: SAFECOPY(instr,JS_GetStringBytes(str)); ! 436: } else ! 437: instr[0]=0; ! 438: ! 439: if(!fgets(instr,sizeof(instr),stdin)) ! 440: return(JS_TRUE); ! 441: ! 442: if((str=JS_NewStringCopyZ(cx, truncnl(instr)))==NULL) ! 443: return(JS_FALSE); ! 444: ! 445: *rval = STRING_TO_JSVAL(str); ! 446: return(JS_TRUE); ! 447: } ! 448: ! 449: static JSBool ! 450: js_chdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 451: { ! 452: char* p; ! 453: ! 454: if((p=JS_GetStringBytes(JS_ValueToString(cx, argv[0])))==NULL) { ! 455: *rval = INT_TO_JSVAL(-1); ! 456: return(JS_TRUE); ! 457: } ! 458: ! 459: *rval = BOOLEAN_TO_JSVAL(chdir(p)==0); ! 460: return(JS_TRUE); ! 461: } ! 462: ! 463: static JSBool ! 464: js_putenv(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 465: { ! 466: char* p; ! 467: ! 468: if((p=JS_GetStringBytes(JS_ValueToString(cx, argv[0])))==NULL) { ! 469: *rval = INT_TO_JSVAL(-1); ! 470: return(JS_TRUE); ! 471: } ! 472: ! 473: *rval = BOOLEAN_TO_JSVAL(putenv(p)==0); ! 474: return(JS_TRUE); ! 475: } ! 476: ! 477: static jsSyncMethodSpec js_global_functions[] = { ! 478: {"log", js_log, 1}, ! 479: {"read", js_read, 1}, ! 480: {"readln", js_readln, 1}, ! 481: {"write", js_write, 0}, ! 482: {"writeln", js_writeln, 0}, ! 483: {"print", js_writeln, 0}, ! 484: {"printf", js_printf, 1}, ! 485: {"alert", js_alert, 1}, ! 486: {"prompt", js_prompt, 1}, ! 487: {"confirm", js_confirm, 1}, ! 488: {"chdir", js_chdir, 1}, ! 489: {"putenv", js_putenv, 1}, ! 490: {0} ! 491: }; ! 492: ! 493: static void ! 494: js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) ! 495: { ! 496: char line[64]; ! 497: char file[MAX_PATH+1]; ! 498: const char* warning; ! 499: ! 500: if(report==NULL) { ! 501: lprintf(LOG_ERR,"!JavaScript: %s", message); ! 502: return; ! 503: } ! 504: ! 505: if(report->filename) ! 506: sprintf(file," %s",report->filename); ! 507: else ! 508: file[0]=0; ! 509: ! 510: if(report->lineno) ! 511: sprintf(line," line %d",report->lineno); ! 512: else ! 513: line[0]=0; ! 514: ! 515: if(JSREPORT_IS_WARNING(report->flags)) { ! 516: if(JSREPORT_IS_STRICT(report->flags)) ! 517: warning="strict warning"; ! 518: else ! 519: warning="warning"; ! 520: } else ! 521: warning=""; ! 522: ! 523: lprintf(LOG_ERR,"!JavaScript %s%s%s: %s",warning,file,line,message); ! 524: } ! 525: ! 526: static JSBool ! 527: js_BranchCallback(JSContext *cx, JSScript *script) ! 528: { ! 529: return(js_CommonBranchCallback(cx,&branch)); ! 530: } ! 531: ! 532: static BOOL js_CreateEnvObject(JSContext* cx, JSObject* glob, char** env) ! 533: { ! 534: char name[256]; ! 535: char* val; ! 536: uint i; ! 537: JSObject* js_env; ! 538: ! 539: if((js_env=JS_NewObject(js_cx, NULL, NULL, glob))==NULL) ! 540: return(FALSE); ! 541: ! 542: if(!JS_DefineProperty(cx, glob, "env", OBJECT_TO_JSVAL(js_env) ! 543: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE)) ! 544: return(FALSE); ! 545: ! 546: for(i=0;env[i]!=NULL;i++) { ! 547: SAFECOPY(name,env[i]); ! 548: truncstr(name,"="); ! 549: val=strchr(env[i],'='); ! 550: if(val==NULL) ! 551: val=""; ! 552: else ! 553: val++; ! 554: if(!JS_DefineProperty(cx, js_env, name, STRING_TO_JSVAL(JS_NewStringCopyZ(cx,val)) ! 555: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE)) ! 556: return(FALSE); ! 557: } ! 558: ! 559: return(TRUE); ! 560: } ! 561: ! 562: static BOOL js_init(char** environ) ! 563: { ! 564: fprintf(statfp,"%s\n",(char *)JS_GetImplementationVersion()); ! 565: ! 566: fprintf(statfp,"JavaScript: Creating runtime: %lu bytes\n" ! 567: ,js_max_bytes); ! 568: ! 569: if((js_runtime = JS_NewRuntime(js_max_bytes))==NULL) ! 570: return(FALSE); ! 571: ! 572: fprintf(statfp,"JavaScript: Initializing context (stack: %lu bytes)\n" ! 573: ,js_cx_stack); ! 574: ! 575: if((js_cx = JS_NewContext(js_runtime, js_cx_stack))==NULL) ! 576: return(FALSE); ! 577: ! 578: if(stack_limit) ! 579: fprintf(statfp,"JavaScript: Thread stack limit: %lu bytes\n" ! 580: ,stack_limit); ! 581: ! 582: JS_SetErrorReporter(js_cx, js_ErrorReporter); ! 583: ! 584: /* Global Object */ ! 585: if((js_glob=js_CreateCommonObjects(js_cx, &scfg, NULL, js_global_functions ! 586: ,time(NULL), host_name, SOCKLIB_DESC /* system */ ! 587: ,&branch /* js */ ! 588: ,NULL,INVALID_SOCKET /* client */ ! 589: ,NULL /* server */ ! 590: ))==NULL) ! 591: return(FALSE); ! 592: ! 593: /* Environment Object (associative array) */ ! 594: if(!js_CreateEnvObject(js_cx, js_glob, environ)) ! 595: return(FALSE); ! 596: ! 597: if(js_CreateUifcObject(js_cx, js_glob)==NULL) ! 598: return(FALSE); ! 599: ! 600: return(TRUE); ! 601: } ! 602: ! 603: static const char* js_ext(const char* fname) ! 604: { ! 605: if(strchr(fname,'.')==NULL) ! 606: return(".js"); ! 607: return(""); ! 608: } ! 609: ! 610: long js_exec(const char *fname, char** args) ! 611: { ! 612: ulong stack_frame; ! 613: int argc=0; ! 614: uint line_no; ! 615: char path[MAX_PATH+1]; ! 616: char line[1024]; ! 617: char rev_detail[256]; ! 618: size_t len; ! 619: char* js_buf=NULL; ! 620: size_t js_buflen; ! 621: JSScript* js_script=NULL; ! 622: JSString* arg; ! 623: JSObject* argv; ! 624: FILE* fp=stdin; ! 625: jsval val; ! 626: jsval rval=JSVAL_VOID; ! 627: int32 result=0; ! 628: long double start; ! 629: long double diff; ! 630: ! 631: if(fname!=NULL) { ! 632: if(strcspn(fname,"/\\")==strlen(fname)) { ! 633: sprintf(path,"%s%s%s",scfg.mods_dir,fname,js_ext(fname)); ! 634: if(scfg.mods_dir[0]==0 || !fexistcase(path)) ! 635: sprintf(path,"%s%s%s",scfg.exec_dir,fname,js_ext(fname)); ! 636: } else ! 637: SAFECOPY(path,fname); ! 638: ! 639: if(!fexistcase(path)) { ! 640: lprintf(LOG_ERR,"!Module file (%s) doesn't exist",path); ! 641: return(-1); ! 642: } ! 643: ! 644: if((fp=fopen(path,"r"))==NULL) { ! 645: lprintf(LOG_ERR,"!Error %d (%s) opening %s",errno,STRERROR(errno),path); ! 646: return(-1); ! 647: } ! 648: } ! 649: JS_ClearPendingException(js_cx); ! 650: ! 651: if(stack_limit) { ! 652: #if JS_STACK_GROWTH_DIRECTION > 0 ! 653: stack_frame=((ulong)&stack_frame)+stack_limit; ! 654: #else ! 655: stack_frame=((ulong)&stack_frame)-stack_limit; ! 656: #endif ! 657: JS_SetThreadStackLimit(js_cx, stack_frame); ! 658: } ! 659: ! 660: argv=JS_NewArrayObject(js_cx, 0, NULL); ! 661: JS_DefineProperty(js_cx, js_glob, "argv", OBJECT_TO_JSVAL(argv) ! 662: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE); ! 663: ! 664: for(argc=0;args[argc];argc++) { ! 665: arg = JS_NewStringCopyZ(js_cx, args[argc]); ! 666: if(arg==NULL) ! 667: break; ! 668: val=STRING_TO_JSVAL(arg); ! 669: if(!JS_SetElement(js_cx, argv, argc, &val)) ! 670: break; ! 671: } ! 672: JS_DefineProperty(js_cx, js_glob, "argc", INT_TO_JSVAL(argc) ! 673: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE); ! 674: ! 675: JS_DefineProperty(js_cx, js_glob, "jsexec_revision" ! 676: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,revision)) ! 677: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE); ! 678: ! 679: sprintf(rev_detail,"JSexec %s%s " ! 680: "Compiled %s %s with %s" ! 681: ,revision ! 682: #ifdef _DEBUG ! 683: ," Debug" ! 684: #else ! 685: ,"" ! 686: #endif ! 687: ,__DATE__, __TIME__, compiler ! 688: ); ! 689: ! 690: JS_DefineProperty(js_cx, js_glob, "jsexec_revision_detail" ! 691: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,rev_detail)) ! 692: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE); ! 693: ! 694: branch.terminated=&terminated; ! 695: ! 696: JS_SetBranchCallback(js_cx, js_BranchCallback); ! 697: ! 698: if(fp==stdin) /* Using stdin for script source */ ! 699: SAFECOPY(path,"stdin"); ! 700: ! 701: fprintf(statfp,"Reading script from %s\n",path); ! 702: line_no=0; ! 703: js_buflen=0; ! 704: while(!feof(fp)) { ! 705: if(!fgets(line,sizeof(line),fp)) ! 706: break; ! 707: line_no++; ! 708: #if defined(__unix__) /* Support Unix Shell Scripts that start with #!/path/to/jsexec */ ! 709: if(line_no==1 && strncmp(line,"#!",2)==0) ! 710: strcpy(line,"\n"); /* To keep line count correct */ ! 711: #endif ! 712: len=strlen(line); ! 713: if((js_buf=realloc(js_buf,js_buflen+len))==NULL) { ! 714: lprintf(LOG_ERR,"!Error allocating %u bytes of memory" ! 715: ,js_buflen+len); ! 716: return(-1); ! 717: } ! 718: memcpy(js_buf+js_buflen,line,len); ! 719: js_buflen+=len; ! 720: } ! 721: if(fp!=NULL && fp!=stdin) ! 722: fclose(fp); ! 723: ! 724: start=xp_timer(); ! 725: if((js_script=JS_CompileScript(js_cx, js_glob, js_buf, js_buflen, fname==NULL ? NULL : path, 1))==NULL) { ! 726: lprintf(LOG_ERR,"!Error compiling script from %s",path); ! 727: return(-1); ! 728: } ! 729: if((diff=xp_timer()-start) > 0) ! 730: mfprintf(statfp,"%s compiled in %.2Lf seconds" ! 731: ,path ! 732: ,diff); ! 733: ! 734: start=xp_timer(); ! 735: JS_ExecuteScript(js_cx, js_glob, js_script, &rval); ! 736: js_EvalOnExit(js_cx, js_glob, &branch); ! 737: ! 738: if((diff=xp_timer()-start) > 0) ! 739: mfprintf(statfp,"%s executed in %.2Lf seconds" ! 740: ,path ! 741: ,diff); ! 742: ! 743: JS_GetProperty(js_cx, js_glob, "exit_code", &rval); ! 744: ! 745: if(rval!=JSVAL_VOID && JSVAL_IS_NUMBER(rval)) { ! 746: mfprintf(statfp,"Using JavaScript exit_code: %s",JS_GetStringBytes(JS_ValueToString(js_cx,rval))); ! 747: JS_ValueToInt32(js_cx,rval,&result); ! 748: } ! 749: ! 750: JS_DestroyScript(js_cx, js_script); ! 751: ! 752: JS_GC(js_cx); ! 753: ! 754: if(js_buf!=NULL) ! 755: free(js_buf); ! 756: ! 757: return(result); ! 758: } ! 759: ! 760: void break_handler(int type) ! 761: { ! 762: lprintf(LOG_NOTICE,"\n-> Terminated Locally (signal: %d)",type); ! 763: terminated=TRUE; ! 764: } ! 765: ! 766: void recycle_handler(int type) ! 767: { ! 768: lprintf(LOG_NOTICE,"\n-> Recycled Locally (signal: %d)",type); ! 769: recycled=TRUE; ! 770: branch.terminated=&recycled; ! 771: } ! 772: ! 773: ! 774: #if defined(_WIN32) ! 775: BOOL WINAPI ControlHandler(DWORD CtrlType) ! 776: { ! 777: break_handler((int)CtrlType); ! 778: return TRUE; ! 779: } ! 780: #endif ! 781: ! 782: /*********************/ ! 783: /* Entry point (duh) */ ! 784: /*********************/ ! 785: int main(int argc, char **argv, char** environ) ! 786: { ! 787: char error[512]; ! 788: char* module=NULL; ! 789: char* p; ! 790: char* omode="w"; ! 791: int argn; ! 792: long result; ! 793: ulong exec_count=0; ! 794: BOOL loop=FALSE; ! 795: BOOL nonbuffered_con=FALSE; ! 796: ! 797: confp=stdout; ! 798: errfp=stderr; ! 799: if((nulfp=fopen(_PATH_DEVNULL,"w+"))==NULL) { ! 800: perror(_PATH_DEVNULL); ! 801: bail(-1); ! 802: } ! 803: if(isatty(fileno(stderr))) ! 804: statfp=stderr; ! 805: else /* if redirected, don't send status messages to stderr */ ! 806: statfp=nulfp; ! 807: ! 808: branch.limit=JAVASCRIPT_BRANCH_LIMIT; ! 809: branch.yield_interval=JAVASCRIPT_YIELD_INTERVAL; ! 810: branch.gc_interval=JAVASCRIPT_GC_INTERVAL; ! 811: branch.auto_terminate=TRUE; ! 812: ! 813: sscanf("$Revision: 1.109 $", "%*s %s", revision); ! 814: DESCRIBE_COMPILER(compiler); ! 815: ! 816: memset(&scfg,0,sizeof(scfg)); ! 817: scfg.size=sizeof(scfg); ! 818: ! 819: if(!winsock_startup()) ! 820: bail(2); ! 821: ! 822: for(argn=1;argn<argc && module==NULL;argn++) { ! 823: if(argv[argn][0]=='-') { ! 824: p=argv[argn]+2; ! 825: switch(argv[argn][1]) { ! 826: case 'a': ! 827: omode="a"; ! 828: break; ! 829: case 'f': ! 830: nonbuffered_con=TRUE; ! 831: break; ! 832: case 'm': ! 833: if(*p==0) p=argv[++argn]; ! 834: js_max_bytes=strtoul(p,NULL,0); ! 835: break; ! 836: case 's': ! 837: if(*p==0) p=argv[++argn]; ! 838: js_cx_stack=strtoul(p,NULL,0); ! 839: break; ! 840: case 'S': ! 841: if(*p==0) p=argv[++argn]; ! 842: stack_limit=strtoul(p,NULL,0); ! 843: break; ! 844: case 'b': ! 845: if(*p==0) p=argv[++argn]; ! 846: branch.limit=strtoul(p,NULL,0); ! 847: break; ! 848: case 'y': ! 849: if(*p==0) p=argv[++argn]; ! 850: branch.yield_interval=strtoul(p,NULL,0); ! 851: break; ! 852: case 'g': ! 853: if(*p==0) p=argv[++argn]; ! 854: branch.gc_interval=strtoul(p,NULL,0); ! 855: break; ! 856: case 'h': ! 857: if(*p==0) ! 858: gethostname(host_name=host_name_buf,sizeof(host_name_buf)); ! 859: else ! 860: host_name=p; ! 861: break; ! 862: case 'L': ! 863: if(*p==0) p=argv[++argn]; ! 864: log_level=strtol(p,NULL,0); ! 865: break; ! 866: case 'E': ! 867: if(*p==0) p=argv[++argn]; ! 868: err_level=strtol(p,NULL,0); ! 869: break; ! 870: case 'e': ! 871: if(*p==0) p=argv[++argn]; ! 872: if((errfp=fopen(p,omode))==NULL) { ! 873: perror(p); ! 874: bail(1); ! 875: } ! 876: break; ! 877: case 'o': ! 878: if(*p==0) p=argv[++argn]; ! 879: if((confp=fopen(p,omode))==NULL) { ! 880: perror(p); ! 881: bail(1); ! 882: } ! 883: break; ! 884: case 'q': ! 885: confp=nulfp; ! 886: break; ! 887: case 'n': ! 888: statfp=nulfp; ! 889: break; ! 890: case 'x': ! 891: branch.auto_terminate=FALSE; ! 892: break; ! 893: case 'l': ! 894: loop=TRUE; ! 895: break; ! 896: case 'p': ! 897: pause_on_exit=TRUE; ! 898: break; ! 899: case '!': ! 900: pause_on_error=TRUE; ! 901: break; ! 902: case 'c': ! 903: if(*p==0) p=argv[++argn]; ! 904: SAFECOPY(scfg.ctrl_dir,p); ! 905: break; ! 906: case 'v': ! 907: banner(statfp); ! 908: fprintf(statfp,"%s\n",(char *)JS_GetImplementationVersion()); ! 909: bail(0); ! 910: #if defined(__unix__) ! 911: case 'd': ! 912: daemonize=TRUE; ! 913: break; ! 914: #endif ! 915: default: ! 916: fprintf(errfp,"\n!Unsupported option: %s\n",argv[argn]); ! 917: case '?': ! 918: usage(errfp); ! 919: bail(1); ! 920: } ! 921: continue; ! 922: } ! 923: module=argv[argn]; ! 924: } ! 925: ! 926: if(scfg.ctrl_dir[0]==0) { ! 927: if((p=getenv("SBBSCTRL"))==NULL) { ! 928: fprintf(errfp,"\nSBBSCTRL environment variable not set and -c option not specified.\n"); ! 929: fprintf(errfp,"\nExample: SET SBBSCTRL=/sbbs/ctrl\n"); ! 930: fprintf(errfp,"\n or: %s -c /sbbs/ctrl [module]\n",argv[0]); ! 931: bail(1); ! 932: } ! 933: SAFECOPY(scfg.ctrl_dir,p); ! 934: } ! 935: ! 936: if(module==NULL && isatty(fileno(stdin))) { ! 937: fprintf(errfp,"\n!Module name not specified\n"); ! 938: usage(errfp); ! 939: bail(1); ! 940: } ! 941: ! 942: banner(statfp); ! 943: ! 944: if(chdir(scfg.ctrl_dir)!=0) ! 945: fprintf(errfp,"!ERROR changing directory to: %s\n", scfg.ctrl_dir); ! 946: ! 947: fprintf(statfp,"\nLoading configuration files from %s\n",scfg.ctrl_dir); ! 948: if(!load_cfg(&scfg,NULL,TRUE,error)) { ! 949: fprintf(errfp,"!ERROR loading configuration files: %s\n",error); ! 950: bail(1); ! 951: } ! 952: SAFECOPY(scfg.temp_dir,"../temp"); ! 953: prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir)); ! 954: ! 955: if(host_name==NULL) ! 956: host_name=scfg.sys_inetaddr; ! 957: ! 958: if(!(scfg.sys_misc&SM_LOCAL_TZ)) ! 959: putenv("TZ=UTC0"); ! 960: ! 961: #if defined(__unix__) ! 962: if(daemonize) { ! 963: fprintf(statfp,"\nRunning as daemon\n"); ! 964: if(daemon(TRUE,FALSE)) { /* Daemonize, DON'T switch to / and DO close descriptors */ ! 965: fprintf(statfp,"!ERROR %d running as daemon\n",errno); ! 966: daemonize=FALSE; ! 967: } ! 968: } ! 969: #endif ! 970: ! 971: /* Don't cache error log */ ! 972: setvbuf(errfp,NULL,_IONBF,0); ! 973: ! 974: if(nonbuffered_con) ! 975: setvbuf(confp,NULL,_IONBF,0); ! 976: ! 977: /* Seed random number generator */ ! 978: sbbs_srand(); ! 979: ! 980: /* Install Ctrl-C/Break signal handler here */ ! 981: #if defined(_WIN32) ! 982: SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */); ! 983: #elif defined(__unix__) ! 984: signal(SIGQUIT,break_handler); ! 985: signal(SIGINT,break_handler); ! 986: signal(SIGTERM,break_handler); ! 987: ! 988: signal(SIGHUP,recycle_handler); ! 989: ! 990: /* Don't die on SIGPIPE */ ! 991: signal(SIGPIPE,SIG_IGN); ! 992: #endif ! 993: ! 994: pthread_mutex_init(&output_mutex,NULL); ! 995: ! 996: do { ! 997: ! 998: if(exec_count++) ! 999: lprintf(LOG_INFO,"\nRe-running: %s", module); ! 1000: ! 1001: recycled=FALSE; ! 1002: ! 1003: if(!js_init(environ)) { ! 1004: lprintf(LOG_ERR,"!JavaScript initialization failure"); ! 1005: bail(1); ! 1006: } ! 1007: fprintf(statfp,"\n"); ! 1008: ! 1009: result=js_exec(module,&argv[argn]); ! 1010: ! 1011: if(result) ! 1012: lprintf(LOG_ERR,"!Module set exit_code: %ld", result); ! 1013: ! 1014: fprintf(statfp,"\n"); ! 1015: fprintf(statfp,"JavaScript: Destroying context\n"); ! 1016: JS_DestroyContext(js_cx); ! 1017: fprintf(statfp,"JavaScript: Destroying runtime\n"); ! 1018: JS_DestroyRuntime(js_runtime); ! 1019: ! 1020: } while((recycled || loop) && !terminated); ! 1021: ! 1022: bail(result); ! 1023: ! 1024: return(-1); /* never gets here */ ! 1025: } ! 1026:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.