资源描述
Linux操作系统实验报告
姓名: 杨子坤
学号: 0938115
班级:09级通信2班
实验三 普通文件和目录编程
1、编写程序mycp.c,实现从命令行读入文件的复制功能,用原始文件系统调用。
程序流程如下:
程序源代码如下:
//mycp.c
//
#include<stdio.h>
#include<fcntl.h>
#include<syscalls.h>
#define PERMS 0666 //默认权限
main(int argc,char *argv[])
{
int f1,f2,n;
char buf[BUFSIZ];
if(argc!=3) //参数个数不正确
printf("Usage:cp from to\n");
if((f1=open(argv[1],O_RDONLY,0))==-1) //只读打开待复制文件
printf("cp:cannot open %s\n",argv[1]);
if((f2=creat(argv[2],PERMS))==-1) //创建目标文件,权限读写
printf("cp:cannot creat %s,mode %03o\n",argv[2],PERMS);
while((n=read(f1,buf,BUFSIZ))>0) //读取文件
if(write(f2,buf,n)!=n) //写入文件
printf("cp:write error on file %s\n",argv[2]);
return 0;
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt3 $ gcc -o mycp mycp.c
kury@kuryyang-Y471A ~/expt/expt3 $ ls
file1 mycat.c mycatf.c mycp mycp.c mycpf.c myls.c newfile.c 实验3.vsd
kury@kuryyang-Y471A ~/expt/expt3 $ ./mycp file1 filenew
kury@kuryyang-Y471A ~/expt/expt3 $ ls
file1 mycat.c mycp mycpf.c newfile.c filenew mycatf.c mycp.c myls.c 实验3.vsd
kury@kuryyang-Y471A ~/expt/expt3 $ cat file1
hello the world
kury@kuryyang-Y471A ~/expt/expt3 $ cat filenew
hello the world
可见在终端中用./mycp file1 filenew实现了把文件file1复制到文件filenew的功能,和cp命令所实现的功能一样。
2、编写程序mycat.c,实现文件内容的显示,用原始文件系统调用实现。
程序流程如下:
程序源代码如下:
//mycat.c
//
#include<stdio.h>
#include<fcntl.h>
main(int argc,char *argv[])
{
int f1,n;
char buf[BUFSIZ]; //存放读取的信息
if(argc==1||argc>2) //输入参数个数不正确
{
printf("enter the right file name\n");
exit(0);
}
else if((f1=open(argv[1],O_RDONLY,0))==-1) //打开文件
printf("cat:cannot open %s\n",argv[1]);
while((n=read(f1,buf,BUFSIZ))>0) //读文件
puts(buf); //输出读取的长度
}
运行结果:
在终端中运行命令./mycat file1输出file1的内容
kury@kuryyang-Y471A ~/expt/expt3 $ gcc -o mycat mycat.c
kury@kuryyang-Y471A ~/expt/expt3 $ ./mycat file1
hello the world
3、用流文件系统重新编写上面的程序。
(1)用流文件系统重新编写程序mycpf.c,实现从命令行读入文件的复制功能。
程序流程如下:
程序源代码如下:
//mycpf.c
//
#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
FILE*fp1,*fp2;
char ch;
if(argc==1) //输入参数个数不正确
{
printf("have not enter file name,press any key exit\n");
getchar(); //输入一个字符,缓冲
exit(0);
}
if((fp1=fopen(argv[1],"r"))==NULL) //只读方式打开待复制的文件
{
printf("Cannot open %s\n",argv[1]);
getchar();
exit(1);
}
if(argc==2) //参数不正确缺少目标文件
{
printf("have not enter dest file name,press any key exit\n");
getchar();
exit(0);
}
else if((fp2=fopen(argv[2],"w+"))==NULL) //创建目标文件,读写允许
{
printf("Cannot open %s\n",argv[2]);
getchar();
exit(1);
}
while((ch=fgetc(fp1))!=EOF) //读取文件内容
fputc(ch,fp2); //输出文件内容
fclose(fp1); //关闭文件
fclose(fp2);
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt3 $ gcc -o mycpf mycpf.c
kury@kuryyang-Y471A ~/expt/expt3 $ ls
file3 mycat.c mycp mycpf myls.c 实验3.vsd mycat mycatf.c mycp.c mycpf.c newfile.c
kury@kuryyang-Y471A ~/expt/expt3 $ ./mycpf file3 filenew1
kury@kuryyang-Y471A ~/expt/expt3 $ ls
file3 mycat mycatf.c mycp.c mycpf.c newfile.c filenew1 mycat.c mycp mycpf myls.
kury@kuryyang-Y471A ~/expt/expt3 $ cat file3
this is a demo
kury@kuryyang-Y471A ~/expt/expt3 $ cat filenew1
this is a demo
(2)用流文件系统重新编写程序mycatf.c,实现文件内容的显示。
程序流程如下:
程序源代码如下:
//mycatf.c
//
#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
FILE *fp;
char ch;
if(argc!=2)
{
printf("please enter legal file name\n");
exit(0);
}
else if((fp=fopen(argv[1],"r"))==NULL) //打开文件
{
printf("Cannot open %s\n",argv[1]);
getchar(); //暂停,输入一个字符
exit(1);
}
ch=fgetc(fp); //读文件
while(ch!=EOF)
{
putchar(ch); //如果不为结尾则输出文件内容
ch=fgetc(fp);
}
fclose(fp);
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt3 $ gcc -o mycatf mycatf.c
kury@kuryyang-Y471A ~/expt/expt3 $ ./mycatf file3
this is a demo
kury@kuryyang-Y471A ~/expt/expt3 $ cat file3
this is a demo
4、调用目录函数,编写程序myls.c,实现按下面格式显示当前目录文件列表:
文件名 文件大小 文件创建时间
注意研究文件创建时间的转换,以及asctime()函数和ctime()函数的用法。
程序流程如下:
程序源代码如下:
//myls.c
//
#include<stdio.h>
#include<stddef.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include <string.h>
#include <time.h>
#include<stdlib.h>
int main()
{
DIR *dp;
struct dirent *ep; //目录操作
struct stat st; //文件目录操作符号相关
dp=opendir("./"); //打开当前目录
if(dp!=NULL)
{
while(ep=readdir(dp)) //目录非空
if(stat(ep->d_name,&st) != -1) //目录下文件名读取
{
print_file_info(ep,st);//自定义返回信息的函数
}
closedir(dp);
}
else
puts("Couldn't open the directory.\n");
return 0;
}
int print_file_info(struct dirent *ep,struct stat st) //结构体作为参数
{
printf("%s",ep->d_name);//输出文件名
printf(" ");
printf("%ld",st.st_size);//输出文件大小(字节)
printf(" ");
char str[50];
strcpy(str,ctime(&(st.st_mtime)));//数组保存创建时间
str[strlen(str)-1] = ' ';
printf("%s",str);
putchar('\n');
return 0;
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt3 $ gcc -o myls myls.c
kury@kuryyang-Y471A ~/expt/expt3 $ ./myls
myls.c 1125 Sun Dec 25 23:12:24 2011
myls 7591 Sun Dec 25 23:09:58 2011
mycpf.c 916 Sun Dec 25 23:03:32 2011
.. 4096 Sun Dec 25 23:12:15 2011
mycatf.c 604 Sun Dec 25 23:07:56 2011
mycp.c 729 Sun Dec 25 22:50:41 2011
. 4096 Sun Dec 25 23:12:24 2011
mycat.c 527 Sun Dec 25 22:55:41 2011
kury@kuryyang-Y471A ~/expt/expt3 $ ls -l
总用量 28
-rw------- 1 kury kury 527 2011-12-25 22:55 mycat.c
-rw------- 1 kury kury 604 2011-12-25 23:07 mycatf.c
-rw------- 1 kury kury 729 2011-12-25 22:50 mycp.c
-rw------- 1 kury kury 916 2011-12-25 23:03 mycpf.c
-rwxrwxr-x 1 kury kury 7591 2011-12-25 23:09 myls
-rw------- 1 kury kury 1125 2011-12-25 23:12 myls.c
可见程序myls能够实现和命令ls –l相似的功能,输出了文件名称、文件大小和创建时间。
实验四 进程实验
1、编写程序,显示所有环境变量的名称和值。
程序流程如下:
程序源代码如下:
//disp.c
//
#include<stdio.h>
#include<unistd.h>
extern char**environ; //声明environ,包含全部环境变量
int main()
{
char **var;
for(var=environ;*var!=NULL;++var) //非结尾则输出
printf("%s\n",*var);
return 0;
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt4 $ gcc -o disp disp.c
kury@kuryyang-Y471A ~/expt/expt4 $ ./disp
SSH_AGENT_PID=1695
GPG_AGENT_INFO=/tmp/keyring-3oBkz7/gpg:0:1
TERM=xterm
SHELL=/bin/bash
XDG_SESSION_COOKIE=c45faa0e8077e59244872ea40000000c-1324827323.847396-1717228196
WINDOWID=54525956
GNOME_KEYRING_CONTROL=/tmp/keyring-3oBkz7
GTK_MODULES=canberra-gtk-module:canberra-gtk-module
USER=kury
LIBGL_DRIVERS_PATH=/usr/lib/fglrx/dri
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
SSH_AUTH_SOCK=/tmp/keyring-3oBkz7/ssh
USERNAME=kury
DEFAULTS_PATH=/usr/share/gconf/gnome-shell.default.path
SESSION_MANAGER=local/kuryyang-Y471A:@/tmp/.ICE-unix/1641,unix/kuryyang-Y471A:/tmp/.ICE-unix/1641
XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome-shell:/etc/xdg
PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
DESKTOP_SESSION=gnome-shell
LC_MESSAGES=zh_CN.UTF-8
QT_IM_MODULE=xim
LC_COLLATE=zh_CN.UTF-8
PWD=/home/kury/expt/expt4
XMODIFIERS=@im=ibus
GNOME_KEYRING_PID=1630
LANG=zh_CN.UTF-8
MANDATORY_PATH=/usr/share/gconf/gnome-shell.mandatory.path
GDMSESSION=gnome-shell
SHLVL=1
HOME=/home/kury
LANGUAGE=zh_CN:en
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=kury
XDG_DATA_DIRS=/usr/share/gnome-shell:/usr/share/gnome:/usr/local/share/:/usr/share/
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-cg20lZ5Qfe,guid=d4da4f5a736bef065010f00a0000002b
LC_CTYPE=zh_CN.UTF-8
DISPLAY=:0.0
XDG_CURRENT_DESKTOP=GNOME
GTK_IM_MODULE=xim
COLORTERM=gnome-terminal
XAUTHORITY=/home/kury/.Xauthority_=./disp
OLDPWD=/home/kury/expt
如上,程序列出了所有的环境变量。
*2、编写程序,模仿讲义上的mysystem程序,实现输入命令的执行。
程序流程如下:
程序源代码如下:
//mysystem.c
//实现输入命令的执行,命令长度超过一个字符串就用 "xxx"
#include<stdio.h>
#include<stdlib.h>
#include<stddef.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#define SHELL "/bin/sh"
int mysystem(const char*command)
{
int status;
pid_t pid;
pid=fork();
if(pid==0) //子进程,执行命令
{
execl(SHELL,SHELL,"-c",command,NULL);
_exit(EXIT_FAILURE);
}
else if(pid<0) //创建子进程失败
status=-1;
else if(waitpid(pid,&status,0)!=pid) //等待子进程结束
status=-1;
return status;
}
int main(int argc,char *argv[])
{
mysystem(argv[1]); //第二个参数为命令
return 0;
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt4 $ gcc -o mysystem mysystem.c
kury@kuryyang-Y471A ~/expt/expt4 $ ./mysystem ls
disp.c mysystem mysystem.c
kury@kuryyang-Y471A ~/expt/expt4 $ ./mysystem pwd
/home/kury/expt/expt4
kury@kuryyang-Y471A ~/expt/expt4 $ ./mysystem "ls -a"
. .. disp.c mysystem mysystem.c
实验五 命名管道实验
1、研究mkfifo命令,在当前目录下创建一个myfifo的命名管道。
在终端中的运行结果:
kury@kuryyang-Y471A ~/expt/expt5 $ mkfifo --help
用法:mkfifo [选项]... 名称...
以指定的名称创建先进先出文件(FIFO)。
长选项必须使用的参数对于短选项时也是必需使用的。
-m, --mode=模式 设置权限模式(类似chmod),而不是rwxrwxrwx 减umask
-Z, --context=CTX 将每个创建的目录的SELinux 安全环境设置为CTX
--help 显示此帮助信息并退出
--version 显示版本信息并退出
kury@kuryyang-Y471A ~/expt/expt5 $ ls
mkfifo.c server1.c server.c
kury@kuryyang-Y471A ~/expt/expt5 $ mkfifo myfifo
kury@kuryyang-Y471A ~/expt/expt5 $ mkfifo myfifo1 -m777
kury@kuryyang-Y471A ~/expt/expt5 $ ls
mkfifo.c myfifo myfifo1 server1.c server.c
2、用mkfifo()函数实现相同的功能。
程序流程如下:
程序源代码如下:
//mkfifo.c
//
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#define FIFO "./fifo_channel" //当前目录下创建管道
int main(int argc,char* argv[])
{
int d;
d=mkfifo(FIFO,0777); //创建管道
if(d==-1){
perror("cannot creat FIFO channel\n");
return 1;
}
return 0;
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt5 $ ls
mkfifo.c server1.c server.c
kury@kuryyang-Y471A ~/expt/expt5 $ gcc -o mkfifo mkfifo.c
kury@kuryyang-Y471A ~/expt/expt5 $ ./mkfifo
kury@kuryyang-Y471A ~/expt/expt5 $ ls
fifo_channel mkfifo mkfifo.c server1.c server.c
3、编写一个服务器程序server.c,实现从管道myfifo中读取内容,并在终端中显示出来。打开命令行终端,运行server,然后打开另一个命令行终端,使用“cp 文件1 myfifo”命令把文件1的内容输出到myfifo,测试server的功能。
程序流程如下:
程序源代码如下:
//server.c
//
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#define FIFO "./FIFO_channel1" //默认管道
int main(int argc,char* argv[])
{
int fd,d;
char buffer[BUFSIZ];
unlink(FIFO); //删除已经存在的管道
d=mkfifo(FIFO,0666); //创建FIFO管道
if(d==-1){
perror("cannot creat FIFO channel\n");
return 1;
}
fd=open(FIFO,O_RDONLY); //打开管道
if(fd==-1){
perror("cannot open the FIFO");
}
//从管道读取信息
if(read(fd,buffer,BUFSIZ)==-1){
perror("process cannot read data from FIFO");
return 1;
}
else
printf("Receive message from FIFO:\n%s",buffer);//收到信息
return 0;
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt5 $ gcc -o server server.c
kury@kuryyang-Y471A ~/expt/expt5 $ ./server
另一终端执行kury@kuryyang-Y471A ~/expt/expt5 $ cp hello FIFO_channel1
kury@kuryyang-Y471A ~/expt/expt5 $ ./server
Receive message from FIFO:
hello the world
4、编写客户机程序,实现把指定文件输出到myfifo的功能,从而实现和服务器程序的通信。测试该程序的功能。
程序流程如下:
程序源代码如下:
//server1.c
//向管道中写入数据,在另一个进程中读取信息测试
//
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define FIFO "./FIFO_channel1"
int main(int argc,char* argv[])
{
int fd,fd1;
int count;
char buffer[BUFSIZ];
if(argc!=2){
printf("Command: %s filename\n",argv[0]);
return 1;
}
//打开命名管道写入数据
fd=open(FIFO,O_WRONLY);
if(fd==-1){
perror("cannot open the FIFO");
}
//打开要写入的文件
if((fd1=open(argv[1],O_RDONLY))==-1){
perror("cannot open the file\n");
return 1;
}
count=read(fd1,buffer,BUFSIZ);
//向管道中写入数据
if(write(fd,buffer,BUFSIZ)==-1){
perror("process cannot write data to FIFO");
return 1;
}
else
printf("send message: \n%s",buffer);
return 0;
}
运行结果:
在当前终端下:
kury@kuryyang-Y471A ~/expt/expt5 $ mkfifo FIFO_channel1
kury@kuryyang-Y471A ~/expt/expt5 $ gcc -o server1 server1.c
kury@kuryyang-Y471A ~/expt/expt5 $ ./server1 hello
另一终端下:
kury@kuryyang-Y471A ~/expt/expt5 $ ./server
Receive message from FIFO:
hello the world
当前终端:
kury@kuryyang-Y471A ~/expt/expt5 $ ./server1 hello
send message:
hello the world
由于第一个程序server.c存在缺陷,没有信号进入管道的时候,管道阻塞从而不能读取,所以只有在打开server.c程序之后再运行server1.c写管道,才能读,从而返回正确的发送结果。
实验六 信号实验
1、研究kill命令,掌握通过kill命令发送信号的方法。
在终端中运行结果:
kury@kuryyang-Y471A ~/expt/expt6 $ ps a
PID TTY STAT TIME COMMAND
1149 tty4 Ss+ 0:00 /sbin/getty -8 38400 tty4
1152 tty5 Ss+ 0:00 /sbin/getty -8 38400 tty5
1162 tty2 Ss+ 0:00 /sbin/getty -8 38400 tty2
1163 tty3 Ss+ 0:00 /sbin/getty -8 38400 tty3
1165 tty6 Ss+ 0:00 /sbin/getty -8 38400 tty6
1197 tty7 Rs+ 0:09 /usr/bin/X :0 -auth /var/run/lightdm/root/:0 -noliste
1520 tty1 Ss+ 0:00 /sbin/getty -8 38400 tty1
2101 pts/0 Ss 0:00 bash
2181 pts/1 Ss+ 0:00 bash
2232 pts/0 R+ 0:00 ps a
kury@kuryyang-Y471A ~/expt/expt6 $ kill -9 2181
kury@kuryyang-Y471A ~/expt/expt6 $ ps a
PID TTY STAT TIME COMMAND
1149 tty4 Ss+ 0:00 /sbin/getty -8 38400 tty4
1152 tty5 Ss+ 0:00 /sbin/getty -8 38400 tty5
1162 tty2 Ss+ 0:00 /sbin/getty -8 38400 tty2
1163 tty3 Ss+ 0:00 /sbin/getty -8 38400 tty3
1165 tty6 Ss+ 0:00 /sbin/getty -8 38400 tty6
1197 tty7 Rs+ 0:09 /usr/bin/X :0 -auth /var/run/lightdm/root/:0 -noliste
1520 tty1 Ss+ 0:00 /sbin/getty -8 38400 tty1
2101 pts/0 Ss 0:00 bash
2233 pts/0 R+ 0:00 ps a
可以看出,使用kill命令把进程号为2181的一个bash进程杀死了。
2、编写程序,通过定义信号处理函数来截获user消息。在消息处理函数中,设置标志变量,测主程序中通过系统调用pause()等待消息,如果消息是user,则在终端上显示消息。打开命令行窗口,运行这个程序。
程序流程如下:
程序源代码如下:
//getmysig.c
//
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
volatile sig_atomic_t m =0; //消息标志位
void sigusr(int signal)
{
m=1;
printf("Got the SIGUSR1 signal.\n");
printf("The label is:%d\n",m);
exit(0);
}
int main(void)
{
if(signal(SIGUSR1,sigusr)==SIG_ERR) //信号处理
{
perror("cannot reset the SIGUSR1 signal handler");
return 1;
}
printf("Waitting signal from user...\n");
printf("The label is:%d\n",m);
pause(); //等待消息信号
return 0;
}
运行结果:
kury@kuryyang-Y471A ~/expt/expt6 $ gcc -o getmysig getmysig.c
kury@kuryyang-Y471A ~/expt/expt6 $ ./getmysig
Waitting signal from user...
The label is:0
可以看出,该进程没有接收到消息信号的时候在等待状态,打印出标志位为原始值。
3、打开命令行窗口,通过ps命令获得2中程序的进程号,用kill命令给该进程发送user消息,观察其输出
运行结果:
终端2:
kury@kuryyang-Y471A ~ $ ps a
PID TTY STAT TIME COMMAND
1149 tty4 Ss+ 0:00 /sbin/getty -8 38400 tty4
1152 tty5 Ss+ 0:00 /sbin/gett
展开阅读全文