Logo Search packages:      
Sourcecode: ksh version File versions

coopen.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1990-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * open a new coshell
 */

#include "colib.h"

#include <namval.h>
#include <proc.h>
#include <sfdisc.h>
#include <tok.h>

static const Namval_t   options[] =
{
      "cross",    CO_CROSS,
      "debug",    CO_DEBUG,
      "devfd",    CO_DEVFD,
      "ignore",   CO_IGNORE,
      "silent",   CO_SILENT,
      "service",  CO_SERVICE,
      0,          0
};

Costate_t         state = { "libcoshell:coshell" };

/*
 * called when ident sequence hung
 */

static void
hung(int sig)
{
      NoP(sig);
      close(sffileno(state.current->msgfp));
}

/*
 * close all open coshells
 */

static void
clean(void)
{
      coclose(NiL);
}

#ifdef SIGCONT

/*
 * pass job control signals to the coshell and self
 */

static void
stop(int sig)
{
      cokill(NiL, NiL, sig);
      signal(sig, SIG_DFL);
      sigunblock(sig);
      kill(getpid(), sig);
      cokill(NiL, NiL, SIGCONT);
      signal(sig, stop);
}

#endif

/*
 * called by stropt() to set options
 */

static int
setopt(register void* co, register const void* p, int n, const char* v)
{
      Coservice_t*      cs;
      char*       s;
      char**            a;

      NoP(v);
      if (p)
      {
            if (n)
            {
                  ((Coshell_t*)co)->flags |= ((Namval_t*)p)->value;
                  if (((Namval_t*)p)->value == CO_SERVICE && v && (cs = newof(0, Coservice_t, 1, 2 * strlen(v))))
                  {
                        a = cs->argv;
                        *a++ = s = cs->path = cs->name = (char*)(cs + 1);
                        while (*s = *v++)
                              if (*s++ == ':')
                              {
                                    *(s - 1) = 0;
                                    if (*v == '-')
                                    {
                                          v++;
                                          if (*v == '-')
                                                v++;
                                    }
                                    if (strneq(v, "command=", 8))
                                          cs->path = s + 8;
                                    else if (strneq(v, "state=", 6))
                                          cs->db = s + 6;
                                    else if (strneq(v, "db=", 3))
                                          cs->db = s + 3;
                                    else if (a < &cs->argv[elementsof(cs->argv)-2] && *v && *v != ':')
                                    {
                                          *a++ = s;
                                          *s++ = '-';
                                          *s++ = '-';
                                    }
                              }
                        if (cs->db)
                              *a++ = cs->db;
                        *a = 0;
                        cs->next = ((Coshell_t*)co)->service;
                        ((Coshell_t*)co)->service = cs;
                  }
            }
            else
                  ((Coshell_t*)co)->mask |= ((Namval_t*)p)->value;
      }
      return 0;
}

