int main(int argc, char *argv[]) {
  if (argc < 3) {
    fprintf(stderr, "usage: catgrepmore pattern infile1 [...infile2...]\n");
    exit(1);
  }
 
  pattern = argv[1];                 

  if(signal(SIGINT, inthandler) == SIG_ERR) 
    fprintf(stderr, "catgrepmore: signal: failed to catch SIGINT\n");
  if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) 
    fprintf(stderr, "catgrepmore: signal: failed to catch SIGPIPE\n");

  for(int i = 2; argv[i] != NULL; i++) {
    fprintf(stderr, "THE CURRENT INFILE IS: %s\n", argv[i]);
    int fds1[2], fds2[2];
    N_INFILES++;
    openpipe(fds1);            /* open pipe between parent and grep: fds1 */
    openpipe(fds2);            /* open pipe between grep and more: fds2 */
    catgrepmore(argv[i], fds1, fds2);
  }
 
  return 0;
}
/*
 * execute command tree
 */
int
execute(struct op * volatile t,
    /* if XEXEC don't fork */
    volatile int flags,
    volatile int * volatile xerrok)
{
	int i;
	volatile int rv = 0, dummy = 0;
	int pv[2];
	const char ** volatile ap = NULL;
	char ** volatile up;
	const char *s, *ccp;
	struct ioword **iowp;
	struct tbl *tp = NULL;
	char *cp;

	if (t == NULL)
		return (0);

	/* Caller doesn't care if XERROK should propagate. */
	if (xerrok == NULL)
		xerrok = &dummy;

	if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
		/* run in sub-process */
		return (exchild(t, flags & ~XTIME, xerrok, -1));

	newenv(E_EXEC);
	if (trap)
		runtraps(0);

	/* we want to run an executable, do some variance checks */
	if (t->type == TCOM) {
		/* check if this is 'var=<<EOF' */
		if (
		    /* we have zero arguments, i.e. no programme to run */
		    t->args[0] == NULL &&
		    /* we have exactly one variable assignment */
		    t->vars[0] != NULL && t->vars[1] == NULL &&
		    /* we have exactly one I/O redirection */
		    t->ioact != NULL && t->ioact[0] != NULL &&
		    t->ioact[1] == NULL &&
		    /* of type "here document" (or "here string") */
		    (t->ioact[0]->flag & IOTYPE) == IOHERE &&
		    /* the variable assignment begins with a valid varname */
		    (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
		    /* and has no right-hand side (i.e. "varname=") */
		    ccp[0] == CHAR && ccp[1] == '=' && ccp[2] == EOS &&
		    /* plus we can have a here document content */
		    herein(t->ioact[0], &cp) == 0 && cp && *cp) {
			char *sp = cp, *dp;
			size_t n = ccp - t->vars[0] + 2, z;

			/* drop redirection (will be garbage collected) */
			t->ioact = NULL;

			/* set variable to its expanded value */
			z = strlen(cp) + 1;
			if (notoktomul(z, 2) || notoktoadd(z * 2, n))
				internal_errorf(Toomem, (unsigned long)-1);
			dp = alloc(z * 2 + n, ATEMP);
			memcpy(dp, t->vars[0], n);
			t->vars[0] = dp;
			dp += n;
			while (*sp) {
				*dp++ = QCHAR;
				*dp++ = *sp++;
			}
			*dp = EOS;
			/* free the expanded value */
			afree(cp, APERM);
		}

		/*
		 * Clear subst_exstat before argument expansion. Used by
		 * null commands (see comexec() and c_eval()) and by c_set().
		 */
		subst_exstat = 0;

		/* for $LINENO */
		current_lineno = t->lineno;

		/*
		 * POSIX says expand command words first, then redirections,
		 * and assignments last..
		 */
		up = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
		if (flags & XTIME)
			/* Allow option parsing (bizarre, but POSIX) */
			timex_hook(t, &up);
		ap = (const char **)up;
		if (Flag(FXTRACE) && ap[0]) {
			shf_puts(substitute(str_val(global("PS4")), 0),
			    shl_out);
			for (i = 0; ap[i]; i++)
				shf_fprintf(shl_out, "%s%c", ap[i],
				    ap[i + 1] ? ' ' : '\n');
			shf_flush(shl_out);
		}
		if (ap[0])
			tp = findcom(ap[0], FC_BI|FC_FUNC);
	}
	flags &= ~XTIME;

	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
		e->savefd = alloc2(NUFILE, sizeof(short), ATEMP);
		/* initialise to not redirected */
		memset(e->savefd, 0, NUFILE * sizeof(short));
	}

	/* mark for replacement later (unless TPIPE) */
	vp_pipest->flag |= INT_L;

	/* do redirection, to be restored in quitenv() */
	if (t->ioact != NULL)
		for (iowp = t->ioact; *iowp != NULL; iowp++) {
			if (iosetup(*iowp, tp) < 0) {
				exstat = rv = 1;
				/*
				 * Redirection failures for special commands
				 * cause (non-interactive) shell to exit.
				 */
				if (tp && tp->type == CSHELL &&
				    (tp->flag & SPEC_BI))
					errorfz();
				/* Deal with FERREXIT, quitenv(), etc. */
				goto Break;
			}
		}

	switch (t->type) {
	case TCOM:
		rv = comexec(t, tp, (const char **)ap, flags, xerrok);
		break;

	case TPAREN:
		rv = execute(t->left, flags | XFORK, xerrok);
		break;

	case TPIPE:
		flags |= XFORK;
		flags &= ~XEXEC;
		e->savefd[0] = savefd(0);
		e->savefd[1] = savefd(1);
		while (t->type == TPIPE) {
			openpipe(pv);
			/* stdout of curr */
			ksh_dup2(pv[1], 1, false);
			/**
			 * Let exchild() close pv[0] in child
			 * (if this isn't done, commands like
			 *	(: ; cat /etc/termcap) | sleep 1
			 * will hang forever).
			 */
			exchild(t->left, flags | XPIPEO | XCCLOSE,
			    NULL, pv[0]);
			/* stdin of next */
			ksh_dup2(pv[0], 0, false);
			closepipe(pv);
			flags |= XPIPEI;
			t = t->right;
		}
		/* stdout of last */
		restfd(1, e->savefd[1]);
		/* no need to re-restore this */
		e->savefd[1] = 0;
		/* Let exchild() close 0 in parent, after fork, before wait */
		i = exchild(t, flags | XPCLOSE | XPIPEST, xerrok, 0);
		if (!(flags&XBGND) && !(flags&XXCOM))
			rv = i;
		break;

	case TLIST:
		while (t->type == TLIST) {
			execute(t->left, flags & XERROK, NULL);
			t = t->right;
		}
		rv = execute(t, flags & XERROK, xerrok);
		break;

	case TCOPROC: {
#ifndef MKSH_NOPROSPECTOFWORK
		sigset_t omask;

		/*
		 * Block sigchild as we are using things changed in the
		 * signal handler
		 */
		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
		e->type = E_ERRH;
		if ((i = kshsetjmp(e->jbuf))) {
			sigprocmask(SIG_SETMASK, &omask, NULL);
			quitenv(NULL);
			unwind(i);
			/* NOTREACHED */
		}
#endif
		/* Already have a (live) co-process? */
		if (coproc.job && coproc.write >= 0)
			errorf("coprocess already exists");

		/* Can we re-use the existing co-process pipe? */
		coproc_cleanup(true);

		/* do this before opening pipes, in case these fail */
		e->savefd[0] = savefd(0);
		e->savefd[1] = savefd(1);

		openpipe(pv);
		if (pv[0] != 0) {
			ksh_dup2(pv[0], 0, false);
			close(pv[0]);
		}
		coproc.write = pv[1];
		coproc.job = NULL;

		if (coproc.readw >= 0)
			ksh_dup2(coproc.readw, 1, false);
		else {
			openpipe(pv);
			coproc.read = pv[0];
			ksh_dup2(pv[1], 1, false);
			/* closed before first read */
			coproc.readw = pv[1];
			coproc.njobs = 0;
			/* create new coprocess id */
			++coproc.id;
		}
#ifndef MKSH_NOPROSPECTOFWORK
		sigprocmask(SIG_SETMASK, &omask, NULL);
		/* no more need for error handler */
		e->type = E_EXEC;
#endif

		/*
		 * exchild() closes coproc.* in child after fork,
		 * will also increment coproc.njobs when the
		 * job is actually created.
		 */
		flags &= ~XEXEC;
		exchild(t->left, flags | XBGND | XFORK | XCOPROC | XCCLOSE,
		    NULL, coproc.readw);
		break;
	}

	case TASYNC:
		/*
		 * XXX non-optimal, I think - "(foo &)", forks for (),
		 * forks again for async... parent should optimise
		 * this to "foo &"...
		 */
		rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
		break;

	case TOR:
	case TAND:
		rv = execute(t->left, XERROK, xerrok);
		if ((rv == 0) == (t->type == TAND))
			rv = execute(t->right, XERROK, xerrok);
		flags |= XERROK;
		if (xerrok)
			*xerrok = 1;
		break;

	case TBANG:
		rv = !execute(t->right, XERROK, xerrok);
		flags |= XERROK;
		if (xerrok)
			*xerrok = 1;
		break;

	case TDBRACKET: {
		Test_env te;

		te.flags = TEF_DBRACKET;
		te.pos.wp = t->args;
		te.isa = dbteste_isa;
		te.getopnd = dbteste_getopnd;
		te.eval = test_eval;
		te.error = dbteste_error;

		rv = test_parse(&te);
		break;
	}

	case TFOR:
	case TSELECT: {
		volatile bool is_first = true;
		ap = (t->vars == NULL) ? e->loc->argv + 1 :
		    (const char **)eval((const char **)t->vars,
		    DOBLANK | DOGLOB | DOTILDE);
		e->type = E_LOOP;
		while ((i = kshsetjmp(e->jbuf))) {
			if ((e->flags&EF_BRKCONT_PASS) ||
			    (i != LBREAK && i != LCONTIN)) {
				quitenv(NULL);
				unwind(i);
			} else if (i == LBREAK) {
				rv = 0;
				goto Break;
			}
		}
		/* in case of a continue */
		rv = 0;
		if (t->type == TFOR) {
			while (*ap != NULL) {
				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
				rv = execute(t->left, flags & XERROK, xerrok);
			}
		} else {
			/* TSELECT */
			for (;;) {
				if (!(ccp = do_selectargs(ap, is_first))) {
					rv = 1;
					break;
				}
				is_first = false;
				setstr(global(t->str), ccp, KSH_UNWIND_ERROR);
				execute(t->left, flags & XERROK, xerrok);
			}
		}
		break;
	}

	case TWHILE:
	case TUNTIL:
		e->type = E_LOOP;
		while ((i = kshsetjmp(e->jbuf))) {
			if ((e->flags&EF_BRKCONT_PASS) ||
			    (i != LBREAK && i != LCONTIN)) {
				quitenv(NULL);
				unwind(i);
			} else if (i == LBREAK) {
				rv = 0;
				goto Break;
			}
		}
		/* in case of a continue */
		rv = 0;
		while ((execute(t->left, XERROK, NULL) == 0) ==
		    (t->type == TWHILE))
			rv = execute(t->right, flags & XERROK, xerrok);
		break;

	case TIF:
	case TELIF:
		if (t->right == NULL)
			/* should be error */
			break;
		rv = execute(t->left, XERROK, NULL) == 0 ?
		    execute(t->right->left, flags & XERROK, xerrok) :
		    execute(t->right->right, flags & XERROK, xerrok);
		break;

	case TCASE:
		i = 0;
		ccp = evalstr(t->str, DOTILDE);
		for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
			for (ap = (const char **)t->vars; *ap; ap++) {
				if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
				    gmatchx(ccp, s, false))) {
					rv = execute(t->left, flags & XERROK,
					    xerrok);
					i = 0;
					switch (t->u.charflag) {
					case '&':
						i = 1;
						/* FALLTHROUGH */
					case '|':
						goto TCASE_next;
					}
					goto TCASE_out;
				}
			}
			i = 0;
 TCASE_next:
			/* empty */;
		}
 TCASE_out:
		break;

	case TBRACE:
		rv = execute(t->left, flags & XERROK, xerrok);
		break;

	case TFUNCT:
		rv = define(t->str, t);
		break;

	case TTIME:
		/*
		 * Clear XEXEC so nested execute() call doesn't exit
		 * (allows "ls -l | time grep foo").
		 */
		rv = timex(t, flags & ~XEXEC, xerrok);
		break;

	case TEXEC:
		/* an eval'd TCOM */
		s = t->args[0];
		up = makenv();
		restoresigs();
		cleanup_proc_env();
		{
			union mksh_ccphack cargs;

			cargs.ro = t->args;
			execve(t->str, cargs.rw, up);
			rv = errno;
		}
		if (rv == ENOEXEC)
			scriptexec(t, (const char **)up);
		else
			errorf("%s: %s", s, cstrerror(rv));
	}
 Break:
	exstat = rv & 0xFF;
	if (vp_pipest->flag & INT_L) {
		unset(vp_pipest, 1);
		vp_pipest->flag = DEFINED | ISSET | INTEGER | RDONLY |
		    ARRAY | INT_U;
		vp_pipest->val.i = rv;
	}

	/* restores IO */
	quitenv(NULL);
	if ((flags&XEXEC))
		/* exit child */
		unwind(LEXIT);
	if (rv != 0 && !(flags & XERROK) &&
	    (xerrok == NULL || !*xerrok)) {
		if (Flag(FERREXIT) & 0x80) {
			/* inside eval */
			Flag(FERREXIT) = 0;
		} else {
			trapsig(ksh_SIGERR);
			if (Flag(FERREXIT))
				unwind(LERROR);
		}
	}
	return (rv);
}
Exemple #3
0
int playback(FILE * streamfd, int pipefd) {
	killed = 0;
	signal(SIGUSR1, sighand);

#ifndef EXTERN_ONLY
	if(!haskey(& rc, "extern")) {
		const char * freetrack = NULL;

		struct stream data;
		struct mad_decoder dec;

#ifdef LIBAO
		static int ao_initialized = 0;

		if(!ao_initialized) {
			ao_initialize();
			ao_initialized = !0;
		}
#else
		unsigned arg;
		int fd;
#endif

		memset(& data, 0, sizeof(struct stream));

		/*
			Check if there's a stream timeout configured and set it up for timed
			reads later.
		*/
		data.timeout = -1;
		if(haskey(& rc, "stream-timeout")) {
			const char * timeout = value(& rc, "stream-timeout");
			data.timeout = atoi(timeout);

			if(data.timeout <= 0) {
				if(data.timeout < 0) 
					fputs("Invalid stream-timeout.\n", stderr);

				data.timeout = -1;
			}
		}


		data.streamfd = streamfd;
		data.parent = getppid();
		data.pipefd = pipefd;
		fcntl(pipefd, F_SETFL, O_NONBLOCK);

#ifdef LIBAO
		data.driver_id = ao_default_driver_id();

		if(-1 == data.driver_id) {
			fputs("Unable to find any usable output device!\n", stderr);
			return 0;
		}

		data.fmt.bits = 16;
		data.fmt.rate = 44100;
		data.fmt.channels = 2;
		data.fmt.byte_format = AO_FMT_NATIVE;
		data.device = ao_open_live(data.driver_id,&data.fmt,NULL);

		if(NULL == data.device) {
			fprintf(stderr, "Unable to open device. %s.\n", strerror(errno));
			return 0;
		}
#else
		data.audiofd = fd = open(value(& rc, "device"), O_WRONLY);

		if(-1 == data.audiofd) {
			fprintf(
					stderr, "Couldn't open %s! %s.\n",
					value(& rc, "device"), strerror(errno)
			);
			return 0;
		}

		arg = 16; /* 16 bits */
		ioctl(data.audiofd, SOUND_PCM_WRITE_BITS, & arg);
#endif

		freetrack = value(& track, "freeTrackURL");

		if(freetrack && strlen(freetrack) > 0 && haskey(& rc, "download")) {
			char * dnam;
			int rv;

			data.finpath = strdup(meta(value(& rc, "download"), M_RELAXPATH, & track));
			assert(data.finpath != NULL);

			data.tmppath = strjoin("", data.finpath, ".streaming", NULL);
			assert(data.tmppath != NULL);

			dnam = strdup(data.tmppath);
			rv = dnam ? mkpath(dirname(dnam)) : -1;
			free(dnam);

			if(access(data.tmppath, R_OK) == -1) {
				data.dump = (rv == 0) ? fopen(data.tmppath, "w") : NULL;

				if(!data.dump)
					fprintf(stderr, "Can't write download to %s.\n", data.tmppath);
			}
			else {
				data.dump = NULL;
			}
		}

		mad_decoder_init(& dec, & data, input, NULL, NULL, output, NULL, NULL);
		mad_decoder_run(& dec, MAD_DECODER_MODE_SYNC);
#ifndef LIBAO
		close(fd);
#endif
		mad_decoder_finish(& dec);

		if(data.dump) {
			fclose(data.dump);

			if(killed) {
				unlink(data.tmppath);
			} else {
				int rv;
#ifdef TAGLIB
				TagLib_File *tagme = taglib_file_new(data.tmppath);
				if(tagme != NULL) {
					TagLib_Tag *tag = taglib_file_tag(tagme);
					taglib_tag_set_title(tag, value(&track, "title"));
					taglib_tag_set_artist(tag, value(&track, "creator"));
					taglib_tag_set_album(tag, value(&track, "album"));
					taglib_file_save(tagme);
					taglib_file_free(tagme);
				}
#endif
				if(haskey(& rc, "pp-cmd")) {
					const char *ppcmd = value(& rc, "pp-cmd");
					size_t ppcmdlen = strlen(ppcmd);
					char *path = shellescape(data.tmppath);
					assert(path != NULL);
					size_t pathlen = strlen(path);
					char *command = malloc(ppcmdlen + pathlen + 2);
					assert(command != NULL);
					memcpy(command, ppcmd, ppcmdlen);
					command[ppcmdlen] = ' ';
					memcpy(command + ppcmdlen + 1, path, pathlen);
					command[ppcmdlen + 1 + pathlen] = 0;
					run(command);
					free(path);
					free(command);
				}

				rv = rename(data.tmppath, data.finpath);
				if (rv == -1)
					fprintf(stderr, "Can't rename %s to %s\n",
							data.tmppath, data.finpath);
			}

			free(data.tmppath);
			free(data.finpath);
		}
	}
	else
#endif
	{
		pid_t ppid = getppid(), cpid = 0;
		const char * cmd = meta(value(& rc, "extern"), M_SHELLESC, & track);
		FILE * ext = openpipe(cmd, & cpid);
		unsigned char * buf;

		if(!ext) {
			fprintf(stderr, "Failed to execute external player (%s). %s.\n",
					cmd, strerror(errno));
			return 0;
		}

		if(!(buf = calloc(BUFSIZE + 1, sizeof(unsigned char)))) {
			fputs("Couldn't allocate enough memory for input buffer.\n", stderr);
			fclose(ext);
			return 0;
		}

		while(!feof(streamfd)) {
			signed nbyte = fread(buf, sizeof(unsigned char), BUFSIZE, streamfd);

			if(nbyte > 0) {
				fwrite(buf, sizeof(unsigned char), nbyte, ext);
				fflush(ext);
			}

			if(kill(ppid, 0) == -1 && errno == ESRCH)
				break;

			if(killed)
				break;
		}

		free(buf);
		fclose(ext);

		waitpid(cpid, NULL, 0);
	}

	return !0;
}