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); }
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; }