Beispiel #1
0
static Char *
dgoto(Char *cp)
{
    Char *dp, *ret;

    if (!ABSOLUTEP(cp))
    {
	Char *p, *q;
	size_t cwdlen;

	cwdlen = Strlen(dcwd->di_name);
	if (cwdlen == 1)	/* root */
	    cwdlen = 0;
	dp = xmalloc((cwdlen + Strlen(cp) + 2) * sizeof(Char));
	for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
	    continue;
	if (cwdlen)
	    p[-1] = '/';
	else
	    p--;		/* don't add a / after root */
	Strcpy(p, cp);
	xfree(cp);
	cp = dp;
	dp += cwdlen;
    }
    else
	dp = cp;

#if defined(WINNT_NATIVE)
    return agetcwd();
#elif defined(__CYGWIN__)
    if (ABSOLUTEP(cp) && cp[1] == ':') { /* Only DOS paths are treated that way */
	return agetcwd();
    } else {
	cleanup_push(cp, xfree);
    	ret = dcanon(cp, dp);
	cleanup_ignore(cp);
	cleanup_until(cp);
    }
#else /* !WINNT_NATIVE */
    cleanup_push(cp, xfree);
    ret = dcanon(cp, dp);
    cleanup_ignore(cp);
    cleanup_until(cp);
#endif /* WINNT_NATIVE */
    return ret;
}
Beispiel #2
0
/*
 * Get HOME directory.
 */
astr get_home_dir(void)
{
  char *s = getenv("HOME");
  astr as;
  if (s != NULL && strlen(s) < PATH_MAX)
    as = astr_new_cstr(s);
  else
    as = agetcwd();
  return as;
}
Beispiel #3
0
int
main(int argc, char *argv[])
{
	char *cwd, c;
	char mode = 'L';

	while((c = getopt(argc, argv, "LP")) != -1)
		switch(c) {
		case 'L':
		case 'P':
			mode = c;
			break;
		default:
			exit(EXIT_FAILURE);
		}
	cwd = agetcwd();
	puts((mode == 'L') ? getpwd(cwd) : cwd);
	return EXIT_SUCCESS;
}
Beispiel #4
0
/*
 * Return the current directory.
 */
static astr get_current_dir(void)
{
  astr buf;
  int p;

  if (cur_bp->filename != NULL)
    /* If the current buffer has a filename, get the current directory
       name from it. */
    buf = astr_new_cstr(cur_bp->filename);
  else { /* Get the current directory name from the system. */
    buf = agetcwd();
    if (astr_len(buf) != 0 && *astr_char(buf, -1) != '/')
      astr_cat_char(buf, '/');
  }

  p = astr_rfind_cstr(buf, "/");
  astr_truncate(buf, p + 1);

  return buf;
}
Beispiel #5
0
Datei: file.c Projekt: M1lan/zile
/*
 * This functions does some corrections and expansions to
 * the passed path:
 *
 * - expands `~/' and `~name/' expressions;
 * - replaces `//' with `/' (restarting from the root directory);
 * - removes `..' and `.' entries.
 *
 * The return value indicates success or failure.
 */
