Merge branch 'newparser' into 'master'
Newparser done See merge request !1
This commit is contained in:
commit
b0b12d9fe9
20
README.md
20
README.md
|
@ -21,23 +21,23 @@ The Shell Assignment (total 42 points)
|
|||
+ `ls > fred`
|
||||
+ 1 ~~Can do file output redirection ">"~~
|
||||
+ `ls < fred`
|
||||
+ 2 Can do command piping "|"
|
||||
+ 2 ~~Can do command piping "|"~~
|
||||
+ `ls | wc`
|
||||
+ 1 Can do lots of pipes
|
||||
+ 1 ~~Can do lots of pipes~~
|
||||
+ `ls | grep fred | wc`
|
||||
+ 1 ~~Can do at least one combination of these things~~
|
||||
+ 1 Can do at least one combination of these things
|
||||
+ `ls | wc > fred`
|
||||
+ 4 Can do any combination of three of <, >, and |
|
||||
+ `cat < filename | sort > sortedFile.txt`
|
||||
+ 2 Can set enviornment variables
|
||||
+ `PATH=:/bin:/sbin:/usr/sbin:/usr/bin`
|
||||
+ 2 Expands enviornment variables on the command line
|
||||
+ 2 ~~Expands enviornment variables on the command line~~
|
||||
+ `ls $HOME`
|
||||
+ 2 Does filename expansion "glob" (Hint: Use the built in glob.)
|
||||
+ 2 ~~Does filename expansion "glob" (Hint: Use the built in glob.)~~
|
||||
+ `ls a*b`
|
||||
+ 1 ~~Knows how to change directory~~
|
||||
+ `cd /fred`
|
||||
+ 1 ~~Bang last command~~
|
||||
+ 1 Bang last command
|
||||
+ `!l` runs ls
|
||||
+ 1 Bang # command
|
||||
+ `!4` runs 4th command from history
|
||||
|
@ -52,9 +52,9 @@ The Shell Assignment (total 42 points)
|
|||
+ 1 Concatenate commands with &. Only runs next command if the previous
|
||||
comand returned success.
|
||||
+ `cd /home/rappleto & rm fred.txt`
|
||||
+ 1 Catch Keyboard interrupt
|
||||
+ 1 ~~Catch Keyboard interrupt~~
|
||||
+ `ctrl + c` = back to prompt
|
||||
+ 1 Replace "~" with the home directory
|
||||
+ 1 ~~Replace "~" with the home directory~~
|
||||
+ `rm ~/junkfile`
|
||||
+ 1 ~~Control-L clears the screen~~
|
||||
+ `ctrl-l` = clear screen
|
||||
|
@ -69,7 +69,7 @@ The Shell Assignment (total 42 points)
|
|||
+ 2 Only runs execuatables from an approved list
|
||||
+ -2 Commands cannot have arguments (i.e. ls -l does not work).
|
||||
|
||||
13 pts
|
||||
20 pts
|
||||
/20
|
||||
|
||||
Some cases to consider
|
||||
|
@ -85,4 +85,4 @@ Some cases to consider
|
|||
+ A regular expression matches lots of files.
|
||||
+ A person tries to change directory to something that does not exist.
|
||||
|
||||
These programs are due Friday before finals week. It will take a totally excellent excuse to move this at all.
|
||||
These programs are due Friday before finals week. It will take a totally excellent excuse to move this at all.
|
||||
|
|
255
bish.cc
255
bish.cc
|
@ -21,166 +21,105 @@ using namespace std;
|
|||
|
||||
int main(int argc, char **argv){
|
||||
|
||||
signal(SIGINT, ctrlCHandler);
|
||||
signal(SIGINT, ctrlCHandler);
|
||||
|
||||
stringstream prompt;
|
||||
static char* line = (char*)NULL;
|
||||
vector<string> path = split(getenv("PATH"), ':');
|
||||
|
||||
const char *homedir;
|
||||
if ((homedir = getenv("HOME")) == NULL) {
|
||||
homedir = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
|
||||
// set up history
|
||||
using_history();
|
||||
string histpath = string(homedir) + string("/.bish_history");
|
||||
if (read_history(histpath.c_str())) {
|
||||
cout << "history file not found. creating `~/.bish_history`." << endl;
|
||||
int hist = open(histpath.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH);
|
||||
close(hist);
|
||||
}
|
||||
|
||||
|
||||
while ("bish") {
|
||||
|
||||
prompt.str("");
|
||||
prompt << "\e[34mbish:\e[92m" << get_current_dir_name() << "\e[34m:$\e[0m ";
|
||||
|
||||
line = readline(prompt.str().c_str());
|
||||
if (line == NULL) break;
|
||||
if (strcmp(line, "") == 0) continue;
|
||||
if (line && *line) add_history (line);
|
||||
|
||||
// char **args = v_to_cpp(split(line));
|
||||
// parse line
|
||||
vector<string> wfwe = split(line, ';');
|
||||
for (auto it: wfwe) {
|
||||
|
||||
|
||||
command *cmd = parse(split(it.c_str()));
|
||||
// print_cmd(cmd);
|
||||
// clear line var
|
||||
free(line);
|
||||
line = (char*)NULL;
|
||||
|
||||
// COMMANDS that do something with the line before fork/exec
|
||||
if (strcmp(cmd->args[0], "!") == 0) {
|
||||
line = history_get(where_history())->line;
|
||||
cmd = parse(split(line));
|
||||
}
|
||||
|
||||
else if (strcmp(cmd->args[0], ".") == 0 || strcmp(cmd->args[0], "source") == 0) {
|
||||
int dotsrcfile = open(cmd->args[1], O_RDONLY);
|
||||
if (dotsrcfile < 0) {
|
||||
perror("dotsrcfile");
|
||||
continue;
|
||||
}
|
||||
// do the thing to read the files
|
||||
}
|
||||
|
||||
// COMMANDS that skip fork/exec
|
||||
// http://www.linuxquestions.org/questions/programming-9/making-a-c-shell-775690/
|
||||
if (strcmp(cmd->args[0], "exit") == 0) break;
|
||||
|
||||
// handle chdir
|
||||
else if (strcmp(cmd->args[0], "cd") == 0) {
|
||||
if (cmd->args[1] == NULL) {
|
||||
if (chdir(homedir) < 0) perror("chdir");
|
||||
}
|
||||
else {
|
||||
if (chdir(cmd->args[1]) < 0) perror("chdir");
|
||||
}
|
||||
}
|
||||
|
||||
// process the line.
|
||||
else {
|
||||
|
||||
pid_t kidpid = fork();
|
||||
// fork error
|
||||
if (kidpid < 0) {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// run it
|
||||
// also check the path for things
|
||||
else if (kidpid == 0){
|
||||
|
||||
// io redirection
|
||||
if (cmd->outfile != "") {
|
||||
int outfd = open(cmd->outfile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
|
||||
if (outfd < 0) {
|
||||
perror("outfile");
|
||||
exit(0);
|
||||
}
|
||||
if (dup2(outfd, 1) == -1) {
|
||||
perror("dup2 outfile");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->infile != "") {
|
||||
int infd = open(cmd->infile.c_str(), O_RDONLY);
|
||||
if (infd < 0) {
|
||||
perror("infile");
|
||||
exit(0);
|
||||
}
|
||||
if (dup2(infd, 0) == -1) {
|
||||
perror("dup2 infile");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// try to run it as is
|
||||
execv(cmd->args[0], cmd->args);
|
||||
// search the path
|
||||
stringstream searchpath;
|
||||
for (auto it: path) {
|
||||
searchpath.str("");
|
||||
searchpath << it << "/" << cmd->args[0];
|
||||
execv(searchpath.str().c_str(), cmd->args);
|
||||
}
|
||||
// nothing found here...
|
||||
cout << "that's not a command, bish" << endl;
|
||||
exit(1);
|
||||
|
||||
}
|
||||
// parent waits for kid to die
|
||||
else {
|
||||
|
||||
int status;
|
||||
|
||||
if (!cmd->background){
|
||||
do {
|
||||
if (waitpid(kidpid, &status, WUNTRACED | WCONTINUED) == -1) {
|
||||
perror("waitpid");
|
||||
exit(1);
|
||||
}
|
||||
if (WIFEXITED(status)) {
|
||||
cout << "(" << WEXITSTATUS(status) << "):";
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
cout << endl << "killed by signal " << WTERMSIG(status) << endl;
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
cout << endl << "stopped by signal " << WSTOPSIG(status) << endl;
|
||||
} else if (WIFCONTINUED(status)) {
|
||||
cout << endl << "continued" << endl;
|
||||
}
|
||||
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// reset args array for the next prompt
|
||||
delete cmd;
|
||||
stringstream prompt;
|
||||
static char* line = (char*)NULL;
|
||||
|
||||
const char *homedir;
|
||||
if ((homedir = getenv("HOME")) == NULL) {
|
||||
homedir = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
}
|
||||
cout << endl;
|
||||
if (write_history(histpath.c_str())) perror("write_history");
|
||||
|
||||
return 0;
|
||||
// set up history
|
||||
using_history();
|
||||
string histpath = string(homedir) + string("/.bish_history");
|
||||
if (read_history(histpath.c_str())) {
|
||||
cout << "history file not found. creating `~/.bish_history`." << endl;
|
||||
int hist = open(histpath.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH);
|
||||
close(hist);
|
||||
}
|
||||
|
||||
|
||||
int done = 0;
|
||||
while (!done) {
|
||||
|
||||
prompt.str("");
|
||||
prompt << "\e[34mbish:\e[92m" << get_current_dir_name() << "\e[34m:$\e[0m ";
|
||||
|
||||
line = readline(prompt.str().c_str());
|
||||
if (line == NULL) break;
|
||||
if (strcmp(line, "") == 0) continue;
|
||||
if (line && *line) add_history (line);
|
||||
|
||||
// handle multiple commands w/ semicolon
|
||||
vector<string> wfwe = split(line, ';');
|
||||
for (auto it: wfwe) {
|
||||
|
||||
command *cmd = parse(split(it.c_str()));
|
||||
int num_cmds = cmd->cmds.size();
|
||||
// debug info
|
||||
// print_cmd(cmd);
|
||||
|
||||
// clear line var cause we already parsed it
|
||||
free(line);
|
||||
line = (char*)NULL;
|
||||
|
||||
if (cmd->cmds[0].vargs[0] == "exit") {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_cmds > 1) {
|
||||
|
||||
int in = 0, fd[2];
|
||||
for (int i = 0; i < num_cmds-1; i++) {
|
||||
if (pipe(fd)) perror("pipe");
|
||||
cmd->cmds[i].ispipe = true;
|
||||
cmd->cmds[i].infd = in;
|
||||
cmd->cmds[i].outfd = fd[1];
|
||||
expand_and_execute(&cmd->cmds[i]);
|
||||
close(fd[1]);
|
||||
in = fd[0];
|
||||
}
|
||||
if (in != 0) {
|
||||
cmd->cmds[num_cmds-1].ispipe = true;
|
||||
cmd->cmds[num_cmds-1].infd = in;
|
||||
cmd->cmds[num_cmds-1].outfd = 1;
|
||||
expand_and_execute(&cmd->cmds[num_cmds-1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cmd->cmds[0].ispipe = false;
|
||||
expand_and_execute(&cmd->cmds[0]);
|
||||
}
|
||||
|
||||
|
||||
// COMMANDS that do something with the line before fork/exec
|
||||
// if (strcmp(cmd->cmds[0]->args[0], "!") == 0) {
|
||||
// line = history_get(where_history())->line;
|
||||
// cout << line << endl;
|
||||
// cmd = parse(split(line));
|
||||
// }
|
||||
|
||||
// else if (strcmp(cmd->cmds[0]->args[0], ".") == 0 || strcmp(cmd->cmds[0]->args[0], "source") == 0) {
|
||||
// int dotsrcfile = open(cmd->cmds[0]->args[1], O_RDONLY);
|
||||
// if (dotsrcfile < 0) {
|
||||
// perror("dotsrcfile");
|
||||
// continue;
|
||||
// }
|
||||
// // do the thing to read the files
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// reset args array for the next prompt
|
||||
delete cmd;
|
||||
|
||||
} // end ';' split
|
||||
} // end main while loop
|
||||
cout << endl;
|
||||
if (write_history(histpath.c_str())) perror("write_history");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
22
bish.l
22
bish.l
|
@ -1,22 +0,0 @@
|
|||
%{
|
||||
#include <string.h>
|
||||
#include "y.tab.h"
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
\n { return NEWLINE;}
|
||||
|
||||
[ \t] {}
|
||||
|
||||
">" { return GT; }
|
||||
"<" { return LT; }
|
||||
">>" { return GTGT; }
|
||||
"|" { return PIPE; }
|
||||
"&" { return AMPERSAND; }
|
||||
[^ \t\n][^ \t\n]* {
|
||||
yylval.string_val = strdup(yytext);
|
||||
return WORD;
|
||||
}
|
||||
|
||||
%%
|
58
parse.cc
58
parse.cc
|
@ -10,53 +10,65 @@ using namespace std;
|
|||
|
||||
|
||||
void print_cmd(command *cmd) {
|
||||
if (cmd->background) cout << "backgroud: true" << endl;
|
||||
if (cmd->piping != "") cout << "piping to: " << cmd->piping << endl;
|
||||
if (cmd->infile != "") cout << "infile: " << cmd->infile << endl;
|
||||
if (cmd->outfile != "") cout << "outfile: " << cmd->outfile << endl;
|
||||
int i = 0;
|
||||
cout << "-----------------------------" << endl;
|
||||
for (auto cmd_iter: cmd->cmds) {
|
||||
if (cmd->background) cout << "backgroud: true" << endl;
|
||||
cout << "command " << ++i << endl;
|
||||
if (cmd_iter.infile != "") cout << "infile: " << cmd_iter.infile << endl;
|
||||
if (cmd_iter.outfile != "") cout << "outfile: " << cmd_iter.outfile << endl << endl;
|
||||
cout << ">>\t";
|
||||
for (auto scmd_iter: cmd_iter.vargs) {
|
||||
cout << "\"" << scmd_iter << "\" ";
|
||||
}
|
||||
cout << endl << endl;
|
||||
}
|
||||
cout << "-----------------------------" << endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
command *parse(vector<string> args) {
|
||||
command *parseinfo = new command();
|
||||
bool in_flag = false, out_flag = false, piping_flag = false;
|
||||
vector<string> cmd;
|
||||
|
||||
for (auto it: args) {
|
||||
if (it == "<") {
|
||||
command *parsed_command = new command();
|
||||
bool in_flag = false, out_flag = false;
|
||||
simple_command *current_simple = new simple_command();
|
||||
|
||||
for (auto iter: args) {
|
||||
if (iter == "<") {
|
||||
in_flag = true;
|
||||
continue;
|
||||
}
|
||||
else if (in_flag) {
|
||||
in_flag = false;
|
||||
parseinfo->infile = it;
|
||||
current_simple->infile = iter;
|
||||
}
|
||||
|
||||
else if (it == ">") {
|
||||
else if (iter == ">") {
|
||||
out_flag = true;
|
||||
continue;
|
||||
}
|
||||
else if (out_flag) {
|
||||
out_flag = false;
|
||||
parseinfo->outfile = it;
|
||||
current_simple->outfile = iter;
|
||||
}
|
||||
|
||||
else if (it == "|") {
|
||||
piping_flag = true;
|
||||
else if (iter == "|") {
|
||||
parsed_command->cmds.push_back(*current_simple);
|
||||
delete current_simple;
|
||||
current_simple = new simple_command();
|
||||
continue;
|
||||
}
|
||||
else if (piping_flag) {
|
||||
piping_flag = false;
|
||||
parseinfo->piping = it;
|
||||
|
||||
else if (iter == args.back() && iter == "&") {
|
||||
parsed_command->background = true;
|
||||
}
|
||||
|
||||
else if (it == args.back() && it == "&") {
|
||||
parseinfo->background = true;
|
||||
else {
|
||||
current_simple->vargs.push_back(iter);
|
||||
}
|
||||
|
||||
else cmd.push_back(it);
|
||||
}
|
||||
parseinfo->args = v_to_cpp(cmd);
|
||||
return parseinfo;
|
||||
parsed_command->cmds.push_back(*current_simple);
|
||||
return parsed_command;
|
||||
}
|
||||
|
|
16
parse.h
16
parse.h
|
@ -7,13 +7,19 @@
|
|||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
// command struct
|
||||
struct command {
|
||||
char** args;
|
||||
bool background;
|
||||
string piping;
|
||||
// simple_command struct
|
||||
struct simple_command {
|
||||
vector<string> vargs;
|
||||
string infile;
|
||||
string outfile;
|
||||
int infd;
|
||||
int outfd;
|
||||
bool ispipe;
|
||||
};
|
||||
// command struct
|
||||
struct command {
|
||||
vector<simple_command> cmds;
|
||||
bool background;
|
||||
};
|
||||
|
||||
// method definitions
|
||||
|
|
14
simplesh.cc
14
simplesh.cc
|
@ -1,14 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_LENGTH 1024
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[MAX_LENGTH];
|
||||
while (1) {
|
||||
printf("simplesh$ ");
|
||||
if (!fgets(line, MAX_LENGTH, stdin)) break;
|
||||
system(line);
|
||||
}
|
||||
return 0;
|
||||
}
|
197
util_fns.cc
197
util_fns.cc
|
@ -6,7 +6,15 @@
|
|||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
// #include "util_fns.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include <wordexp.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/wait.h>
|
||||
#include "parse.h"
|
||||
#include "util_fns.h"
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
@ -38,3 +46,190 @@ char** v_to_cpp(vector<string> vargs) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void check_cmd_io(simple_command *cmd) {
|
||||
if (cmd->ispipe) {
|
||||
if (!remap_pipe_stdin_stdout(cmd->infd, cmd->outfd)) {
|
||||
// perror("dup2-remap_pipe_stdin_stdout");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (cmd->infile != "") {
|
||||
cmd->infd = open(cmd->infile.c_str(), O_RDONLY);
|
||||
if (cmd->infd < 0) {
|
||||
perror("infile");
|
||||
return;
|
||||
}
|
||||
if (dup2(cmd->infd, 0) == -1) {
|
||||
perror("dup2 infile");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else cmd->infd = 0;
|
||||
|
||||
if (cmd->outfile != "") {
|
||||
cmd->outfd = open(cmd->outfile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
|
||||
if (cmd->outfd < 0) {
|
||||
perror("outfile");
|
||||
return;
|
||||
}
|
||||
if (dup2(cmd->outfd, 1) == -1) {
|
||||
perror("dup2 outfile");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else cmd->outfd = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// http://www.gnu.org/software/libc/manual/html_node/Wordexp-Example.html
|
||||
int expand_and_execute (simple_command *cmd) {
|
||||
const char *program = cmd->vargs[0].c_str();
|
||||
char **options = v_to_cpp(cmd->vargs);
|
||||
wordexp_t result;
|
||||
pid_t pid;
|
||||
int status, i;
|
||||
|
||||
|
||||
/* Expand the string for the program to run. */
|
||||
switch (wordexp (program, &result, 0)) {
|
||||
case 0: /* Successful. */
|
||||
break;
|
||||
case WRDE_NOSPACE:
|
||||
/* If the error was WRDE_NOSPACE,
|
||||
then perhaps part of the result was allocated. */
|
||||
wordfree (&result);
|
||||
default: /* Some other error. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Expand the strings specified for the arguments. */
|
||||
for (i = 1; options[i] != NULL; i++) {
|
||||
if (wordexp (options[i], &result, WRDE_APPEND)) {
|
||||
wordfree (&result);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const char *homedir;
|
||||
if ((homedir = getenv("HOME")) == NULL) {
|
||||
homedir = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
|
||||
if (strcmp(program, "cd") == 0) {
|
||||
if (options[1]) {
|
||||
if (chdir(result.we_wordv[1]) < 0) perror("chdir");
|
||||
} else {
|
||||
if (chdir(homedir) < 0) perror("chdir");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
/* This is the child process. Execute the command. */
|
||||
// int in = 0, out = 1;
|
||||
check_cmd_io(cmd);
|
||||
|
||||
execvp (result.we_wordv[0], result.we_wordv);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
else if (pid < 0)
|
||||
/* The fork failed. Report failure. */
|
||||
status = -1;
|
||||
else
|
||||
/* This is the parent process. Wait for the child to complete. */
|
||||
if (waitpid (pid, &status, 0) != pid)
|
||||
status = -1;
|
||||
|
||||
wordfree (&result);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define DUP2CLOSE(oldfd, newfd) (dup2(oldfd, newfd) == 0 && close(oldfd) == 0)
|
||||
// http://unixwiz.net/techtips/remap-pipe-fds.c.txt
|
||||
// !!!!!!!
|
||||
bool remap_pipe_stdin_stdout(int rpipe, int wpipe) {
|
||||
/*------------------------------------------------------------------
|
||||
* CASE [A]
|
||||
*
|
||||
* This is the trivial case that probably never happens: the two FDs
|
||||
* are already in the right place and we have nothing to do. Though
|
||||
* this probably doesn't happen much, it's guaranteed that *doing*
|
||||
* any shufflingn would close descriptors that shouldn't have been.
|
||||
*/
|
||||
if ( rpipe == 0 && wpipe == 1 ) return true;
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* CASE [B] and [C]
|
||||
*
|
||||
* These two have the same handling but not the same rules. In case
|
||||
* [C] where both FDs are "out of the way", it doesn't matter which
|
||||
* of the FDs is closed first, but in case [B] it MUST be done in
|
||||
* this order.
|
||||
*/
|
||||
if ( rpipe >= 1 && wpipe > 1 ) {
|
||||
return DUP2CLOSE(rpipe, 0)
|
||||
&& DUP2CLOSE(wpipe, 1);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* CASE [D]
|
||||
* CASE [E]
|
||||
*
|
||||
* In these cases, *one* of the FDs is already correct and the other
|
||||
* one can just be dup'd to the right place:
|
||||
*/
|
||||
if ( rpipe == 0 && wpipe >= 1 )
|
||||
return DUP2CLOSE(wpipe, 1);
|
||||
|
||||
if ( rpipe >= 1 && wpipe == 1 )
|
||||
return DUP2CLOSE(rpipe, 0);
|
||||
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* CASE [F]
|
||||
*
|
||||
* Here we have the write pipe in the read slot, but the read FD
|
||||
* is out of the way: this means we can do this in just two steps
|
||||
* but they MUST be in this order.
|
||||
*/
|
||||
if ( rpipe >= 1 && wpipe == 0 ) {
|
||||
return DUP2CLOSE(wpipe, 1)
|
||||
&& DUP2CLOSE(rpipe, 0);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* CASE [G]
|
||||
*
|
||||
* This is the trickiest case because the two file descriptors are
|
||||
* *backwards*, and the only way to make it right is to make a
|
||||
* third temporary FD during the swap.
|
||||
*/
|
||||
if ( rpipe == 1 && wpipe == 0 ) {
|
||||
const int tmp = dup(wpipe); /* NOTE! this is not dup2() ! */
|
||||
|
||||
return tmp > 1
|
||||
&& close(wpipe) == 0
|
||||
&& DUP2CLOSE(rpipe, 0)
|
||||
&& DUP2CLOSE(tmp, 1);
|
||||
}
|
||||
|
||||
/* SHOULD NEVER GET HERE */
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -13,4 +13,8 @@ void ctrlCHandler(int sig);
|
|||
vector<string> split(const char *str, char c = ' ');
|
||||
char** v_to_cpp(vector<string> vargs);
|
||||
|
||||
void check_cmd_io(simple_command *cmd);
|
||||
int expand_and_execute (simple_command *cmd);
|
||||
bool remap_pipe_stdin_stdout(int rpipe, int wpipe);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue