rpm 5.3.7
|
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 (void) gpsee_destroyInterpreter(js->I); 00125 #endif 00126 js->I = NULL; 00127 } 00128 00129 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00130 rpmioPool _rpmjsPool; 00131 00132 static rpmjs rpmjsGetPool(/*@null@*/ rpmioPool pool) 00133 /*@globals _rpmjsPool, fileSystem @*/ 00134 /*@modifies pool, _rpmjsPool, fileSystem @*/ 00135 { 00136 rpmjs js; 00137 00138 if (_rpmjsPool == NULL) { 00139 _rpmjsPool = rpmioNewPool("js", sizeof(*js), -1, _rpmjs_debug, 00140 NULL, NULL, rpmjsFini); 00141 pool = _rpmjsPool; 00142 } 00143 return (rpmjs) rpmioGetPool(pool, sizeof(*js)); 00144 } 00145 00146 static rpmjs rpmjsI(void) 00147 /*@globals _rpmjsI @*/ 00148 /*@modifies _rpmjsI @*/ 00149 { 00150 if (_rpmjsI == NULL) { 00151 #if defined(WITH_GPSEE) 00152 gpsee_verbosity(0); /* XXX hack around syslog(3) in GPSEE */ 00153 #endif 00154 _rpmjsI = rpmjsNew(NULL, 0); 00155 } 00156 if (_rpmjs_debug) 00157 fprintf(stderr, "<== %s() _rpmjsI %p\n", __FUNCTION__, _rpmjsI); 00158 return _rpmjsI; 00159 } 00160 00161 /* XXX FIXME: Iargv/Ienviron are now associated with running. */ 00162 rpmjs rpmjsNew(char ** av, uint32_t flags) 00163 { 00164 rpmjs js = 00165 #ifdef NOTYET 00166 (flags & 0x80000000) ? rpmjsI() : 00167 #endif 00168 rpmjsGetPool(_rpmjsPool); 00169 JSI_t I = NULL; 00170 00171 #if defined(WITH_GPSEE) 00172 if (flags == 0) 00173 flags = _rpmjs_options; 00174 00175 if (F_ISSET(flags, NOUTF8) || getenv("GPSEE_NO_UTF8_C_STRINGS")) { 00176 JS_DestroyRuntime(JS_NewRuntime(1024)); 00177 putenv((char *) "GPSEE_NO_UTF8_C_STRINGS=1"); 00178 } 00179 00180 /* XXX FIXME: js->Iargv/js->Ienviron for use by rpmjsRunFile() */ 00181 I = gpsee_createInterpreter(); 00182 #ifdef NOTYET /* FIXME: dig out where NOCACHE has moved. */ 00183 if (F_ISSET(flags, NOCACHE)) 00184 I->useCompilerCache = 0; 00185 #endif 00186 if (F_ISSET(flags, NOWARN)) { 00187 gpsee_runtime_t * grt = JS_GetRuntimePrivate(JS_GetRuntime(I->cx)); 00188 grt->errorReport |= er_noWarnings; 00189 } 00190 00191 JS_SetOptions(I->cx, (flags & 0xffff)); 00192 #if defined(JS_GC_ZEAL) 00193 JS_SetGCZeal(I->cx, _rpmjs_zeal); 00194 #endif 00195 #endif /* WITH_GPSEE */ 00196 00197 js->flags = flags; 00198 js->I = I; 00199 00200 return rpmjsLink(js); 00201 } 00202 00203 #if defined(WITH_GPSEE) 00204 static FILE * rpmjsOpenFile(rpmjs js, const char * fn, const char ** msgp) 00205 /*@modifies js @*/ 00206 { 00207 FILE * fp = NULL; 00208 00209 fp = fopen(fn, "r"); 00210 if (fp == NULL || ferror(fp)) { 00211 if (fp) { 00212 if (msgp) 00213 *msgp = xstrdup(strerror(errno)); 00214 (void) fclose(fp); 00215 fp = NULL; 00216 } else { 00217 if (msgp) /* XXX FIXME: add __FUNCTION__ identifier? */ 00218 *msgp = xstrdup("unknown error"); 00219 } 00220 goto exit; 00221 } 00222 00223 gpsee_flock(fileno(fp), GPSEE_LOCK_SH); 00224 00225 if (F_ISSET(js->flags, SKIPSHEBANG)) { 00226 char buf[BUFSIZ]; 00227 00228 if (fgets(buf, sizeof(buf), fp)) { 00229 if (!(buf[0] == '#' && buf[1] == '!')) { 00230 /* XXX FIXME: return through *msgp */ 00231 rpmlog(RPMLOG_WARNING, "%s: %s: no \'#!\' on 1st line\n", 00232 __FUNCTION__, fn); 00233 rewind(fp); 00234 } else { 00235 #ifdef NOTYET /* XXX FIXME */ 00236 gpsee_interpreter_t * I = js->I; 00237 I->linenoOffset += 1; 00238 #endif /* NOTYET */ 00239 do { /* consume entire first line, regardless of length */ 00240 if (strchr(buf, '\n')) 00241 break; 00242 } while (fgets(buf, sizeof(buf), fp)); 00243 /* 00244 * Make spidermonkey think the script starts with a blank line, 00245 * to keep line numbers in sync. 00246 */ 00247 ungetc('\n', fp); 00248 } 00249 } 00250 } 00251 00252 exit: 00253 00254 if (_rpmjs_debug) 00255 fprintf(stderr, "<== %s(%p,%s,%p) fp %p\n", __FUNCTION__, js, fn, msgp, fp); 00256 00257 return fp; 00258 } 00259 00260 #ifdef NOTYET /* XXX FIXME */ 00261 static void processInlineFlags(rpmjs js, FILE * fp, signed int *verbosity_p) 00262 { 00263 char buf[256]; 00264 off_t offset; 00265 00266 offset = ftello(fp); 00267 00268 while (fgets(buf, sizeof(buf), fp)) { 00269 char *s, *e; 00270 00271 if ((buf[0] != '/') || (buf[1] != '/')) 00272 break; 00273 00274 for (s = buf + 2; *s == ' ' || *s == '\t'; s++); 00275 if (strncmp(s, "gpsee:", 6) != 0) 00276 continue; 00277 00278 for (s = s + 6; *s == ' ' || *s == '\t'; s++); 00279 00280 for (e = s; *e; e++) { 00281 switch (*e) { 00282 case '\r': 00283 case '\n': 00284 case '\t': 00285 case ' ': 00286 *e = '\0'; 00287 break; 00288 } 00289 } 00290 00291 if (s[0]) 00292 processFlags(gsr, s, verbosity_p); 00293 } 00294 00295 fseeko(fp, offset, SEEK_SET); 00296 } 00297 #endif /* NOTYET */ 00298 #endif /* WITH_GPSEE */ 00299 00300 rpmRC rpmjsRunFile(rpmjs js, const char * fn, 00301 char *const * Iargv, 00302 const char ** resultp) 00303 { 00304 rpmRC rc = RPMRC_FAIL; 00305 00306 if (js == NULL) js = rpmjsI(); 00307 00308 if (fn != NULL) { 00309 #if defined(WITH_GPSEE) 00310 gpsee_interpreter_t * I = js->I; 00311 FILE * fp = rpmjsOpenFile(js, fn, resultp); 00312 00313 if (fp == NULL) { 00314 /* XXX FIXME: strerror in *reultp */ 00315 goto exit; 00316 } 00317 00318 #ifdef NOTYET /* XXX FIXME */ 00319 processInlineFlags(js, fp, &verbosity); 00320 gpsee_setVerbosity(verbosity); 00321 #endif 00322 00323 /* Just compile and exit? */ 00324 if (F_ISSET(js->flags, NOEXEC)) { 00325 JSScript *script = NULL; 00326 JSObject *scrobj = NULL; 00327 00328 if (!gpsee_compileScript(I->cx, fn, 00329 fp, NULL, &script, I->realm->globalObject, &scrobj)) 00330 { 00331 /* XXX FIXME: isatty(3) */ 00332 gpsee_reportUncaughtException(I->cx, JSVAL_NULL, 00333 (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) 00334 || 00335 ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) 00336 && isatty(STDERR_FILENO))); 00337 } else 00338 rc = RPMRC_OK; 00339 } else { 00340 char *const * Ienviron = NULL; 00341 00342 if (F_ISSET(js->flags, ALLOW)) { 00343 #if defined(__APPLE__) 00344 Ienviron = (char *const *) _NSGetEnviron(); 00345 #else 00346 Ienviron = environ; 00347 #endif 00348 } 00349 00350 if (!gpsee_runProgramModule(I->cx, fn, 00351 NULL, fp, Iargv, Ienviron)) 00352 { 00353 int code = gpsee_getExceptionExitCode(I->cx); 00354 if (code >= 0) { 00355 /* XXX FIXME: format and return code in *resultp. */ 00356 /* XXX hack tp get code into rc -> ec by negating */ 00357 rc = -code; 00358 } else { 00359 gpsee_reportUncaughtException(I->cx, JSVAL_NULL, 00360 (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) 00361 || 00362 ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) 00363 && isatty(STDERR_FILENO))); 00364 } 00365 } else 00366 rc = RPMRC_OK; 00367 } 00368 fclose(fp); 00369 fp = NULL; 00370 #endif /* WITH_GPSEE */ 00371 } 00372 00373 #if defined(WITH_GPSEE) 00374 exit: 00375 #endif /* WITH_GPSEE */ 00376 00377 if (_rpmjs_debug) 00378 fprintf(stderr, "<== %s(%p,%s) rc %d\n", __FUNCTION__, js, fn, rc); 00379 00380 return rc; 00381 } 00382 00383 rpmRC rpmjsRun(rpmjs js, const char * str, const char ** resultp) 00384 { 00385 rpmRC rc = RPMRC_FAIL; 00386 00387 if (js == NULL) js = rpmjsI(); 00388 00389 if (str != NULL) { 00390 #if defined(WITH_GPSEE) 00391 gpsee_interpreter_t * I = js->I; 00392 jsval v = JSVAL_VOID; 00393 JSBool ok; 00394 00395 ok = JS_EvaluateScript(I->cx, I->realm->globalObject, str, strlen(str), 00396 __FILE__, __LINE__, &v); 00397 if (ok) { 00398 rc = RPMRC_OK; 00399 if (resultp) { 00400 JSString *rstr = JS_ValueToString(I->cx, v); 00401 *resultp = JS_GetStringBytes(rstr); 00402 } 00403 } 00404 v = JSVAL_NULL; 00405 #endif /* WITH_GPSEE */ 00406 } 00407 00408 if (_rpmjs_debug) 00409 fprintf(stderr, "<== %s(%p,%p[%u]) rc %d\n", __FUNCTION__, js, str, (unsigned)(str ? strlen(str) : 0), rc); 00410 00411 return rc; 00412 }