|
|
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.