CGI-SpeedyCGI
view release on metacpan or search on metacpan
src/speedy_perl.c view on Meta::CPAN
return hv_fetch(hash, key, key_len, lval);
}
/* Find the SpeedyScript structure in the hash, using a devino key
* Create a new one if not found.
*/
static SpeedyScript *find_scr(SpeedyDevIno devino, int *is_new) {
SV *sv;
SpeedyScript *retval;
sv = find_devino(devino, scr_hash, 1)[0];
if ((*is_new = !SvOK(sv))) {
speedy_new(retval, 1, SpeedyScript);
retval->handler = NULL;
retval->last_cwd = NULL;
sv_setiv(sv, (IV) retval);
} else {
retval = (SpeedyScript *) SvIV(sv);
}
return retval;
}
/* Get the directory that holds the filename */
static char *fname_dir(const char *p) {
char *s;
if (p && (s = strrchr(p, '/')))
return speedy_util_strndup(p, max(1,s-p));
else
return NULL;
}
static void my_call_sv(SV *sv) {
if (sv) {
dSP;
PUSHMARK(SP);
call_sv(sv, G_DISCARD | G_NOARGS);
}
}
static void cwd_refcnt_dec(SpeedyCwd *cwd) {
if (!--(cwd->refcnt)) {
char key[DEVINO_STR_SIZE];
int key_len;
key_len = devino_str(cwd->devino, key);
hv_delete(cwd_hash, key, key_len, G_DISCARD);
hv_delete_ent(cwd_hash, cwd->path, G_DISCARD, 0);
SvREFCNT_dec(cwd->path);
speedy_free(cwd);
}
}
static int stat_cwd_fd(SpeedyDevIno *devino) {
struct stat stbuf;
if (cwd_fd != -1) {
if (fstat(cwd_fd, &stbuf) != -1) {
*devino = speedy_util_stat_devino(&stbuf);
return 1;
}
close(cwd_fd);
cwd_fd = -1;
}
return 0;
}
static int chdir_path(const char *path, SpeedyDevIno *devino) {
int retval;
if (!path || !path[0])
return 0;
if (cwd_fd != -1)
close(cwd_fd);
retval = path
? (((path[0] == '.' && path[1] == '\0')) ? 0 : chdir(path))
: -1;
cwd_fd = retval != -1
? speedy_util_pref_fd(open(".", O_RDONLY), PREF_FD_CWD)
: -1;
if (cwd_fd != -1)
fcntl(cwd_fd, F_SETFD, FD_CLOEXEC);
/* TEST - simulate unreadable "." directory */
/* close(cwd_fd); cwd_fd = -1; */
/* Get device/inode for "." */
if (retval != -1 && devino && !stat_cwd_fd(devino)) {
struct stat stbuf;
if (cwd_fd == -1) {
if (stat(".", &stbuf) == -1) {
devino->d = 0;
devino->i = 0;
}
} else {
*devino = speedy_util_stat_devino(&stbuf);
}
}
return retval;
}
static int quick_cd(SpeedyDevIno dest) {
SpeedyDevIno devino;
/*
* See if cwd_fd is the correct dir - if so fchdir there.
*/
if (stat_cwd_fd(&devino) && DEVINO_SAME(dest, devino) &&
fchdir(cwd_fd) != -1)
{
return 1;
}
/* Stat "." */
chdir_path(".", &devino);
/* See if "." is the right directory */
return DEVINO_SAME(dest, devino);
}
static void *get_perlvar(SpeedyPerlVar *pv) {
if (!pv->ptr) {
switch(pv->type) {
case SVt_PVIO:
pv->ptr = gv_fetchpv(pv->name, 1, SVt_PVIO);
break;
case SVt_PVAV:
pv->ptr = get_av(pv->name, 1);
break;
case SVt_PVHV:
pv->ptr = get_hv(pv->name, 1);
break;
case SVt_PVCV:
pv->ptr = get_cv(pv->name, 0);
break;
default:
pv->ptr = get_sv(pv->name, 1);
break;
}
if (pv->type != SVt_PVCV && !pv->ptr)
DIE_QUIET("Cannot create perl variable %s", pv->name);
}
return pv->ptr;
}
/* Shutdown and exit. */
static void all_done(void) {
speedy_file_set_state(FS_CLOSED);
/* Destroy the interpreter */
if (my_perl) {
src/speedy_perl.c view on Meta::CPAN
speedy_new(cwd, 1, SpeedyCwd);
/* Chdir to the given path */
if (!path || chdir_path(path, &(cwd->devino)) == -1) {
speedy_free(cwd);
return NULL;
}
/* Make a new cwd structure */
cwd->refcnt = 0;
cwd->path = newSVpv(path, 0);
/* Store in the hash */
sv = newSViv((IV)cwd);
SvREFCNT_inc(sv);
key_len = devino_str(cwd->devino, key);
my_hv_store(cwd_hash, key, key_len, sv);
if (!hv_store_ent(cwd_hash, cwd->path, sv, 0))
SvREFCNT_dec(sv);
return cwd;
}
static void store_last_cwd(SpeedyCwd **last_cwd, SpeedyCwd *cwd) {
SpeedyCwd *prev_ptr = *last_cwd;
cwd->refcnt++;
*last_cwd = cwd;
if (prev_ptr)
cwd_refcnt_dec(prev_ptr);
}
#define PACKAGE_FMT SPEEDY_PKG("_%s")
#define COLON_HANDLER "::handler"
#define PACKAGE1 "package "
#define PACKAGE2 "; sub handler { "
static void load_script(
SpeedyDevIno devino, SpeedyScript *scr, const char *scr_path
)
{
SV *sv;
char pkg[sizeof(PACKAGE_FMT)+DEVINO_STR_SIZE+sizeof(COLON_HANDLER)+5];
/* Get package name */
{
char hex_str[DEVINO_STR_SIZE];
devino_str(devino, hex_str);
sprintf(pkg, PACKAGE_FMT, hex_str);
}
/* Create phony package in sv with the script code in the handler func */
{
struct stat stbuf;
SpeedyMapInfo *mi = NULL;
int fd;
/* Grab the contents of the file */
if ((fd = speedy_util_open_stat(scr_path, &stbuf)) != -1) {
mi = speedy_util_mapin(fd, -1, stbuf.st_size);
close(fd);
}
if (fd == -1 || mi == NULL)
speedy_util_die(scr_path);
/* Create sv to eval */
sv = newSVpvn(PACKAGE1, sizeof(PACKAGE1)-1);
sv_catpv (sv, pkg);
sv_catpvn(sv, PACKAGE2, sizeof(PACKAGE2)-1);
sv_catpvn(sv, mi->addr, mi->maplen);
sv_catpvn(sv, "; }", 3);
/* Get rid of the file contents */
speedy_util_mapout(mi);
}
/* Evaluate the sv to create the handler */
{
dSP;
PUSHMARK(SP);
eval_sv(sv, G_DISCARD | G_NOARGS | G_VOID | G_EVAL | G_KEEPERR);
}
SvREFCNT_dec(sv);
/* If there were no eval errors, then store a reference to the handler */
scr->handler = NULL;
if (!SvTRUE(PERLVAL_EVAL_ERROR)) {
CV *cv;
strcat(pkg, COLON_HANDLER);
if ((cv = get_cv(pkg, 0)))
scr->handler = newRV_inc((SV*)cv);
}
/* Die if we couldn't create the handler for whatever reason */
if (!scr->handler) {
DIE_QUIET("Could not compile code for %s: %s",
scr_path, my_SvPV(PERLVAL_EVAL_ERROR));
}
}
static void cleanup_after_perl(void) {
/* Cached time is now invalid */
speedy_util_time_invalidate();
/* Cancel any alarms */
alarm(0);
/* Terminate if a forked child returned */
if (getpid() != speedy_util_getpid()) {
speedy_util_pid_invalidate();
speedy_file_fork_child();
all_done();
}
/* Tell our file code that its fd is suspect */
speedy_file_fd_is_suspect();
}
src/speedy_perl.c view on Meta::CPAN
}
#endif
return exit_val;
}
/* Called from xs_init */
void speedy_xs_init(void) {
int i;
SV *sv;
/*
* Put things here that have to be done in the perl interpreter before
* a script runs its BEGIN block.
*/
/* Find/create our perl vars in the interpreter */
for (i = 0; i < PERLVAR_COUNT; ++i) {
(void) get_perlvar(SpeedyPerlVars + i);
}
scr_hash = newHV();
cwd_hash = newHV();
/* Tell our module that we are speedycgi */
sv_inc(PERLVAL_I_AM_SPEEDY);
/* Avoid warnings about "used only once" */
GvMULTI_on(
gv_fetchpv(PERLVAR_I_AM_SPEEDY.name, 0, PERLVAR_I_AM_SPEEDY.type)
);
/*
* Initialize options variables in our module.
*/
for (i = 0; i < SPEEDY_NUMOPTS; ++i) {
OptRec *o = speedy_optdefs + i;
if (o->type == OTYPE_STR) {
if (!STR_OPTVAL(o))
continue;
sv = newSVpv(STR_OPTVAL(o), 0);
} else {
sv = newSViv(INT_OPTVAL(o));
}
my_hv_store(PERLVAL_OPTS, o->name, o->name_len, sv);
}
}
void speedy_perl_init(void) {
char **perl_argv;
const char *temp_script_name;
int use_devfd, is_new;
char dev_fd_name[sizeof(DEVFD)+10];
SpeedyScript *scr;
int single_script = DOING_SINGLE_SCRIPT;
/* If we're exec'ing a setuid script then we must use a temporary
* script name of /dev/fd/N
*/
use_devfd = single_script &&
speedy_script_getstat()->st_mode & (S_ISUID|S_ISGID);
if (single_script) {
if (use_devfd) {
sprintf(dev_fd_name, DEVFD, speedy_script_open());
temp_script_name = dev_fd_name;
} else {
temp_script_name = NULL;
}
} else {
temp_script_name = "-e&{$" SPEEDY_PKG("_sub") "}(@ARGV);";
}
/* Parse perl file. */
perl_argv = speedy_opt_perl_argv(temp_script_name);
if (perl_parse(my_perl, xs_init,
speedy_util_argc((const char * const *)perl_argv), perl_argv, NULL))
{
DIE_QUIET("perl_parse error");
}
cleanup_after_perl();
/* If we had to use /dev/fd/N, perl will close the file for us, so
* make sure our code knows it's closed. If we need it from here on out
* it'll have to be re-opened.
*/
if (use_devfd)
speedy_script_close();
/* Create a SpeedyScript entry for the standard script */
scr = find_scr(speedy_util_stat_devino(speedy_script_getstat()), &is_new);
/* If using groups, try pre-loading the script to save time later */
if (!single_script && !speedy_script_open_failure()) {
load_script(
speedy_util_stat_devino(speedy_script_getstat()),
scr, speedy_opt_script_fname()
);
cleanup_after_perl();
}
/* Time to close stderr */
close(2);
}
void speedy_perl_run(slotnum_t gslotnum, slotnum_t bslotnum) {
int numrun, exit_val;
int single_script = DOING_SINGLE_SCRIPT;
/* Start listening on our socket */
speedy_ipc_listen(bslotnum);
/* Main loop */
for (numrun = 0; !OPTVAL_MAXRUNS || numrun < OPTVAL_MAXRUNS; ++numrun) {
/* Lock/mmap our temp file. If our group is invalid, exit quietly */
if (getppid() == 1 || !speedy_group_lock(gslotnum))
all_done();
/* Update our maturity level */
FILE_SLOT(be_slot, bslotnum).maturity = numrun ? 2 : 1;
/* Put ourself onto the be_wait list */
speedy_backend_be_wait_put(gslotnum, bslotnum);
/* If we were listed as starting, turn that off */
if (FILE_SLOT(gr_slot, gslotnum).be_starting == speedy_util_getpid())
FILE_SLOT(gr_slot, gslotnum).be_starting = 0;
/* Send out alarm signal to frontends */
speedy_group_sendsigs(gslotnum);
/* Fix our listener fd */
speedy_ipc_listen_fixfd(bslotnum);
/* Unlock file */
speedy_file_set_state(FS_HAVESLOTS);
/* Do an accept on our socket */
backend_accept();
/* Lock file. If our group is invalid, exit quietly */
if (!speedy_group_lock(gslotnum))
all_done();
/* If we were listed as starting, turn that off */
if (FILE_SLOT(gr_slot, gslotnum).be_starting == speedy_util_getpid())
FILE_SLOT(gr_slot, gslotnum).be_starting = 0;
/* Wake up any waiting frontends */
speedy_group_sendsigs(gslotnum);
/* Unlock the file */
speedy_file_set_state(FS_HAVESLOTS);
/* Run the perl code once */
( run in 3.011 seconds using v1.01-cache-2.11-cpan-e1769b4cff6 )