bool
expand_path (astr path)
{
  int ok = true;
  const char *sp = astr_cstr (path);
  astr epath = astr_new ();

  if (*sp != '/' && *sp != '~')
    {
      astr_cat (epath, agetcwd ());
      if (astr_len (epath) == 0 ||
          astr_get (epath, astr_len (epath) - 1) != '/')
        astr_cat_char (epath, '/');
    }

  for (const char *p = sp; *p != '\0';)
    {
      if (*p == '/')
        {
          if (*++p == '/')
            { /* Got `//'.  Restart from this point. */
              while (*p == '/')
                p++;
              astr_truncate (epath, 0);
            }
          if (astr_len (epath) == 0 ||
              astr_get (epath, astr_len (epath) - 1) != '/')
            astr_cat_char (epath, '/');
        }
      else if (*p == '~' && (p == sp || p[-1] == '/'))
        { /* Got `/~' or leading `~'.  Restart from this point. */
          struct passwd *pw;

          astr_truncate (epath, 0);
          ++p;

          if (*p == '/')
            { /* Got `~/'.  Insert the user's home directory. */
              pw = getpwuid (getuid ());
              if (pw == NULL)
                {
                  ok = false;
                  break;
                }
              if (!STREQ (pw->pw_dir, "/"))
                astr_cat_cstr (epath, pw->pw_dir);
            }
          else
            { /* Got `~something'.  Insert that user's home directory. */
              astr as = astr_new ();
              while (*p != '\0' && *p != '/')
                astr_cat_char (as, *p++);
              pw = getpwnam (astr_cstr (as));
              if (pw == NULL)
                {
                  ok = false;
                  break;
                }
              astr_cat_cstr (epath, pw->pw_dir);
            }
        }
      else if (*p == '.' && (p[1] == '/' || p[1] == '\0'))
        { /* Got `.'. */
          ++p;
        }
      else if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0'))
        { /* Got `..'. */
          if (astr_len (epath) >= 1 && astr_get (epath, astr_len (epath) - 1) == '/')
            astr_truncate (epath, astr_len (epath) - 1);
          while (astr_get (epath, astr_len (epath) - 1) != '/' && astr_len (epath) >= 1)
            astr_truncate (epath, astr_len (epath) - 1);
          p += 2;
        }

      if (*p != '~')
        while (*p != '\0' && *p != '/')
          astr_cat_char (epath, *p++);
    }

  astr_cpy (path, epath);

  return ok;
}
Beispiel #6
0
int main(int argc, char *argv[])
{
    if (argc < 1) {
        dprintf(STDERR_FILENO, "wrun called without argument\n");
        terminate_nocore();
    }
    shift(&argc, &argv);
    if (argc > 1 && !strcmp(argv[0], "--tool_name")) {
        shift(&argc, &argv);
        tool_name = shift(&argc, &argv);
    }

    fill_std_fd_info_identity(STDIN_FILENO);
    fill_std_fd_info_identity(STDOUT_FILENO);
    fill_std_fd_info_identity(STDERR_FILENO);

    bool force_redirects = false;
    bool silent_breakaway = false;

    int port;
    bool terminate = !get_outbash_infos(&port, &force_redirects);

    struct string outbash_command = string_create("");

    if (argc && !strcmp(argv[0], ":")) {
        shift(&argc, &argv);
        string_append(&outbash_command, "cd:~\n");
    } else {
        char* cwd = agetcwd();
        if (is_absolute_drive_fs_path(cwd)) {
            char* cwd_win32 = convert_drive_fs_path_to_win32(cwd);
            string_append(&outbash_command, "cd:");
            string_append(&outbash_command, cwd_win32);
            string_append(&outbash_command, "\n");
            free(cwd_win32);
        }
        free(cwd);
    }

    while (argc && !strncmp(argv[0], "--", 2)) {

        if (!strcmp(argv[0], "--")) {
            shift(&argc, &argv);
            break;
        }

        if (!strcmp(argv[0], "--env")) {
            shift(&argc, &argv);
            while (argc && strncmp(argv[0], "--", 2) != 0
                        && *argv[0] != '\0' && strchr(argv[0] + 1, '=')) {
                string_append(&outbash_command, "env:");
                string_append(&outbash_command, argv[0]);
                string_append(&outbash_command, "\n");
                shift(&argc, &argv);
            }
        } else if (!strcmp(argv[0], "--force-redirects")) {
            force_redirects = true;
            shift(&argc, &argv);
        } else if (!strcmp(argv[0], "--silent-breakaway")) {
            silent_breakaway = true;
            shift(&argc, &argv);
        } else if (!strcmp(argv[0], "--help")) {
            print_help();
            exit(1);
        } else {
            dprintf(STDERR_FILENO, "%s: unknown command line option: %s\n", tool_name, argv[0]);
            dprintf(STDERR_FILENO, "type %s --help for more information.\n", tool_name);
            terminate_nocore();
        }
    }
    if (terminate)
        terminate_nocore();
    check_argc(argc);

    decide_will_redirect(STDIN_FILENO,  force_redirects);
    decide_will_redirect(STDOUT_FILENO, force_redirects);
    decide_will_redirect(STDERR_FILENO, force_redirects);

    int sock_ctrl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock_ctrl < 0) {
        dprintf(STDERR_FILENO, "%s: socket() failed: %s\n", tool_name, my_strerror(errno));
        terminate_nocore();
    }

