示例#1
0
/*
 * This is so ripe with races that you should *really* not touch this
 * unless you know exactly what you are doing. All the changes have to be
 * made atomically, or there may be incorrect pointers all over the place.
 */
static int init_dev(int dev)
{
	struct tty_struct *tty, *o_tty;
	struct termios *tp, *o_tp, *ltp, *o_ltp;
	int retval;
	int o_dev;

	o_dev = PTY_OTHER(dev);
	tty = o_tty = NULL;
	tp = o_tp = NULL;
	ltp = o_ltp = NULL;
repeat:
	retval = -EAGAIN;
	if (IS_A_PTY_MASTER(dev) && tty_table[dev] && tty_table[dev]->count)
		goto end_init;
	retval = -ENOMEM;
	if (!tty_table[dev] && !tty) {
		if (!(tty = (struct tty_struct*) get_free_page(GFP_KERNEL)))
			goto end_init;
		initialize_tty_struct(dev, tty);
		goto repeat;
	}
	if (!tty_termios[dev] && !tp) {
		tp = (struct termios *) kmalloc(sizeof(struct termios),
						GFP_KERNEL);
		if (!tp)
			goto end_init;
		initialize_termios(dev, tp);
		goto repeat;
	}
	if (!termios_locked[dev] && !ltp) {
		ltp = (struct termios *) kmalloc(sizeof(struct termios),
						 GFP_KERNEL);
		if (!ltp)
			goto end_init;
		memset(ltp, 0, sizeof(struct termios));
		goto repeat;
	}
	if (IS_A_PTY(dev)) {
		if (!tty_table[o_dev] && !o_tty) {
			o_tty = (struct tty_struct *)
				get_free_page(GFP_KERNEL);
			if (!o_tty)
				goto end_init;
			initialize_tty_struct(o_dev, o_tty);
			goto repeat;
		}
		if (!tty_termios[o_dev] && !o_tp) {
			o_tp = (struct termios *)
				kmalloc(sizeof(struct termios), GFP_KERNEL);
			if (!o_tp)
				goto end_init;
			initialize_termios(o_dev, o_tp);
			goto repeat;
		}
		if (!termios_locked[o_dev] && !o_ltp) {
			o_ltp = (struct termios *)
				kmalloc(sizeof(struct termios), GFP_KERNEL);
			if (!o_ltp)
				goto end_init;
			memset(o_ltp, 0, sizeof(struct termios));
			goto repeat;
		}
		
	}
	/* Now we have allocated all the structures: update all the pointers.. */
	if (!tty_termios[dev]) {
		tty_termios[dev] = tp;
		tp = NULL;
	}
	if (!tty_table[dev]) {
		tty->termios = tty_termios[dev];
		tty_table[dev] = tty;
		tty = NULL;
	}
	if (!termios_locked[dev]) {
		termios_locked[dev] = ltp;
		ltp = NULL;
	}
	if (IS_A_PTY(dev)) {
		if (!tty_termios[o_dev]) {
			tty_termios[o_dev] = o_tp;
			o_tp = NULL;
		}
		if (!termios_locked[o_dev]) {
			termios_locked[o_dev] = o_ltp;
			o_ltp = NULL;
		}
		if (!tty_table[o_dev]) {
			o_tty->termios = tty_termios[o_dev];
			tty_table[o_dev] = o_tty;
			o_tty = NULL;
		}
		tty_table[dev]->link = tty_table[o_dev];
		tty_table[o_dev]->link = tty_table[dev];
	}
	tty_table[dev]->count++;
	if (IS_A_PTY_MASTER(dev))
		tty_table[o_dev]->count++;
	retval = 0;
end_init:
	if (tty)
		free_page((unsigned long) tty);
	if (o_tty)
		free_page((unsigned long) o_tty);
	if (tp)
		kfree_s(tp, sizeof(struct termios));
	if (o_tp)
		kfree_s(o_tp, sizeof(struct termios));
	if (ltp)
		kfree_s(ltp, sizeof(struct termios));
	if (o_ltp)
		kfree_s(o_ltp, sizeof(struct termios));
	return retval;
}
示例#2
0
文件: Shell.cpp 项目: sahil9912/haiku
status_t
Shell::_Spawn(int row, int col, const ShellParameters& parameters)
{
	const char** argv = (const char**)parameters.Arguments();
	int argc = parameters.ArgumentCount();
	const char* defaultArgs[3] = {kDefaultShell, "-l", NULL};
	struct passwd passwdStruct;
	struct passwd *passwdResult;
	char stringBuffer[256];

	if (argv == NULL || argc == 0) {
		if (!getpwuid_r(getuid(), &passwdStruct, stringBuffer,
				sizeof(stringBuffer), &passwdResult)) {
			defaultArgs[0] = passwdStruct.pw_shell;
		}

		argv = defaultArgs;
		argc = 2;

		fShellInfo.SetDefaultShell(true);
	} else
		fShellInfo.SetDefaultShell(false);

	fShellInfo.SetEncoding(parameters.Encoding());

	signal(SIGTTOU, SIG_IGN);

	// get a pseudo-tty
	int master = posix_openpt(O_RDWR | O_NOCTTY);
	const char *ttyName;

	if (master < 0) {
		fprintf(stderr, "Didn't find any available pseudo ttys.");
		return errno;
	}

	if (grantpt(master) != 0 || unlockpt(master) != 0
		|| (ttyName = ptsname(master)) == NULL) {
		close(master);
		fprintf(stderr, "Failed to init pseudo tty.");
		return errno;
	}

	/*
	 * Get the modes of the current terminal. We will duplicates these
	 * on the pseudo terminal.
	 */

	thread_id terminalThread = find_thread(NULL);

	/* Fork a child process. */
	fShellInfo.SetProcessID(fork());
	if (fShellInfo.ProcessID() < 0) {
		close(master);
		return B_ERROR;
	}

	handshake_t handshake;

	if (fShellInfo.ProcessID() == 0) {
		// Now in child process.

		// close the PTY master side
		close(master);

		/*
		 * Make our controlling tty the pseudo tty. This hapens because
		 * we cleared our original controlling terminal above.
		 */

		/* Set process session leader */
		if (setsid() < 0) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				"could not set session leader.");
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		/* open slave pty */
		int slave = -1;
		if ((slave = open(ttyName, O_RDWR)) < 0) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				"can't open tty (%s).", ttyName);
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		/* set signal default */
		signal(SIGCHLD, SIG_DFL);
		signal(SIGHUP, SIG_DFL);
		signal(SIGQUIT, SIG_DFL);
		signal(SIGTERM, SIG_DFL);
		signal(SIGINT, SIG_DFL);
		signal(SIGTTOU, SIG_DFL);

		struct termios tio;
		/* get tty termios (not necessary).
		 * TODO: so why are we doing it ?
		 */
		tcgetattr(slave, &tio);

		initialize_termios(tio);

		/*
		 * change control tty.
		 */

		dup2(slave, 0);
		dup2(slave, 1);
		dup2(slave, 2);

		/* close old slave fd. */
		if (slave > 2)
			close(slave);

		/*
		 * set terminal interface.
		 */
		if (tcsetattr(0, TCSANOW, &tio) == -1) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				"failed set terminal interface (TERMIOS).");
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		/*
		 * set window size.
		 */

		handshake.status = PTY_WS;
		send_handshake_message(terminalThread, handshake);
		receive_handshake_message(handshake);

		if (handshake.status != PTY_WS) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				"mismatch handshake.");
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		struct winsize ws = { handshake.row, handshake.col };

		ioctl(0, TIOCSWINSZ, &ws);

		tcsetpgrp(0, getpgrp());
			// set this process group ID as the controlling terminal
		set_thread_priority(find_thread(NULL), B_NORMAL_PRIORITY);

		/* pty open and set termios successful. */
		handshake.status = PTY_OK;
		send_handshake_message(terminalThread, handshake);

		/*
		 * setenv TERM and TTY.
		 */
		setenv("TERM", kTerminalType, true);
		setenv("TTY", ttyName, true);
		setenv("TTYPE", fShellInfo.EncodingName(), true);

		// set the current working directory, if one is given
		if (parameters.CurrentDirectory().Length() > 0)
			chdir(parameters.CurrentDirectory().String());

		execve(argv[0], (char * const *)argv, environ);

		// Exec failed.
		// TODO: This doesn't belong here.

		sleep(1);

		BString alertCommand = "alert --stop '";
		alertCommand += B_TRANSLATE("Cannot execute \"%command\":\n\t%error");
		alertCommand += "' '";
		alertCommand += B_TRANSLATE("Use default shell");
		alertCommand += "' '";
		alertCommand += B_TRANSLATE("Abort");
		alertCommand += "'";
		alertCommand.ReplaceFirst("%command", argv[0]);
		alertCommand.ReplaceFirst("%error", strerror(errno));

		int returnValue = system(alertCommand.String());
		if (returnValue == 0) {
			execl(kDefaultShell, kDefaultShell,
				"-l", NULL);
		}

		exit(1);
	}

	/*
	 * In parent Process, Set up the input and output file pointers so
	 * that they can write and read the pseudo terminal.
	 */

	/*
	 * close parent control tty.
	 */

	int done = 0;
	while (!done) {
		receive_handshake_message(handshake);

		switch (handshake.status) {
			case PTY_OK:
				done = 1;
				break;

			case PTY_NG:
				fprintf(stderr, "%s\n", handshake.msg);
				done = -1;
				break;

			case PTY_WS:
				handshake.row = row;
				handshake.col = col;
				handshake.status = PTY_WS;
				send_handshake_message(fShellInfo.ProcessID(), handshake);
				break;
		}
	}

	if (done <= 0)
		return B_ERROR;

	fFd = master;

	return B_OK;
}
示例#3
0
文件: Shell.cpp 项目: mariuz/haiku
status_t
Shell::_Spawn(int row, int col, const char *encoding, int argc, const char **argv)
{
	const char *kDefaultShellCommand[] = { "/bin/sh", "--login", NULL };

	if (argv == NULL || argc == 0) {
		argv = kDefaultShellCommand;
		argc = 2;
	}

	signal(SIGTTOU, SIG_IGN);

#ifdef __HAIKU__
	// get a pseudo-tty
	int master = posix_openpt(O_RDWR | O_NOCTTY);
	const char *ttyName;
#else /* __HAIKU__ */
	/*
	 * Get a pseudo-tty. We do this by cycling through files in the
	 * directory. The operating system will not allow us to open a master
	 * which is already in use, so we simply go until the open succeeds.
	 */
	char ttyName[B_PATH_NAME_LENGTH];
	int master = -1;
	DIR *dir = opendir("/dev/pt/");
	if (dir != NULL) {
		struct dirent *dirEntry;
		while ((dirEntry = readdir(dir)) != NULL) {
			// skip '.' and '..'
			if (dirEntry->d_name[0] == '.')
				continue;

			char ptyName[B_PATH_NAME_LENGTH];
			snprintf(ptyName, sizeof(ptyName), "/dev/pt/%s", dirEntry->d_name);

			master = open(ptyName, O_RDWR);
			if (master >= 0) {
				// Set the tty that corresponds to the pty we found
				snprintf(ttyName, sizeof(ttyName), "/dev/tt/%s", dirEntry->d_name);
				break;
			} else {
				// B_BUSY is a normal case
				if (errno != B_BUSY)
					fprintf(stderr, B_TRANSLATE("could not open %s: %s\n"),
						ptyName, strerror(errno));
			}
		}
		closedir(dir);
	}
#endif /* __HAIKU__ */

	if (master < 0) {
    	fprintf(stderr, B_TRANSLATE("Didn't find any available pseudo ttys."));
    	return errno;
	}

#ifdef __HAIKU__
	if (grantpt(master) != 0 || unlockpt(master) != 0
		|| (ttyName = ptsname(master)) == NULL) {
		close(master);
    	fprintf(stderr, B_TRANSLATE("Failed to init pseudo tty."));
		return errno;
	}
#endif /* __HAIKU__ */

	/*
	 * Get the modes of the current terminal. We will duplicates these
	 * on the pseudo terminal.
	 */

	thread_id terminalThread = find_thread(NULL);

	/* Fork a child process. */
	if ((fProcessID = fork()) < 0) {
		close(master);
		return B_ERROR;
	}

	handshake_t handshake;

	if (fProcessID == 0) {
		// Now in child process.

		// close the PTY master side
		close(master);

		/*
		 * Make our controlling tty the pseudo tty. This hapens because
		 * we cleared our original controlling terminal above.
		 */

		/* Set process session leader */
		if (setsid() < 0) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				B_TRANSLATE("could not set session leader."));
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		/* open slave pty */
		int slave = -1;
		if ((slave = open(ttyName, O_RDWR)) < 0) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				B_TRANSLATE("can't open tty (%s)."), ttyName);
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		/* set signal default */
		signal(SIGCHLD, SIG_DFL);
		signal(SIGHUP, SIG_DFL);
		signal(SIGQUIT, SIG_DFL);
		signal(SIGTERM, SIG_DFL);
		signal(SIGINT, SIG_DFL);
		signal(SIGTTOU, SIG_DFL);

		struct termios tio;
		/* get tty termios (not necessary).
		 * TODO: so why are we doing it ?
		 */
		tcgetattr(slave, &tio);

		initialize_termios(tio);

		/*
		 * change control tty.
		 */

		dup2(slave, 0);
		dup2(slave, 1);
		dup2(slave, 2);

		/* close old slave fd. */
		if (slave > 2)
			close(slave);

		/*
		 * set terminal interface.
		 */
		if (tcsetattr(0, TCSANOW, &tio) == -1) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				B_TRANSLATE("failed set terminal interface (TERMIOS)."));
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		/*
		 * set window size.
		 */

		handshake.status = PTY_WS;
		send_handshake_message(terminalThread, handshake);
		receive_handshake_message(handshake);

		if (handshake.status != PTY_WS) {
			handshake.status = PTY_NG;
			snprintf(handshake.msg, sizeof(handshake.msg),
				B_TRANSLATE("mismatch handshake."));
			send_handshake_message(terminalThread, handshake);
			exit(1);
		}

		struct winsize ws = { handshake.row, handshake.col };

		ioctl(0, TIOCSWINSZ, &ws);

		tcsetpgrp(0, getpgrp());
			// set this process group ID as the controlling terminal
