setup() { close(fsym); fsym = -1; #ifndef VFORK IF (pid = fork()) == 0 #else IF (pid = vfork()) == 0 #endif THEN ptrace(PT_TRACE_ME,0,0,0); #ifdef VFORK signal(SIGTRAP,nullsig); #endif signal(SIGINT,sigint); signal(SIGQUIT,sigqit); doexec(); exit(0); ELIF pid == -1 THEN error(NOFORK); ELSE bpwait(); readregs(); lp[0]=EOR; lp[1]=0; fsym=open(symfil,wtflag); IF errflg THEN printf("%s: cannot execute\n",symfil); endpcs(); error(0); FI FI bpstate=BPOUT; }
/* com */ void syscmd (char *s) { register status, sig; if (metas (s)) { if (usecshell) runl(0, cshabsname, cshname, "-f", "-c", s, NULL); else runl(0, shabsname, shname, "-c", s, NULL); return; } status = doexec (s); sig = status & 0177; if (! sig) return; if (sig == 0177) outerr("ptrace: ",0); else if (sig < numsysmsg && sysmsg [sig]) outerr(sysmsg [sig],0); else outerr("Signal %d", sig); if (status & 0200) outerr(" - core dumped\n",0); else outerr("\n",0); }
int main(const int argc, char* argv[]) { FILE *image; enum exe_type et; if (argc < 2) { fprintf(stderr, "Synopsis: %s file.exe [...]\n", argv[0]); return 0; } #ifdef ENABLE_DEBUG if (!strcmp(argv[1], "--pretend") && argc >= 3) { pretending = 1; argv[1] = argv[2]; /* we won't be using argv[2+] anyway */ } #endif image = fopen(argv[1], "r"); et = detect_format(image); /* image can be NULL here */ if (et == EXE_ERROR) perror("I/O error while reading executable"); if (image) fclose(image); if (et < EXE_ERROR) { char* const handler = read_conf(et); if (handler) doexec(handler, argv); } return 127; }
int dosys(char *comstring, int nohalt, int nowait, char *prefix) { int status; struct process *procp; /* make sure there is room in the process stack */ if(nproc >= MAXPROC) waitstack(MAXPROC-1); /* make sure fewer than proclimit processes are running */ while(proclive >= proclimit) { enbint(SIG_IGN); waitproc(&status); enbint(intrupt); } if(prefix) { fputs(prefix, stdout); fputs(comstring, stdout); } procp = procstack + nproc; procp->pid = (forceshell || metas(comstring) ) ? doshell(comstring,nohalt) : doexec(comstring); if(procp->pid == -1) fatal("fork failed"); procstack[nproc].nohalt = nohalt; procstack[nproc].nowait = nowait; procstack[nproc].done = NO; ++proclive; ++nproc; if(nowait) { printf(" &%d\n", procp->pid); fflush(stdout); return 0; } if(prefix) { putchar('\n'); fflush(stdout); } return waitstack(nproc-1); }
/*ARGSUSED*/ void execash(tchar **t, struct command *kp) { #ifdef TRACE tprintf("TRACE- execash()\n"); #endif rechist(); (void) signal(SIGINT, parintr); (void) signal(SIGQUIT, parintr); (void) signal(SIGTERM, parterm); /* if doexec loses, screw */ lshift(kp->t_dcom, 1); exiterr++; doexec(kp); /*NOTREACHED*/ }
/*********************** * do_target() * * Connects to the consultant's machine on port 'tunnelPort' * Once established, waits for an 'OK' that signifies the client has connected. * Once received, connects locally to the port specified by 'servicePort' * and shovels bits across the tunnel between the client program and the local service port. */ int do_target(const char *consultantHost, const char *targetHost, const int tunnelPort, const int servicePort) { int tunnelSock, serviceSock; char buf[BUF_SIZE]; // connect to the consultant's host printf("Target: Establishing tunnel with remote host on %s:%d\n", consultantHost, tunnelPort); if((tunnelSock = connect_socket(tunnelPort, consultantHost)) == -1) return 1; // send an ACK if(send(tunnelSock, "OK", 2, 0) == -1) { perror("ERROR: send()"); return 1; } printf("Target: Tunnel is up, waiting for client to connect on remote end...\n"); // wait for an ACK from the consultant before connecting to the local service if(recv(tunnelSock, buf, 2, 0) == -1) { perror("ERROR: recv()"); return 1; } if(buf[0] != 'O' || buf[1] != 'K') { printf("ERROR: Failed to acknowledge tunnel\n"); return 1; } printf("Target: Client has connected on the remote end\n"); // spawn a connect-back shell if needed if(pr00gie) { doexec(tunnelSock); return 1; // we only hit this on exec() throwing an error } // if we're not spawning a shell we must be building a tunnel. Let's do it! // connect to local service printf("Target: Connecting to local service port %d\n", servicePort); if((serviceSock = connect_socket(servicePort, targetHost)) == -1) return 1; printf("Target: Connected to service port %s:%d\n", targetHost, servicePort); printf("Target: Shovelling data across the tunnel...\n"); // shovel data between the client and the target return shovel_data(tunnelSock, serviceSock); }
void startpcs(void) { if ((pid = fork()) == 0) { pid = getpid(); msgpcs("hang"); doexec(); exits(0); } if (pid == -1) error("can't fork"); child++; sprint(procname, "/proc/%d/mem", pid); corfil = procname; msgpcs("waitstop"); bpwait(); if (adrflg) rput(cormap, mach->pc, adrval); while (rdc() != EOR) ; reread(); }
/* * This is /usr/sbin/mount: the generic command that in turn * execs the appropriate /usr/lib/fs/{fstype}/mount. * The -F flag and argument are NOT passed. * If the usr file system is not mounted a duplicate copy * can be found in /sbin and this version execs the * appropriate /etc/fs/{fstype}/mount * * If the -F fstype, special or directory are missing, * /etc/vfstab is searched to fill in the missing arguments. * * -V will print the built command on the stdout. * It isn't passed either. */ int main(int argc, char *argv[]) { char *special, /* argument of special/resource */ *mountp, /* argument of mount directory */ *fstype, /* wherein the fstype name is filled */ *newargv[ARGV_MAX], /* arg list for specific command */ *farg = NULL, *Farg = NULL; int ii, ret, cc, fscnt; struct stat64 stbuf; struct vfstab vget, vref; mode_t mode; FILE *fd; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); myname = strrchr(argv[0], '/'); if (myname) myname++; else myname = argv[0]; if (myname == 0) myname = "path unknown"; /* Process the args. */ while ((cc = getopt(argc, argv, "?acd:f:F:gmno:pqrvVO")) != -1) switch (cc) { case 'a': aflg++; break; case 'c': cflg++; break; #ifdef DEBUG case 'd': dflg = atoi(optarg); break; #endif case 'f': fflg++; farg = optarg; break; case 'F': Fflg++; Farg = optarg; break; case 'g': gflg++; break; case 'm': mflg++; break; /* do not update /etc/mnttab */ case 'o': oflg++; if ((specific_opts = strdup(optarg)) == NULL) nomem(); break; /* fstype dependent options */ case 'O': Oflg++; break; case 'p': pflg++; break; case 'q': qflg++; break; case 'r': rflg++; generic_opts = "ro"; break; case 'v': vflg++; break; case 'V': Vflg++; break; case '?': questflg++; break; } /* copy '--' to specific */ if (strcmp(argv[optind-1], "--") == 0) dashflg++; /* option checking */ /* more than two args not allowed if !aflg */ if (!aflg && (argc - optind > 2)) usage(); /* pv mututally exclusive */ if (pflg + vflg + aflg > 1) { fprintf(stderr, gettext ("%s: -a, -p, and -v are mutually exclusive\n"), myname); usage(); } /* * Can't have overlaying mounts on the same mount point during * a parallel mount. */ if (aflg && Oflg) { fprintf(stderr, gettext ("%s: -a and -O are mutually exclusive\n"), myname); usage(); } /* dfF mutually exclusive */ if (fflg + Fflg > 1) { fprintf(stderr, gettext ("%s: More than one FSType specified\n"), myname); usage(); } /* no arguments, only allow p,v,V or [F]? */ if (!aflg && optind == argc) { if (cflg || fflg || mflg || oflg || rflg || qflg) usage(); if (Fflg && !questflg) usage(); if (questflg) { if (Fflg) { newargv[2] = "-?"; newargv[3] = NULL; doexec(Farg, newargv); } usage(); } } if (questflg) usage(); /* one or two args, allow any but p,v */ if (optind != argc && (pflg || vflg)) { fprintf(stderr, gettext("%s: Cannot use -p and -v with arguments\n"), myname); usage(); } /* if only reporting mnttab, generic prints mnttab and exits */ if (!aflg && optind == argc) { if (Vflg) { printf("%s", myname); if (pflg) printf(" -p"); if (vflg) printf(" -v"); printf("\n"); exit(0); } print_mnttab(vflg, pflg); exit(0); } /* * Get filesystem type here. If "-F FStype" is specified, use * that fs type. Otherwise, determine the fs type from /etc/vfstab * if the entry exists. Otherwise, determine the local or remote * fs type from /etc/default/df or /etc/dfs/fstypes respectively. */ if (fflg) { if ((strcmp(farg, "S51K") != 0) && (strcmp(farg, "S52K") != 0)) { fstype = farg; } else fstype = "ufs"; } else /* if (Fflg) */ fstype = Farg; fscnt = argc - optind; if (aflg && (fscnt != 1)) exit(parmount(argv + optind, fscnt, fstype)); /* * Then don't bother with the parallel over head. Everything * from this point is simple/normal single execution. */ aflg = 0; /* get special and/or mount-point from arg(s) */ if (fscnt == 2) special = argv[optind++]; else special = NULL; if (optind < argc) mountp = argv[optind++]; else mountp = NULL; /* lookup only if we need to */ if (fstype == NULL || specific_opts == NULL || special == NULL || mountp == NULL) { if ((fd = fopen(vfstab, "r")) == NULL) { if (fstype == NULL || special == NULL || mountp == NULL) { fprintf(stderr, gettext( "%s: Cannot open %s\n"), myname, vfstab); exit(1); } else { /* * No vfstab, but we know what we want * to mount. */ goto out; } } vfsnull(&vref); vref.vfs_special = special; vref.vfs_mountp = mountp; vref.vfs_fstype = fstype; /* get a vfstab entry matching mountp or special */ while ((ret = getvfsany(fd, &vget, &vref)) > 0) vfserror(ret, vget.vfs_special); /* if no entry and there was only one argument */ /* then the argument could be the special */ /* and not mount point as we thought earlier */ if (ret == -1 && special == NULL) { rewind(fd); special = vref.vfs_special = mountp; mountp = vref.vfs_mountp = NULL; /* skip erroneous lines; they were reported above */ while ((ret = getvfsany(fd, &vget, &vref)) > 0) ; } fclose(fd); if (ret == 0) { if (fstype == NULL) fstype = vget.vfs_fstype; if (special == NULL) special = vget.vfs_special; if (mountp == NULL) mountp = vget.vfs_mountp; if (oflg == 0 && vget.vfs_mntopts) { oflg++; specific_opts = vget.vfs_mntopts; } } else if (special == NULL) { if (stat64(mountp, &stbuf) == -1) { fprintf(stderr, gettext("%s: cannot stat %s\n"), myname, mountp); exit(2); } if (((mode = (stbuf.st_mode & S_IFMT)) == S_IFBLK) || (mode == S_IFCHR)) { fprintf(stderr, gettext("%s: mount point cannot be determined\n"), myname); exit(1); } else { fprintf(stderr, gettext("%s: special cannot be determined\n"), myname); exit(1); } } else if (fstype == NULL) fstype = default_fstype(special); } out: if (realpath(mountp, realdir) == NULL) { (void) fprintf(stderr, "mount: "); perror(mountp); exit(1); } if ((mountp = strdup(realdir)) == NULL) nomem(); if (check_fields(fstype, mountp)) exit(1); /* create the new arg list, and end the list with a null pointer */ ii = 2; if (cflg) newargv[ii++] = "-c"; if (gflg) newargv[ii++] = "-g"; if (mflg) newargv[ii++] = "-m"; /* * The q option needs to go before the -o option as some * filesystems complain during first pass option parsing. */ if (qflg) newargv[ii++] = "-q"; if (oflg) { newargv[ii++] = "-o"; newargv[ii++] = specific_opts; } if (Oflg) newargv[ii++] = "-O"; if (rflg) newargv[ii++] = "-r"; if (dashflg) newargv[ii++] = "--"; newargv[ii++] = special; newargv[ii++] = mountp; newargv[ii] = NULL; doexec(fstype, newargv); return (0); }
/* * Performs the exec argument processing, all of the child forking and * execing, and child cleanup. * Sets exitcode to non-zero if any errors occurred. */ void do_mounts(void) { int i, isave, cnt; vfsent_t *vp, *vpprev, **vl; char *newargv[ARGV_MAX]; pid_t child; /* * create the arg list once; the only differences among * the calls are the options, special and mountp fields. */ i = 2; if (cflg) newargv[i++] = "-c"; if (gflg) newargv[i++] = "-g"; if (mflg) newargv[i++] = "-m"; if (Oflg) newargv[i++] = "-O"; if (qflg) newargv[i++] = "-q"; if (rflg) newargv[i++] = "-r"; if (dashflg) newargv[i++] = "--"; if (oflg) { newargv[i++] = "-o"; newargv[i++] = specific_opts; } isave = i; /* * Main loop for the mount processes */ vl = vfsarray; cnt = vfsarraysize; for (vpprev = *vl; vp = *vl; vpprev = vp, vl++, cnt--) { /* * Check to see if we cross a mount level: e.g., * /a/b -> /a/b/c. If so, we need to wait for all current * mounts to finish, rerun realpath on the remaining mount * points, and resort the list. * * Also, we mount serially as long as there are lofs's * to mount to avoid improper mount ordering. */ if (vp->mlevel > vpprev->mlevel || lofscnt > 0) { vfsent_t **vlp; while (nrun > 0 && (dowait() != -1)) ; /* * Gads! It's possible for real path mounts points to * change after mounts are done at a lower mount * level. * Thus, we need to recalculate mount levels and * resort the list from this point. */ for (vlp = vl; *vlp; vlp++) (void) setrpath(*vlp); /* * Sort the remaining entries based on their newly * resolved path names. * Do not sort if we still have lofs's to mount. */ if (lofscnt == 0) { qsort((void *)vl, cnt, sizeof (vfsent_t *), mlevelcmp); vp = *vl; } } if (vp->flag & VRPFAILED) { fprintf(stderr, gettext( "%s: Nonexistent mount point: %s\n"), myname, vp->v.vfs_mountp); vp->flag |= VNOTMOUNTED; exitcode = 1; continue; } /* * If mount options were not specified on the command * line, then use the ones found in the vfstab entry, * if any. */ i = isave; if (!oflg && vp->v.vfs_mntopts) { newargv[i++] = "-o"; newargv[i++] = vp->v.vfs_mntopts; } newargv[i++] = vp->v.vfs_special; newargv[i++] = vp->rpath; newargv[i] = NULL; /* * This should never really fail. */ while (setup_iopipe(vp) == -1 && (dowait() != -1)) ; while (nrun >= maxrun && (dowait() != -1)) /* throttle */ ; if ((child = fork()) == -1) { perror("fork"); cleanup(-1); /* not reached */ } if (child == 0) { /* child */ signal(SIGHUP, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGINT, SIG_IGN); setup_output(vp); doexec(vp->v.vfs_fstype, newargv); perror("exec"); exit(1); } /* parent */ (void) close(vp->sopipe[WRPIPE]); (void) close(vp->sepipe[WRPIPE]); vp->pid = child; nrun++; } /* * Mostly done by now - wait and clean up the stragglers. */ cleanup(0); }
int main(int ac, char **av) { int i; int mask = VARSYM_ALL_MASK; int level = VARSYM_USER; int deleteOpt = 0; int verboseOpt = 1; int allOpt = 0; int execok = 0; int ret = 0; while ((i = getopt(ac, av, "adhpqsux")) != -1) { switch (i) { case 'a': allOpt = 1; break; case 'd': deleteOpt = 1; break; case 'p': mask = VARSYM_PROC_MASK; level = VARSYM_PROC; break; case 'q': verboseOpt = 0; break; case 's': mask = VARSYM_SYS_MASK; level = VARSYM_SYS; break; case 'u': mask = VARSYM_USER_MASK; level = VARSYM_USER; break; case 'x': mask = VARSYM_PROC_MASK; level = VARSYM_PROC; execok = 1; break; case 'h': default: usage(); return(-1); } } if (allOpt) { char buf[1024]; int marker = 0; int bytes; for (;;) { bytes = varsym_list(level, buf, sizeof(buf), &marker); if (bytes < 0) /* error occured */ break; dumpvars(buf, bytes); if (marker < 0) /* no more vars */ break; } if (bytes < 0) { fprintf(stderr, "varsym_list(): %s\n", strerror(errno)); return 1; } } for ( ; optind < ac; optind++) { char *name = av[optind]; char *data = strchr(name, '='); int error; char buf[MAXVARSYM_DATA]; if (data) *data++ = 0; if (execok) { if (deleteOpt) { usage(); exit(1); } if (data) { error = varsym_set(level, name, data); if (error) ret = 2; } else { error = doexec(av + optind); } } else if (deleteOpt) { error = varsym_set(level, name, NULL); if (error) ret = 2; } else if (data) { error = varsym_set(level, name, data); if (error) ret = 2; } else { error = varsym_get(mask, name, buf, sizeof(buf)); if (error >= 0 && error <= (int)sizeof(buf)) { if (verboseOpt) printf("%s=", name); printf("%s\n", buf); } else { ret = 1; } } if (error < 0 && verboseOpt) fprintf(stderr, "%s: %s\n", name, strerror(errno)); } return ret; }
arg_t _execve(void) { /* We aren't re-entrant where this matters */ uint8_t hdr[16]; staticfast inoptr ino; char **nargv; /* In user space */ char **nenvp; /* In user space */ struct s_argblk *abuf, *ebuf; int argc; uint16_t progptr; uint16_t progload; staticfast uint16_t top; uint16_t bin_size; /* Will need to be bigger on some cpus */ uint16_t bss; top = ramtop; if (!(ino = n_open_lock(name, NULLINOPTR))) return (-1); if (!((getperm(ino) & OTH_EX) && (ino->c_node.i_mode & F_REG) && (ino->c_node.i_mode & (OWN_EX | OTH_EX | GRP_EX)))) { udata.u_error = EACCES; goto nogood; } setftime(ino, A_TIME); udata.u_offset = 0; udata.u_count = 16; udata.u_base = hdr; udata.u_sysio = true; readi(ino, 0); if (udata.u_done != 16) { udata.u_error = ENOEXEC; goto nogood; } if (!header_ok(hdr)) { udata.u_error = ENOEXEC; goto nogood2; } progload = hdr[7] << 8; if (progload == 0) progload = PROGLOAD; top = *(uint16_t *)(hdr + 8); if (top == 0) /* Legacy 'all space' binary */ top = ramtop; else /* Requested an amount, so adjust for the base */ top += progload; bss = *(uint16_t *)(hdr + 14); /* Binary doesn't fit */ /* FIXME: review overflows */ bin_size = ino->c_node.i_size; progptr = bin_size + 1024 + bss; if (progload < PROGLOAD || top - progload < progptr || progptr < bin_size) { udata.u_error = ENOMEM; goto nogood2; } udata.u_ptab->p_status = P_NOSLEEP; /* If we made pagemap_realloc keep hold of some defined area we could in theory just move the arguments up or down as part of the process - that would save us all this hassle but replace it with new hassle */ /* Gather the arguments, and put them in temporary buffers. */ abuf = (struct s_argblk *) tmpbuf(); /* Put environment in another buffer. */ ebuf = (struct s_argblk *) tmpbuf(); /* Read args and environment from process memory */ if (rargs(argv, abuf) || rargs(envp, ebuf)) goto nogood3; /* SN */ /* This must be the last test as it makes changes if it works */ /* FIXME: once we sort out chmem we can make stack and data two elements. We never allocate 'code' as there is no split I/D */ /* This is only safe from deadlocks providing pagemap_realloc doesn't sleep */ if (pagemap_realloc(0, top - MAPBASE, 0)) goto nogood3; /* From this point on we are commmited to the exec() completing */ /* Core dump and ptrace permission logic */ #ifdef CONFIG_LEVEL_2 /* Q: should uid == 0 mean we always allow core */ if ((!(getperm(ino) & OTH_RD)) || (ino->c_node.i_mode & (SET_UID | SET_GID))) udata.u_flags |= U_FLAG_NOCORE; else udata.u_flags &= ~U_FLAG_NOCORE; #endif udata.u_top = top; udata.u_ptab->p_top = top; /* setuid, setgid if executable requires it */ if (ino->c_node.i_mode & SET_UID) udata.u_euid = ino->c_node.i_uid; if (ino->c_node.i_mode & SET_GID) udata.u_egid = ino->c_node.i_gid; /* FIXME: In the execve case we may on some platforms have space below PROGLOAD to clear... */ /* We are definitely going to succeed with the exec, * so we can start writing over the old program */ uput(hdr, (uint8_t *)progload, 16); /* At this point, we are committed to reading in and * executing the program. This call must not block. */ close_on_exec(); /* * Read in the rest of the program, block by block. We rely upon * the optimization path in readi to spot this is a big move to user * space and move it directly. */ progptr = progload + 16; if (bin_size > 16) { bin_size -= 16; udata.u_base = (uint8_t *)progptr; /* We copied the first block already */ udata.u_count = bin_size; udata.u_sysio = false; readi(ino, 0); if (udata.u_done != bin_size) goto nogood4; progptr += bin_size; } /* Wipe the memory in the BSS. We don't wipe the memory above that on 8bit boxes, but defer it to brk/sbrk() */ uzero((uint8_t *)progptr, bss); /* Set initial break for program */ udata.u_break = (int)ALIGNUP(progptr + bss); /* Turn off caught signals */ memset(udata.u_sigvec, 0, sizeof(udata.u_sigvec)); // place the arguments, environment and stack at the top of userspace memory, // Write back the arguments and the environment nargv = wargs(((char *) top - 2), abuf, &argc); nenvp = wargs((char *) (nargv), ebuf, NULL); // Fill in udata.u_name with program invocation name uget((void *) ugetw(nargv), udata.u_name, 8); memcpy(udata.u_ptab->p_name, udata.u_name, 8); tmpfree(abuf); tmpfree(ebuf); i_deref(ino); /* Shove argc and the address of argv just below envp FIXME: should flip them in crt0.S of app for R2L setups so we can get rid of the ifdefs */ #ifdef CONFIG_CALL_R2L /* Arguments are stacked the 'wrong' way around */ uputw((uint16_t) nargv, nenvp - 2); uputw((uint16_t) argc, nenvp - 1); #else uputw((uint16_t) nargv, nenvp - 1); uputw((uint16_t) argc, nenvp - 2); #endif /* Set stack pointer for the program */ udata.u_isp = nenvp - 2; /* Start execution (never returns) */ udata.u_ptab->p_status = P_RUNNING; doexec(progload); /* tidy up in various failure modes */ nogood4: /* Must not run userspace */ ssig(udata.u_ptab, SIGKILL); nogood3: udata.u_ptab->p_status = P_RUNNING; tmpfree(abuf); tmpfree(ebuf); nogood2: nogood: i_unlock_deref(ino); return (-1); }
int main(int argc, char **argv) { char *myname; char *optionp; char *opigp; int mflag; int readonly; struct cachefs_mountargs margs; char *backfstypep; char *reducep; char *specp; int xx; int stat_loc; char *newargv[20]; char *mntp; pid_t pid; int mounted; int c; int lockid; int Oflg; char *strp; char servname[33]; int notify = 1; struct stat64 statb; struct mnttagdesc mtdesc; char mops[MAX_MNTOPT_STR]; char cfs_nfsv4ops[MAX_MNTOPT_STR]; uint32_t nfsvers = 0; uint32_t nfsvers_error = FALSE; int nfsv3pass = 0; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); if (argv[0]) { myname = strrchr(argv[0], '/'); if (myname) myname++; else myname = argv[0]; } else { myname = "path unknown"; } optionp = NULL; nomnttab = 0; quiet = 0; readonly = 0; Oflg = 0; cfs_nfsv4ops[0] = '\0'; /* process command line options */ while ((c = getopt(argc, argv, "mo:Orq")) != EOF) { switch (c) { case 'm': /* no entry in /etc/mnttab */ nomnttab = 1; break; case 'o': optionp = optarg; break; case 'O': Oflg++; break; case 'r': /* read only mount */ readonly = 1; break; case 'q': quiet = 1; break; default: usage("invalid option"); return (1); } } /* if -o not specified */ if (optionp == NULL) { usage(gettext("\"-o backfstype\" must be specified")); return (1); } /* verify special device and mount point are specified */ if (argc - optind < 2) { usage(gettext("must specify special device and mount point")); return (1); } /* Store mount point and special device. */ specp = argv[argc - 2]; mntp = argv[argc - 1]; /* Initialize default mount values */ margs.cfs_options.opt_flags = CFS_ACCESS_BACKFS; margs.cfs_options.opt_popsize = DEF_POP_SIZE; margs.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE; margs.cfs_fsid = NULL; memset(margs.cfs_cacheid, 0, sizeof (margs.cfs_cacheid)); margs.cfs_cachedir = CFS_DEF_DIR; margs.cfs_backfs = NULL; margs.cfs_acregmin = 0; margs.cfs_acregmax = 0; margs.cfs_acdirmin = 0; margs.cfs_acdirmax = 0; mflag = MS_OPTIONSTR; if (nomnttab) mflag |= MS_NOMNTTAB; backfstypep = NULL; /* process -o options */ xx = set_cfs_args(optionp, &margs, &mflag, &backfstypep, &reducep, ¬ify, &nfsv3pass); if (xx) { return (1); } strcpy(mops, optionp); /* backfstype has to be specified */ if (backfstypep == NULL) { usage(gettext("\"-o backfstype\" must be specified")); return (1); } if ((strcmp(backfstypep, "nfs") != 0) && (strcmp(backfstypep, "hsfs") != 0)) { pr_err(gettext("%s as backfstype is not supported."), backfstypep); return (1); } /* set default write mode if not specified */ if ((margs.cfs_options.opt_flags & (CFS_WRITE_AROUND|CFS_NONSHARED)) == 0) { margs.cfs_options.opt_flags |= CFS_WRITE_AROUND; if (strcmp(backfstypep, "hsfs") == 0) mflag |= MS_RDONLY; } /* if read-only was specified with the -r option */ if (readonly) { mflag |= MS_RDONLY; } /* if overlay was specified with -O option */ if (Oflg) { mflag |= MS_OVERLAY; } /* get the fsid of the backfs and the cacheid */ margs.cfs_fsid = get_back_fsid(specp); if (margs.cfs_fsid == NULL) { pr_err(gettext("out of memory")); return (1); } /* * If using this cachedir to mount a file system for the first time * after reboot, the ncheck for the sanity of the cachedir */ if (first_time_ab(margs.cfs_cachedir)) if (check_cache(margs.cfs_cachedir)) return (1); /* get the front file system cache id if necessary */ if (margs.cfs_cacheid[0] == '\0') { char *cacheid = get_cacheid(margs.cfs_fsid, mntp); if (cacheid == NULL) { pr_err(gettext("default cacheid too long")); return (1); } strcpy(margs.cfs_cacheid, cacheid); } /* lock the cache directory shared */ lockid = cachefs_dir_lock(margs.cfs_cachedir, 1); if (lockid == -1) { /* exit if could not get the lock */ return (1); } /* if no mount point was specified and we are not remounting */ mounted = 0; if ((margs.cfs_backfs == NULL) && (((mflag & MS_REMOUNT) == 0) || (margs.cfs_options.opt_flags & CFS_SLIDE))) { /* if a disconnectable mount */ xx = 0; if (margs.cfs_options.opt_flags & CFS_DISCONNECTABLE) { /* see if the server is alive */ xx = pingserver(specp); } /* attempt to mount the back file system */ if (xx == 0) { xx = dobackmnt(&margs, reducep, specp, backfstypep, myname, readonly); /* * nfs mount exits with a value of 32 if a timeout * error occurs trying the mount. */ if (xx && (xx != 32)) { cachefs_dir_unlock(lockid); rmdir(margs.cfs_backfs); return (1); } if (xx == 0) mounted = 1; } } /* * At this point the back file system should be mounted. * Get NFS version information for the back filesystem if * it is NFS. The version information is required * because NFS version 4 is incompatible with cachefs * and we provide pass-through support for NFS version 4 * with cachefs, aka the cachefs mount is installed but * there is no caching. This is indicated to the kernel * during the mount by setting the CFS_BACKFS_NFSV4 flag. */ if (margs.cfs_backfs != NULL && strcmp(backfstypep, "nfs") == 0) { nfsvers = cachefs_get_back_nfsvers(margs.cfs_backfs, nomnttab); switch (nfsvers) { case 2: break; case 3: if (nfsv3pass) { /* Force pass through (for debugging) */ margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4; if (cfs_nfsv4_build_opts(optionp, cfs_nfsv4ops) != 0) { nfsvers_error = TRUE; goto clean_backmnt; } } break; case 4: /* * overwrite old option flags with NFSv4 flag. * Note that will also operate in strict * consistency mode. Clean up the option string * to get rid of the cachefs-specific options * to be in sync with the opt flags, otherwise * these can make it into the mnttab and cause * problems (esp. the disconnected option). */ margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4; if (cfs_nfsv4_build_opts(optionp, cfs_nfsv4ops) != 0) { nfsvers_error = TRUE; goto clean_backmnt; } break; default: /* error, unknown version */ nfsvers_error = TRUE; goto clean_backmnt; } } /* * Grab server name from special file arg if it is there or set * server name to "server unknown". */ margs.cfs_hostname = servname; strncpy(servname, specp, sizeof (servname)); servname[sizeof (servname) - 1] = '\0'; strp = strchr(servname, ':'); if (strp == NULL) { margs.cfs_hostname = "server unknown"; margs.cfs_backfsname = specp; } else { *strp = '\0'; /* * The rest of the special file arg is the name of * the back filesystem. */ strp++; margs.cfs_backfsname = strp; } /* mount the cache file system */ xx = mount((margs.cfs_backfs != NULL) ? margs.cfs_backfs : "nobackfs", mntp, mflag | MS_DATA, MNTTYPE_CFS, &margs, sizeof (margs), (cfs_nfsv4ops[0] == '\0' ? mops : cfs_nfsv4ops), MAX_MNTOPT_STR); clean_backmnt: if (xx == -1 || nfsvers_error) { if (nfsvers_error) { pr_err(gettext("nfs version error.")); } else if (errno == ESRCH) { pr_err(gettext("mount failed, options do not match.")); } else if ((errno == EAGAIN) && (margs.cfs_backfs == NULL)) { pr_err(gettext("mount failed, server not responding.")); } else { pr_err(gettext("mount failed %s"), strerror(errno)); } /* try to unmount the back file system if we mounted it */ if (mounted) { xx = 1; newargv[xx++] = "umount"; newargv[xx++] = margs.cfs_backfs; newargv[xx++] = NULL; /* fork */ if ((pid = fork()) == -1) { pr_err(gettext("could not fork: %s"), strerror(errno)); cachefs_dir_unlock(lockid); return (1); } /* if the child */ if (pid == 0) { /* do the unmount */ doexec(backfstypep, newargv, "umount"); } /* else if the parent */ else { wait(0); } rmdir(margs.cfs_backfs); } cachefs_dir_unlock(lockid); return (1); } /* release the lock on the cache directory */ cachefs_dir_unlock(lockid); /* record the mount information in the fscache directory */ record_mount(mntp, specp, margs.cfs_backfs, backfstypep, margs.cfs_cachedir, margs.cfs_cacheid, (cfs_nfsv4ops[0] == '\0' ? optionp : cfs_nfsv4ops), reducep); /* notify the daemon of the mount */ if (notify) daemon_notify(margs.cfs_cachedir, margs.cfs_cacheid); /* update mnttab file if necessary */ if (!nomnttab) { /* * If we added the back file system, tag it with ignore, * however, don't fail the mount after its done * if the tag can't be added (eg., this would cause * automounter problems). */ if (mounted) { FILE *mt; struct extmnttab mnt; if ((mt = fopen(MNTTAB, "r")) == NULL) return (1); while (getextmntent(mt, &mnt, sizeof (mnt)) != -1) { if (mnt.mnt_mountp != NULL && strcmp(margs.cfs_backfs, mnt.mnt_mountp) == 0) { /* found it, do tag ioctl */ mtdesc.mtd_major = mnt.mnt_major; mtdesc.mtd_minor = mnt.mnt_minor; mtdesc.mtd_mntpt = margs.cfs_backfs; mtdesc.mtd_tag = MNTOPT_IGNORE; (void) ioctl(fileno(mt), MNTIOC_SETTAG, &mtdesc); break; } } fclose(mt); } } /* return success */ return (0); }
int main(int argc, char * const argv[]) { char **vec; unsigned int num; char *s; int state; char *sstate; char *p; char buf[80]; int type = DEVTYPE_UNKNOWN; int ch; int debug_fd; FILE *pidfile_f; while ((ch = getopt(argc, argv, "dfl:p:s:")) != -1) { switch (ch) { case 'd': dflag = 1; break; case 'f': fflag = 1; break; case 'l': log_file = optarg; break; case 'p': pidfile = pidfile; case 's': vbd_script = optarg; break; default: usage(); } } if (vbd_script == NULL) vbd_script = VBD_SCRIPT; if (pidfile == NULL) pidfile = PID_FILE; if (log_file == NULL) log_file = LOG_FILE; openlog("xenbackendd", LOG_PID | LOG_NDELAY, LOG_DAEMON); if (fflag == 0) { /* open log file */ debug_fd = open(log_file, O_RDWR | O_CREAT | O_TRUNC, 0644); if (debug_fd == -1) { dolog(LOG_ERR, "can't open %s: %s", log_file, strerror(errno)); exit(EXIT_FAILURE); } } if (fflag == 0) { /* daemonize */ pidfile_f = fopen(pidfile, "w"); if (pidfile_f == NULL) { dolog(LOG_ERR, "can't open %s: %s", pidfile, strerror(errno)); exit(EXIT_FAILURE); } if (daemon(0, 0) < 0) { dolog(LOG_ERR, "can't daemonize: %s", strerror(errno)); exit(EXIT_FAILURE); } fprintf(pidfile_f, "%d\n", (int)getpid()); fclose(pidfile_f); /* redirect stderr to log file */ if (dup2(debug_fd, STDERR_FILENO) < 0) { dolog(LOG_ERR, "can't redirect stderr to %s: %s\n", log_file, strerror(errno)); exit(EXIT_FAILURE); } /* also redirect stdout if we're in debug mode */ if (dflag) { if (dup2(debug_fd, STDOUT_FILENO) < 0) { dolog(LOG_ERR, "can't redirect stdout to %s: %s\n", log_file, strerror(errno)); exit(EXIT_FAILURE); } } close(debug_fd); debug_fd = -1; } if (xen_setup() < 0) exit(EXIT_FAILURE); for (;;) { vec = xs_read_watch(xs, &num); if (!vec) { dolog(LOG_ERR, "xs_read_watch: NULL\n"); continue; } if (strlen(vec[XS_WATCH_PATH]) < sizeof("state")) goto next1; /* find last component of path, check if it's "state" */ p = &vec[XS_WATCH_PATH][ strlen(vec[XS_WATCH_PATH]) - sizeof("state")]; if (p[0] != '/') goto next1; p[0] = '\0'; p++; if (strcmp(p, "state") != 0) goto next1; snprintf(buf, sizeof(buf), "%s/state", vec[XS_WATCH_PATH]); sstate = xs_read(xs, XBT_NULL, buf, 0); if (sstate == NULL) { dolog(LOG_ERR, "Failed to read %s (%s)", buf, strerror(errno)); goto next1; } state = atoi(sstate); snprintf(buf, sizeof(buf), "%s/hotplug-status", vec[XS_WATCH_PATH]); s = xs_read(xs, XBT_NULL, buf, 0); if (s != NULL && state != 6 /* XenbusStateClosed */) goto next2; if (strncmp(vec[XS_WATCH_PATH], DOMAIN_PATH "/backend/vif", strlen(DOMAIN_PATH "/backend/vif")) == 0) type = DEVTYPE_VIF; if (strncmp(vec[XS_WATCH_PATH], DOMAIN_PATH "/backend/vbd", strlen(DOMAIN_PATH "/backend/vbd")) == 0) type = DEVTYPE_VBD; switch(type) { case DEVTYPE_VIF: if (s) free(s); snprintf(buf, sizeof(buf), "%s/script", vec[XS_WATCH_PATH]); s = xs_read(xs, XBT_NULL, buf, 0); if (s == NULL) { dolog(LOG_ERR, "Failed to read %s (%s)", buf, strerror(errno)); goto next2; } doexec(s, vec[XS_WATCH_PATH], sstate); break; case DEVTYPE_VBD: doexec(vbd_script, vec[XS_WATCH_PATH], sstate); break; default: break; } next2: if (s) free(s); free(sstate); next1: free(vec); } return 0; }
arg_t _execve(void) { /* Not ideal on stack */ struct binfmt_flat binflat; inoptr ino; char **nargv; /* In user space */ char **nenvp; /* In user space */ struct s_argblk *abuf, *ebuf; int argc; uint32_t bin_size; /* Will need to be bigger on some cpus */ uaddr_t progbase, top; uaddr_t go; uint32_t true_brk; if (!(ino = n_open_lock(name, NULLINOPTR))) return (-1); if (!((getperm(ino) & OTH_EX) && (ino->c_node.i_mode & F_REG) && (ino->c_node.i_mode & (OWN_EX | OTH_EX | GRP_EX)))) { udata.u_error = EACCES; goto nogood; } setftime(ino, A_TIME); udata.u_offset = 0; udata.u_count = sizeof(struct binfmt_flat); udata.u_base = (void *)&binflat; udata.u_sysio = true; readi(ino, 0); if (udata.u_done != sizeof(struct binfmt_flat)) { udata.u_error = ENOEXEC; goto nogood; } /* FIXME: ugly - save this as valid_hdr modifies it */ true_brk = binflat.bss_end; /* Hard coded for our 68K format. We don't quite use the ucLinux names, we don't want to load a ucLinux binary in error! */ if (memcmp(binflat.magic, "bFLT", 4) || !valid_hdr(ino, &binflat)) { udata.u_error = ENOEXEC; goto nogood2; } /* Memory needed */ bin_size = binflat.bss_end + binflat.stack_size; /* Overflow ? */ if (bin_size < binflat.bss_end) { udata.u_error = ENOEXEC; goto nogood2; } /* Gather the arguments, and put them in temporary buffers. */ abuf = (struct s_argblk *) tmpbuf(); /* Put environment in another buffer. */ ebuf = (struct s_argblk *) tmpbuf(); /* Read args and environment from process memory */ if (rargs(argv, abuf) || rargs(envp, ebuf)) goto nogood3; /* This must be the last test as it makes changes if it works */ /* FIXME: need to update this to support split code/data and to fix stack handling nicely */ /* FIXME: ENOMEM fix needs to go to 16bit ? */ if ((udata.u_error = pagemap_realloc(0, bin_size, 0)) != 0) goto nogood3; /* Core dump and ptrace permission logic */ #ifdef CONFIG_LEVEL_2 /* Q: should uid == 0 mean we always allow core */ if ((!(getperm(ino) & OTH_RD)) || (ino->c_node.i_mode & (SET_UID | SET_GID))) udata.u_flags |= U_FLAG_NOCORE; else udata.u_flags &= ~U_FLAG_NOCORE; #endif udata.u_codebase = progbase = pagemap_base(); /* From this point on we are commmited to the exec() completing so we can start writing over the old program */ uput(&binflat, (uint8_t *)progbase, sizeof(struct binfmt_flat)); /* setuid, setgid if executable requires it */ if (ino->c_node.i_mode & SET_UID) udata.u_euid = ino->c_node.i_uid; if (ino->c_node.i_mode & SET_GID) udata.u_egid = ino->c_node.i_gid; top = progbase + bin_size; udata.u_top = top; udata.u_ptab->p_top = top; // kprintf("user space at %p\n", progbase); // kprintf("top at %p\n", progbase + bin_size); bin_size = binflat.reloc_start + 4 * binflat.reloc_count; go = (uint32_t)progbase + binflat.entry; close_on_exec(); /* * Read in the rest of the program, block by block. We rely upon * the optimization path in readi to spot this is a big move to user * space and move it directly. */ if (bin_size > sizeof(struct binfmt_flat)) { /* We copied the header already */ bin_size -= sizeof(struct binfmt_flat); udata.u_base = (uint8_t *)progbase + sizeof(struct binfmt_flat); udata.u_count = bin_size; udata.u_sysio = false; readi(ino, 0); if (udata.u_done != bin_size) goto nogood4; } /* Header isn't counted in relocations */ relocate(&binflat, progbase, bin_size); /* This may wipe the relocations */ uzero((uint8_t *)progbase + binflat.data_end, binflat.bss_end - binflat.data_end + binflat.stack_size); /* Use of brk eats into the stack allocation */ /* Use the temporary we saved (hack) as we mangled bss_end */ udata.u_break = udata.u_codebase + true_brk; /* Turn off caught signals */ memset(udata.u_sigvec, 0, sizeof(udata.u_sigvec)); /* place the arguments, environment and stack at the top of userspace memory. */ /* Write back the arguments and the environment */ nargv = wargs(((char *) top - 4), abuf, &argc); nenvp = wargs((char *) (nargv), ebuf, NULL); /* Fill in udata.u_name with Program invocation name */ uget((void *) ugetl(nargv, NULL), udata.u_name, 8); memcpy(udata.u_ptab->p_name, udata.u_name, 8); tmpfree(abuf); tmpfree(ebuf); i_unlock_deref(ino); /* Shove argc and the address of argv just below envp */ uputl((uint32_t) nargv, nenvp - 1); uputl((uint32_t) argc, nenvp - 2); // Set stack pointer for the program udata.u_isp = nenvp - 2; /* * Sort of - it's a good way to deal with all the stupidity of * random 68K platforms we will have to handle, and a nice place * to stuff the signal trampoline 8) */ install_vdso(); // kprintf("Go = %p ISP = %p\n", go, udata.u_isp); doexec(go); nogood4: /* Must not run userspace */ ssig(udata.u_ptab, SIGKILL); nogood3: tmpfree(abuf); tmpfree(ebuf); nogood2: nogood: i_unlock_deref(ino); return (-1); }
void execute(struct command *t, int wtty, int *pipein, int *pipeout) { static sigset_t csigset, ocsigset; static int nosigchld = 0, onosigchld = 0; volatile int wanttty = wtty; struct biltins * volatile bifunc; int pv[2], pid; sigset_t nsigset; int forked; UNREGISTER(forked); UNREGISTER(bifunc); UNREGISTER(wanttty); forked = 0; pid = 0; if (t == 0) return; if (t->t_dflg & F_AMPERSAND) wanttty = 0; switch (t->t_dtyp) { case NODE_COMMAND: if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) (void)Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); if ((t->t_dflg & F_REPEAT) == 0) Dfix(t); /* $ " ' \ */ if (t->t_dcom[0] == 0) return; /* FALLTHROUGH */ case NODE_PAREN: if (t->t_dflg & F_PIPEOUT) mypipe(pipeout); /* * Must do << early so parent will know where input pointer should be. * If noexec then this is all we do. */ if (t->t_dflg & F_READ) { (void)close(0); heredoc(t->t_dlef); if (noexec) (void)close(0); } set(STRstatus, Strsave(STR0)); /* * This mess is the necessary kludge to handle the prefix builtins: * nice, nohup, time. These commands can also be used by themselves, * and this is not handled here. This will also work when loops are * parsed. */ while (t->t_dtyp == NODE_COMMAND) if (eq(t->t_dcom[0], STRnice)) { if (t->t_dcom[1]) { if (strchr("+-", t->t_dcom[1][0])) { if (t->t_dcom[2]) { setname("nice"); t->t_nice = getn(t->t_dcom[1]); lshift(t->t_dcom, 2); t->t_dflg |= F_NICE; } else break; } else { t->t_nice = 4; lshift(t->t_dcom, 1); t->t_dflg |= F_NICE; } } else break; } else if (eq(t->t_dcom[0], STRnohup)) { if (t->t_dcom[1]) { t->t_dflg |= F_NOHUP; lshift(t->t_dcom, 1); } else break; } else if (eq(t->t_dcom[0], STRtime)) { if (t->t_dcom[1]) { t->t_dflg |= F_TIME; lshift(t->t_dcom, 1); } else break; } else break; /* is it a command */ if (t->t_dtyp == NODE_COMMAND) { /* * Check if we have a builtin function and remember which one. */ bifunc = isbfunc(t); if (noexec && bifunc != NULL) { /* * Continue for builtins that are part of the scripting language */ if (bifunc->bfunct != dobreak && bifunc->bfunct != docontin && bifunc->bfunct != doelse && bifunc->bfunct != doend && bifunc->bfunct != doforeach && bifunc->bfunct != dogoto && bifunc->bfunct != doif && bifunc->bfunct != dorepeat && bifunc->bfunct != doswbrk && bifunc->bfunct != doswitch && bifunc->bfunct != dowhile && bifunc->bfunct != dozip) break; } } else { /* not a command */ bifunc = NULL; if (noexec) break; } /* * We fork only if we are timed, or are not the end of a parenthesized * list and not a simple builtin function. Simple meaning one that is * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not * fork in some of these cases. */ /* * Prevent forking cd, pushd, popd, chdir cause this will cause the * shell not to change dir! */ if (bifunc && (bifunc->bfunct == dochngd || bifunc->bfunct == dopushd || bifunc->bfunct == dopopd)) t->t_dflg &= ~(F_NICE); if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 && (!bifunc || t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP)))) || /* * We have to fork for eval too. */ (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 && bifunc->bfunct == doeval)) { if (t->t_dtyp == NODE_PAREN || t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) { forked++; /* * We need to block SIGCHLD here, so that if the process does * not die before we can set the process group */ if (wanttty >= 0 && !nosigchld) { sigemptyset(&nsigset); (void)sigaddset(&nsigset, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &nsigset, &csigset); nosigchld = 1; } pid = pfork(t, wanttty); if (pid == 0 && nosigchld) { (void)sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) backpid = pid; } else { int ochild, osetintr, ohaderr, odidfds; int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp; sigset_t osigset; /* * Prepare for the vfork by saving everything that the child * corrupts before it exec's. Note that in some signal * implementations which keep the signal info in user space * (e.g. Sun's) it will also be necessary to save and restore * the current sigaction's for the signals the child touches * before it exec's. */ if (wanttty >= 0 && !nosigchld && !noexec) { sigemptyset(&nsigset); (void)sigaddset(&nsigset, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &nsigset, &csigset); nosigchld = 1; } sigemptyset(&nsigset); (void)sigaddset(&nsigset, SIGCHLD); (void)sigaddset(&nsigset, SIGINT); (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); ochild = child; osetintr = setintr; ohaderr = haderr; odidfds = didfds; oSHIN = SHIN; oSHOUT = SHOUT; oSHERR = SHERR; oOLDSTD = OLDSTD; otpgrp = tpgrp; ocsigset = csigset; onosigchld = nosigchld; Vsav = Vdp = 0; Vexpath = 0; Vt = 0; pid = vfork(); if (pid < 0) { (void)sigprocmask(SIG_SETMASK, &osigset, NULL); stderror(ERR_NOPROC); } forked++; if (pid) { /* parent */ child = ochild; setintr = osetintr; haderr = ohaderr; didfds = odidfds; SHIN = oSHIN; SHOUT = oSHOUT; SHERR = oSHERR; OLDSTD = oOLDSTD; tpgrp = otpgrp; csigset = ocsigset; nosigchld = onosigchld; xfree((ptr_t) Vsav); Vsav = 0; xfree((ptr_t) Vdp); Vdp = 0; xfree((ptr_t) Vexpath); Vexpath = 0; blkfree((Char **) Vt); Vt = 0; /* this is from pfork() */ palloc(pid, t); (void)sigprocmask(SIG_SETMASK, &osigset, NULL); } else { /* child */ /* this is from pfork() */ int pgrp; int ignint = 0; if (nosigchld) { (void)sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if (setintr) ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) || (gointr && eq(gointr, STRminus)); pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); child++; if (setintr) { setintr = 0; if (ignint) { (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); } else { (void)signal(SIGINT, vffree); (void)signal(SIGQUIT, SIG_DFL); } if (wanttty >= 0) { (void)signal(SIGTSTP, SIG_DFL); (void)signal(SIGTTIN, SIG_DFL); (void)signal(SIGTTOU, SIG_DFL); } (void)signal(SIGTERM, parterm); } else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); } pgetty(wanttty, pgrp); if (t->t_dflg & F_NOHUP) (void)signal(SIGHUP, SIG_IGN); if (t->t_dflg & F_NICE) (void)setpriority(PRIO_PROCESS, 0, t->t_nice); } } } if (pid != 0) { /* * It would be better if we could wait for the whole job when we * knew the last process had been started. Pwait, in fact, does * wait for the whole job anyway, but this test doesn't really * express our intentions. */ if (didfds == 0 && t->t_dflg & F_PIPEIN) { (void)close(pipein[0]); (void)close(pipein[1]); } if ((t->t_dflg & F_PIPEOUT) == 0) { if (nosigchld) { (void)sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if ((t->t_dflg & F_AMPERSAND) == 0) pwait(); } break; } doio(t, pipein, pipeout); if (t->t_dflg & F_PIPEOUT) { (void)close(pipeout[0]); (void)close(pipeout[1]); } /* * Perform a builtin function. If we are not forked, arrange for * possible stopping */ if (bifunc) { func(t, bifunc); if (forked) exitstat(); break; } if (t->t_dtyp != NODE_PAREN) doexec(NULL, t); /* * For () commands must put new 0,1,2 in FSH* and recurse */ (void) ioctl(OLDSTD = dcopy(0, FOLDSTD), FIOCLEX, NULL); (void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, NULL); (void) ioctl(SHERR = dcopy(2, FSHERR), FIOCLEX, NULL); (void) close(SHIN); SHIN = -1; didfds = 0; wanttty = -1; t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT; execute(t->t_dspr, wanttty, NULL, NULL); exitstat(); /* NOTREACHED */ case NODE_PIPE: t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT)); execute(t->t_dcar, wanttty, pipein, pv); t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT)); if (wanttty > 0) wanttty = 0; /* got tty already */ execute(t->t_dcdr, wanttty, pv, pipeout); break; case NODE_LIST: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; execute(t->t_dcar, wanttty, NULL, NULL); /* * In strange case of A&B make a new job after A */ if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) pendjob(); } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT); execute(t->t_dcdr, wanttty, NULL, NULL); } break; case NODE_OR: case NODE_AND: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; execute(t->t_dcar, wanttty, NULL, NULL); if ((getn(value(STRstatus)) == 0) != (t->t_dtyp == NODE_AND)) return; } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT); execute(t->t_dcdr, wanttty, NULL, NULL); } break; } /* * Fall through for all breaks from switch * * If there will be no more executions of this command, flush all file * descriptors. Places that turn on the F_REPEAT bit are responsible for * doing donefds after the last re-execution */ if (didfds && !(t->t_dflg & F_REPEAT)) donefds(); }
/*VARARGS 1*/ void execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout, int do_glob) { int forked = 0; const struct biltins * volatile bifunc; pid_t pid = 0; int pv[2]; sigset_t set; static sigset_t csigset; #ifdef VFORK static int onosigchld = 0; #endif /* VFORK */ static int nosigchld = 0; (void) &wanttty; (void) &forked; (void) &bifunc; if (t == 0) return; #ifdef WINNT_NATIVE { if ((varval(STRNTslowexec) == STRNULL) && !t->t_dcdr && !t->t_dcar && !t->t_dflg && !didfds && (intty || intact) && (t->t_dtyp == NODE_COMMAND) && !isbfunc(t)) { if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); Dfix(t); if (nt_try_fast_exec(t) == 0) return; } } #endif /* WINNT_NATIVE */ /* * Ed [email protected] & Dominic [email protected] * Sat Feb 25 03:13:11 PST 1995 * try implicit cd if we have a 1 word command */ if (implicit_cd && (intty || intact) && t->t_dcom && t->t_dcom[0] && t->t_dcom[0][0] && (blklen(t->t_dcom) == 1) && !noexec) { Char *sCName; struct stat stbuf; char *pathname; sCName = dollar(t->t_dcom[0]); if (sCName != NULL && sCName[0] == '~') { struct Strbuf buf = Strbuf_INIT; const Char *name_end; for (name_end = sCName + 1; *name_end != '\0' && *name_end != '/'; name_end++) continue; if (name_end != sCName + 1) { Char *name, *home; name = Strnsave(sCName + 1, name_end - (sCName + 1)); home = gethdir(name); if (home != NULL) { Strbuf_append(&buf, home); xfree(home); } else Strbuf_append(&buf, name); xfree(name); } else Strbuf_append(&buf, varval(STRhome)); Strbuf_append(&buf, name_end); xfree(sCName); sCName = Strbuf_finish(&buf); } pathname = short2str(sCName); xfree(sCName); /* if this is a dir, tack a "cd" on as the first arg */ if (pathname != NULL && ((stat(pathname, &stbuf) != -1 && S_ISDIR(stbuf.st_mode)) #ifdef WINNT_NATIVE || (pathname[0] && pathname[1] == ':' && pathname[2] == '\0') #endif /* WINNT_NATIVE */ )) { Char *vCD[2]; Char **ot_dcom = t->t_dcom; vCD[0] = Strsave(STRcd); vCD[1] = NULL; t->t_dcom = blkspl(vCD, ot_dcom); xfree(ot_dcom); if (implicit_cd > 1) { blkpr(t->t_dcom); xputchar( '\n' ); } } } /* * From: Michael Schroeder <*****@*****.**> * Don't check for wantty > 0... */ if (t->t_dflg & F_AMPERSAND) wanttty = 0; switch (t->t_dtyp) { case NODE_COMMAND: if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) memmove(t->t_dcom[0], t->t_dcom[0] + 1, (Strlen(t->t_dcom[0] + 1) + 1) * sizeof (*t->t_dcom[0])); if ((t->t_dflg & F_REPEAT) == 0) Dfix(t); /* $ " ' \ */ if (t->t_dcom[0] == 0) { return; } /*FALLTHROUGH*/ case NODE_PAREN: #ifdef BACKPIPE if (t->t_dflg & F_PIPEIN) mypipe(pipein); #else /* !BACKPIPE */ if (t->t_dflg & F_PIPEOUT) mypipe(pipeout); #endif /* BACKPIPE */ /* * Must do << early so parent will know where input pointer should be. * If noexec then this is all we do. */ if (t->t_dflg & F_READ) { xclose(0); heredoc(t->t_dlef); if (noexec) xclose(0); } setcopy(STRstatus, STR0, VAR_READWRITE); /* * This mess is the necessary kludge to handle the prefix builtins: * nice, nohup, time. These commands can also be used by themselves, * and this is not handled here. This will also work when loops are * parsed. */ while (t->t_dtyp == NODE_COMMAND) if (eq(t->t_dcom[0], STRnice)) { if (t->t_dcom[1]) { if (strchr("+-", t->t_dcom[1][0])) { if (t->t_dcom[2]) { setname("nice"); t->t_nice = (unsigned char)getn(t->t_dcom[1]); lshift(t->t_dcom, 2); t->t_dflg |= F_NICE; } else break; } else { t->t_nice = 4; lshift(t->t_dcom, 1); t->t_dflg |= F_NICE; } } else break; } else if (eq(t->t_dcom[0], STRnohup)) { if (t->t_dcom[1]) { t->t_dflg |= F_NOHUP; lshift(t->t_dcom, 1); } else break; } else if (eq(t->t_dcom[0], STRhup)) { if (t->t_dcom[1]) { t->t_dflg |= F_HUP; lshift(t->t_dcom, 1); } else break; } else if (eq(t->t_dcom[0], STRtime)) { if (t->t_dcom[1]) { t->t_dflg |= F_TIME; lshift(t->t_dcom, 1); } else break; } #ifdef F_VER else if (eq(t->t_dcom[0], STRver)) if (t->t_dcom[1] && t->t_dcom[2]) { setname("ver"); t->t_systype = getv(t->t_dcom[1]); lshift(t->t_dcom, 2); t->t_dflg |= F_VER; } else break; #endif /* F_VER */ else break; /* is it a command */ if (t->t_dtyp == NODE_COMMAND) { /* * Check if we have a builtin function and remember which one. */ bifunc = isbfunc(t); if (noexec) { /* * Continue for builtins that are part of the scripting language */ if (bifunc == NULL) break; if (bifunc->bfunct != (bfunc_t)dobreak && bifunc->bfunct != (bfunc_t)docontin && bifunc->bfunct != (bfunc_t)doelse && bifunc->bfunct != (bfunc_t)doend && bifunc->bfunct != (bfunc_t)doforeach&& bifunc->bfunct != (bfunc_t)dogoto && bifunc->bfunct != (bfunc_t)doif && bifunc->bfunct != (bfunc_t)dorepeat && bifunc->bfunct != (bfunc_t)doswbrk && bifunc->bfunct != (bfunc_t)doswitch && bifunc->bfunct != (bfunc_t)dowhile && bifunc->bfunct != (bfunc_t)dozip) break; } } else { /* not a command */ bifunc = NULL; if (noexec) break; } /* * GrP Executing a command - run jobcmd hook * Don't run for builtins * Don't run if we're not in a tty * Don't run if we're not really executing */ /* * CR - Charles Ross Aug 2005 * added "isoutatty". * The new behavior is that the jobcmd won't be executed * if stdout (SHOUT) isnt attached to a tty.. IE when * redirecting, or using backquotes etc.. */ if (t->t_dtyp == NODE_COMMAND && !bifunc && !noexec && intty && isoutatty) { Char *cmd = unparse(t); cleanup_push(cmd, xfree); job_cmd(cmd); cleanup_until(cmd); } /* * We fork only if we are timed, or are not the end of a parenthesized * list and not a simple builtin function. Simple meaning one that is * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not * fork in some of these cases. */ #ifdef BACKPIPE /* * Can't have NOFORK for the tail of a pipe - because it is not the * last command spawned (even if it is at the end of a parenthesised * list). */ if (t->t_dflg & F_PIPEIN) t->t_dflg &= ~(F_NOFORK); #else /* * "command | builtin" may cause major misbehaviour as noted in * in the BUGS file entry * Subject: Redirected input to built-in functions misbehaves badly * forking when the builtin is the end of the pipe corrects the * problem. */ if (bifunc && (t->t_dflg & F_PIPEIN)) t->t_dflg &= ~(F_NOFORK); #endif /* BACKPIPE */ /* * Prevent forking cd, pushd, popd, chdir cause this will cause the * shell not to change dir! (XXX: but only for nice?) */ if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd || bifunc->bfunct == (bfunc_t)dopushd || bifunc->bfunct == (bfunc_t)dopopd)) t->t_dflg &= ~(F_NICE); if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 && (!bifunc || t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) || /* * We have to fork for eval too. */ (bifunc && (t->t_dflg & F_PIPEIN) != 0 && bifunc->bfunct == (bfunc_t)doeval)) { #ifdef VFORK if (t->t_dtyp == NODE_PAREN || t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) #endif /* VFORK */ { forked++; /* * We need to block SIGCHLD here, so that if the process does * not die before we can set the process group */ if (wanttty >= 0 && !nosigchld) { sigemptyset(&set); sigaddset(&set, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &set, &csigset); nosigchld = 1; } pid = pfork(t, wanttty); if (pid == 0 && nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) backpid = pid; } #ifdef VFORK else { int ochild, osetintr, ohaderr, odidfds; int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; int oisoutatty, oisdiagatty; sigset_t oset, ocsigset; # ifndef CLOSE_ON_EXEC int odidcch; # endif /* !CLOSE_ON_EXEC */ /* * Prepare for the vfork by saving everything that the child * corrupts before it exec's. Note that in some signal * implementations which keep the signal info in user space * (e.g. Sun's) it will also be necessary to save and restore * the current sigvec's for the signals the child touches * before it exec's. */ /* * Sooooo true... If this is a Sun, save the sigvec's. (Skip * Gilbrech - 11/22/87) */ # ifdef SAVESIGVEC struct sigaction savesv[NSIGSAVED]; sigset_t savesm; # endif /* SAVESIGVEC */ if (wanttty >= 0 && !nosigchld && !noexec) { sigemptyset(&set); sigaddset(&set, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &set, &csigset); nosigchld = 1; } sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGINT); (void)sigprocmask(SIG_BLOCK, &set, &oset); ochild = child; osetintr = setintr; ohaderr = haderr; odidfds = didfds; # ifndef CLOSE_ON_EXEC odidcch = didcch; # endif /* !CLOSE_ON_EXEC */ oSHIN = SHIN; oSHOUT = SHOUT; oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; oisoutatty = isoutatty; oisdiagatty = isdiagatty; ocsigset = csigset; onosigchld = nosigchld; Vsav = Vdp = 0; Vexpath = 0; Vt = 0; # ifdef SAVESIGVEC savesigvec(savesv, savesm); # endif /* SAVESIGVEC */ if (use_fork) pid = fork(); else pid = vfork(); if (pid < 0) { # ifdef SAVESIGVEC restoresigvec(savesv, savesm); # endif /* SAVESIGVEC */ sigprocmask(SIG_SETMASK, &oset, NULL); stderror(ERR_NOPROC); } forked++; if (pid) { /* parent */ # ifdef SAVESIGVEC restoresigvec(savesv, savesm); # endif /* SAVESIGVEC */ child = ochild; setintr = osetintr; haderr = ohaderr; didfds = odidfds; SHIN = oSHIN; # ifndef CLOSE_ON_EXEC didcch = odidcch; # endif /* !CLOSE_ON_EXEC */ SHOUT = oSHOUT; SHDIAG = oSHDIAG; OLDSTD = oOLDSTD; tpgrp = otpgrp; isoutatty = oisoutatty; isdiagatty = oisdiagatty; csigset = ocsigset; nosigchld = onosigchld; xfree(Vsav); Vsav = 0; xfree(Vdp); Vdp = 0; xfree(Vexpath); Vexpath = 0; blk_cleanup(Vt); Vt = 0; /* this is from pfork() */ palloc(pid, t); sigprocmask(SIG_SETMASK, &oset, NULL); } else { /* child */ /* this is from pfork() */ pid_t pgrp; int ignint = 0; if (nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if (setintr) ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) || (gointr && eq(gointr, STRminus)); pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); child++; if (setintr) { setintr = 0; /* * casts made right for SunOS 4.0 by Douglas C. Schmidt * <*****@*****.**> * (thanks! -- PWP) * * ignint ifs cleaned by Johan Widen <[email protected]> * (thanks again) */ if (ignint) { (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); } else { (void) signal(SIGINT, vffree); (void) signal(SIGQUIT, SIG_DFL); } # ifdef BSDJOBS if (wanttty >= 0) { (void) signal(SIGTSTP, SIG_DFL); (void) signal(SIGTTIN, SIG_DFL); (void) signal(SIGTTOU, SIG_DFL); } # endif /* BSDJOBS */ sigaction(SIGTERM, &parterm, NULL); } else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); } pgetty(wanttty, pgrp); if (t->t_dflg & F_NOHUP) (void) signal(SIGHUP, SIG_IGN); if (t->t_dflg & F_HUP) (void) signal(SIGHUP, SIG_DFL); if (t->t_dflg & F_NICE) { int nval = SIGN_EXTEND_CHAR(t->t_nice); # if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) stderror(ERR_SYSTEM, "setpriority", strerror(errno)); # else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */ (void) nice(nval); # endif /* HAVE_SETPRIORITY && PRIO_PROCESS */ } # ifdef F_VER if (t->t_dflg & F_VER) { tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); dohash(NULL, NULL); } # endif /* F_VER */ } } #endif /* VFORK */ } if (pid != 0) { /* * It would be better if we could wait for the whole job when we * knew the last process had been started. Pwait, in fact, does * wait for the whole job anyway, but this test doesn't really * express our intentions. */ #ifdef BACKPIPE if (didfds == 0 && t->t_dflg & F_PIPEOUT) { xclose(pipeout[0]); xclose(pipeout[1]); } if ((t->t_dflg & F_PIPEIN) != 0) break; #else /* !BACKPIPE */ if (didfds == 0 && t->t_dflg & F_PIPEIN) { xclose(pipein[0]); xclose(pipein[1]); } if ((t->t_dflg & F_PIPEOUT) != 0) break; #endif /* BACKPIPE */ if (nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if ((t->t_dflg & F_AMPERSAND) == 0) pwait(); break; } doio(t, pipein, pipeout); #ifdef BACKPIPE if (t->t_dflg & F_PIPEIN) { xclose(pipein[0]); xclose(pipein[1]); } #else /* !BACKPIPE */ if (t->t_dflg & F_PIPEOUT) { xclose(pipeout[0]); xclose(pipeout[1]); } #endif /* BACKPIPE */ /* * Perform a builtin function. If we are not forked, arrange for * possible stopping */ if (bifunc) { if (forked) { func(t, bifunc); exitstat(); } else { jmp_buf_t oldexit; int ohaderr = haderr; getexit(oldexit); if (setexit() == 0) func(t, bifunc); resexit(oldexit); haderr = ohaderr; if (adrof(STRprintexitvalue)) { int rv = getn(varval(STRstatus)); if (rv != 0) xprintf(CGETS(17, 2, "Exit %d\n"), rv); } } break; } if (t->t_dtyp != NODE_PAREN) { doexec(t, do_glob); /* NOTREACHED */ } /* * For () commands must put new 0,1,2 in FSH* and recurse */ if ((OLDSTD = dcopy(0, FOLDSTD)) >= 0) (void)close_on_exec(OLDSTD, 1); if ((SHOUT = dcopy(1, FSHOUT)) >= 0) { (void)close_on_exec(SHOUT, 1); isoutatty = isatty(SHOUT); } if ((SHDIAG = dcopy(2, FSHDIAG)) >= 0) { (void)close_on_exec(SHDIAG, 1); isdiagatty = isatty(SHDIAG); } xclose(SHIN); SHIN = -1; #ifndef CLOSE_ON_EXEC didcch = 0; #else (void) close_on_exec(FSHOUT, 1); (void) close_on_exec(FSHDIAG, 1); (void) close_on_exec(FOLDSTD, 1); #endif /* !CLOSE_ON_EXEC */ didfds = 0; wanttty = -1; t->t_dspr->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dspr, wanttty, NULL, NULL, do_glob); exitstat(); case NODE_PIPE: #ifdef BACKPIPE t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcar, wanttty, pipein, pv, do_glob); #else /* !BACKPIPE */ t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcar, wanttty, pipein, pv, do_glob); t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); #endif /* BACKPIPE */ break; case NODE_LIST: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dcar, wanttty, NULL, NULL, do_glob); /* * In strange case of A&B make a new job after A */ if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) pendjob(); } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT | F_BACKQ); execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); } break; case NODE_OR: case NODE_AND: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dcar, wanttty, NULL, NULL, do_glob); if ((getn(varval(STRstatus)) == 0) != (t->t_dtyp == NODE_AND)) { return; } } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT | F_BACKQ); execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); } break; default: break; } /* * Fall through for all breaks from switch * * If there will be no more executions of this command, flush all file * descriptors. Places that turn on the F_REPEAT bit are responsible for * doing donefds after the last re-execution */ if (didfds && !(t->t_dflg & F_REPEAT)) donefds(); }
/*ARGSUSED*/ void execash(Char **t, struct command *kp) { jmp_buf osetexit; sig_t osigint, osigquit, osigterm; int my_reenter, odidfds, oOLDSTD, oSHERR, oSHIN, oSHOUT; int saveDIAG, saveIN, saveOUT, saveSTD; if (chkstop == 0 && setintr) panystop(0); /* * Hmm, we don't really want to do that now because we might * fail, but what is the choice */ rechist(); osigint = signal(SIGINT, parintr); osigquit = signal(SIGQUIT, parintr); osigterm = signal(SIGTERM, parterm); odidfds = didfds; oSHIN = SHIN; oSHOUT = SHOUT; oSHERR = SHERR; oOLDSTD = OLDSTD; saveIN = dcopy(SHIN, -1); saveOUT = dcopy(SHOUT, -1); saveDIAG = dcopy(SHERR, -1); saveSTD = dcopy(OLDSTD, -1); lshift(kp->t_dcom, 1); getexit(osetexit); if ((my_reenter = setexit()) == 0) { SHIN = dcopy(0, -1); SHOUT = dcopy(1, -1); SHERR = dcopy(2, -1); didfds = 0; doexec(t, kp); } (void)signal(SIGINT, osigint); (void)signal(SIGQUIT, osigquit); (void)signal(SIGTERM, osigterm); doneinp = 0; didfds = odidfds; (void)close(SHIN); (void)close(SHOUT); (void)close(SHERR); (void)close(OLDSTD); SHIN = dmove(saveIN, oSHIN); SHOUT = dmove(saveOUT, oSHOUT); SHERR = dmove(saveDIAG, oSHERR); OLDSTD = dmove(saveSTD, oOLDSTD); resexit(osetexit); if (my_reenter) stderror(ERR_SILENT); }
int dobackmnt(struct cachefs_mountargs *margsp, char *reducep, char *specp, char *backfstypep, char *mynamep, int readonly) { int xx; pid_t pid; char *newargv[20]; int stat_loc; /* get a suitable mount point */ xx = get_mount_point(margsp->cfs_cachedir, specp, &margsp->cfs_backfs); if (xx) return (1); /* construct argument list for mounting the back file system */ xx = 1; newargv[xx++] = "mount"; if (readonly) newargv[xx++] = "-r"; if (nomnttab) newargv[xx++] = "-m"; if (quiet) newargv[xx++] = "-q"; if (reducep) { newargv[xx++] = "-o"; newargv[xx++] = reducep; } newargv[xx++] = specp; newargv[xx++] = margsp->cfs_backfs; newargv[xx++] = NULL; /* fork */ if ((pid = fork()) == -1) { pr_err(gettext("could not fork %s"), strerror(errno)); return (1); } /* if the child */ if (pid == 0) { /* do the mount */ doexec(backfstypep, newargv, mynamep); } /* else if the parent */ else { /* wait for the child to exit */ if (wait(&stat_loc) == -1) { pr_err(gettext("wait failed %s"), strerror(errno)); return (1); } if (!WIFEXITED(stat_loc)) { pr_err(gettext("back mount did not exit")); return (1); } xx = WEXITSTATUS(stat_loc); if (xx) { pr_err(gettext("back mount failed")); return (xx); } } return (0); }