#define STDIN_NEEDS_SOCKET_REDIRECT     1
#define STDOUT_NEEDS_SOCKET_REDIRECT    2
#define STDERR_NEEDS_SOCKET_REDIRECT    4
#define STDERR_SOCKREDIR_TO_STDOUT      8
    int redirects =   (needs_socket_redirect(STDIN_FILENO)  ? STDIN_NEEDS_SOCKET_REDIRECT  : 0)
                    | (needs_socket_redirect(STDOUT_FILENO) ? STDOUT_NEEDS_SOCKET_REDIRECT : 0);
    if (needs_socket_redirect(STDERR_FILENO)) {
        if ((redirects & STDOUT_NEEDS_SOCKET_REDIRECT) && are_stdfd_to_same_thing(STDOUT_FILENO, STDERR_FILENO))
            redirects |= STDERR_SOCKREDIR_TO_STDOUT;
        else
            redirects |= STDERR_NEEDS_SOCKET_REDIRECT;
    }

    struct listening_socket lsock_in = NO_LISTENING_SOCKET;
    struct listening_socket lsock_out = NO_LISTENING_SOCKET;
    struct listening_socket lsock_err = NO_LISTENING_SOCKET;
    if (redirects & STDIN_NEEDS_SOCKET_REDIRECT) lsock_in = socket_listen_one_loopback();
    if (redirects & STDOUT_NEEDS_SOCKET_REDIRECT) lsock_out = socket_listen_one_loopback();
    if (redirects & STDERR_NEEDS_SOCKET_REDIRECT) lsock_err = socket_listen_one_loopback();
    ask_redirect(&outbash_command, "stdin:", STDIN_FILENO, lsock_in.port);
    ask_redirect(&outbash_command, "stdout:", STDOUT_FILENO, lsock_out.port);
    ask_redirect(&outbash_command, "stderr:", STDERR_FILENO,
                 (redirects & STDERR_NEEDS_SOCKET_REDIRECT) ? lsock_err.port : lsock_out.port);

    if (silent_breakaway)
        string_append(&outbash_command, "silent_breakaway:1\n");

    char* win32_module;
    if (is_absolute_drive_fs_path(argv[0])) {
        win32_module = convert_drive_fs_path_to_win32(argv[0]);
        string_append(&outbash_command, "module:");
        string_append(&outbash_command, win32_module);
        string_append(&outbash_command, "\n");
    } else {
        win32_module = convert_slash_to_backslash(argv[0]);
    }

    const bool module_need_quotes = (NULL != strpbrk(win32_module, " \t"));
    string_append(&outbash_command, "run:");
    if (module_need_quotes)
        string_append(&outbash_command, "\"");
    string_append(&outbash_command, win32_module);
    if (module_need_quotes)
        string_append(&outbash_command, "\"");

    free(win32_module);

    for (int i = 1; i < argc; i++) {
        string_append(&outbash_command, " ");
        string_append(&outbash_command, argv[i]);
    }
    string_append(&outbash_command, "\n\n");
    //dprintf(STDOUT_FILENO, "%s", outbash_command.str);
    //return EXIT_FAILURE;

    signal(SIGPIPE, SIG_IGN);

    sigset_t signal_set, orig_mask;

    //////////////////////////// unblock SIGUSR1
    sigemptyset(&signal_set);
    sigaddset(&signal_set, SIGUSR1);
    pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);

    //////////////////////////// block SIGTSTP
    sigemptyset(&signal_set);
    sigaddset(&signal_set, SIGTSTP);
    pthread_sigmask(SIG_BLOCK, &signal_set, &orig_mask);

    //////////////////////////// install custom SIGTSTP handler if signal was not ignored
    struct sigaction sa;
    sigaction(SIGTSTP, NULL, &sa);
    const bool ignore_sigtstp = (sa.sa_handler == SIG_IGN);
    if (!ignore_sigtstp) {
        sa.sa_handler = tstop_handler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction(SIGTSTP, &sa, NULL);
    }

    //////////////////////////// install custom SIGUSR1 handler to wake-up blocked IO forwarding threads
    // NOTE: the handler itself do nothing, but any blocked syscall will return with EINTR error
    sa.sa_handler = noop_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);

    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    serv_addr.sin_port = htons(port);
    if (connect(sock_ctrl, (const struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        // NOTE: I'm not sure that WSL does what Linux does concerning
        // http://www.madore.org/~david/computers/connect-intr.html
        // for now we do not expect to recover after an interruption here.
        dprintf(STDERR_FILENO, "%s: connect() failed: %s\n", tool_name, my_strerror(errno));
        terminate_nocore();
    }

    if (send_all(sock_ctrl, outbash_command.str, outbash_command.length, 0) < 0) {
        dprintf(STDERR_FILENO, "%s: send_all() failed: %s\n", tool_name, my_strerror(errno));
        terminate_nocore();
    }
    string_destroy(&outbash_command);

    static struct forward_state fs[3];
    fs_init_accept_as_needed(&fs[STDIN_FILENO],  &lsock_in,  redirects & STDIN_NEEDS_SOCKET_REDIRECT,  STDIN_FILENO,  "stdin");
    fs_init_accept_as_needed(&fs[STDOUT_FILENO], &lsock_out, redirects & STDOUT_NEEDS_SOCKET_REDIRECT, STDOUT_FILENO, "stdout");
    fs_init_accept_as_needed(&fs[STDERR_FILENO], &lsock_err, redirects & STDERR_NEEDS_SOCKET_REDIRECT, STDERR_FILENO, "stderr");

    char *line = ctrl_readln(sock_ctrl, NULL);
    if (!line || strcmp(line, "connected")) {
        dprintf(STDERR_FILENO, "%s: did not receive connection validation from outbash.exe\n", tool_name);
        terminate_nocore();
    }

    close_listener(&lsock_in);
    close_listener(&lsock_out);
    close_listener(&lsock_err);

    enum state_e state = RUNNING;
    int program_return_code = 255;

    pthread_t   forward_threads[3];
    bool        active_threads[3] = {0};

    for (int i = 0; i < 3; i++) {
        if ((!fs[i].dead_in) || (!fs[i].dead_out)) {
            int err = pthread_create(&forward_threads[i], NULL, forward_one_stream, &fs[i]);
            if (err != 0) {
                dprintf(STDERR_FILENO, "%s: pthread_create() failed: %s\n", tool_name, my_strerror(err));
                terminate_nocore();
            }
            active_threads[i] = true;
        }
    }

    int nfds = sock_ctrl + 1;

    while (state != TERMINATED) {
        fd_set rfds;
        FD_ZERO(&rfds);
        if (sock_ctrl < 0 || sock_ctrl >= FD_SETSIZE) {
            dprintf(STDERR_FILENO, "%s: sock_ctrl=%d out of range\n", tool_name, sock_ctrl);
            abort();
        }
        FD_SET(sock_ctrl, &rfds);

        int pselect_res = pselect(nfds, &rfds, NULL, NULL, NULL, &orig_mask); // tstop_handler can run here
        int pselect_errno = errno;

        if (tstop_req && state == RUNNING) {
            int r = send_all(sock_ctrl, "suspend\n", strlen("suspend\n"), 0);
            if (r < 0 && err_is_connection_broken(errno)) {
                // We will never be able to ask outbash to suspend the
                // Windows process, the expected reason is that it actually
                // has already terminated and we don't know yet about that,
                // so stop the suspend forwarding mechanism and suspend
                // ourselves immediately.
                shutdown(sock_ctrl, SHUT_WR); // also we can't send anything anymore // XXX to comment for WSL bug workaround? proba low here...
                signal(SIGTSTP, SIG_DFL);
                state = DYING;
                raise(SIGTSTP);
                pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
            } else if (r < 0) { // other errors
                dprintf(STDERR_FILENO, "%s: send_all(\"suspend\\n\") failed: %s\n", tool_name, my_strerror(errno));
                abort();
            } else { // OK
                // It's up to outbash now, just wait for its "suspend_ok"
                // answer after it has suspended the Windows process.
                state = SUSPEND_PENDING;
            }
        }

        if (pselect_res < 0 && pselect_errno == EINTR) {
            // "On error, -1 is returned, and errno is set appropriately;
            //  the sets and timeout become undefined, so do not rely on
            //  their contents after an error."
            continue;
        }

        if (pselect_res < 0) {
            dprintf(STDERR_FILENO, "%s: pselect() failed: %s\n", tool_name, my_strerror(pselect_errno));
            abort();
        }

        if (FD_ISSET(sock_ctrl, &rfds)) {
            while (1) {
                int nonblock_marker;
                line = ctrl_readln(sock_ctrl, &nonblock_marker);
                if (!line && nonblock_marker) break;
                if (line && !strcmp(line, "suspend_ok")) {
                    if (state == SUSPEND_PENDING) {
                        signal(SIGTSTP, SIG_DFL);
                        raise(SIGTSTP);
                        sigset_t previous_mask;
                        pthread_sigmask(SIG_SETMASK, &orig_mask, &previous_mask);
                            // >>> Process will Stop here, until SIGCONT <<<
                        pthread_sigmask(SIG_SETMASK, &previous_mask, NULL);
                        tstop_req = 0;
                        int r = send_all(sock_ctrl, "resume\n", strlen("resume\n"), 0);
                        if (r < 0 && err_is_connection_broken(errno)) {
                            // killed when suspended (if this is possible?)
                            // or maybe just before an attempt?
                            shutdown(sock_ctrl, SHUT_WR); // XXX to comment for WSL bug workaround? proba low here...
                            state = DYING;
                            pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
                        } else if (r < 0) {
                            dprintf(STDERR_FILENO, "%s: send_all(\"resume\\n\") failed: %s\n", tool_name, my_strerror(errno));
                            abort();
                        } else {
                            state = RUNNING;
                            sa.sa_handler = tstop_handler;
                            sigemptyset(&sa.sa_mask);
                            sa.sa_flags = 0;
                            sigaction(SIGTSTP, &sa, NULL);
                        }
                    } else {
                        dprintf(STDERR_FILENO, "%s: spurious \"suspend_ok\" received\n", tool_name);
                    }
                } else { // not "suspend_ok" => for now only other cases are exit conditions
                    program_return_code = get_return_code(line);
                    shutdown(sock_ctrl, SHUT_RDWR);
                    signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
                    if ((tstop_req && state == RUNNING) || state == SUSPEND_PENDING) {
                        // We expect to stop soon, but not without flushing the OS TCP
                        // buffers and our owns, and other WSL processes in a pipe might
                        // already be suspended, so we better honor suspend requests ASAP.
                        raise(SIGTSTP);
                    }
                    pthread_sigmask(SIG_SETMASK, &orig_mask, NULL);
                    tstop_req = 0;
                    state = TERMINATED;
                    break;
                }
            }
        }
    }

    // XXX: this is not ideal if the Win32 side managed to maintain the
    // redirection socket beyond the lifetime of the launched process,
    // however things seem to already be not reliable for Windows reasons
    // in this case
    if (active_threads[0]) {
        __sync_fetch_and_add(&fs[0].ask_terminate, 1);
        useconds_t usec_sleep = 1000;
        while (!__sync_fetch_and_add(&fs[0].finished, 0)) {
            pthread_kill(forward_threads[0], SIGUSR1);
            usleep(usec_sleep);
            usec_sleep *= 2;
            if (usec_sleep > 60000000)
                usec_sleep = 60000000;
        }
    }

    for (int i = 0; i < 3; i++)
        if (active_threads[i])
            pthread_join(forward_threads[i], NULL);

    return program_return_code;
}
Beispiel #7
0
/*
 * This functions does some corrections and expansions to
 * the passed path:
 * - expands `~/' and `~name/' expressions;
 * - replaces `//' with `/' (restarting from the root directory);
 * - removes `..' and `.' entries.
 *
 * If something goes wrong, the string is deleted and NULL returned
 */
astr expand_path(astr path)
{
  int ret = TRUE;
  struct passwd *pw;
  const char *sp = astr_cstr(path);
  astr epath = astr_new();

  if (*sp != '/') {
    astr_cat_delete(epath, agetcwd());
    if (astr_len(epath) == 0 || *astr_char(epath, -1) != '/')
      astr_cat_char(epath, '/');
  }

  while (*sp != '\0') {
    if (*sp == '/') {
      if (*++sp == '/') {
        /* Got `//'.  Restart from this point. */
        while (*sp == '/')
          sp++;
        astr_truncate(epath, 0);
      }
      astr_cat_char(epath, '/');
    } else if (*sp == '~') {
      if (*(sp + 1) == '/') {
        /* Got `~/'. Restart from this point and insert the user's
           home directory. */
        astr_truncate(epath, 0);
        if ((pw = getpwuid(getuid())) == NULL) {
          ret = FALSE;
          break;
        }
        if (strcmp(pw->pw_dir, "/") != 0)
          astr_cat_cstr(epath, pw->pw_dir);
        ++sp;
      } else {
        /* Got `~something'.  Restart from this point and insert that
           user's home directory. */
        astr as = astr_new();
        astr_truncate(epath, 0);
        ++sp;
        while (*sp != '\0' && *sp != '/')
          astr_cat_char(as, *sp++);
        pw = getpwnam(astr_cstr(as));
        astr_delete(as);
        if (pw == NULL) {
          ret = FALSE;
          break;
        }
        astr_cat_cstr(epath, pw->pw_dir);
      }
    } else if (*sp == '.') {
      if (*(sp + 1) == '/' || *(sp + 1) == '\0') {
        ++sp;
        if (*sp == '/' && *(sp + 1) != '/')
          ++sp;
      } else if (*(sp + 1) == '.' &&
                 (*(sp + 2) == '/' || *(sp + 2) == '\0')) {
        if (astr_len(epath) >= 1 && *astr_char(epath, -1) == '/')
          astr_truncate(epath, -1);
        while (*astr_char(epath, -1) != '/' &&
               astr_len(epath) >= 1)
          astr_truncate(epath, -1);
        sp += 2;
        if (*sp == '/' && *(sp + 1) != '/')
          ++sp;
      } else
        goto got_component;
    } else {
      const char *p;
    got_component:
      p = sp;
      while (*p != '\0' && *p != '/')
        p++;
      if (*p == '\0') { /* Final filename */
        astr_cat_cstr(epath, sp);
        break;
      } else { /* Non-final directory */
        while (*sp != '/')
          astr_cat_char(epath, *sp++);
      }
    }
  }

  astr_cpy(path, epath);
  astr_delete(epath);

  if (!ret) {
    astr_delete(path);
    return NULL;
  }
  return path;
}
Beispiel #8
0
/*
 * dinit - initialize current working directory
 */
void
dinit(Char *hp)
{
    Char *cp, *tcp;
    struct directory *dp;

    /* Don't believe the login shell home, because it may be a symlink */
    tcp = agetcwd();
    if (tcp == NULL) {
	xprintf("%s: %s\n", progname, strerror(errno));
	if (hp && *hp) {
	    char *xcp = short2str(hp);
	    dstart(xcp);
	    if (chdir(xcp) == -1)
		cp = NULL;
	    else
		cp = Strsave(hp);
	}
	else
	    cp = NULL;
	if (cp == NULL) {
	    dstart("/");
	    if (chdir("/") == -1)
		/* I am not even try to print an error message! */
		xexit(1);
	    cp = SAVE("/");
	}
    }
    else {
#ifdef S_IFLNK
	struct stat swd, shp;
	int swd_ok;

	swd_ok = stat(short2str(tcp), &swd) == 0;
	/*
	 * See if $HOME is the working directory we got and use that
	 */
	if (swd_ok && hp && *hp && stat(short2str(hp), &shp) != -1 &&
	    DEV_DEV_COMPARE(swd.st_dev, shp.st_dev)  &&
		swd.st_ino == shp.st_ino)
	    cp = Strsave(hp);
	else {
	    char   *cwd;

	    /*
	     * use PWD if we have it (for subshells)
	     */
	    if (swd_ok && (cwd = getenv("PWD")) != NULL) {
		if (stat(cwd, &shp) != -1 &&
			DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) &&
		        swd.st_ino == shp.st_ino) {
		    tcp = SAVE(cwd);
		    cleanup_push(tcp, xfree);
		}
	    }
	    cleanup_push(tcp, xfree);
	    cp = dcanon(tcp, STRNULL);
	    cleanup_ignore(tcp);
	    cleanup_until(tcp);
	}
#else /* S_IFLNK */
	cleanup_push(tcp, xfree);
	cp = dcanon(tcp, STRNULL);
	cleanup_ignore(tcp);
	cleanup_until(tcp);
#endif /* S_IFLNK */
    }

    dp = xcalloc(sizeof(struct directory), 1);
    dp->di_name = cp;
    dp->di_count = 0;
    dhead.di_next = dhead.di_prev = dp;
    dp->di_next = dp->di_prev = &dhead;
    printd = 0;
    dnewcwd(dp, 0);
    setcopy(STRdirstack, dp->di_name, VAR_READWRITE|VAR_NOGLOB);
}
Beispiel #9
0
/*
 * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
 *	we are of course assuming that the file system is standardly
 *	constructed (always have ..'s, directories have links)
 */
