/* shell_dealloc(): * Remove the requested shell variable from the list. Return 0 if * the variable was removed successfully, otherwise return -1. */ static int shell_dealloc(char *name) { struct s_shell *sp; sp = shell_vars; while(1) { if (sp->name == (char *)0) { if (sp->next == (struct s_shell *)0) return(-1); else { sp = sp->next; continue; } } if (strcmp(name,sp->name) == 0) { env_free(sp->name); env_free(sp->val); sp->name = (char *)0; sp->val = (char *)0; return(0); } if (sp->next == (struct s_shell *)0) return(-1); else sp = sp->next; } }
struct envelope * env_create( const char *dir, const char *id, const char *e_mail, const struct envelope *parent ) { struct envelope *env; struct timeval tv_now; int pid; /* way bigger than we should ever need */ char buf[ 1024 ]; env = calloc( 1, sizeof( struct envelope )); if (( id == NULL ) || ( *id == '\0' )) { if ( simta_gettimeofday( &tv_now ) != 0 ) { env_free( env ); return( NULL ); } if (( pid = getpid()) < 0 ) { syslog( LOG_ERR, "Syserror: env_set_id getpid: %m" ); env_free( env ); return( NULL ); } snprintf( buf, 1023, "%lX.%lX.%d", (unsigned long)tv_now.tv_sec, (unsigned long)tv_now.tv_usec, pid ); id = buf; } env->e_id = strdup( id ); if ( e_mail != NULL ) { if ( env_sender( env, e_mail ) != 0 ) { env_free( env ); return( NULL ); } } if ( parent ) { env->e_dinode = parent->e_dinode; env->e_n_exp_level = parent->e_n_exp_level + 1; env_jail_set( env, parent->e_jail ); } else if ( simta_rqueue_policy == RQUEUE_POLICY_JAIL ) { env_jail_set( env, ENV_JAIL_PRISONER ); } env->e_dir = dir; return( env ); }
/* clearenv(): * Clear out the entire environment. */ void clearenv(void) { struct s_shell *sp; for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) { if (sp->name != (char *)0) { env_free(sp->name); env_free(sp->val); sp->name = (char *)0; sp->val = (char *)0; } } }
void trap(struct Trapframe *tf) { // The environment may have set DF and some versions // of GCC rely on DF being clear asm volatile("cld" ::: "cc"); // Halt the CPU if some other CPU has called panic() extern char *panicstr; if (panicstr) asm volatile("hlt"); // Re-acqurie the big kernel lock if we were halted in // sched_yield() if (xchg(&thiscpu->cpu_status, CPU_STARTED) == CPU_HALTED) lock_kernel(); // Check that interrupts are disabled. If this assertion // fails, DO NOT be tempted to fix it by inserting a "cli" in // the interrupt path. assert(!(read_eflags() & FL_IF)); if ((tf->tf_cs & 3) == 3) { // Trapped from user mode. // Acquire the big kernel lock before doing any // serious kernel work. // LAB 4: Your code here. assert(curenv); lock_kernel(); // Garbage collect if current enviroment is a zombie if (curenv->env_status == ENV_DYING) { env_free(curenv); curenv = NULL; sched_yield(); } // Copy trap frame (which is currently on the stack) // into 'curenv->env_tf', so that running the environment // will restart at the trap point. curenv->env_tf = *tf; // The trapframe on the stack should be ignored from here on. tf = &curenv->env_tf; } // Record that tf is the last real trapframe so // print_trapframe can print some additional information. last_tf = tf; // Dispatch based on what type of trap occurred trap_dispatch(tf); // If we made it to this point, then no other environment was // scheduled, so we should return to the current environment // if doing so makes sense. if (curenv && curenv->env_status == ENV_RUNNING) env_run(curenv); else sched_yield(); }
void free_entry(entry *e) { free(e->cmd); free(e->pwd); env_free(e->envp); free(e); }
void hx509_env_free(hx509_env *env) { if (*env) env_free(*env); *env = NULL; }
static void core_free(t_core *core) { free(core->name_term); cut_tab_free(core->cut_tab); env_free(core->env); jobs_free(core->jobs); close_modules(core->mods); }
// // Frees environment e. // If e was the current env, then runs a new environment (and does not return // to the caller). // void env_destroy(struct Env *e) { env_free(e); //cprintf("Destroyed the only environment - nothing more to do!\n"); while (1) run_command_prompt(); }
// // Frees environment e. // If e was the current env, then runs a new environment (and does not return // to the caller). // void env_destroy(struct Env *e) { env_free(e); cprintf("Destroyed the only environment - nothing more to do!\n"); while (1) monitor(NULL); }
// // Frees environment e. // If e was the current env, then runs a new environment (and does not return // to the caller). // void env_destroy(struct Env *e) { env_free(e); if (curenv == e) { curenv = NULL; sched_yield(); } }
ENV* env_stackout(ENV* env) { ENV* parent; assert(env != NULL); parent = env->parent; env_free(env); return parent; }
// // Frees environment e. // If e was the current env, then runs a new environment (and does not return // to the caller). // void env_destroy(struct Env *e) { env_free(e); if (curenv == e) { //cprintf("here\n"); curenv = NULL; sched_yield(); } }
int run_prompt() { Node *ptree; AstNode *stree; EmCodeObject *co; Environment *env; EmObject *retval; env = newenv(vm->topenv); while (1) { ptree = parse(); if (ptree) { if (ptree->type != MAGIC_COMMAND) { // printtree(ptree); stree = ast_from_ptree(ptree); // printstree(stree); co = compile_ast_tree(stree); INCREF(&nulobj); retval = run_codeobject(co, env, &nulobj); if (retval) DECREF(retval); vm_reset_for_prompt(); freetree(ptree); freestree(stree); } else { // MAGIC_COMMAND printf("got magic command %d\n", CHILD(ptree,0)->type); if (NCH(ptree) == 2) { printf("magic command arg = %s\n", CHILD(ptree,1)->lexeme); } if (CHILD(ptree,0)->type == MCA_EXIT) { freetree(ptree); // release memory before exit break; } // Always release memory of parse tree freetree(ptree); } } } env_free(env); return 1; }
int main() { int tx_port = 0; char *source = "test/test_defs.b"; sys_init(0); tx_server(source, "bin/state", &tx_port); vol_init(0, "bin/volume"); char *code = sys_load(source); env = env_new(source, code); mem_free(code); int len = 0; char **files = sys_list("test/data", &len); vars = vars_new(len); rvars = vars_new(len); for (int i = 0; i < len; ++i) { vars_add(rvars, files[i], 0, NULL); vars_add(vars, files[i], 0, NULL); } vars_add(vars, "___param", 0, NULL); test_vars(); test_load(); test_param(); test_clone(); test_eq(); test_store(); test_select(); test_rename(); test_extend(); test_join(); test_project(); test_semidiff(); test_summary(); test_union(); test_compound(); test_call(); tx_free(); env_free(env); mem_free(files); vars_free(vars); vars_free(rvars); return 0; }
void render(struct page *p) { int depth; FILE *out; struct lacy_env env; struct page_stack p_stack; struct ut_str outfile; str_init(&curtok); if (NULL == p) return; str_init(&outfile); str_append_str(&outfile, conf.output_dir.s); str_append(&outfile, '/'); str_append_str(&outfile, p->file_path); /* depth - 1 since we added output dir to path */ depth = build_depth(outfile.s) - 1; if (NULL == (out = fopen(outfile.s, "w"))) fatal("Unable to open: %: ", outfile.s); p_stack.size = 0; p_stack.pos = 0; /* Build Environment */ env.depth = depth; env.p_stack = &p_stack; env.sym_tbl = NULL; env_build(p, &env); /* set stack back to top */ p_stack.pos = 0; /* do it already */ build_tree(&env); write_tree(out, &env); env_free(&env); fclose(out); str_free(&curtok); if (verbosity > 0) { printf("Rendered %s\n", outfile.s); } str_free(&outfile); }
// // Frees environment e. // If e was the current env, then runs a new environment (and does not return // to the caller). // void env_destroy(struct Env *e) { env_free(e); //after free the env, clean the tickets of the env global_tickets -= e->tickets; e->tickets = 0; if (curenv == e) { curenv = NULL; sched_yield(); } }
static void env_free(hx509_env b) { while(b) { hx509_env next = b->next; if (b->type == env_string) free(b->u.string); else if (b->type == env_list) env_free(b->u.list); free(b->name); free(b); b = next; } }
void execute_external(int argc, char **argv) { UCHAR LoadError[255]; PSZ Args; PSZ Envs; RESULTCODES ChildRC; APIRET rc; /* Return code */ char *env; int i; log("execute_external():\n"); log("argc=%d\n", argc); for (i = 0; i < argc; i++) log("argv[%d]=%s\n", i, argv[i]); env = env_get(); rc = DosExecPgm(LoadError, /* Object name buffer */ sizeof(LoadError), /* Length of object name buffer */ EXEC_SYNC, /* Asynchronous/Trace flags */ argv[0], /* Argument string */ env, /* Environment string */ &ChildRC, /* Termination codes */ argv[0]); /* Program file name */ env_free(env); if (rc != NO_ERROR) { // printf("DosExecPgm error: return code = %u\n",rc); VioWrtTTY("DosExecPgm error\r\n", 18, 0); //: return code = %u\n",rc); return ; } else { // printf("DosExecPgm complete. Termination Code: %u Return Code: %u\n", // ChildRC.codeTerminate, // ChildRC.codeResult); /* This is explicitly set by other pgm */ } /* endif */ }
void cleanup_envelope_list( struct envelope **env_p ) { struct envelope *env; while ( *env_p != NULL ) { env = *env_p; env_p = &(env->e_next); /* unlink if written to disk */ if (( env->e_flags & ENV_FLAG_EFILE ) != 0 ) { queue_remove_envelope( env ); if ( env_unlink( env ) == 0 ) { syslog( LOG_INFO, "Expand env <%s>: Message Deleted: " "System error, unwinding expansion", env->e_id ); } else { syslog( LOG_ERR, "Expand env <%s>: " "System error, can't unwind expansion", env->e_id ); } } env_free( env ); } }
static int shell_alloc(char *name,char *value) { int namelen, valuelen; struct s_shell *sp; sp = shell_vars; namelen = strlen(name); valuelen = strlen(value); while(1) { if (sp->name == (char *)0) { if (sp->next != (struct s_shell *)0) { sp = sp->next; continue; } else break; } if (strcmp(sp->name,name) == 0) { if (sp->vsize < valuelen+1) { /* If new value is smaller */ env_free(sp->val); /* than the old value, then */ sp->val = env_alloc(valuelen+1);/* don't re-allocate any */ if (!sp->val) /* memory, just copy into */ return(-1); /* the space used by the */ sp->vsize = valuelen+1; /* previous value. */ } strcpy(sp->val,value); return(0); } if (sp->next == (struct s_shell *)0) break; sp = sp->next; } sp = shell_vars; while(1) { if (sp->name == (char *)0) { sp->name = env_alloc(namelen+1); if (!sp->name) return(-1); strcpy(sp->name,name); sp->val = env_alloc(valuelen+1); if (!sp->val) return(-1); sp->vsize = valuelen+1; strcpy(sp->val,value); return(0); } if (sp->next != (struct s_shell *)0) sp = sp->next; else { sp->next = (struct s_shell *)env_alloc(sizeof(struct s_shell)); if (!sp->next) return(-1); sp = sp->next; sp->name = env_alloc(namelen+1); if (!sp->name) return(-1); strcpy(sp->name,name); sp->val = env_alloc(valuelen+1); if (!sp->val) return(-1); sp->vsize = valuelen+1; strcpy(sp->val,value); sp->next = (struct s_shell *)0; return(0); } } }
/* envToExec(): Create a file of "set" commands that can be run to recreate the current environment. Changed Oct 2008 to eliminate use of getAppRamStart(). */ int envToExec(char *filename) { int err, vartot, size, rc; char *buf, *bp, *cp; register struct s_shell *sp; sp = shell_vars; vartot = size = rc = 0; /* First go through the list to see how much space we need * to allocate... */ while(1) { if (validEnvToExecVar(sp->name)) { size += strlen(sp->name) + 6; cp = sp->val; while(*cp) { if (*cp == '$') size++; size++; cp++; } size += 3; vartot++; } if (sp->next != (struct s_shell *)0) sp = sp->next; else break; } if (size == 0) return(0); /* Now that we know the space needed (stored in 'size' variable), * allocate it and build the new file in that space, then use tfsadd() * to create the file... */ vartot = 0; sp = shell_vars; buf = bp = (char *)env_alloc(size); while(1) { /* Note: if this code changes, then the code above that is used to * allocate the buffer size may also need to change... */ if (validEnvToExecVar(sp->name)) { bp += sprintf(bp,"set %s \"",sp->name); cp = sp->val; while(*cp) { if (*cp == '$') *bp++ = '\\'; *bp++ = *cp++; } *bp++ = '\"'; *bp++ = '\n'; *bp = 0; vartot++; } if (sp->next != (struct s_shell *)0) sp = sp->next; else break; } if (vartot > 0) { err = tfsadd(filename,"envsetup","e",(unsigned char *)buf,strlen(buf)); if (err != TFS_OKAY) { printf("%s: %s\n",filename,(char *)tfsctrl(TFS_ERRMSG,err,0)); rc = -1; } } env_free(buf); return(rc); }
int main( int argc, char *argv[]) { struct envelope *env; const char *sender = "*****@*****.**"; int c; int nextargc = 1; int exp_level = 0; int error = 0; extern int optind; extern char *optarg; simta_debug = 1; simta_expand_debug = 1; while ((c = getopt(argc, argv, "f:x:")) != EOF) { switch (c) { case 'x': if (( exp_level = atoi( optarg )) < 0 ) { error++; } nextargc = nextargc + 2; break; case 'f': sender = strdup( optarg ); nextargc = nextargc + 2; break; default: error++; nextargc++; break; } } if (( argc < 3 ) | ( error )) { fprintf( stderr, "Usage: %s [ -x level ] [-f sendermail] conf_file " "address\n", argv[ 0 ]); exit( EX_USAGE ); } if ( simta_read_config( argv[ nextargc ] ) < 0 ) { fprintf( stderr, "simta_read_config error: %s\n", argv[ nextargc ] ); exit( EX_DATAERR ); } /* init simta config / defaults */ if ( simta_config( ) != 0 ) { fprintf( stderr, "simta_config error\n" ); exit( EX_DATAERR ); } simta_openlog( 0, 0 ); env = env_create( NULL, "DEAD60FF", sender, NULL ); env->e_n_exp_level = exp_level; do { nextargc++; printf( "Original Recipient: %s\n", argv[ nextargc ]); env_recipient( env, argv[ nextargc ]); } while ( nextargc < argc - 1 ); if ( expand( env ) != 0 ) { return( 1 ); } env_free( env ); return( 0 ); }
/* return NULL if eof or syntax error occurs; * otherwise return a pointer to a new entry. */ entry * load_entry(FILE *file, void (*error_func)(const char *), struct passwd *pw, char **envp) { /* this function reads one crontab entry -- the next -- from a file. * it skips any leading blank lines, ignores comments, and returns * NULL if for any reason the entry can't be read and parsed. * * the entry is also parsed here. * * syntax: * user crontab: * minutes hours doms months dows cmd\n * system crontab (/etc/crontab): * minutes hours doms months dows USERNAME cmd\n */ ecode_e ecode = e_none; entry *e; int ch; char cmd[MAX_COMMAND]; char envstr[MAX_ENVSTR]; char **tenvp; Debug(DPARS, ("load_entry()...about to eat comments\n")); skip_comments(file); ch = get_char(file); if (ch == EOF) return (NULL); /* ch is now the first useful character of a useful line. * it may be an @special or it may be the first character * of a list of minutes. */ e = calloc(sizeof(*e), sizeof(char)); if (ch == '@') { /* all of these should be flagged and load-limited; i.e., * instead of @hourly meaning "0 * * * *" it should mean * "close to the front of every hour but not 'til the * system load is low". Problems are: how do you know * what "low" means? (save me from /etc/cron.conf!) and: * how to guarantee low variance (how low is low?), which * means how to we run roughly every hour -- seems like * we need to keep a history or let the first hour set * the schedule, which means we aren't load-limited * anymore. too much for my overloaded brain. (vix, jan90) * HINT */ ch = get_string(cmd, MAX_COMMAND, file, " \t\n"); if (!strcmp("reboot", cmd)) { e->flags |= WHEN_REBOOT; } else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){ bit_set(e->minute, 0); bit_set(e->hour, 0); bit_set(e->dom, 0); bit_set(e->month, 0); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOW_STAR; } else if (!strcmp("monthly", cmd)) { bit_set(e->minute, 0); bit_set(e->hour, 0); bit_set(e->dom, 0); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOW_STAR; } else if (!strcmp("weekly", cmd)) { bit_set(e->minute, 0); bit_set(e->hour, 0); bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1)); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_set(e->dow, 0); e->flags |= DOM_STAR; } else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) { bit_set(e->minute, 0); bit_set(e->hour, 0); bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1)); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOM_STAR | DOW_STAR; } else if (!strcmp("hourly", cmd)) { bit_set(e->minute, 0); bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1)); bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1)); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOM_STAR | DOW_STAR; } else { ecode = e_timespec; goto eof; } /* Advance past whitespace between shortcut and * username/command. */ Skip_Blanks(ch, file); if (ch == EOF || ch == '\n') { ecode = e_cmd; goto eof; } } else { Debug(DPARS, ("load_entry()...about to parse numerics\n")); if (ch == '*') e->flags |= MIN_STAR; ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE, PPC_NULL, ch, file); if (ch == EOF) { ecode = e_minute; goto eof; } /* hours */ if (ch == '*') e->flags |= HR_STAR; ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR, PPC_NULL, ch, file); if (ch == EOF) { ecode = e_hour; goto eof; } /* DOM (days of month) */ if (ch == '*') e->flags |= DOM_STAR; ch = get_list(e->dom, FIRST_DOM, LAST_DOM, PPC_NULL, ch, file); if (ch == EOF) { ecode = e_dom; goto eof; } /* month */ ch = get_list(e->month, FIRST_MONTH, LAST_MONTH, MonthNames, ch, file); if (ch == EOF) { ecode = e_month; goto eof; } /* DOW (days of week) */ if (ch == '*') e->flags |= DOW_STAR; ch = get_list(e->dow, FIRST_DOW, LAST_DOW, DowNames, ch, file); if (ch == EOF) { ecode = e_dow; goto eof; } } /* make sundays equivalent */ if (bit_test(e->dow, 0) || bit_test(e->dow, 7)) { bit_set(e->dow, 0); bit_set(e->dow, 7); } /* check for permature EOL and catch a common typo */ if (ch == '\n' || ch == '*') { ecode = e_cmd; goto eof; } /* ch is the first character of a command, or a username */ unget_char(ch, file); if (!pw) { char *username = cmd; /* temp buffer */ Debug(DPARS, ("load_entry()...about to parse username\n")); ch = get_string(username, MAX_COMMAND, file, " \t\n"); Debug(DPARS, ("load_entry()...got %s\n",username)); if (ch == EOF || ch == '\n' || ch == '*') { ecode = e_cmd; goto eof; } pw = getpwnam(username); if (pw == NULL) { ecode = e_username; goto eof; } Debug(DPARS, ("load_entry()...uid %ld, gid %ld\n", (long)pw->pw_uid, (long)pw->pw_gid)); } if ((e->pwd = pw_dup(pw)) == NULL) { ecode = e_memory; goto eof; } (void)memset(e->pwd->pw_passwd, 0, strlen(e->pwd->pw_passwd)); /* copy and fix up environment. some variables are just defaults and * others are overrides. */ if ((e->envp = env_copy(envp)) == NULL) { ecode = e_memory; goto eof; } if (!env_get("SHELL", e->envp)) { if (glue_strings(envstr, sizeof envstr, "SHELL", _PATH_BSHELL, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set SHELL"); } if (!env_get("HOME", e->envp)) { if (glue_strings(envstr, sizeof envstr, "HOME", pw->pw_dir, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set HOME"); } /* If login.conf is in used we will get the default PATH later. */ if (!env_get("PATH", e->envp)) { if (glue_strings(envstr, sizeof envstr, "PATH", _PATH_DEFPATH, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set PATH"); } if (glue_strings(envstr, sizeof envstr, "LOGNAME", pw->pw_name, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set LOGNAME"); #if defined(BSD) || defined(__linux) if (glue_strings(envstr, sizeof envstr, "USER", pw->pw_name, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set USER"); #endif Debug(DPARS, ("load_entry()...about to parse command\n")); /* If the first character of the command is '-' it is a cron option. */ while ((ch = get_char(file)) == '-') { switch (ch = get_char(file)) { case 'q': e->flags |= DONT_LOG; Skip_Nonblanks(ch, file); break; default: ecode = e_option; goto eof; } Skip_Blanks(ch, file); if (ch == EOF || ch == '\n') { ecode = e_cmd; goto eof; } } unget_char(ch, file); /* Everything up to the next \n or EOF is part of the command... * too bad we don't know in advance how long it will be, since we * need to malloc a string for it... so, we limit it to MAX_COMMAND. */ ch = get_string(cmd, MAX_COMMAND, file, "\n"); /* a file without a \n before the EOF is rude, so we'll complain... */ if (ch == EOF) { ecode = e_cmd; goto eof; } /* got the command in the 'cmd' string; save it in *e. */ if ((e->cmd = strdup(cmd)) == NULL) { ecode = e_memory; goto eof; } Debug(DPARS, ("load_entry()...returning successfully\n")); /* success, fini, return pointer to the entry we just created... */ return (e); eof: if (e->envp) env_free(e->envp); if (e->pwd) free(e->pwd); if (e->cmd) free(e->cmd); free(e); while (ch != '\n' && !feof(file)) ch = get_char(file); if (ecode != e_none && error_func) (*error_func)(ecodes[(int)ecode]); return (NULL); }
void spawn() { int i; char** env = NULL; env = env_copy(environ, env); child = malloc(sizeof(uv_process_t)); uv_stdio_container_t stdio[4]; uv_process_options_t options; uv_pipe_init(loop, &child_stdout, 0); uv_pipe_init(loop, &child_stderr, 0); uv_pipe_init(loop, &child_ipc, 0); // // Setup child's stdio. stdout and stderr are pipes so that we can read // child process' output. // FD 3 is a pipe used for IPC. // options.stdio_count = 4; stdio[0].flags = UV_INHERIT_FD; stdio[0].data.fd = 0; stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; stdio[1].data.stream = (uv_stream_t*) &child_stdout; stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; stdio[2].data.stream = (uv_stream_t*) &child_stderr; stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; stdio[3].data.stream = (uv_stream_t*) &child_ipc; options.env = env; options.cwd = NULL; options.file = arguments[0]; options.args = arguments; options.flags = 0; options.stdio = stdio; options.exit_cb = on_process_exit; for (i = 0; i < PLUGIN_COUNT; i++) { if (plugins[i].process_options_cb) { plugins[i].process_options_cb(&options); } } if (uv_spawn(loop, child, options)) { fprintf(stderr, "uv_spawn: %s\n", uv_err_name(uv_last_error(loop))); return; } for (i = 0; i < PLUGIN_COUNT; i++) { if (plugins[i].process_spawned_cb) { plugins[i].process_spawned_cb(child, &options); } } uv_read_start(options.stdio[1].data.stream, forza__on_alloc, forza__on_stdout_read); uv_read_start(options.stdio[2].data.stream, forza__on_alloc, forza__on_stderr_read); uv_read_start(options.stdio[3].data.stream, forza__on_alloc, forza__on_ipc_read); // Switch to using `options->env` here instead of `env`, since plugins can // override `options->env` using, for example `env_set`, like in the start // plugin. env_free(options.env); }
int expand( struct envelope *unexpanded_env ) { struct expand exp; struct envelope *base_error_env; struct envelope *env_dead = NULL; struct envelope *env; struct envelope **env_p; struct recipient *rcpt; struct expand_output *host_stab = NULL; struct expand_output *eo; struct expand_output *eo_free; struct exp_addr *e_addr; struct exp_addr *next_e_addr; struct simta_red *hq_red; char *domain; SNET *snet = NULL; int n_rcpts; int return_value = 1; int env_out = 0; int fast_file_start; int sendermatch; char e_original[ MAXPATHLEN ]; char d_original[ MAXPATHLEN ]; char d_out[ MAXPATHLEN ]; /* RFC 5321 4.5.3.1.3. Path * The maximum total length of a reverse-path or forward-path is 256 * octets (including the punctuation and element separators). */ char header[ 270 ]; #ifdef HAVE_LDAP char *p; int loop_color = 1; struct exp_link *memonly; struct exp_link *parent; #endif /* HAVE_LDAP */ if ( unexpanded_env->e_hostname != NULL ) { syslog( LOG_INFO, "Expand env <%s>: already expanded for host %s", unexpanded_env->e_id, unexpanded_env->e_hostname ); return_value = 0; goto done; } memset( &exp, 0, sizeof( struct expand )); exp.exp_env = unexpanded_env; fast_file_start = simta_fast_files; /* call address_expand on each address in the expansion list. * * if an address is expandable, the address(es) that it expands to will * be added to the expansion list. These non-terminal addresses must * have their st_data set to NULL to specify that they are not to be * included in the terminal expansion list. * * Any address in the expansion list whose st_data is not NULL is * considered a terminal address and will be written out as one * of the addresses in expanded envelope(s). */ if (( base_error_env = address_bounce_create( &exp )) == NULL ) { syslog( LOG_ERR, "Expand env <%s>: address_bounce_create: %m", unexpanded_env->e_id ); goto done; } if ( env_recipient( base_error_env, unexpanded_env->e_mail ) != 0 ) { syslog( LOG_ERR, "Expand env <%s>: env_recipient: %m", unexpanded_env->e_id ); goto done; } /* add all of the original recipients to the expansion list */ for ( rcpt = unexpanded_env->e_rcpt; rcpt != NULL; rcpt = rcpt->r_next ) { if ( add_address( &exp, rcpt->r_rcpt, base_error_env, ADDRESS_TYPE_EMAIL, exp.exp_env->e_mail ) != 0 ) { /* add_address syslogs errors */ goto cleanup1; } } /* process the expansion list */ for ( exp.exp_addr_cursor = exp.exp_addr_head; exp.exp_addr_cursor != NULL; exp.exp_addr_cursor = exp.exp_addr_cursor->e_addr_next ) { switch ( address_expand( &exp )) { case ADDRESS_EXCLUDE: exp.exp_addr_cursor->e_addr_terminal = 0; /* the address is not a terminal local address */ break; case ADDRESS_FINAL: exp.exp_addr_cursor->e_addr_terminal = 1; break; case ADDRESS_SYSERROR: goto cleanup1; default: panic( "Expand: address_expand out of range" ); } } #ifdef HAVE_LDAP /* Members-only processing */ for ( memonly = exp.exp_memonly; memonly != NULL; memonly = memonly->el_next ) { if ((( p = parent_permitted( memonly->el_exp_addr )) != NULL ) || ( sender_is_child( memonly->el_exp_addr->e_addr_children, loop_color++ ))) { if ( p != NULL ) { syslog( LOG_INFO, "Expand env <%s>: members-only group %s OK: " "parent %s permitted", unexpanded_env->e_id, memonly->el_exp_addr->e_addr, p ); } else { syslog( LOG_INFO, "Expand env <%s>: members-only group %s OK: " "sender is child", unexpanded_env->e_id, memonly->el_exp_addr->e_addr ); } memonly->el_exp_addr->e_addr_ldap_flags = ( memonly->el_exp_addr->e_addr_ldap_flags & ( ~STATUS_LDAP_MEMONLY )); if ( memonly->el_exp_addr->e_addr_env_moderated != NULL ) { env_free( memonly->el_exp_addr->e_addr_env_moderated ); memonly->el_exp_addr->e_addr_env_moderated = NULL; } } else { syslog( LOG_NOTICE, "Expand env <%s>: members-only group %s suppressed", unexpanded_env->e_id, memonly->el_exp_addr->e_addr ); memonly->el_exp_addr->e_addr_ldap_flags |= STATUS_LDAP_SUPPRESSOR; suppress_addrs( memonly->el_exp_addr->e_addr_children, loop_color++ ); } } #endif /* HAVE_LDAP */ sprintf( d_original, "%s/D%s", unexpanded_env->e_dir, unexpanded_env->e_id ); /* Create one expanded envelope for every host we expanded address for */ for ( e_addr = exp.exp_addr_head; e_addr != NULL; e_addr = e_addr->e_addr_next ) { #ifdef HAVE_LDAP if ((( e_addr->e_addr_ldap_flags & STATUS_LDAP_SUPPRESSED ) != 0 ) && ( !unblocked_path_to_root( e_addr, loop_color++ ))) { if ( simta_expand_debug != 0 ) { printf( "Suppressed: %s\n", e_addr->e_addr ); } continue; } if ( e_addr->e_addr_env_gmailfwd != NULL ) { e_addr->e_addr_env_gmailfwd->e_attributes = unexpanded_env->e_attributes | ENV_ATTR_ARCHIVE_ONLY; if ( simta_expand_debug != 0 ) { printf( "Group mail forwarding: %s\n", e_addr->e_addr ); env_stdout( e_addr->e_addr_env_gmailfwd ); continue; } sprintf( d_out, "%s/D%s", e_addr->e_addr_env_gmailfwd->e_dir, e_addr->e_addr_env_gmailfwd->e_id ); if ( env_dfile_copy( e_addr->e_addr_env_gmailfwd, d_original, NULL ) == 0 ) { syslog( LOG_ERR, "Expand env <%s>: %s: env_dfile_copy failed", unexpanded_env->e_id, e_addr->e_addr_env_gmailfwd->e_id ); goto cleanup3; } simta_debuglog( 2, "Expand env <%s>: group mail env %s dinode %d", unexpanded_env->e_id, e_addr->e_addr_env_gmailfwd->e_id, (int)e_addr->e_addr_env_gmailfwd->e_dinode ); sendermatch = !strcasecmp( unexpanded_env->e_mail, e_addr->e_addr_env_gmailfwd->e_mail ); n_rcpts = 0; for ( rcpt = e_addr->e_addr_env_gmailfwd->e_rcpt; rcpt != NULL; rcpt = rcpt->r_next ) { n_rcpts++; if ( sendermatch ) { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s>", unexpanded_env->e_id, e_addr->e_addr_env_gmailfwd->e_id, rcpt->r_rcpt, e_addr->e_addr_env_gmailfwd->e_mail ); } else { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s> (%s)", unexpanded_env->e_id, e_addr->e_addr_env_gmailfwd->e_id, rcpt->r_rcpt, e_addr->e_addr_env_gmailfwd->e_mail, unexpanded_env->e_mail ); } } syslog( LOG_INFO, "Expand env <%s>: %s: Expanded %d group mail forwarders", unexpanded_env->e_id, e_addr->e_addr_env_gmailfwd->e_id, n_rcpts ); if ( env_outfile( e_addr->e_addr_env_gmailfwd ) != 0 ) { /* env_outfile syslogs errors */ if ( unlink( d_out ) != 0 ) { syslog( LOG_ERR, "Syserror: expand unlink %s: %m", d_out ); } goto cleanup3; } env_out++; queue_envelope( e_addr->e_addr_env_gmailfwd ); continue; } if ( e_addr->e_addr_env_moderated != NULL ) { e_addr->e_addr_env_moderated->e_attributes = unexpanded_env->e_attributes; if ( simta_expand_debug != 0 ) { printf( "Moderated: %s\n", e_addr->e_addr ); env_stdout( e_addr->e_addr_env_moderated ); continue; } sprintf( d_out, "%s/D%s", e_addr->e_addr_env_moderated->e_dir, e_addr->e_addr_env_moderated->e_id ); if ( env_dfile_copy( e_addr->e_addr_env_moderated, d_original, NULL ) == 0 ) { syslog( LOG_ERR, "Expand env <%s>: %s: env_dfile_copy failed", unexpanded_env->e_id, e_addr->e_addr_env_moderated->e_id ); goto cleanup3; } simta_debuglog( 2, "Expand env <%s>: %s: moderation env dinode %d", unexpanded_env->e_id, e_addr->e_addr_env_moderated->e_id, (int)e_addr->e_addr_env_moderated->e_dinode ); sendermatch = !strcasecmp( unexpanded_env->e_mail, e_addr->e_addr_env_moderated->e_mail ); n_rcpts = 0; for ( rcpt = e_addr->e_addr_env_moderated->e_rcpt; rcpt != NULL; rcpt = rcpt->r_next ) { n_rcpts++; if ( sendermatch ) { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s>", unexpanded_env->e_id, e_addr->e_addr_env_moderated->e_id, rcpt->r_rcpt, e_addr->e_addr_env_moderated->e_mail ); } else { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s> (%s)", unexpanded_env->e_id, e_addr->e_addr_env_moderated->e_id, rcpt->r_rcpt, e_addr->e_addr_env_moderated->e_mail, unexpanded_env->e_mail ); } } syslog( LOG_INFO, "Expand env <%s>: %s: Expanded %d moderators", unexpanded_env->e_id, e_addr->e_addr_env_moderated->e_id, n_rcpts ); if ( env_outfile( e_addr->e_addr_env_moderated ) != 0 ) { /* env_outfile syslogs errors */ if ( unlink( d_out ) != 0 ) { syslog( LOG_ERR, "expand unlink %s: %m", d_out ); } goto cleanup3; } env_out++; queue_envelope( e_addr->e_addr_env_moderated ); continue; } else if ( e_addr->e_addr_ldap_flags & STATUS_LDAP_SUPPRESSOR ) { for ( parent = e_addr->e_addr_parents; parent != NULL; parent = parent->el_next ) { if ( parent->el_exp_addr == NULL ) { if ( bounce_text( base_error_env, TEXT_ERROR, "Members only group conditions not met: ", e_addr->e_addr, NULL ) != 0 ) { goto cleanup3; } if ( bounce_text( base_error_env, TEXT_ERROR, "If you have any questions, please contact the group owner: ", e_addr->e_addr_owner, NULL ) != 0 ) { goto cleanup3; } } else if (( e_addr->e_addr_ldap_flags & STATUS_LDAP_PRIVATE ) == 0 ) { if ( bounce_text( parent->el_exp_addr->e_addr_errors, TEXT_ERROR, "Members only group conditions not met: ", e_addr->e_addr, NULL ) != 0 ) { goto cleanup3; } if ( bounce_text( parent->el_exp_addr->e_addr_errors, TEXT_ERROR, "If you have any questions, please contact the group owner: ", e_addr->e_addr_owner, NULL ) != 0 ) { goto cleanup3; } } } continue; } #endif /* HAVE_LDAP */ if ( e_addr->e_addr_terminal == 0 ) { if ( simta_expand_debug != 0 ) { printf( "Non-terminal: %s\n", e_addr->e_addr ); } /* not a terminal expansion, do not add */ continue; } if ( simta_expand_debug != 0 ) { printf( "Terminal: %s\n", e_addr->e_addr ); } switch ( e_addr->e_addr_type ) { case ADDRESS_TYPE_EMAIL: if (( domain = strchr( e_addr->e_addr, '@' )) == NULL ) { syslog( LOG_ERR, "Expand env <%s>: strchr blivet", unexpanded_env->e_id ); goto cleanup3; } domain++; env = eo_lookup( host_stab, domain, e_addr->e_addr_from ); break; case ADDRESS_TYPE_DEAD: domain = NULL; env = env_dead; break; default: panic( "expand: address type out of range" ); } if ( env == NULL ) { /* Create envelope and add it to list */ if (( env = env_create( domain ? simta_dir_fast : simta_dir_dead, NULL, e_addr->e_addr_from, unexpanded_env )) == NULL ) { syslog( LOG_ERR, "Expand env <%s>: env_create: %m", unexpanded_env->e_id ); goto cleanup3; } simta_debuglog( 2, "Expand env <%s>: %s: expansion env dinode %d", unexpanded_env->e_id, env->e_id, (int)env->e_dinode ); /* fill in env */ env->e_attributes = unexpanded_env->e_attributes; if ( domain != NULL ) { if ( env_hostname( env, domain ) != 0 ) { env_free( env ); goto cleanup3; } } else { env_dead = env; } /* Add env to host_stab */ if ( eo_insert( &host_stab, env ) != 0 ) { syslog( LOG_ERR, "Expand env <%s>: eo_insert %s failed: %m", unexpanded_env->e_id, env->e_id ); env_free( env ); goto cleanup3; } } if ( env_recipient( env, e_addr->e_addr ) != 0 ) { goto cleanup3; } syslog( LOG_NOTICE, "Expand env <%s>: %s: recipient <%s> added to env for host %s", unexpanded_env->e_id, env->e_id, e_addr->e_addr, env->e_hostname ? env->e_hostname : "NULL" ); } /* Write out all expanded envelopes and place them in to the host_q */ for ( eo = host_stab; eo != NULL; eo = eo->eo_next ) { env = eo->eo_env; if ( simta_expand_debug == 0 ) { sprintf( d_out, "%s/D%s", env->e_dir, env->e_id ); /* RFC 5321 4.4 Trace Information * When the delivery SMTP server makes the "final delivery" of a * message, it inserts a return-path line at the beginning of the * mail data. This use of return-path is required; mail systems * MUST support it. The return-path line preserves the * information in the <reverse-path> from the MAIL command. * Here, final delivery means the message has left the SMTP * environment. */ if ((( hq_red = red_host_lookup( eo->eo_hostname )) != NULL ) && ( hq_red->red_deliver_type == RED_DELIVER_BINARY )) { if ( snprintf( header, 270, "Return-Path: <%s>", env->e_mail ) >= 270 ) { syslog( LOG_ERR, "Expand env <%s>: %s: return path is too large", unexpanded_env->e_id, env->e_id ); } if ( env_dfile_copy( env, d_original, header ) == 0 ) { syslog( LOG_ERR, "Expand env <%s>: %s: env_dfile_copy failed", unexpanded_env->e_id, env->e_id ); goto cleanup4; } } else { /* Dfile: link Dold_id env->e_dir/Dnew_id */ if ( link( d_original, d_out ) != 0 ) { syslog( LOG_ERR, "Syserror: expand link %s %s: %m", d_original, d_out ); goto cleanup4; } } sendermatch = !strcasecmp( unexpanded_env->e_mail, env->e_mail ); n_rcpts = 0; for ( rcpt = env->e_rcpt; rcpt != NULL; rcpt = rcpt->r_next ) { n_rcpts++; if ( sendermatch ) { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s>", unexpanded_env->e_id, env->e_id, rcpt->r_rcpt, env->e_mail ); } else { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s> (%s)", unexpanded_env->e_id, env->e_id, rcpt->r_rcpt, env->e_mail, unexpanded_env->e_mail ); } } syslog( LOG_INFO, "Expand env <%s>: %s: Expanded %d recipients", unexpanded_env->e_id, env->e_id, n_rcpts ); /* Efile: write env->e_dir/Enew_id for all recipients at host */ syslog( LOG_NOTICE, "Expand env <%s>: %s: writing Efile for %s", unexpanded_env->e_id, env->e_id, env->e_hostname ? env->e_hostname : "NULL" ); if ( env_outfile( env ) != 0 ) { /* env_outfile syslogs errors */ if ( unlink( d_out ) != 0 ) { syslog( LOG_ERR, "Syserror: expand unlink %s: %m", d_out ); } goto cleanup4; } env_out++; queue_envelope( env ); } else { printf( "\n" ); env_stdout( env ); } } if ( env_out == 0 ) { syslog( LOG_NOTICE, "Expand env <%s>: no terminal recipients, " "deleting message", unexpanded_env->e_id ); } /* write errors out to disk */ env_p = &(exp.exp_errors); while (( env = *env_p ) != NULL ) { if ( simta_expand_debug == 0 ) { if ( env->e_error != 0 ) { env_p = &(env->e_next); if ( snet == NULL ) { if (( snet = snet_open( d_original, O_RDONLY, 0, 1024 * 1024 )) == NULL ) { syslog( LOG_ERR, "Liberror: expand snet_open %s: %m", d_original ); goto cleanup5; } } else { if ( lseek( snet_fd( snet ), (off_t)0, SEEK_SET ) != 0 ) { syslog( LOG_ERR, "Syserror: q_deliver lseek: %m" ); panic( "q_deliver lseek fail" ); } } /* write out error text, get Dfile inode */ if ( bounce_dfile_out( env, snet ) == 0 ) { if ( snet != NULL ) { if ( snet_close( snet ) != 0 ) { syslog( LOG_ERR, "Liberror: expand snet_close %s: %m", d_original ); } } goto cleanup5; } simta_debuglog( 2, "Expand env <%s>: %s: errors env dinode %d", unexpanded_env->e_id, env->e_id, (int)env->e_dinode ); line_file_free( env->e_err_text ); env->e_err_text = NULL; env->e_error = 0; if ( env_outfile( env ) != 0 ) { /* env_outfile syslogs errors */ sprintf( d_out, "%s/D%s", env->e_dir, env->e_id ); if ( unlink( d_out ) != 0 ) { syslog( LOG_ERR, "Syserror: expand unlink %s: %m", d_out ); } goto cleanup5; } sendermatch = !strcasecmp( unexpanded_env->e_mail, env->e_mail ); n_rcpts = 0; for ( rcpt = env->e_rcpt; rcpt != NULL; rcpt = rcpt->r_next ) { n_rcpts++; if ( sendermatch ) { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s>", unexpanded_env->e_id, env->e_id, rcpt->r_rcpt, env->e_mail ); } else { syslog( LOG_INFO, "Expand env <%s>: %s: To <%s> From <%s> (%s)", unexpanded_env->e_id, env->e_id, rcpt->r_rcpt, env->e_mail, unexpanded_env->e_mail ); } } syslog( LOG_NOTICE, "Expand env <%s>: %s: Expanded %d bounces", unexpanded_env->e_id, env->e_id, n_rcpts ); queue_envelope( env ); } else { *env_p = env->e_next; env_free( env ); } } else { *env_p = env->e_next; bounce_stdout( env ); env_free( env ); } } if ( snet != NULL ) { if ( snet_close( snet ) != 0 ) { syslog( LOG_ERR, "Liberror: expand snet_close %s: %m", d_original ); sprintf( d_out, "%s/D%s", env->e_dir, env->e_id ); if ( unlink( d_out ) != 0 ) { syslog( LOG_ERR, "Syserror: expand unlink %s: %m", d_out ); } goto cleanup5; } snet = NULL; } syslog( LOG_INFO, "Expand env <%s>: Metric %d entries %d levels", unexpanded_env->e_id, exp.exp_entries, exp.exp_max_level ); if ( simta_expand_debug != 0 ) { return_value = 0; goto cleanup2; } if ( utime( d_original, NULL ) != 0 ) { syslog( LOG_ERR, "Syserror: expand utime %s: %m", d_original ); goto cleanup5; } if ( unexpanded_env->e_dir != simta_dir_fast ) { /* truncate orignal Efile */ sprintf( e_original, "%s/E%s", unexpanded_env->e_dir, unexpanded_env->e_id ); if ( truncate( e_original, (off_t)0 ) != 0 ) { syslog( LOG_ERR, "Syserror: expand truncate %s: %m", e_original ); goto cleanup5; } } /* delete original message */ if ( env_unlink( unexpanded_env ) != 0 ) { syslog( LOG_ERR, "Expand env <%s>: Expansion complete, can't delete message", unexpanded_env->e_id ); } else { syslog( LOG_INFO, "Expand env <%s>: Expansion complete, message deleted", unexpanded_env->e_id ); } return_value = 0; goto cleanup2; cleanup5: cleanup_envelope_list( &exp.exp_errors ); #ifdef HAVE_LDAP cleanup_envelope_list( &exp.exp_gmailfwding ); #endif /* HAVE_LDAP */ cleanup4: for ( eo = host_stab; eo != NULL; eo = eo->eo_next ) { env = eo->eo_env; eo->eo_env = NULL; if (( env->e_flags & ENV_FLAG_EFILE ) != 0 ) { queue_remove_envelope( env ); if ( env_unlink( env ) == 0 ) { syslog( LOG_WARNING, "Expand env <%s>: Message Deleted: " "System error, unwinding expansion", env->e_id ); } else { syslog( LOG_ERR, "Expand env <%s>: " "System error, can't unwind expansion", env->e_id ); } } env_free( env ); } cleanup3: #ifdef HAVE_LDAP for ( memonly = exp.exp_memonly; memonly != NULL; memonly = memonly->el_next ) { if (( memonly->el_exp_addr->e_addr_env_moderated != NULL ) && (( memonly->el_exp_addr->e_addr_env_moderated->e_flags & ENV_FLAG_EFILE ) != 0 )) { env_unlink( memonly->el_exp_addr->e_addr_env_moderated ); env_free( memonly->el_exp_addr->e_addr_env_moderated ); memonly->el_exp_addr->e_addr_env_moderated = NULL; } } #endif /* HAVE_LDAP */ if ( simta_fast_files != fast_file_start ) { syslog( LOG_ERR, "Expand env <%s>: could not unwind expansion", unexpanded_env->e_id ); return_value = 1; } cleanup2: /* free host_stab */ eo = host_stab; while ( eo != NULL ) { eo_free = eo; eo = eo->eo_next; free( eo_free ); } cleanup1: #ifdef HAVE_LDAP exp_addr_link_free( exp.exp_memonly ); #endif /* HAVE_LDAP */ /* free the expansion list */ for ( e_addr = exp.exp_addr_head; e_addr != NULL; e_addr = next_e_addr ) { next_e_addr = e_addr->e_addr_next; #ifdef HAVE_LDAP exp_addr_link_free( e_addr->e_addr_parents ); exp_addr_link_free( e_addr->e_addr_children ); permitted_destroy( e_addr ); if (( e_addr->e_addr_env_moderated != NULL ) && (( e_addr->e_addr_env_moderated->e_flags & ENV_FLAG_EFILE ) == 0 )) { env_free( e_addr->e_addr_env_moderated ); } if ( e_addr->e_addr_owner ) { free( e_addr->e_addr_owner ); } if ( e_addr->e_addr_dn ) { free( e_addr->e_addr_dn ); } #endif free( e_addr->e_addr ); free( e_addr->e_addr_from ); free( e_addr ); } done: if ( return_value != 0 ) { syslog( LOG_ERR, "Expand env <%s>: Expansion failed", unexpanded_env->e_id ); } return( return_value ); }
user * load_user(int crontab_fd, struct passwd *pw, const char *name) { char envstr[MAX_ENVSTR]; FILE *file; user *u; entry *e; int status, save_errno; char **envp, **tenvp; if (!(file = fdopen(crontab_fd, "r"))) { perror("fdopen on crontab_fd in load_user"); return (NULL); } Debug(DPARS, ("load_user()\n")) /* file is open. build user entry, then read the crontab file. */ if ((u = (user *) malloc(sizeof(user))) == NULL) return (NULL); if ((u->name = strdup(name)) == NULL) { save_errno = errno; free(u); errno = save_errno; return (NULL); } u->crontab = NULL; /* init environment. this will be copied/augmented for each entry. */ if ((envp = env_init()) == NULL) { save_errno = errno; free(u->name); free(u); errno = save_errno; return (NULL); } /* load the crontab */ while ((status = load_env(envstr, file)) >= OK) { switch (status) { case ERR: free_user(u); u = NULL; goto done; case FALSE: e = load_entry(file, NULL, pw, envp); if (e) { e->next = u->crontab; u->crontab = e; } break; case TRUE: if ((tenvp = env_set(envp, envstr)) == NULL) { save_errno = errno; free_user(u); u = NULL; errno = save_errno; goto done; } envp = tenvp; break; } } done: env_free(envp); fclose(file); Debug(DPARS, ("...load_user() done\n")) return (u); }
static void processor(const char *tx_addr, int port) { sys_init(1); sys_log('E', "started port=%d, tx=%s\n", port, tx_addr); /* connect to the control thread */ char addr[MAX_ADDR]; sys_address(addr, port); IO *io = sys_connect(addr, IO_CHUNK); tx_attach(tx_addr); /* get env code from the tx */ char *code = tx_program(); char *res = mem_alloc(MAX_BLOCK); while (!io->stop) { sys_iready(io, -1); int status = -1; long long sid = 0LL, time = sys_millis(); Env *env = NULL; Arg *arg = NULL; Vars *v = vars_new(0), *r = NULL, *w = NULL; Http_Req *req = http_parse_req(io); if (io->stop) goto exit; if (req == NULL) { status = http_400(io); goto exit; } if (req->method == OPTIONS) { status = http_opts(io); goto exit; } env = env_new("net", code); if (str_idx(req->path, "/fn") == 0) { int idx = (req->path[3] == '/') ? 4 : 3; int i = 0, len = 1, cnt = 0; Func **fns = env_funcs(env, req->path + idx, &cnt); status = http_200(io); while (status == 200 && len) { len = pack_fn2csv(fns, cnt, res, MAX_BLOCK, &i); status = http_chunk(io, res, len); } mem_free(fns); goto exit; } /* compare the request with the function defintion */ Func *fn = env_func(env, req->path + 1); if (fn == NULL) { Error *err = error_new("unknown function '%s'", req->path + 1); status = http_404(io, err->msg); mem_free(err); goto exit; } if (fn->rp.name != NULL && req->method != POST) { status = http_405(io, POST); goto exit; } if (fn->rp.name == NULL && req->method == POST) { status = http_405(io, GET); goto exit; } /* TODO: think what to do with duplicate parameter values */ for (int i = 0; i < req->args->len; ++i) { char *name = req->args->names[i]; if (array_freq(req->args->names, req->args->len, name) > 1) { Error *err = error_new("duplicate parameter '%s' " "(not supported)", name); status = http_404(io, err->msg); mem_free(err); goto exit; } } if (fn->pp.len != req->args->len) { Error *err = error_new("expected %d primitive parameters, got %d", fn->pp.len, req->args->len); status = http_404(io, err->msg); mem_free(err); goto exit; } arg = mem_alloc(sizeof(Arg)); for (int i = 0; i < fn->pp.len; ++i) { char *name = fn->pp.names[i]; Type t = fn->pp.types[i]; int idx = array_scan(req->args->names, req->args->len, name); if (idx < 0) { Error *err = error_new("unknown parameter '%s'", name); status = http_404(io, err->msg); mem_free(err); goto exit; } char *val = req->args->vals[idx]; int error = 0; if (t == Int) { arg->vals[i].v_int = str_int(val, &error); } else if (t == Real) arg->vals[i].v_real = str_real(val, &error); else if (t == Long) arg->vals[i].v_long = str_long(val, &error); else if (t == String) { error = str_len(val) > MAX_STRING; if (!error) str_cpy(arg->vals[i].v_str, val); } if (error) { Error *err = error_new("value '%s' (parameter '%s') " "is not of type '%s'", val, name, type_to_str(t)); status = http_404(io, err->msg); mem_free(err); goto exit; } } if (fn->rp.name != NULL) { TBuf *body = NULL; if (req->len > 0) { Error *err = pack_csv2rel(req->body, fn->rp.head, &body); if (err != NULL) { status = http_404(io, err->msg); mem_free(err); goto exit; } } else { body = tbuf_new(); } vars_add(v, fn->rp.name, 0, body); /* project the parameter */ Rel *param = rel_project(rel_load(fn->rp.head, fn->rp.name), fn->rp.head->names, fn->rp.head->len); rel_eval(param, v, arg); /* clean the previous version */ tbuf_clean(body); tbuf_free(body); /* replace with the new body */ int vpos = array_scan(v->names, v->len, fn->rp.name); v->vals[vpos] = param->body; param->body = NULL; rel_free(param); } /* start a transaction */ r = vars_new(fn->r.len); w = vars_new(fn->w.len); for (int i = 0; i < fn->r.len; ++i) vars_add(r, fn->r.names[i], 0, NULL); for (int i = 0; i < fn->w.len; ++i) vars_add(w, fn->w.names[i], 0, NULL); sid = tx_enter(addr, r, w); /* prepare variables */ for (int i = 0; i < r->len; ++i) { TBuf *body = vol_read(r->vols[i], r->names[i], r->vers[i]); vars_add(v, r->names[i], 0, body); } for (int i = 0; i < w->len; ++i) { int pos = array_scan(v->names, v->len, w->names[i]); if (pos < 0) vars_add(v, w->names[i], 0, NULL); } for (int i = 0; i < fn->t.len; ++i) vars_add(v, fn->t.names[i], 0, NULL); /* evaluate the function body */ for (int i = 0; i < fn->slen; ++i) rel_eval(fn->stmts[i], v, arg); /* prepare the return value. note, the resulting relation is just a container for the body, so it is not freed */ Rel *ret = NULL; if (fn->ret != NULL) ret = fn->stmts[fn->slen - 1]; /* persist the global variables */ for (int i = 0; i < w->len; ++i) { int idx = array_scan(v->names, v->len, w->names[i]); if (idx < 0) { status = http_500(io); goto exit; } vol_write(w->vols[i], v->vals[idx], w->names[i], w->vers[i]); tbuf_free(v->vals[idx]); v->vals[idx] = NULL; } /* confirm a success and send the result back */ status = http_200(io); if (status != 200) goto exit; tx_commit(sid); /* N.B. there is no explicit revert as the transaction manager handles nested tx_enter and a connectivity failure as a rollback */ int len = 1, i = 0; while (status == 200 && len) { len = pack_rel2csv(ret, res, MAX_BLOCK, i++); status = http_chunk(io, res, len); } exit: if (status != -1) sys_log('E', "%016llX method %c, path %s, time %lldms - %3d\n", sid, (req == NULL) ? '?' : req->method, (req == NULL) ? "malformed" : req->path, sys_millis() - time, status); if (r != NULL) vars_free(r); if (w != NULL) vars_free(w); if (arg != NULL) mem_free(arg); if (req != NULL) http_free_req(req); if (env != NULL) env_free(env); for (int i = 0; i < v->len; ++i) if (v->vals[i] != NULL) { tbuf_clean(v->vals[i]); tbuf_free(v->vals[i]); } vars_free(v); sys_term(io); } mem_free(code); mem_free(res); tx_detach(); sys_close(io); }
/* * Get data from the keyboard. If we finish a character, return it. Else 0. * Return -1 if no data. */ static int kbd_proc_data(void) { int c; uint8_t data; static uint32_t shift; if ((inb(KBSTATP) & KBS_DIB) == 0) return -1; data = inb(KBDATAP); if (data == 0xE0) { // E0 escape character shift |= E0ESC; return 0; } else if (data & 0x80) { // Key released data = (shift & E0ESC ? data : data & 0x7F); shift &= ~(shiftcode[data] | E0ESC); return 0; } else if (shift & E0ESC) { // Last character was an E0 escape; or with 0x80 data |= 0x80; shift &= ~E0ESC; } shift |= shiftcode[data]; shift ^= togglecode[data]; c = charcode[shift & (CTL | SHIFT)][data]; //cprintf("shift:%08x,c:%08x\n",shift, c); if (shift & CAPSLOCK) { if ('a' <= c && c <= 'z') c += 'A' - 'a'; else if ('A' <= c && c <= 'Z') c += 'a' - 'A'; } if((shift & CTL ) && c == 0x3) { //cprintf("ctrl+c\n"); struct Env *env; //env->env_status = ENV_NOT_RUNNABLE; //sched_yield(); int i; for(i = NENV - 1; i >= 0; i--) { env = &envs[i]; //cprintf("i:%08x\n",i); while(env->env_id != envs[0].env_id) { //cprintf("shforkid position:%08x\n",ENVX(shforkid)); //cprintf("envid->parent_id:%08x\n",env->env_parent_id); if(env->env_id == shforkid) { //cprintf("destroy %08x\n",i); env_free(&envs[i]); //after free the env, clean the tickets of the env global_tickets -= envs[i].tickets; envs[i].tickets = 0; break; } env = &envs[ENVX(env->env_parent_id)]; if(ENVX(env->env_id) < ENVX(shforkid)) break; //cprintf("envid position:%08x\n",ENVX(env->env_id)); } /* if(envs[i].env_parent_id == curenv ->env_id ||envs[i].env_id == curenv -> env_parent_id) { cprintf("destroy i:%08x\n",i); env_destroy(&envs[i]); } */ } //env_destroy(curenv); } // Process special keys // Ctrl-Alt-Del: reboot if (!(~shift & (CTL | ALT)) && c == KEY_DEL) { cprintf("Rebooting!\n"); outb(0x92, 0x3); // courtesy of Chris Frost } return c; }