Coshell_t*
coopen(const char* path, int flags, const char* attributes)
{
      register Coshell_t*     co;
      register char*          s;
      register int            i;
      char*             t;
      int               n;
      Proc_t*                 proc;
      Cojob_t*          cj;
      Sfio_t*                 sp;
      Sig_handler_t           handler;
      int               pio[2];
      int               pex[2];
      long              ops[4];
      char              devfd[16];
      char*             av[8];

      static char*      sh[] = { 0, 0, "ksh", "sh", "/bin/sh" };

      if (!state.type && (!(s = getenv(CO_ENV_TYPE)) || !(state.type = strdup(s))))
            state.type = "";
      if ((flags & CO_ANY) && (co = state.coshells))
            return co;
      if (!(co = newof(0, Coshell_t, 1, 0)))
      {
            errormsg(state.lib, ERROR_LIBRARY|2, "out of space");
            return 0;
      }
      pex[0] = -1;
      pex[1] = -1;
      pio[0] = -1;
      pio[1] = -1;
      stropt(getenv(CO_ENV_OPTIONS), options, sizeof(*options), setopt, co);
      if (attributes)
            stropt(attributes, options, sizeof(*options), setopt, co);
      co->flags |= CO_INIT | ((flags | CO_DEVFD) & ~co->mask);
      if (pipe(pex) < 0 || pipe(pio) < 0)
      {
            errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot allocate pipes");
            goto bad;
      }
      co->cmdfd = pio[1];
      co->gsmfd = pex[1];
      if (!(co->msgfp = sfnew(NiL, NiL, 256, pex[0], SF_READ)))
      {
            errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot allocate message stream");
            goto bad;
      }
      sfdcslow(co->msgfp);
      sfsprintf(devfd, sizeof(devfd), "%d", co->gsmfd);
      setenv(CO_ENV_MSGFD, devfd, 1);
      ops[0] = PROC_FD_DUP(pio[0], 0, PROC_FD_PARENT);
      ops[1] = PROC_FD_CLOSE(pio[1], PROC_FD_CHILD);
      ops[2] = PROC_FD_CLOSE(pex[0], PROC_FD_CHILD);
      ops[3] = 0;
      sfsprintf(devfd, sizeof(devfd), "/dev/fd/%d", pio[0]);
      flags = !access(devfd, F_OK);
      sh[0] = (char*)path;
      sh[1] = getenv(CO_ENV_SHELL);
      for (i = 0; i < elementsof(sh); i++)
            if ((s = sh[i]) && *s && (s = strdup(s)))
            {
                  if ((n = tokscan(s, NiL, " %v ", av, elementsof(av) - 1)) > 0)
                  {
                        if (t = strrchr(s = av[0], '/'))
                              av[0] = t + 1;
                        if (flags || (co->flags & CO_DEVFD) && strmatch(s, "*ksh*"))
                              av[n++] = devfd;
                        av[n] = 0;
                        proc = procopen(s, av, NiL, ops, PROC_DAEMON|PROC_IGNORE);
                        if (proc)
                        {
                              if (!state.sh)
                                    state.sh = strdup(s);
                              free(s);
                              co->pid = proc->pid;
                              procfree(proc);
                              break;
                        }
                  }
                  free(s);
            }
      if (i >= elementsof(sh))
      {
            errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot execute");
            goto bad;
      }

      /*
       * send the shell identification sequence
       */

      if (!(sp = sfstropen()))
      {
            errormsg(state.lib, ERROR_LIBRARY|2, "out of buffer space");
            goto bad;
      }
      sfprintf(sp, "#%05d\n%s='", 0, CO_ENV_ATTRIBUTES);
      if (t = getenv(CO_ENV_ATTRIBUTES))
      {
            coquote(sp, t, 0);
            if (attributes)
                  sfprintf(sp, ",");
      }
      if (attributes)
            coquote(sp, attributes, 0);
      sfprintf(sp, "'\n");
      sfprintf(sp, coident, pex[1]);
      i = sfstrtell(sp);
      sfstrseek(sp, 0, SEEK_SET);
      sfprintf(sp, "#%05d\n", i - 7);
      i = write(co->cmdfd, sfstrbase(sp), i) != i;
      sfstrclose(sp);
      if (i)
      {
            errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "cannot write initialization message");
            goto nope;
      }
      state.current = co;
      handler = signal(SIGALRM, hung);
      i = alarm(30);
      if (!(s = sfgetr(co->msgfp, '\n', 1)))
      {
            if (errno == EINTR)
                  errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "identification message read timeout");
            goto nope;
      }
      alarm(i);
      signal(SIGALRM, handler);
      if (co->flags & CO_DEBUG)
            errormsg(state.lib, 2, "shell identification \"%s\"", s);
      switch (*s)
      {
      case 'o':
            co->flags |= CO_OSH;
            /*FALLTHROUGH*/
      case 'b':
            s = cobinit;
            break;
      case 'k':
            co->flags |= CO_KSH;
            s = cokinit;
            break;
      case 'i':   /* NOTE: 'i' is obsolete */
      case 's':
            co->flags |= CO_SERVER;
            co->pid = 0;
            for (;;)
            {
                  if (t = strchr(s, ','))
                        *t = 0;
                  if (streq(s, CO_OPT_ACK))
                        co->mode |= CO_MODE_ACK;
                  else if (streq(s, CO_OPT_INDIRECT))
                        co->mode |= CO_MODE_INDIRECT;
                  if (!(s = t))
                        break;
                  s++;
            }
            if (!(co->mode & CO_MODE_INDIRECT))
                  wait(NiL);
            break;
      default:
            goto nope;
      }
      if (s)
      {
            if (!(cj = coexec(co, s, 0, NiL, NiL, NiL)) || cowait(co, cj) != cj)
            {
                  errormsg(state.lib, ERROR_LIBRARY|ERROR_SYSTEM|2, "initialization message exec error");
                  goto nope;
            }
            co->total = 0;
            co->user = 0;
            co->sys = 0;
      }
      co->flags &= ~CO_INIT;
#ifdef SIGCONT
#ifdef SIGTSTP
      signal(SIGTSTP, stop);
#endif
#ifdef SIGTTIN
      signal(SIGTTIN, stop);
#endif
#ifdef SIGTTOU
      signal(SIGTTOU, stop);
#endif
#endif
      co->next = state.coshells;
      state.coshells = co;
      if (!state.init)
      {
            state.init = 1;
            atexit(clean);
      }
      return co;
 bad:
      i = errno;
      close(pio[0]);
      close(pio[1]);
      if (co->msgfp)
            sfclose(co->msgfp);
      else
            close(pex[0]);
      close(pex[1]);
      coclose(co);
      errno = i;
      return 0;
 nope:
      i = errno;
      if (!(s = sh[1]) || (s = (t = strrchr(s, '/')) ? (t + 1) : s) && !strmatch(s, "?(k)sh") && !streq(s, CO_ID))
            error(2, "export %s={ksh,sh,%s}", CO_ENV_SHELL, CO_ID);
      coclose(co);
      errno = i;
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index