|
rpm
5.4.4
|
00001 /* ***** BEGIN LICENSE BLOCK ***** 00002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 00003 * 00004 * The contents of this file are subject to the Mozilla Public License Version 00005 * 1.1 (the "License"); you may not use this file except in compliance with 00006 * the License. You may obtain a copy of the License at 00007 * http://www.mozilla.org/MPL/ 00008 * 00009 * Software distributed under the License is distributed on an "AS IS" basis, 00010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 00011 * for the specific language governing rights and limitations under the 00012 * License. 00013 * 00014 * The Initial Developer of the Original Code is PageMail, Inc. 00015 * 00016 * Portions created by the Initial Developer are 00017 * Copyright (c) 2007-2009, PageMail, Inc. All Rights Reserved. 00018 * 00019 * Contributor(s): 00020 * 00021 * Alternatively, the contents of this file may be used under the terms of 00022 * either of the GNU General Public License Version 2 or later (the "GPL"), 00023 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 00024 * in which case the provisions of the GPL or the LGPL are applicable instead 00025 * of those above. If you wish to allow use of your version of this file only 00026 * under the terms of either the GPL or the LGPL, and not to allow others to 00027 * use your version of this file under the terms of the MPL, indicate your 00028 * decision by deleting the provisions above and replace them with the notice 00029 * and other provisions required by the GPL or the LGPL. If you do not delete 00030 * the provisions above, a recipient may use your version of this file under 00031 * the terms of any one of the MPL, the GPL or the LGPL. 00032 * 00033 * ***** END LICENSE BLOCK ***** 00034 */ 00035 00036 #include "system.h" 00037 00038 #include "rpmio_internal.h" 00039 #include <argv.h> 00040 #include <popt.h> 00041 00042 #if defined(__APPLE__) 00043 #include <crt_externs.h> 00044 #else 00045 extern char ** environ; 00046 #endif 00047 00048 #if defined(WITH_GPSEE) 00049 #define XP_UNIX 1 00050 #include "jsprf.h" 00051 #include "jsapi.h" 00052 00053 #include <gpsee.h> 00054 typedef gpsee_interpreter_t * JSI_t; 00055 #define _RPMJS_OPTIONS \ 00056 (JSOPTION_STRICT | JSOPTION_RELIMIT | JSOPTION_ANONFUNFIX | JSOPTION_JIT) 00057 #else /* WITH_GPSEE */ 00058 typedef void * JSI_t; 00059 #define _RPMJS_OPTIONS 0 00060 #endif /* WITH_GPSEE */ 00061 00062 #define _RPMJS_INTERNAL 00063 #include "rpmjs.h" 00064 00065 #include "debug.h" 00066 00067 #define F_ISSET(_flags, _FLAG) ((_flags) & RPMJS_FLAGS_##_FLAG) 00068 00069 /*@unchecked@*/ 00070 int _rpmjs_debug = 0; 00071 00072 /*@unchecked@*/ /*@relnull@*/ 00073 rpmjs _rpmjsI = NULL; 00074 00075 /*@unchecked@*/ 00076 uint32_t _rpmjs_options = _RPMJS_OPTIONS; 00077 00078 /*@unchecked@*/ 00079 int _rpmjs_zeal = 2; 00080 00081 struct rpmjs_s _rpmjs; 00082 00083 struct poptOption rpmjsIPoptTable[] = { 00084 { "allow", 'a', POPT_BIT_SET, &_rpmjs.flags, RPMJS_FLAGS_ALLOW, 00085 N_("Allow (read-only) access to caller's environmen"), NULL }, 00086 { "nocache", 'C', POPT_BIT_SET, &_rpmjs.flags, RPMJS_FLAGS_NOCACHE, 00087 N_("Disables compiler caching via JSScript XDR serialization"), NULL }, 00088 { "loadrc", 'R', POPT_BIT_SET, &_rpmjs.flags, RPMJS_FLAGS_LOADRC, 00089 N_("Load RC file for interpreter based on script filename."), NULL }, 00090 { "nowarn", 'W', POPT_BIT_SET, &_rpmjs.flags, RPMJS_FLAGS_NOWARN, 00091 N_("Do not report warnings"), NULL }, 00092 00093 { "norelimit", 'e', POPT_BIT_CLR, &_rpmjs.flags, RPMJS_FLAGS_RELIMIT, 00094 N_("Do not limit regexps to n^3 levels of backtracking"), NULL }, 00095 { "nojit", 'J', POPT_BIT_CLR, &_rpmjs.flags, RPMJS_FLAGS_JIT, 00096 N_("Disable nanojit"), NULL }, 00097 { "nostrict", 'S', POPT_BIT_CLR, &_rpmjs.flags, RPMJS_FLAGS_STRICT, 00098 N_("Disable Strict mode"), NULL }, 00099 { "noutf8", 'U', POPT_BIT_SET, &_rpmjs.flags, RPMJS_FLAGS_NOUTF8, 00100 N_("Disable UTF-8 C string processing"), NULL }, 00101 { "xml", 'x', POPT_BIT_SET, &_rpmjs.flags, RPMJS_FLAGS_XML, 00102 N_("Parse <!-- comments --> as E4X tokens"), NULL }, 00103 00104 { "anonfunfix", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &_rpmjs.flags, RPMJS_FLAGS_ANONFUNFIX, 00105 N_("Parse //@line number [\"filename\"] for XUL"), NULL }, 00106 { "atline", 'A', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &_rpmjs.flags, RPMJS_FLAGS_ATLINE, 00107 N_("Parse //@line number [\"filename\"] for XUL"), NULL }, 00108 { "werror", 'w', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &_rpmjs.flags, RPMJS_FLAGS_WERROR, 00109 N_("Convert warnings to errors"), NULL }, 00110 00111 POPT_TABLEEND 00112 }; 00113 00114 static void rpmjsFini(void * _js) 00115 /*@globals fileSystem @*/ 00116 /*@modifies *_js, fileSystem @*/ 00117 { 00118 rpmjs js = _js; 00119 00120 if (_rpmjs_debug) 00121 fprintf(stderr, "==> %s(%p) I %p\n", __FUNCTION__, js, js->I); 00122 00123 #if defined(WITH_GPSEE) 00124 #if defined(XXX_GPSEE_DEBUGGER) 00125 gpsee_finiDebugger(js->jsdc); 00126 js->jsdc = NULL; 00127 #endif 00128 00129 (void) gpsee_destroyInterpreter(js->I); 00130 #endif 00131 js->I = NULL; 00132 } 00133 00134 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00135 rpmioPool _rpmjsPool; 00136 00137 static rpmjs rpmjsGetPool(/*@null@*/ rpmioPool pool) 00138 /*@globals _rpmjsPool, fileSystem @*/ 00139 /*@modifies pool, _rpmjsPool, fileSystem @*/ 00140 { 00141 rpmjs js; 00142 00143 if (_rpmjsPool == NULL) { 00144 _rpmjsPool = rpmioNewPool("js", sizeof(*js), -1, _rpmjs_debug, 00145 NULL, NULL, rpmjsFini); 00146 pool = _rpmjsPool; 00147 } 00148 return (rpmjs) rpmioGetPool(pool, sizeof(*js)); 00149 } 00150 00151 static rpmjs rpmjsI(void) 00152 /*@globals _rpmjsI @*/ 00153 /*@modifies _rpmjsI @*/ 00154 { 00155 if (_rpmjsI == NULL) { 00156 #if defined(WITH_GPSEE) 00157 gpsee_verbosity(0); /* XXX hack around syslog(3) in GPSEE */ 00158 #endif 00159 _rpmjsI = rpmjsNew(NULL, 0); 00160 } 00161 if (_rpmjs_debug) 00162 fprintf(stderr, "<== %s() _rpmjsI %p\n", __FUNCTION__, _rpmjsI); 00163 return _rpmjsI; 00164 } 00165 00166 /* XXX FIXME: Iargv/Ienviron are now associated with running. */ 00167 rpmjs rpmjsNew(char ** av, uint32_t flags) 00168 { 00169 rpmjs js = 00170 #ifdef NOTYET 00171 (flags & 0x80000000) ? rpmjsI() : 00172 #endif 00173 rpmjsGetPool(_rpmjsPool); 00174 JSI_t I = NULL; 00175 00176 #if defined(WITH_GPSEE) 00177 00178 #if defined(XXX_GPSEE_DEBUGGER) /* XXX js->jsdc? */ 00179 JSDContext *jsdc; 00180 #endif 00181 00182 if (flags == 0) 00183 flags = _rpmjs_options; 00184 00185 if (F_ISSET(flags, NOUTF8) || getenv("GPSEE_NO_UTF8_C_STRINGS")) { 00186 JS_DestroyRuntime(JS_NewRuntime(1024)); 00187 putenv((char *) "GPSEE_NO_UTF8_C_STRINGS=1"); 00188 } 00189 00190 /* XXX FIXME: js->Iargv/js->Ienviron for use by rpmjsRunFile() */ 00191 I = gpsee_createInterpreter(); 00192 #if defined(XXX_GPSEE_DEBUGGER) 00193 js->jsdc = gpsee_initDebugger(I->cx, I->realm, DEBUGGER_JS); 00194 #endif 00195 00196 #ifdef NOTYET /* FIXME: dig out where NOCACHE has moved. */ 00197 if (F_ISSET(flags, NOCACHE)) 00198 I->useCompilerCache = 0; 00199 #endif 00200 if (F_ISSET(flags, NOWARN)) { 00201 gpsee_runtime_t * grt = JS_GetRuntimePrivate(JS_GetRuntime(I->cx)); 00202 grt->errorReport |= er_noWarnings; 00203 } 00204 00205 JS_SetOptions(I->cx, (flags & 0xffff)); 00206 #if defined(JS_GC_ZEAL) 00207 JS_SetGCZeal(I->cx, _rpmjs_zeal); 00208 #endif 00209 #endif /* WITH_GPSEE */ 00210 00211 js->flags = flags; 00212 js->I = I; 00213 00214 return rpmjsLink(js); 00215 } 00216 00217 #if defined(WITH_GPSEE) 00218 static FILE * rpmjsOpenFile(rpmjs js, const char * fn, const char ** msgp) 00219 /*@modifies js @*/ 00220 { 00221 FILE * fp = NULL; 00222 00223 fp = fopen(fn, "r"); 00224 if (fp == NULL || ferror(fp)) { 00225 if (fp) { 00226 if (msgp) 00227 *msgp = xstrdup(strerror(errno)); 00228 (void) fclose(fp); 00229 fp = NULL; 00230 } else { 00231 if (msgp) /* XXX FIXME: add __FUNCTION__ identifier? */ 00232 *msgp = xstrdup("unknown error"); 00233 } 00234 goto exit; 00235 } 00236 00237 gpsee_flock(fileno(fp), GPSEE_LOCK_SH); 00238 00239 if (F_ISSET(js->flags, SKIPSHEBANG)) { 00240 char buf[BUFSIZ]; 00241 00242 if (fgets(buf, sizeof(buf), fp)) { 00243 if (!(buf[0] == '#' && buf[1] == '!')) { 00244 /* XXX FIXME: return through *msgp */ 00245 rpmlog(RPMLOG_WARNING, "%s: %s: no \'#!\' on 1st line\n", 00246 __FUNCTION__, fn); 00247 rewind(fp); 00248 } else { 00249 #ifdef NOTYET /* XXX FIXME */ 00250 gpsee_interpreter_t * I = js->I; 00251 I->linenoOffset += 1; 00252 #endif /* NOTYET */ 00253 do { /* consume entire first line, regardless of length */ 00254 if (strchr(buf, '\n')) 00255 break; 00256 } while (fgets(buf, sizeof(buf), fp)); 00257 /* 00258 * Make spidermonkey think the script starts with a blank line, 00259 * to keep line numbers in sync. 00260 */ 00261 ungetc('\n', fp); 00262 } 00263 } 00264 } 00265 00266 exit: 00267 00268 if (_rpmjs_debug) 00269 fprintf(stderr, "<== %s(%p,%s,%p) fp %p\n", __FUNCTION__, js, fn, msgp, fp); 00270 00271 return fp; 00272 } 00273 00274 #ifdef NOTYET /* XXX FIXME */ 00275 static void processInlineFlags(rpmjs js, FILE * fp, signed int *verbosity_p) 00276 { 00277 char buf[256]; 00278 off_t offset; 00279 00280 offset = ftello(fp); 00281 00282 while (fgets(buf, sizeof(buf), fp)) { 00283 char *s, *e; 00284 00285 if ((buf[0] != '/') || (buf[1] != '/')) 00286 break; 00287 00288 for (s = buf + 2; *s == ' ' || *s == '\t'; s++); 00289 if (strncmp(s, "gpsee:", 6) != 0) 00290 continue; 00291 00292 for (s = s + 6; *s == ' ' || *s == '\t'; s++); 00293 00294 for (e = s; *e; e++) { 00295 switch (*e) { 00296 case '\r': 00297 case '\n': 00298 case '\t': 00299 case ' ': 00300 *e = '\0'; 00301 break; 00302 } 00303 } 00304 00305 if (s[0]) 00306 processFlags(gsr, s, verbosity_p); 00307 } 00308 00309 fseeko(fp, offset, SEEK_SET); 00310 } 00311 #endif /* NOTYET */ 00312 #endif /* WITH_GPSEE */ 00313 00314 rpmRC rpmjsRunFile(rpmjs js, const char * fn, 00315 char *const * Iargv, 00316 const char ** resultp) 00317 { 00318 rpmRC rc = RPMRC_FAIL; 00319 00320 if (js == NULL) js = rpmjsI(); 00321 00322 if (fn != NULL) { 00323 #if defined(WITH_GPSEE) 00324 gpsee_interpreter_t * I = js->I; 00325 FILE * fp = rpmjsOpenFile(js, fn, resultp); 00326 00327 if (fp == NULL) { 00328 /* XXX FIXME: strerror in *reultp */ 00329 goto exit; 00330 } 00331 00332 #ifdef NOTYET /* XXX FIXME */ 00333 processInlineFlags(js, fp, &verbosity); 00334 gpsee_setVerbosity(verbosity); 00335 #endif 00336 00337 /* Just compile and exit? */ 00338 if (F_ISSET(js->flags, NOEXEC)) { 00339 JSScript *script = NULL; 00340 JSObject *scrobj = NULL; 00341 00342 if (!gpsee_compileScript(I->cx, fn, 00343 fp, NULL, &script, I->realm->globalObject, &scrobj)) 00344 { 00345 /* XXX FIXME: isatty(3) */ 00346 gpsee_reportUncaughtException(I->cx, JSVAL_NULL, 00347 (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) 00348 || 00349 ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) 00350 && isatty(STDERR_FILENO))); 00351 } else 00352 rc = RPMRC_OK; 00353 } else { 00354 char *const * Ienviron = NULL; 00355 00356 if (F_ISSET(js->flags, ALLOW)) { 00357 #if defined(__APPLE__) 00358 Ienviron = (char *const *) _NSGetEnviron(); 00359 #else 00360 Ienviron = environ; 00361 #endif 00362 } 00363 00364 if (!gpsee_runProgramModule(I->cx, fn, 00365 NULL, fp, Iargv, Ienviron)) 00366 { 00367 int code = gpsee_getExceptionExitCode(I->cx); 00368 if (code >= 0) { 00369 /* XXX FIXME: format and return code in *resultp. */ 00370 /* XXX hack tp get code into rc -> ec by negating */ 00371 rc = -code; 00372 } else { 00373 gpsee_reportUncaughtException(I->cx, JSVAL_NULL, 00374 (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) 00375 || 00376 ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) 00377 && isatty(STDERR_FILENO))); 00378 } 00379 } else 00380 rc = RPMRC_OK; 00381 } 00382 fclose(fp); 00383 fp = NULL; 00384 #endif /* WITH_GPSEE */ 00385 } 00386 00387 #if defined(WITH_GPSEE) 00388 exit: 00389 #endif /* WITH_GPSEE */ 00390 00391 if (_rpmjs_debug) 00392 fprintf(stderr, "<== %s(%p,%s) rc %d\n", __FUNCTION__, js, fn, rc); 00393 00394 return rc; 00395 } 00396 00397 rpmRC rpmjsRun(rpmjs js, const char * str, const char ** resultp) 00398 { 00399 rpmRC rc = RPMRC_FAIL; 00400 00401 if (js == NULL) js = rpmjsI(); 00402 00403 if (str != NULL) { 00404 #if defined(WITH_GPSEE) 00405 gpsee_interpreter_t * I = js->I; 00406 jsval v = JSVAL_VOID; 00407 JSBool ok; 00408 00409 ok = JS_EvaluateScript(I->cx, I->realm->globalObject, str, strlen(str), 00410 __FILE__, __LINE__, &v); 00411 if (ok) { 00412 rc = RPMRC_OK; 00413 if (resultp) { 00414 JSString *rstr = JS_ValueToString(I->cx, v); 00415 *resultp = gpsee_getStringBytes(I->cx, rstr); 00416 } 00417 } 00418 v = JSVAL_NULL; 00419 #endif /* WITH_GPSEE */ 00420 } 00421 00422 if (_rpmjs_debug) 00423 fprintf(stderr, "<== %s(%p,%p[%u]) rc %d\n", __FUNCTION__, js, str, (unsigned)(str ? strlen(str) : 0), rc); 00424 00425 return rc; 00426 }
1.7.5.1