练习题:实现伪终端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pwd.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>
// 读取一行输入,移除末尾的换行符
char* getLine(char* buf, int size) {
fgets(buf, size, stdin);
int len = strlen(buf);
if (buf[len - 1] == '\n') {
buf[len - 1] = 0; // 替换换行符为字符串结束符
}
return buf; // 返回修改后的字符串
}
int main(int argc, const char *argv[]) {
while (1) { // 死循环,直到程序被外部方式终止
int retval = fork(); // 创建子进程
if (retval > 0) {
wait(0); // 父进程等待子进程结束
} else if (retval == 0) { // 子进程分支
char* username = getlogin(); // 获取当前登录用户名
char hostname[64] = {0};
char pwd[128] = {0};
gethostname(hostname, 64); // 获取主机名
getcwd(pwd, 128); // 获取当前工作目录
// 打印提示符
printf("\033[1;32;10m%s@%s\033[0m:\033[1;34;10m%s\033[0m$ ", username, hostname, pwd);
fflush(stdout); // 清空输出缓冲区,确保提示符立即显示
char* arg[20] = {0}; // 分配命令参数数组
char cmd[128] = {0}; // 存储用户输入的命令
getLine(cmd, 128); // 读取用户输入的命令
char* token = NULL;
int i = 0;
do {
if (token == NULL) {
token = strtok(cmd, " "); // 首次调用strtok
} else {
token = strtok(NULL, " "); // 后续调用strtok
}
arg[i++] = token; // 将token添加到参数数组中
} while (token != NULL); // 循环直到没有更多token
// 特殊处理cd命令
if (strcmp(arg[0], "cd") == 0) {
if (arg[1] != NULL) { // 确保有cd的目标目录
chdir(arg[1]); // 改变工作目录
}
} else {
execvp(arg[0], arg); // 执行用户命令
// 如果execvp返回,说明命令未找到或出错
perror("execvp failed"); // 打印错误信息
}
// 注意:这里没有返回语句,因为execvp在成功时不会返回
// 如果execvp失败,子进程会执行到这里,但通常我们会希望终止它
// 可以通过exit(EXIT_FAILURE)来退出子进程
exit(EXIT_FAILURE);
} else {
// fork失败的情况
perror("fork failed");
exit(EXIT_FAILURE);
}
}
return 0;
}