#ifndef __HAIKU__
		ioctl(0, 'pgid', getpid());
#endif
		set_thread_priority(find_thread(NULL), B_NORMAL_PRIORITY);

		/* pty open and set termios successful. */
		handshake.status = PTY_OK;
		send_handshake_message(terminalThread, handshake);

		/*
		 * setenv TERM and TTY.
		 */
		setenv("TERM", "xterm", true);
		setenv("TTY", ttyName, true);
		setenv("TTYPE", encoding, true);

		execve(argv[0], (char * const *)argv, environ);

		// Exec failed.
		// TODO: This doesn't belong here.

		sleep(1);

		BString alertCommand = "alert --stop '";
		alertCommand += B_TRANSLATE("Cannot execute \"%command\":\n\t%error");
		alertCommand += "' '";
		alertCommand += B_TRANSLATE("Use default shell");
		alertCommand += "' '";
		alertCommand += B_TRANSLATE("Abort");
		alertCommand += "'";
		alertCommand.ReplaceFirst("%command", argv[0]);
		alertCommand.ReplaceFirst("%error", strerror(errno));

		int returnValue = system(alertCommand.String());
		if (returnValue == 0) {
			execl(kDefaultShellCommand[0], kDefaultShellCommand[0],
				kDefaultShellCommand[1], NULL);
		}

		exit(1);
	}

	/*
	 * In parent Process, Set up the input and output file pointers so
	 * that they can write and read the pseudo terminal.
	 */

	/*
	 * close parent control tty.
	 */

	int done = 0;
	while (!done) {
		receive_handshake_message(handshake);

		switch (handshake.status) {
			case PTY_OK:
				done = 1;
				break;

			case PTY_NG:
				fprintf(stderr, "%s\n", handshake.msg);
				done = -1;
				break;

			case PTY_WS:
				handshake.row = row;
				handshake.col = col;
				handshake.status = PTY_WS;
				send_handshake_message(fProcessID, handshake);
				break;
		}
	}

	if (done <= 0)
		return B_ERROR;

	fFd = master;

	return B_OK;
}