Bir kabuk yazıyor ve boruları ve IO'ları uygulamak zorundayım. Tam programı yazdım ve yönlendirmeler çalışıyor. Bir komutun çıktısını bir dosyaya yazabilirim ve bir dosyadan bir komut için girdiyi okuyabilirim. Boruları uygulamakta gerçekten çok zorlanıyorum.Küçük kabukta boruların uygulanması
/bin/ls | /usr/bin/sort
gibi bir komutu alabilmem gerekiyor. Bu, /bin/ls
çıktısını almalı ve /usr/bin/sort
'a girdi olarak sağlamalıdır. Yukarıdaki komutu çalıştığınızda alıyorum bu:
ls: |: No such file or directory
/usr/bin/sort
Daha önce belirtildiği gibi, tek tek bu görevi başarmak mümkün.
Kodum:
/*
* eval - Evaluate the command line that the user has just typed in
*
* If the user has requested a built-in command (quit, jobs, bg or fg)
* then execute it immediately. Otherwise, fork a child process and
* run the job in the context of the child. If the job is running in
* the foreground, wait for it to terminate and then return. Note:
* each child process must have a unique process group ID so that our
* background children don't receive SIGINT (SIGTSTP) from the kernel
* when we type ctrl-c (ctrl-z) at the keyboard.
*/
void eval(char *cmdline) {
int bg; // Background or foreground
struct cmdline_tokens cmd_tokens; // Command line tokens
pid_t pid; // Processing ID
int fd; // File discriptor
int oldfd; // Temp file discriptor
struct job_t *pjob; // Job pointer
sigset_t sigchld_mask; // SIGCHLD mask
sigset_t sigint_mask; // SIGINT mask
sigset_t sigtstp_mask; // SIGTSTP mask
/* Initializing Masks */
if (sigemptyset(&sigchld_mask)) {
unix_error("main: sigemptyset error");
exit(1);
}
if (sigaddset(&sigchld_mask, SIGCHLD)) {
unix_error("main: sigaddset error");
exit(1);
}
if (sigemptyset(&sigint_mask)) {
unix_error("main: sigemptyset error");
exit(1);
}
if (sigaddset(&sigint_mask, SIGINT)) {
unix_error("main: sigaddset error");
exit(1);
}
if (sigemptyset(&sigtstp_mask)) {
unix_error("main: sigemptyset error");
exit(1);
}
if (sigaddset(&sigtstp_mask, SIGTSTP)) {
unix_error("main: sigaddset error");
exit(1);
}
bg = parseline(cmdline, &cmd_tokens) + 1;
if (bg == 0 || cmd_tokens.argv[0] == NULL) {
// If line is empty, i.e., there are no arguments
return;
}
if (!builtin_cmd(cmd_tokens)) {
if (addjob(jobs, 1, bg, cmdline)) {
// If job list is not full
// TODO: find tutorial link and add here
if (sigprocmask(SIG_BLOCK, &sigchld_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if (sigprocmask(SIG_BLOCK, &sigint_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if (sigprocmask(SIG_BLOCK, &sigtstp_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if ((pid = fork()) == 0) {
if (sigprocmask(SIG_UNBLOCK, &sigchld_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if (sigprocmask(SIG_UNBLOCK, &sigint_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if (sigprocmask(SIG_UNBLOCK, &sigtstp_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if (setpgid(0, 0)) { // Set group ID
unix_error("eval: setpgid error");
exit(1);
}
oldfd = 0;
if (cmd_tokens.infile) {
fd = open(cmd_tokens.infile, O_RDONLY, 0);
dup2(fd, STDIN_FILENO);
}
if (cmd_tokens.outfile) {
oldfd = open(cmd_tokens.outfile, O_RDONLY, 0);
dup2(STDOUT_FILENO, oldfd);
fd = open(cmd_tokens.outfile, O_WRONLY, 0);
dup2(fd, STDOUT_FILENO);
}
if (execve(cmd_tokens.argv[0], cmd_tokens.argv, environ) < 0) {
if (oldfd) {
dup2(oldfd, STDOUT_FILENO);
}
printf("%s: Command not found\n", cmd_tokens.argv[0]);
exit(0);
}
}
if (nextjid == 1) {
pjob = getjobjid(jobs, MAXJOBS);
} else {
pjob = getjobjid(jobs, nextjid - 1);
}
pjob->pid = pid;
if (sigprocmask(SIG_UNBLOCK, &sigint_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if (sigprocmask(SIG_UNBLOCK, &sigtstp_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
if (bg == FG) { // Foreground job
waitfg(pid);
} else { // Background job
printf("[%d] (%d) %s\n", pjob->jid, pjob->pid, pjob->cmdline);
}
if (sigprocmask(SIG_UNBLOCK, &sigchld_mask, NULL)) {
unix_error("eval: sigprocmask error");
exit(1);
}
} else {
printf("eval: addjob error\n");
}
}
return;
}
/*
* parseline - Parse the command line and build the argv array.
*
* Parameters:
* cmdline: The command line, in the form:
*
* command [arguments...] [< infile] [> oufile] [&]
*
* cmd_tokens: Pointer to a cmdline_tokens structure. The elements of this
* structure will be populated with the parsed tokens. Characters
* enclosed in single or double quotes are treated as a single
* argument.
* Returns:
* 1: if the user has requested a BG job
* 0: if the user has requested a FG job
* -1: if cmdline is incorrectly formatted
*
* Note: The string elements of cmd_tokens (e.g., argv[], infile, outfile)
* are statically allocated inside parseline() and will be
* overwritten the next time this function is invoked.
*/
int parseline(const char *cmdline, struct cmdline_tokens *cmd_tokens) {
// TODO: find tutorial link and add here
/* Changing parseline to parse struct cmd_tokens */
static char array[MAXLINE]; /* holds local copy of command line */
const char delims[10] = " \t\r\n"; /* argument delimiters (white-space) */
char *buf = array; /* ptr that traverses command line */
char *next; /* ptr to the end of the current arg */
char *endbuf; /* ptr to end of cmdline string */
int is_bg; /* background job? */
int parsing_state; /* indicates if the next token is the
input or output file */
if (cmdline == NULL) {
(void) fprintf(stderr, "Error: command line is NULL\n");
return -1;
}
(void) strncpy(buf, cmdline, MAXLINE);
endbuf = buf + strlen(buf);
cmd_tokens->infile = NULL;
cmd_tokens->outfile = NULL;
/* Build the argv list */
parsing_state = ST_NORMAL;
cmd_tokens->argc = 0;
while (buf < endbuf) {
/* Skip the white-spaces */
buf += strspn (buf, delims);
if (buf >= endbuf) break;
/* Check for I/O redirection specifiers */
if (*buf == '<') {
if (cmd_tokens->infile) {
(void) fprintf(stderr, "Error: Ambiguous I/O redirection\n");
return -1;
}
parsing_state |= ST_INFILE;
buf++;
continue;
}
if (*buf == '>') {
if (cmd_tokens->outfile) {
(void) fprintf(stderr, "Error: Ambiguous I/O redirection\n");
return -1;
}
parsing_state |= ST_OUTFILE;
buf ++;
continue;
}
if (*buf == '\'' || *buf == '\"') {
/* Detect quoted tokens */
buf++;
next = strchr (buf, *(buf-1));
} else {
/* Find next delimiter */
next = buf + strcspn (buf, delims);
}
if (next == NULL) {
/* Returned by strchr(); this means that the closing
quote was not found. */
(void) fprintf (stderr, "Error: unmatched %c.\n", *(buf-1));
return -1;
}
/* Terminate the token */
*next = '\0';
/* Record the token as either the next argument or the i/o file */
switch (parsing_state) {
case ST_NORMAL:
cmd_tokens->argv[cmd_tokens->argc++] = buf;
break;
case ST_INFILE:
cmd_tokens->infile = buf;
break;
case ST_OUTFILE:
cmd_tokens->outfile = buf;
break;
default:
(void) fprintf(stderr, "Error: Ambiguous I/O redirection\n");
return -1;
}
parsing_state = ST_NORMAL;
/* Check if argv is full */
if (cmd_tokens->argc >= MAXARGS-1) break;
buf = next + 1;
}
if (parsing_state != ST_NORMAL) {
(void) fprintf(stderr,
"Error: must provide file name for redirection\n");
return -1;
}
/* The argument list must end with a NULL pointer */
cmd_tokens->argv[cmd_tokens->argc] = NULL;
if (cmd_tokens->argc == 0) /* ignore blank line */
return 1;
if (!strcmp(cmd_tokens->argv[0], "quit")) { /* quit command */
cmd_tokens->builtins = BUILTIN_QUIT;
} else if (!strcmp(cmd_tokens->argv[0], "jobs")) { /* jobs command */
cmd_tokens->builtins = BUILTIN_JOBS;
} else if (!strcmp(cmd_tokens->argv[0], "bg")) { /* bg command */
cmd_tokens->builtins = BUILTIN_BG;
} else if (!strcmp(cmd_tokens->argv[0], "fg")) { /* fg command */
cmd_tokens->builtins = BUILTIN_FG;
} else {
cmd_tokens->builtins = BUILTIN_NONE;
}
/* Should the job run in the background? */
if ((is_bg = (*cmd_tokens->argv[cmd_tokens->argc-1] == '&')) != 0)
cmd_tokens->argv[--cmd_tokens->argc] = NULL;
return is_bg;
}
ben kod örneği gerçekten büyük, ama tüm fonksiyonlar birbirine bağlanır ve çözüm bulmaktan bir yardımcı olabileceğini biliyoruz. Ayrıca kodu azaltmak için yardımcı fonksiyonlardan oluşan bir kupon bıraktım. Şu ana kadar parseline
ve eval
işlevlerine bakıyorum. eval()
işlevi, yönlendirmelerin yapıldığı yer olduğu için, buradaki boruyu uygulamaya çalışıyorum.
Bazı insanlar daha önce bu yüzden yaptım kod azaltmak için söylemişti ama bunu gerekirse, bu benim koduna ham dosyasıdır: https://cdn.rawgit.com/sukritchhabra/sc3349-cs283-winter2016/master/G4/tsh.c
(yeniden) bir MCVE oluşturma hakkında okuyunuz ([MCVE]) . Kodunuzu derleyemiyoruz, örneğin, 'struct cmdline_tokens' tanımına sahip değiliz. Gösterdiğiniz hata mesajlarından söylemek zor, ama '' 'sembolünü' ls' olarak komut adı olarak geçiyormuşsunuz gibi görünüyor ve böyle bir dosyayı bulamıyor. “Echo” Merhaba ”> '| |' 'ı deneyebilir ve ardından kabuğunuzu yeniden çalıştırabilir ve farklı bir sonuç alıp alamayacağınızı görebilirsiniz. Ve belki de ls -l |/usr/bin/sort' de. –
Bunu daha önce yaptım, ama insanlar kodun çok büyük olduğunu söylediler, bu yüzden onu düşürdüm ve yeniden yayınladım –
Oluşturduğunuz yapıların ayrıntılarını dökmek için fonksiyonlara sahip olmalısınız. ve bir komut satırı ayrıştırma bitti ve belki de ayrıştırma yapıyorsunuz. Bu tür hata ayıklama işlevleri çok değerli olabilir. Unix_error() 'işlevinizi değiştirir, böylece çıkar veya unix_error()' i çağırıp yeni bir işlev oluşturur ve çıkar. Hata işleme için kod miktarını azaltırdı. Ancak, en çok test ettiğiniz (sisteminizin hepsini kontrol etmedim) sistem çağrıları iyidir. –