Char   *
dcanon(Char *cp, Char *p)
{
    Char *sp;
    Char *p1, *p2;	/* general purpose */
    int    slash;
#ifdef HAVE_SLASHSLASH
    int    slashslash;
#endif /* HAVE_SLASHSLASH */
    size_t  clen;

#ifdef S_IFLNK			/* if we have symlinks */
    Char *mlink, *newcp;
    char *tlink;
    size_t cc;
#endif /* S_IFLNK */

    clen = Strlen(cp);

    /*
     * christos: if the path given does not start with a slash prepend cwd. If
     * cwd does not start with a slash or the result would be too long try to
     * correct it.
     */
    if (!ABSOLUTEP(cp)) {
	Char *tmpdir;
	size_t	len;

	p1 = varval(STRcwd);
	if (p1 == STRNULL || !ABSOLUTEP(p1)) {
	    Char *new_cwd = agetcwd();

	    if (new_cwd == NULL) {
		xprintf("%s: %s\n", progname, strerror(errno));
		setcopy(STRcwd, str2short("/"), VAR_READWRITE|VAR_NOGLOB);
	    }
	    else
		setv(STRcwd, new_cwd, VAR_READWRITE|VAR_NOGLOB);
	    p1 = varval(STRcwd);
	}
	len = Strlen(p1);
	tmpdir = xmalloc((len + clen + 2) * sizeof (*tmpdir));
	(void) Strcpy(tmpdir, p1);
	(void) Strcat(tmpdir, STRslash);
	(void) Strcat(tmpdir, cp);
	xfree(cp);
	cp = p = tmpdir;
    }

#ifdef HAVE_SLASHSLASH
    slashslash = (cp[0] == '/' && cp[1] == '/');
#endif /* HAVE_SLASHSLASH */

    while (*p) {		/* for each component */
	sp = p;			/* save slash address */
	while (*++p == '/')	/* flush extra slashes */
	    continue;
	if (p != ++sp)
	    for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
		continue;
	p = sp;			/* save start of component */
	slash = 0;
	if (*p) 
	    while (*++p)	/* find next slash or end of path */
		if (*p == '/') {
		    slash = 1;
		    *p = 0;
		    break;
		}

#ifdef HAVE_SLASHSLASH
	if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0')
	    slashslash = 1;
#endif /* HAVE_SLASHSLASH */
	if (*sp == '\0') {	/* if component is null */
	    if (--sp == cp)	/* if path is one char (i.e. /) */ 
		break;
	    else
		*sp = '\0';
	}
	else if (sp[0] == '.' && sp[1] == 0) {
	    if (slash) {
		for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
		    continue;
		p = --sp;
	    }
	    else if (--sp != cp)
		*sp = '\0';
	    else
		sp[1] = '\0';
	}
	else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
	    /*
	     * We have something like "yyy/xxx/..", where "yyy" can be null or
	     * a path starting at /, and "xxx" is a single component. Before
	     * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
	     * symbolic link.
	     */
	    *--sp = 0;		/* form the pathname for readlink */
#ifdef S_IFLNK			/* if we have symlinks */
	    if (sp != cp && /* symlinks != SYM_IGNORE && */
		(tlink = areadlink(short2str(cp))) != NULL) {
		mlink = str2short(tlink);
		xfree(tlink);

		if (slash)
		    *p = '/';
		/*
		 * Point p to the '/' in "/..", and restore the '/'.
		 */
		*(p = sp) = '/';
		if (*mlink != '/') {
		    /*
		     * Relative path, expand it between the "yyy/" and the
		     * "/..". First, back sp up to the character past "yyy/".
		     */
		    while (*--sp != '/')
			continue;
		    sp++;
		    *sp = 0;
		    /*
		     * New length is "yyy/" + mlink + "/.." and rest
		     */
		    p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
					  Strlen(p) + 1) * sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at expanded "/xxx".
		     */
		    p = sp - cp - 1 + newcp;
		}
		else {
		    newcp = Strspl(mlink, p);
		    /*
		     * Restart canonicalization at beginning
		     */
		    p = newcp;
		}
		xfree(cp);
		cp = newcp;
#ifdef HAVE_SLASHSLASH
                slashslash = (cp[0] == '/' && cp[1] == '/');
#endif /* HAVE_SLASHSLASH */
		continue;	/* canonicalize the link */
	    }
#endif /* S_IFLNK */
	    *sp = '/';
	    if (sp != cp)
		while (*--sp != '/')
		    continue;
	    if (slash) {
		for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
		    continue;
		p = sp;
	    }
	    else if (cp == sp)
		*++sp = '\0';
	    else
		*sp = '\0';
	}
	else {			/* normal dir name (not . or .. or nothing) */

#ifdef S_IFLNK			/* if we have symlinks */
	    if (sp != cp && symlinks == SYM_CHASE &&
		(tlink = areadlink(short2str(cp))) != NULL) {
		mlink = str2short(tlink);
		xfree(tlink);

		/*
		 * restore the '/'.
		 */
		if (slash)
		    *p = '/';

		/*
		 * point sp to p (rather than backing up).
		 */
		sp = p;

		if (*mlink != '/') {
		    /*
		     * Relative path, expand it between the "yyy/" and the
		     * remainder. First, back sp up to the character past
		     * "yyy/".
		     */
		    while (*--sp != '/')
			continue;
		    sp++;
		    *sp = 0;
		    /*
		     * New length is "yyy/" + mlink + "/.." and rest
		     */
		    p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
					  Strlen(p) + 1) * sizeof(Char));
		    /*
		     * Copy new path into newcp
		     */
		    for (p2 = cp; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
			continue;
		    for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
			continue;
		    /*
		     * Restart canonicalization at expanded "/xxx".
		     */
		    p = sp - cp - 1 + newcp;
		}
		else {
		    newcp = Strspl(mlink, p);
		    /*
		     * Restart canonicalization at beginning
		     */
		    p = newcp;
		}
		xfree(cp);
		cp = newcp;
#ifdef HAVE_SLASHSLASH
                slashslash = (cp[0] == '/' && cp[1] == '/');
#endif /* HAVE_SLASHSLASH */
		continue;	/* canonicalize the mlink */
	    }
