#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include <unistd.h>
#include<glob.h>
#define DEMLIMS " \t\n"
struct cmd_st
{
glob_t globres;
};
//打印命令行提示
static void prompt(void)
{
printf("mysh-$ ");
}
//解析拆分linebuf并存到glob_t中
static void parse(char*linebuf,struct cmd_st* cmd)
{
char* str;
glob_t globres;
int i=0;
while(1)
{
//将输入信息按照空格回车tab分割
str=strsep(&linebuf,DEMLIMS);
if(str==NULL)
{
break;
}
//命令中存在空格连串的 例如 ls -l
if(str[0]=='\0')
{
continue;
}
//将解析到的命令追加到globres中 仅第一次不追加(原因gl_pathc和gl_pathv一开始为随机值) *优先级高于|
glob(str,GLOB_NOCHECK|GLOB_APPEND*i,NULL,&(cmd->globres));
i=1;
}
}
int main(int argc,char** agv)
{
pid_t pid;
char* linebuf=NULL;
size_t linebuf_size=0;
struct cmd_st cmd;
while(1)
{
//打印命令提示行
prompt();
//获取外部输入 返回值小于0,则函数出现错误
if(getline(&linebuf,&linebuf_size,stdin)<0)
break;
//解析外部输入
parse(linebuf,&cmd);
if(0) //外部命令
{
}
else //内部命令
{
pid=fork();
if(pid<0)
{
perror("fork()");
exit(1);
}
if(pid==0)//子进程
{
//输入的命令名找到其命令,跳转命令
execvp(cmd.globres.gl_pathv[0],cmd.globres.gl_pathv);
perror("execvp()");
exit(1);
}
else //回收子进程
{
wait(NULL);
}
}
}
exit(0);
}
~
结果展示:
book@100ask:~/tmpfile/process_basic$ make mysh
cc mysh.c -o mysh
book@100ask:~/tmpfile/process_basic$ ./mysh
mysh-$ ls
execl_date few fork0 fork1 fork2 forkwait0 mysh
execl_date.c few.c fork0.c fork1.c fork2.c forkwait0.c mysh.c
mysh-$ date
Sun Oct 27 04:10:57 EDT 2024
mysh-$ ps axf
PID TTY STAT TIME COMMAND
2 ? S 0:00 [kthreadd]
3 ? I< 0:00 \_ [rcu_gp]
4 ? I< 0:00 \_ [rcu_par_gp]
6 ? I< 0:00 \_ [kworker/0:0H-kb]
8 ? I< 0:00 \_ [mm_percpu_wq]
9 ? S 0:00 \_ [ksoftirqd/0]
10 ? I 0:18 \_ [rcu_sched]
11 ? S 0:00 \_ [migration/0]
外部命令不可实现:
mysh-$ cd
execvp(): No such file or directory
扩展,将该函数应用到用户作为其shell:
步骤1:登录root
book@100ask:~/tmpfile/process_basic$ su -
Password:
root@100ask:~#
步骤2:将mysh复制到指定目录下
root@100ask:~# cp /home/book/tmpfile/process_basic/mysh /usr/local/bin/mysh
步骤3:创建要运用这个的用户,设置密码
root@100ask:~# useradd john
root@100ask:~# passwd john
Enter new UNIX password:
步骤4:进入passwd文件 修改用户john最后的路径为mysh的路径
root@100ask:~# vim /etc/passwd
修改文件
john:x:1002:1002::/home/john:/usr/local/bin/mysh
步骤5:更改登录用户,可见mysh替代了shell但仅可使用shell内部命令
root@100ask:~# su - john
No directory, logging in with HOME=/
mysh-$ ls
bin dev initrd.img lib32 lost+found opt run srv usr vmlinuz.old
boot etc initrd.img.old lib64 media proc sbin sys var
cdrom home lib libx32 mnt root snap tmp vmlinuz
mysh-$ date
Sun Oct 27 04:21:46 EDT 2024
mysh-$