#endif /* S_IFLNK */
	    if (slash)
		*p = '/';
	}
    }

    /*
     * fix home...
     */
#ifdef S_IFLNK
    p1 = varval(STRhome);
    cc = Strlen(p1);
    /*
     * See if we're not in a subdir of STRhome
     */
    if (p1 && *p1 == '/' && (Strncmp(p1, cp, cc) != 0 ||
	(cp[cc] != '/' && cp[cc] != '\0'))) {
	static ino_t home_ino = (ino_t) -1;
	static dev_t home_dev = (dev_t) -1;
	static Char *home_ptr = NULL;
	struct stat statbuf;
	int found;
	Char *copy;

	/*
	 * Get dev and ino of STRhome
	 */
	if (home_ptr != p1 &&
	    stat(short2str(p1), &statbuf) != -1) {
	    home_dev = statbuf.st_dev;
	    home_ino = statbuf.st_ino;
	    home_ptr = p1;
	}
	/*
	 * Start comparing dev & ino backwards
	 */
	p2 = copy = Strsave(cp);
	found = 0;
	while (*p2 && stat(short2str(p2), &statbuf) != -1) {
	    if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) &&
			statbuf.st_ino == home_ino) {
			found = 1;
			break;
	    }
	    if ((sp = Strrchr(p2, '/')) != NULL)
		*sp = '\0';
	}
	/*
	 * See if we found it
	 */
	if (*p2 && found) {
	    /*
	     * Use STRhome to make '~' work
	     */
	    newcp = Strspl(p1, cp + Strlen(p2));
	    xfree(cp);
	    cp = newcp;
	}
	xfree(copy);
    }
#endif /* S_IFLNK */

#ifdef HAVE_SLASHSLASH
    if (slashslash) {
	if (cp[1] != '/') {
	    p = xmalloc((Strlen(cp) + 2) * sizeof(Char));
	    *p = '/';
	    (void) Strcpy(&p[1], cp);
	    xfree(cp);
	    cp = p;
	}
    }
    if (cp[1] == '/' && cp[2] == '/') {
	for (p1 = &cp[1], p2 = &cp[2]; (*p1++ = *p2++) != '\0';)
	    continue;
    }
#endif /* HAVE_SLASHSLASH */
    return cp;
}
Beispiel #10
0
/*
 * dfollow - change to arg directory; fall back on cdpath if not valid
 */
static Char *
dfollow(Char *cp, int old)
{
    Char *dp;
    struct varent *c;
    int serrno;

    cp = old ? Strsave(cp) : globone(cp, G_ERROR);
    cleanup_push(cp, xfree);
#ifdef apollo
    if (Strchr(cp, '`')) {
	char *dptr;
	if (chdir(dptr = short2str(cp)) < 0) 
	    stderror(ERR_SYSTEM, dptr, strerror(errno));
	dp = agetcwd();
	cleanup_push(dp, xfree);
	if (dp != NULL) {
	    cleanup_until(cp);
	    return dgoto(dp);
	}
	else
	    stderror(ERR_SYSTEM, dptr, strerror(errno));
    }
#endif /* apollo */

    /*
     * if we are ignoring symlinks, try to fix relatives now.
     * if we are expading symlinks, it should be done by now.
     */ 
    dp = dnormalize(cp, symlinks == SYM_IGNORE);
    if (chdir(short2str(dp)) >= 0) {
        cleanup_until(cp);
        return dgoto(dp);
    }
    else {
        xfree(dp);
        if (chdir(short2str(cp)) >= 0) {
	    cleanup_ignore(cp);
	    cleanup_until(cp);
	    return dgoto(cp);
	}
	else if (errno != ENOENT && errno != ENOTDIR) {
	    int err;

	    err = errno;
	    stderror(ERR_SYSTEM, short2str(cp), strerror(err));
	}
	serrno = errno;
    }

    if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
	&& (c = adrof(STRcdpath)) && c->vec != NULL) {
	struct Strbuf buf = Strbuf_INIT;
	Char  **cdp;

	for (cdp = c->vec; *cdp; cdp++) {
	    size_t len = Strlen(*cdp);
	    buf.len = 0;
	    if (len > 0) {
		Strbuf_append(&buf, *cdp);
		if ((*cdp)[len - 1] != '/')
		    Strbuf_append1(&buf, '/');
	    }
	    Strbuf_append(&buf, cp);
	    Strbuf_terminate(&buf);
	    /*
	     * We always want to fix the directory here
	     * If we are normalizing symlinks
	     */
	    dp = dnormalize(buf.s, symlinks == SYM_IGNORE || 
				   symlinks == SYM_EXPAND);
	    if (chdir(short2str(dp)) >= 0) {
		printd = 1;
		xfree(buf.s);
		cleanup_until(cp);
		return dgoto(dp);
	    }
	    else if (chdir(short2str(cp)) >= 0) {
		printd = 1;
		xfree(dp);
		xfree(buf.s);
		cleanup_ignore(cp);
		cleanup_until(cp);
		return dgoto(cp);
	    }
	}
	xfree(buf.s);
    }
    dp = varval(cp);
    if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
	cleanup_until(cp);
	cp = Strsave(dp);
	printd = 1;
	return dgoto(cp);
    }
    /*
     * on login source of ~/.cshdirs, errors are eaten. the dir stack is all
     * directories we could get to.
     */
    if (!bequiet)
	stderror(ERR_SYSTEM, short2str(cp), strerror(serrno));
    cleanup_until(cp);
    return (NULL);
}
Beispiel #11
0
int
main(int argc, char **argv)
{
	int i;
	char *p;
	FILE *fp = NULL;
	char *file;
	char *mode = "w";
	int sortenv = 0;
	char *include = NULL;
	char **itab = NULL;
	pid_t pid = 0;
	int sig = SIGHUP;
	
	progname = strrchr(argv[0], '/');
	if (progname)
		progname++;
	else
		progname = argv[0];
	while ((i = getopt(argc, argv, "af:hi:k:s")) != EOF)
		switch (i) {
		case 'a':
			mode = "a";
			break;
		case 'f':
			file = optarg;
			break;
		case 'h':
			printf("usage: %s [-ahsx] [-f FILE] [-i INCLUDELIST] [-k [@]PID[:SIG]] [ARGS...]\n",
			       progname);
			return 0;
		case 's':
			sortenv = 1;
			break;
		case 'i':
			include = optarg;
			break;
		case 'k':
			read_pid_and_sig(optarg, &pid, &sig);
			break;
		default:
			return 1;
		}

	if (file) {
		fp = fopen(file, mode);
		if (!fp) {
			fprintf(stderr, "%s: ", progname);
			perror(file);
			return 1;
		}
	} else
		fp = stderr;
	
	fprintf(fp, "# Dump of execution environment\n");
	p = agetcwd();
	if (p) {
		fprintf(fp, "cwd is %s\n", p);
		free(p);
	}
	fprintf(fp, "# Arguments\n");
	for (i = 0; i < argc; i++)
		fprintf(fp, "argv[%d]=%s\n", i, argv[i]);

	if (sortenv) {
		for (i = 0; environ[i]; i++);
		qsort(environ, i, sizeof(environ[0]), compenv);
	}
	if (include) {
		i = 1;
		for (p = include; *p; p++) {
			if (*p == ':')
				i++;
		}
		itab = calloc(i + 1, sizeof(itab));

		itab[0] = include;
		for (p = include, i = 1; *p; p++) {
			if (*p == ':') {
				*p = 0;
				itab[i++] = p + 1;
			}
		}
		itab[i] = NULL;
	}
		
	fprintf(fp, "# Environment\n");
	for (i = 0; environ[i]; i++) {
		if (!itab || locate(itab, environ[i]))
			fprintf(fp, "%s\n", environ[i]);
	}
	fprintf(fp, "# End\n");

	if (pid)
		kill(pid, sig);

	return 0;
}