linux-programming-note-8(POSIX IPC)

<本笔记基于《LINUX编程技术详解》(人民邮电出版社)>
Author:tunpishuang (tunpishuang at gmail dot com)
Chapter 11-------POSIX IPC
使用信号传递的信息有限
使用管道只能传输“无格式的字节流”?-->不理解
AT&T发行的system V 引入3种新的进程间通信(IPC)
分别是:消息队列,共享内存,信号量

linux-programming-note-7(-管道与命名管道(pipe and named pile))

<本笔记基于《LINUX编程技术详解》(人民邮电出版社)>
Author:tunpishuang (tunpishuang at gmail dot com)
Chapter 10-------管道与命名管道(pipe and name pile)
管道在某个时刻只能单项传输数据,成为半双工模式,(全双工是发送的同时可以接收数据)
图:
进程A______写入数据______->管道_____读取数据____->进程B
管道只能再父子和兄弟进程间创建,之外的进程可以使用命名管道和消息队列。
piplle()
header	<unistd.h>
synopsis	int pipe(int filedes[2]);
return	suc:0	fail:-1	errno:yes
fildes[0]用于读取管道数据,fildes[1]用于往管道写入数据
eg:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char* argv[])
{
	int f_des[2];
	int pid;
	char msg[BUFSIZ];
	if(argc!=2)
	{
		printf("usage:%s message\n",argv[0]);
		return 1;
	}
	if(pipe(f_des)==-1) {perror("cannot create the IPC pipe\n"); return 1;}
	pid=fork();
	if(pid==-1) {perror("cannot create new process\n"); return 1;}
	else if(pid==0)
	{
		close(f_des[1]);
		if(read(f_des[0],msg,BUFSIZ)==-1)
		{
			perror("child process cannot read the data from pipe\n");
			return 1;
		}else printf("in child process, receive message: %s\n",msg);
		_exit(0);
	}else 	{
			close(f_des[0]);
			if(write(f_des[1],argv[1],strlen(argv[1]))==-1)
			{
				perror("parent process cannot wirte data to pipe\n");
				return 1;
			}else printf("int parent process ,send message %s\n",argv[1]);
			wait(NULL);
			_exit(0);
		}
	return 0;
}
-----------------------------------
使用管道实现进程间的双向通信
#include <stdio.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
	int f_des[2];
	int pid;
	if(argc!=3) {printf("usage: %s cmd1 cmd2\n",argv[0]);	return 1;}
	if(pipe(f_des)==-1) {perror("cannto create the IPC pipe\n"); return 1;}
	pid=fork();
	if(pid==-1)
	{
		perror("fork failed\n");
		return 1;
	}else if(pid==0)
	{
		dup2(f_des[1],STDOUT_FILENO);
		close(f_des[0]);
		close(f_des[1]);
		if(execlp(argv[1],argv[1],NULL)==-1)
		{
			perror("in child process,cannot execute the command\n");
			return 1;
		}
		return 1;
	}else
	{
		dup2(f_des[0],STDIN_FILENO);
		close(f_des[0]);
		close(f_des[0]);
		if(execlp(argv[2],argv[2],NULL)==-1)
		{
			perror("in parent process,cannot execute the command\n");
			return 1;
		}
		return 1;
	}
	return 0;
}
----------------------------------------./pipe3 ls less测试
popen()创建管道,比pipe,fork,dup2,exec的联合使用简单
header		<stdio.h>
synopsis	FILE *poen(const char *command,const char *type);
return		suc:指向FILE的指针	fail:NULL	errno:Yes
pclose()	关闭popen获得执行FILE的指针
stream=popen(command,"r") 子进程STDOUT_FILENO数据写入父进程文件流stream
stream=popen(command,"w") 文件流stream中的数据写入子进程STDIN_FILENO
pclose()
header		<stdio.h>
synopsis	int pclose(FILE *stream);
return		suc:命令退出状态	fail:-1	errno:yes
eg:
#include <stdio.h>
#include <unistd.h>
int main()
{
	FILE* fs=popen("sort","w");
	if(fs=NULL)
	{
		perror("popen failed\n");
		return 1;
	}
	fprintf(fs,"test1\n");
	fprintf(fs,"test2\n");
	fprintf(fs,"test3\n");
	pclose(fs);
	return 0;
}
---------------------------------------运行后segmentation fault段错误,?
shell管道重定向程序的再实现
stream=popen(argv[1],"r")-->stream-->stream=popen(argv[2],"w")
#include <stdio.h>
#include <unistd.h>
#define BUFFER_SIZE 300
int main(int argc,char* argv[])
{
	FILE* stream_in,stream_out;
	int nLen;
	char buffer[BUFFER_SIZE];
	if(argc!=3)
	{
		printf("usage: %s cmd1 cmd2\n",argv[0]);
		return 1;
	}
	stream_in=popen(argv[1],"r");
	if(stream_in==NULL)
	{
		perror("call popen function fail\n");
		return 1;
	}
	fflush(stream_out);
	nLen=read(fileno(stream_in),buffer,PIPE_BUF);
	while(nLen>0)
	{
		write(fileno(stream_out),buffer,nLen);
		nLen=read(fileno(stream_in),buffer,PIPE_BUF);
	}
	pclose(stream_in);
	pclose(stream_out);
	return 0;
}
-----------------------------没有编译成功,应该是某个头文件未包含,但不知道是哪个,
output:incompatible type for argument 1 of 'fileno' 'pclose' 'fflush'
PIPE_BUF也没有定义,晕死。
命名管道----非亲缘关系的进程间的通信。
命名管道,也被成为FIFO(first in,first out),特殊设备文件,通过open,close打开关闭,
写入的数据会加在末尾,从开始位置读取数据,写入FIFO设备并没有写入文件系统。
在shell中创建命名管道
1:使用mknod /mkfifo创建FIFO文件
mknod用于在文件系统上创建特殊特备文件
mknod /tmp/fifo_nod p 和mkfifo /tmp/fifo_mkfifo功能一样
例如:
ls / >/tmp/fifo &  //把ls的输出转到/tmp/fifo管道文件
cat < /tmp/fifo    //把/tmp/fifo通过cat输出
ls一直阻塞直到有进程向管道读取数据,
--------------
mkfifo()
	mknod()容易在nfs上出问题,不推荐使用mkmod()
header		<sys/types.h>
		<sys/stat.h>
synopsis	int mkfifo(const char *pathname,mode_t mode);
return	 	suc:0		fail:-1	errno:yes
pathname:指定创建出的FIFO文件名称,
读取FIFO后,没有写入,阻塞
写入FIFO后,没有读取,阻塞
eg:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define FIFO_CHANNEL "/tmp/fifo.channel"
int main(int argc,char* argv[])
{
	int fd,pid;
	char r_msg[BUFSIZ];
	char* s_msg="send message to other process";
	if(argc!=2)
	{
		printf("usage:%s option (read-2/write-1)\n",argv[0]);
		return 1;
	}
	if(atoi(argv[1])==1)
	{
		if(mkfifo(FIFO_CHANNEL,0777)==-1)
		{
			perror("cannot create FIFO channel\n");
			return 1;
		}
		fd=open(FIFO_CHANNEL,O_WRONLY);
		if(fd==-1)
		{
			perror("cannot open FIFO\n");
			return 1;
		}else printf("send message: %s \n",s_msg);
	}
	if(atoi(argv[1])==2)
	{
		fd=open(FIFO_CHANNEL,O_RDONLY);
		if(fd==-1)
		{
			perror("cannot open the FIFO\n");
			return 1;
		}
		if(read(fd,r_msg,BUFSIZ)==-1)
		{
			perror("process cannot read data from FIFO\n");
			return 1;
		}else printf("receive message from FIFO:%s\n",r_msg);
	}
	return 0;
}
----------------------------------END

linux-programming-note-6(基本进程间通信方法)

<本笔记基于《LINUX编程技术详解》(人民邮电出版社)>
Author:tunpishuang (tunpishuang at gmail dot com)
Chapter 9-------基本进程间通信方法
控制多线程下对某个非共享资源的访问,最简单的方法是使用临时文件作为访问标志。
首先进程判断临时文件是否存在,如果存在表明有进程占用了该资源。
进程A------\
	     \|文件存在?---------资源
进程B_______/
使用文件实现进程互斥程序实例
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int get_access_right(int inq_interval,int retry_times,char* file_name)
{
	int fd,count;
	count=0;
	fd=creat(file_name,0);
	while(fd==-1 && errno==EACCES)
	{
		printf("pid:%ld process try to get access right...\n",(long)getpid());
		if(++count<retry_times)
			sleep(inq_interval);
		else	return -1;
		fd=creat(file_name,0);
	}
	close(fd);
	if(fd==-1) return 1;
	else return -1;
}
int release_right(char* file_name)
{
	int result;
	result=unlink(file_name);
	if(result==0) return 1;
	else return -1;
}
int main(int argc,char* argv[])
{
	int retry_times,inq_interval;
	char* file_name;
	int len,count=0;
	if(argc!=4)
		{
		printf("usages: %s retry_times inquire_interval file_name\n",argv[0]);
		return 1;
		}
	inq_interval=atoi(argv[2]);
	if(inq_interval<=0) {printf("illegal retry times\n"); return 1;}
	len=strlen(argv[3]);
	if(len==0) {printf("illegal file name\n");	return 1;}
	if(get_access_right(inq_interval,retry_times,argv[3])==1)
	{
		while(count<5)
		{
			printf("pid: %ld process is occupying the resource,circle %d\n",(long)getpid(),count);
			count++;
			sleep(inq_interval);
		}
		release_right(file_name);
		return 0;
	}else
	printf("pid: %ld process cannot access the resource .....retry %d times\n",(long)getpid(),retry_times);
	return 0;
}
--------------------------
使用文件作为访问资源的标志的缺陷:
1.限制了进程间信息量的传输
2.对存储器的读写的效率远远的低于内存和CPU
3.如果两个问题同时查询文件,执行结果unexpected(不可预测)
4.如果进程不稳定崩溃了而没有删除标志文件,其他进程永远可以不能访问到资源
Linux文件锁:修改文件属性来控制进程通信
fcntl()
head	<unistd.h>
	<fcntl.h>
define	int fcntl(int fd,int cmd);
	int fcntl(int fd,int cmd,long arg);
	int fcntl(int fd,int cmd,struct flock *lock);
return	suc:返回值依赖cmd参数	fail:-1	errno:yes
cmd:
F_DUPFD(复制文件描述符)		FD_CLOEXEC(文件描述符标志)	F_GETFL F_SETFL(文件状态标志)
F_GETLK / F_SETLK /F_SETLKW(非强制文件锁[advisory locking])
struct flock
{........
short l_type;  //锁类型 F_RDLCK . F_WRLCK. F_UNLCK
short l_whence;//l_start起始点 可以为SEEK_SET SEEK_CUR SEEK_END
off_t l_start; //锁的起始偏移量
off_t l_len;、、被锁定的大小
off_t l_pid;
...............
}
fcntl调用结果
参数		return
F_DUPFD		新的fd
F_GETFD		fd标志
F_GETFL		文件状态
F_GETOWN	fd所有者
其他参数		0
失败		-1
eg:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc,char* argv[])
{
	int fd;
	int file_stat;
	if(argc!=2) {printf("usage:%s filename\n",argv[0]); return 1;}
	fd=open(argv[1],O_RDONLY);
	if(fd==-1) {perror("cannot open the file\n"); return 1;}
	file_stat=fcntl(fd,F_GETFL);
	if(file_stat<0) {perror("cannot get the file status\n"); return 1;}
	switch(file_stat & O_ACCMODE)
	{
		case O_RDONLY: printf("file:%s read only\n",argv[0]); break;
		case O_WRONLY: printf("file:%s write only \n",argv[0]); break;
		case O_RDWR:  printf("file:%s Read and write\n",argv[0]); break;
		default: printf("unkown access right\n");
	}
	return 0;
}
-----------------------------------
使用fcntl实现进程互斥
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc,char* argv[])
{
	int fd,count=0;
	if(argc!=2)
	{
		printf("usage:%s lock_file_name",argv[0]);
		return 1;
	}
	struct flock lock;
	fd=open(argv[1],O_RDWR);
	if(fd<0) {perror("cannot open the file\n"); return 1;}
	lock.l_type=F_WRLCK;
	lock.l_whence=0;
	lock.l_start=0;
	while(fcntl(fd,F_SETLK,&lock)<0)
	{
		switch(errno)
		{
			case EAGAIN:
			case EACCES:
				if(++count<5)
					sleep(5);
				else
				{
					fcntl(fd,F_GETLK,&lock);
					printf("pid:%ld process find pid:%ld lock the file %s\n",(long)getpid(),(long)lock.l_pid,argv[1]);
					return 1;
				}
				continue;
		}
		perror("function fcntl call fail\n");
		return 1;
	}
	printf("pid:%ld process lock the file\n",(long)getpid());
	printf("pid:%ld process release the file\n",(long)getpid());
	return 0;
}
--------------------------------------------
lockf()是fcntl()在文件锁方面的一个简单调用,添加,检测和解除文件锁。
head	<unistd.h>
define	int lockf(int fd,int cmd,off_t len);
return	suc:0	fail:-1	errno:yes
cmd:
F_LOCK		F_TLOCK		F_ULOCK		F_TEST
eg:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc,char* argv[])
{
	int fd,lock_result;
	struct flock lock;
	if(argc!=2) {printf("usage:%s lock_file_name\n",argv[0]); return 1;}
	fd=open(argv[1],O_RDWR);
	if(fd<0) {perror("cannot open the file\n"); return 1;}
	lock_result=lockf(fd,F_LOCK,0);
	if(lock_result==-1) {perror("cannot get the lock\n"); return 0;}
	printf("pid:%ld process lock the file\n",(long)getpid());
	printf("pid:%ld process release the file\n",(long)getpid());
	return 0;
}
----------------------------
flock() 实现对文件的加锁解锁
head	<sys/file.h>
define	int flock(int fd,int operation);
return 	suc:0	fail:-1	errno:yes
operation:
LOCK_SH:设置共享锁,多个进程可同时对同一文件拥有共享锁
LOCK_EX:设置互斥锁
LOCK_UN:解除文件锁
锁定是不阻塞:LOCK_NB   eg:flock(fd,LOCk_EX|LOCK_NB)
---------------
信号:
查看Linux支持的信号:kill -l
man 7 signal
Man pages are grouped into sections. To see the full list of Linux man pages for a section, pick one of:
Section 1
    user commands (introduction)
Section 2
    system calls (introduction)
Section 3
    library functions (introduction)
Section 4
    special files (introduction)
Section 5
    file formats (introduction)
Section 6
    games (introduction)
Section 7
    conventions and miscellany (introduction)
Section 8
    administration and privileged commands (introduction)
Section L
    math library functions
Section N
    tcl functions
产生信号函数kill() raise() alarm()
Name
kill - send signal to a process
Synopsis
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
Description
The kill() system call can be used to send any signal to any process group or process.
If pid is positive, then signal sig is sent to pid.
If pid equals 0, then sig is sent to every process in the process group of the current process.
If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init), but see below.
If pid is less than -1, then sig is sent to every process in the process group -pid.
If sig is 0, then no signal is sent, but error checking is still performed.
Return Value
On success (at least one signal was sent), zero is returned. On error, -1 is returned, and errno is set appropriately.
Errors
---------------------
raise()用于给调用进程自身发送信号
head	<signal.h>
synopsis	int raise(int sig);
return	suc:0	fail:!0	errno:-   raise()等同于kill(getpid(),sig)
alarm()	定时产生SIGALRM信号
header	<unistd.h>
synopsis	unsigned int alarm(unsigned int seconds);
return	suc:不存在警告时钟返回0,存在,返回上一个警告时钟等待时间 	fail:-	errno:-
eg:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
	int pid,wait_pid,status,i;
	for(i=1;i<=5;i++)
	{
		pid=fork();
		if(pid<0) {perror("cannot create the new process\n"); return 1;}
		else if(pid==0)
		{
			printf("in child process(pid:%ld),the process will terminate in %d seconds\n",(long)getpid(),i);
			alarm(i);
			pause();
		}
	}
	while((wait_pid=wait(&status)) && wait_pid!=-1)
	{
		if(WIFSIGNALED(status)) printf("process id:%d receive SIG:%d exit\n",pid,WTERMSIG(status));
		if(WIFEXITED(status)) printf("process id:%d exit code %d\n",pid,WEXITSTATUS(status));
	}
	return 0;
}
-----------------------------------
进程对信号有3种处理方法:1.系统处理 2.忽略信号 3.捕获信号
signal()
header	<signal.h>
synopsis	typedef void  (*sighandler_t)(int);
	sighandler_t signal(int signum,sighandler_t handler);
return	suc:原来的信号处理函数	fail:SIG_ERR	errno:yes
signum:要捕获的信号值,handler指向要调用的函数指针,可以为SIG_IGN(忽略信号)SIG_DFL(标准信号)也可以是自己的处理函数
eg:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
void sigusr1(int sig)
{
	printf("got the SIGUSR1 signal\n");
	exit(0);
}
int main(void)
{
	if(signal(SIGINT,SIG_IGN)==SIG_ERR)
	{
		perror("cannot reset the SIGINT signal handler\n");
		return 1;
	}
	if(signal(SIGUSR1,sigusr1)==SIG_ERR)
	{
		perror("cannot reset the SIGUSR1 signal handler\n");
		return 1;
	}
	pause();
	return 0;
}
--------------------./signal后台运行 。对SIGINT忽略,对SIGUSR1信号输出信息,分别用kill -SIGINT  和-SIGUSR1测试结果 用jobs查看结果
sigaction() 检查,修改指定信号的处理动作
在处理小于SIGRTMIN的信号中  某些unix版本中采用函数处理后恢复成系统处理方式,所以每次处理信号后都要重新设置信号处理函数。
这个问题Linux不存在,为了代码的可移植性,采用sigaction()
header	<signal.h>
synopsis	int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact);
return	suc:0	fail:-1	errno:yes
signum为要捕获的信号,除了不能捕获的SIGKILL SIGSTOP
act:指定动作指针,oldact信号原有处理函数
struct sigaction{
	void (*sa_handler)(int);
	void (*sa_sigaction)(int,siginfo_t *,void *);
	sigset_t	sa_mask;
	int sa_flags;
	void (*sa_restorer)(void);
	}
sa_mask:用于指定进行信号处理时要屏蔽的信号值,
sa_flags用于指定响应信号时的其他行为,取值如下:
SA_NOCLDSTOP	SA_NOCLDWAIT	SA_RESETHAND	SA_RESTART	SA_NODEFER	SA_SIGINFO
sa_handler用于指定信号的处理函数,SIG_DFL	SIG_IGN
siginfo_t{
	int si_signo;
	int si_errno;
	int si_code;
	int si_pid;
	pid_t si_pid;
	uid_t si_uid;
	int si_status;
	clock_t	si_utime;
	clock_t	si_stime;
	sigval_t	si_value;
	int	si_int;
	void * si_ptr;
	void * si_addr;
	int si_band;
	int si_fd;
	}
eg:
#include <stdio.h>
#include <signal.h>
void signal_set(struct sigaction *act)
{
	switch(act->sa_flags)
	{
		case (int)SIG_DFL:
			printf("using default handler\n");
			break;
		case (int)SIG_IGN:
			printf("ignore the signal\n");
			break;
		default: printf("%0x\n",act->sa_handler);
	}
}
int main(int argc,char* argv)
{
	int i;
	struct sigaction act,oldact;
	act.sa_handler=signal_set;
	act.sa_flags=SA_NODEFER | SA_RESETHAND;
	sigaction(SIGUSR1,&act,&oldact);
	for(i=1;i<12;i++)
	{
		printf("signal %d handler is :",i);
		sigaction(i,NULL,&oldact);
		signal_set(&oldact);
	}
	return 0;
}
---------------------------------
综合实例:实现对用户邮件的自动检测
/var/mail/username 判断该文件大小,
守候进程和信号处理模块,lib.base.c
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int daemon(int nochdir,int noclose)
{
	pid_t pid;
	pid=fork();
	if(pid<0) {perror("fork\n"); return -1;}
	if(pid!=0) exit(0);
	pid=setsid();
	if(pid<-1) {perror("setpid\n"); return -1;}
	if(!nochdir) chdir("/");
	if(!noclose)
	{
		int fd;
		fd=open("/dev/null",O_RDWR,0);
		if(fd!=-1)
		{
			dup2(fd,STDIN_FILENO);
			dup2(fd,STDOUT_FILENO);
			dup2(fd,STDERR_FILENO);
			if(fd>2) close(fd);
		}
	}
	umask(0027);
	return 0;
}
void * signal_set(int signo,void(*func)(int))
{
	int ret;
	struct sigaction sig,osig;
	sig.sa_handler=func;
	sigemptyset(&sig.sa_mask);
	sig.sa_flags=0;
	#ifdef SA_RESTART
	sig.sa_flags|=SA_RESTART;
	#endif
	ret=sigaction(signo,&sig,&osig);
	if(ret<0) return (SIG_ERR);
	else return (osig.sa_handler);
}
void sigint(int sig)
{
}
void sigtstp(int sig)
{}
void signal_init()
{
	signal_set(SIGINT,sigint);
	signal_set(SIGTSTP,sigtstp);
}
----------------------------
lib.mail.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <syslog.h>
#define SLEEP_TIME 5
long get_file_size(const char* filename)
{
	struct stat status;
	long size;
	if(stat(filename,&status)==-1) {perror("cannot get the file status\n"); return -1;}
	size=status.st_size;
	return size;
}
void mail_log(const char* progname,const char* mail_pos)
{
	fprintf(stderr,"%s notice: you have new mail in %s\n",progname,mail_pos);
}
int check_mail(const char *filename,const char* progname)
{
	long old_mail_size,mail_size;
	old_mail_size=get_file_size(filename);
	if(old_mail_size==-1) return 1;
	if(old_mail_size>0) mail_log(progname,filename);
	sleep(SLEEP_TIME);
	while(1)
	{
		mail_size=get_file_size(filename);
		if(mail_size!=old_mail_size) mail_log(progname,filename);
	}
	old_mail_size=mail_size;
	sleep(SLEEP_TIME);
}
-----------------------
mail.c
#include <stdio.h>
#define USER_ACCOUNT "/var/mail/tps"
	extern void signal_init();
	extern int daemon(int nochdir,int noclose);
	int check_mail(const char *filename,const char* progname);
	int main(int argc,char* argv[])
	{
		char *p;
		int opt,daemon_mode=1;
		char* progname;
		signal_init();
		if(daemon_mode) daemon(0,1);
		check_mail(USER_ACCOUNT,argv[0]);
		return 0;
	}
-----------------------------------------------------------------END

linux-programming-note-5(进程与进程环境(proccess)

<本笔记基于《LINUX编程技术详解》(人民邮电出版社)>
Author:tunpishuang (tunpishuang at gmail dot com)
Chapter 7-------------进程与进程环境(proccess)
	|---交互进程,(给出参数后才可运行)
进程分类|
	|---批处理进程(进程序列)
	|
	|---守候进程(执行特定功能或者执行系统相关任务的后台进程)
linux采用虚拟内存管理技术,32位系统支持寻址4GB的线性地址空间。
查看虚拟内存使用情况---vmstat
进程内存结构 分为:代码段,数据段(包括初始化和未初始化),堆栈段
每个进程创建的时候,系统会分配一个进程ID给该进程,如果ID达到系统最大值(<linux/threads.h>中定义的PID_MAX),系统将从新使用最小且当前未使用的PID
查看进程---ps -aux
getpid(),getppid() 获得进程ID和父进程ID
head	<sys/types.h>
	<unistd.h>
define	pid_t getpid(void);
	pid_t getppid(void);
return	suc: pid /ppid	fail:-	set errno:yes
eg:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
	printf("current process ID:%ld\n",(long)getpid());
	printf("curren parent proccess ID:%ld\n",getppid());
	return 0;
}
--------------------------ppid是-bash
用户表识和有效用户标示(UID and EUID)
getuid() / geteuid()
head	<sys/types.h>
	<unistd.h>
define	uid_t getuid(void);
	uid_t geteuid(void);
return	suc:uid/euid	fail:-	errno:-
uid表明进程的创建者,euid表明进程对于资源和文件的访问权限。
因为修改/etc/shadow文件才能更改用户密码,所以可以通过设置euid
让/usr/bin/passwd具有rws权限,这样普通用户就可以访问root的passwd
getgid()/getegid()
head	<sys/types.h>
	<unistd.h>
define	uid_t getgid(void);
	uid_t getegid(void);
return	suc:gid/egid	fail:- 	set errno:-
-------------------------------------------
fork()  创建进程
head	<sys/types.h>
	<unistd.h>
define	pid_t fork(void);
return	suc:放回两次,如果再父进程中,返回子进程号,如果在子进程中,返回0 	fail:-1 	errno:yes
fork创建的进程为当前进程的子进程,特点:一次调用两次返回。
eg:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
	pid_t pid;
	if(pid=fork()<0) {perror("failed to create the new proccess\n"); return 1;}
	else if(pid==0) {printf("in Child proccess\n"); return 0;}
	else printf("in Parent proccess\n"); return 0;
	return 0;
}
------------------------
vfork()和fork()全部一样,除了一点:vfork创建新的进程,父子进程共享虚拟内存空间
fork和vfork的区别:
fork创建的子进程会复制所有的父进程的所有资源,而vfork不会复制,父子进程将共享地址空间,子进程对虚拟内存空间的任何修改实际上是再修改父进程虚拟内存空间内容
在使用vfork创建子进程后,父进程会被阻塞,知道子进程调用了exec或_exit函数推出 ,vfork避免了资源复制的消耗。
/*test the diff between fork() and vfork()*/
/*change vfork into fork to see the diff*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int g_var=0;
int main(void)
{
	pid_t pid;
	int var=1;
	printf("process id:%ld\n",(long)getpid());
	printf("before execute the fork system call,g_var=%d var=%d\n",g_var,var);
	if(pid=vfork()<0) {perror("cannot create new proccess\n"); return 1;}
	else if(pid==0)
	{
		g_var++;
		var++;
		printf("process id:%ld,g_var=%d var=%d\n",(long)getpid(),g_var,var);
		_exit(0);
	}
	printf("process id:%ld, g_var=%d var=%d\n",(long)getpid(),g_var,var);
	return 0;
}
----------------------------------
exec函数族 用于对创建新进程中的数据段、代码段和堆栈段进行替换。
进程调用exec后,代码段会被替换成新的代码段,同时获得新程序的数据段和堆栈段,
pid保持不变,
head 	<unistd.h>
	extern char **environ;
define	int execl(const char *path,const char *arg,...);
	int execlp(const char *file,const char *arg,...);
	int execle(const char *path,const char *arg,...,char * const envp[]);
	int execv(const char *path,char *const argv[]);
	int execve(const char *filename,char *const argv[],char *const envp[]);
	int execvp(const char *file,char *const argv[]);
return	suc:-		fail:-1		set errno:yes
l表示(list),参数可变
p表示自动搜索PATH路径
区别在于参数以及再查找可执行程序时是否使用系统路径。
eg:execlp函数使用可变参数,实现ls
#include <stdio.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
	if(argc<2) {printf("usage: %s path\n",argv[0]);	return 1;}
	execlp("/bin/ls","ls",argv[1],(char*)NULL);
	return 0;
}
----------------(char*)NULL参数结束的标志
execvp支持参数列表,具有更大的灵活性
#include <stdio.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
	if(argc<2) {printf("usage: %s arg list...\n",argv[0]);	return 1;}
	execvp(argv[1],&argv[1]);
	return 0;
}
-------------------------
exit() / _exit()  / return 的区别
exit()
head	<stdlib.h>
define	void exit(int status)
return	suc:-	fail:-	set errno:-
将返回(status &0377)给父进程,status为推出进程时的状态,父进程将获得该状态值,EXIT_SUCCESS和EXIT_FAILUR为正常结束和机场终止的两个宏。
_exit()
head	<unistd.h>
define	void _exit(int status);
return	suc:-	fail:-	errno:-
区别:
1:exit在ansi c中说明,_exit再Posix标准说明
2:_exit终止调用进程,但不关闭文件,不清除缓存,也不调用atexit注册的回调函数。
------------------
wait() 让父进程等待子进程结束
head	<sys/wait.h>
	<sys/types.h>
define	pid_t wait(int *status);
return	suc:结束的子进程pid和结束状态,fail:-1	errno:yes
wait系统调用将挂起当前进程,直到子进程结束。
kill -l查看linux系统中定义的64种信号类型。
int kill(pid_t pid,int sig);
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc,char* argv[])
{
	pid_t pid;
	int exit_code;
	pid=getpid();
	srand((unsigned)pid);
	exit_code=(int)(rand()%256);
	sleep(10);
	if(atoi(*(argv+1))%2)
	{	printf("the child process id:%d receive signal SIGKILL\n",pid);
		kill(pid,9);
	}
	else
	{
		printf("the child process id:%d normally exit,exit_code is %0x\n",pid,exit_code);
		exit(exit_code);
	}
}
--------------kill.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc,char* argv[])
{
	pid_t pid,wait_pid;
	int status;
	int i;
	if(argc<4)
		{
		printf("usage: %s para1 para2 para3 \n",argv[0]);
		return 1;
		}
	for(i=1;i<4;i++)
		if((pid=fork())==0) execl("./kill","kill",argv[i],NULL);
		else printf("create the child process id %d \n",pid);
	while((wait_pid=wait(&status))&& wait_pid!=1)
		printf("process id:%d exit,exit_code is %0x\n",wait_pid,status);
	return 0;
}
----------------kill2.c
检测退出状态的宏
WIFEXITED(status)	WEXITSTATUS(status)	WIFSIGHALED(status)	WTERMSIG(status)
WCOREDUMP(status)	WIFSTOPPED(status)	WSTOPSIG(status)	WIFCONTINUED(status)
waipid() 根据进程号等待指定的进程
head	<sys/wait.h>
	<sys/types.h>
define	pid_t waitpid(pid_t pid,int *status,int options);
return	suc:返回状态和子进程的pid	fail:-1		errno:yes
option:
WNOHANG		WUNTRACED	WCONTINUED
pid:
<-1:等待子进程,子进程所属进程组id与进程号的绝对值相等。
-1:等待所有子进程
0:等待子进程,进程组id与调用进程的组Id相等。
>0:等待指定的进程。
eg:
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
	pid_t pid,wait_pid;
	int status;
	pid=fork();
	if(pid==-1)
		{
		perror("cannot create new process\n");
		exit(1);
		}
	else if(pid==0)
		{
		printf("child process id: %ld\n",(long)getpid());
		pause();
		_exit(0);
		}
	else
		{
			do
			{
				wait_pid=waitpid(pid,&status,WUNTRACED | WCONTINUED);
				if(wait_pid==-1) {perror("cannot using waitpid function\n"); exit(1);}
				if(WIFEXITED(status)) { printf("child process exites,status=%d\n",WEXITSTATUS(status));}
				if(WIFSIGNALED(status)) {printf("child process is killed by signal %d\n",WTERMSIG(status));}
				if(WIFSTOPPED(status)) {printf("child process is stopped by signal %d\n",WSTOPSIG(status));}
				if(WIFCONTINUED(status)) printf("child process resume running ...\n");
			}while(!WIFEXITED(status) && !WIFSIGNALED(status));
		exit(0);
		}
}
------------------用&后台运行,然后kil -sig process
僵死进程(zombie process)
子进程退出后父进程没有用wait来收集子进程的状态而产生,占用进程表。
eg:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
	pid_t pid;
	pid=fork();
	if(pid<0) {perror("cannot create new process \n");	exit(1);}
	if(pid>0) sleep(60);
	else exit(0);
	return 0;
}
-----------------------------------END
Chapter 8-------------守候进程(daemon)
日志系统是记录daemon信息的手段
实现daemon的步骤
1:让init成为新产生进程的父进程
2:调用setsid函数
作用:使得新创建的进程脱离控制终端,同时创建新的进程组,并成为该进程组的首进程
setsid()
head	<unistd.h>
define	pid_t setsid(void);
return	suc:调用进程的会话id	fail:-1	set errno:yes
3:更改当前工作目录
chdir() daemon一般会将其工作目录更改到根目录下。
4:关闭文件描述符,并重定向到stdin/stdout/stderr
daemon不应该输出任何信息,定向到空设备/dev/null
.......
int fd;
fd=open("/dev/null",O_RDWR,0);
if(fd!=1)
{
	dup2(fd,STDIN_FILENO);
	dup2(fd,STDOUT_FILENO);
	dup2(fd,STDERR_FILENO);
	if(fd>2)
	  close(fd);
}
...............
5:设置daemon的文件权限创建掩码
daemon会创建临时文件,给其分配合理的权限。
daemon的具体实现:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int daemon(int nochdir,int noclose)
{
	pid_t pid;
	pid=fork();
	if(pid<0) {perror("fork\n"); 	return -1;}
	if(pid!=0) exit(0);
	pid=setsid();
	if(pid<-1) {perror("setsid\n");	return -1;}
	if(!nochdir) 	chdir("/");
	if(!noclose)
	{
		int fd;
		fd=open("/dev/null",O_RDWR,0);
		if(fd!=-1)
		{
			dup2(fd,STDIN_FILENO);
			dup2(fd,STDOUT_FILENO);
			dup2(fd,STDERR_FILENO);
			if(fd>2) close(fd);
		}
	}
	umask(0027);
	return 0;
}
int main(void)
{
	daemon(0,0);
	sleep(1000);
	return 0;
}
-------------------------------------------------------
daemon的日志实现
syslogd通过接受其他daemon的信息,并将这些信息记录在指定位置来解决日志记录问题。
configuration file :/etc/syslog.conf
man 5 syslog.conf
facility	value 			level	value
kern	0			emerg	0
user 	1			alert	1
mail	2			crit	2
daemon 	3			err	3
auth	4			warning	4
syslog	5			notice	5
lpr	6			info	6
news	7			debug	7
uucp	8
cron 	9
authpriv 	10
ftp 	11
系统保留	12-15
local0-local7	16-23
openlog() 打开系统日志连接 /   syslog()   /closelog()
head	<syslog.h>
define	void openlog(const char *ident,int option,int facility);
	void syslog(int priority,const char *format,...);
	void closelog(void);
return	suc:-	fail:-	errno:-
ident:信息来源,option:控制标志,priority:消息的级别,format为消息格式输出与printf类似。
option:
LOG_CONS	LOG_NDELAY	LOG_NOWAIT	LOG_ODELAY
LOG_PERROR	LOG_PID
---------------------------------
openlog函数参数facility值		syslog.conf对应的facility取值
LOG_KERN			kern
LOG_USER			user
LOG_MAIL			mail
LOG_DAEMON			daemon
LOG_AUTH			auth
LOG_SYSLOG			syslog
LOG_LPR				lpr
LOG_NEWS			news
LOG_UUCP			uucp
LOG_CRON			cron
LOG_AUTHPRIV			authpriv
LOG_FTP				ftp
LOG_LOCAL0~LOG_LOCAL7		local0~local7
-----------------------------------------
priority:
LOG_EMERG	emerg
LOG_ALERT	alert
LOG_CRIT	crit
LOG_ERR		err
LOG_WARNING	warning
LOG_NOTICE 	notice
LOG_INFO	info
LOG_DEBUG 	debug
-----------------------------------------------------
添加日志的流程
openlog()-->syslog()-->closelog()
#include <stdio.h>
#include <syslog.h>
int main(int argc,char* argv[])
{
	openlog(argv[0],LOG_CONS|LOG_PID,LOG_USER);
	int count=0;
	while(count<5)
	{
		syslog(LOG_INFO,"%d , log info test...\n",count);
		count++;
	}
	closelog();
	return 0;
}
--------------------------------------END

linux-programming-note-4(设备文件)

<本笔记基于《LINUX编程技术详解》(人民邮电出版社)>
Author:tunpishuang (tunpishuang at gmail dot com)
Chapter 6-------------设备文件(device file)
	|--字符文件,按字节访问,如串口
设备文件|
	|--块文件,一个读写任意字节数据,如文件系统
	|
	|--网络接口
终端设备和一般计算机区别:没有自己的CPU单元和内存单元
Linux系统中所有的终端设备被称为tty(teletypes or tele-typerwriters),是字符设备
	|-串口端口终端(/dev/ttySn)ttyS0到S3对应COM1到COM4
	|
	|-伪终端(/dev/pts/n) telnet实际登陆在伪终端上。
终端设备|
	|-控制终端(/dev/tty)
	|
	|-控制台终端(/dev/ttyn,/dev/console) 指显示器,称为虚拟终端
终端控制:stty -a
重置终端:reset
ttyname() 获得当前终端名称
head	<unistd.h>
define	char *ttyname(int fd);
return	suc:终端名称	fail:NULL	Set errno:yes
fd:打开终端获得的文件描述符
eg:
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
char* tty_out_name;
char* tty_in_name;
char* tty_err_name;
if((tty_out_name=ttyname(STDOUT_FILENO))==NULL)
	{perror("cannot get tty name\n"); return 1;}
if((tty_in_name=ttyname(STDIN_FILENO))==NULL)
	{perror("cannot get tty name\n"); return 1;}
if((tty_err_name=ttyname(STDERR_FILENO))==NULL)
	{perror("cannot get tty name\n"); return 1;}
printf("STDIN_FILENO ttyname is %s\n",tty_in_name);
printf("STDOUT_FILENO ttyname is %s\n",tty_out_name);
printf("STDERR_FILENO ttyname is %s \n",tty_err_name);
return 0;
}
------------------------------------
tcgetattr() 获取终端相关信息
tcsetattr() 设置终端参数
head	<termios.h>
	<unistd.h>
define	int tcgetattr(int fd,struct termios *termios_p);
	int tcsetattr(int fd,int optional_actions,const struct termios *termios_p);
return 	suc:o 		fail:-1 	set errno:yes
fd:终端文件描述符
tcflag_t c_iflag;      /* 输入模式 */
tcflag_t c_oflag;      /* 输出模式 */
tcflag_t c_cflag;      /* 控制模式 */
tcflag_t c_lflag;      /* 本地模式 */
cc_t c_cc[NCCS];       /* 控制字符 */
c_iflag:
IGNBRK		BRKINT		IGNPAR		INPCK		ISTRIP
INLCR		IGNCR		ICRNL		IUCLC		IXON
IXANY		IXOFF		IMAXBEL
c_oflag:
OPOST		OLCUC		ONLCR		OCRNL		ONOCR
ONLRET		OFILL		OFDEL		NLDLY		CRDLY
TABDLY		BSDLY		VTDLY		FFDLY
c_cflag:
CBAUD		CBAUDEX		CSIZE		CSTOPB		CREAD
PARENB		PARODD		HUPCL		CLOCAL		CRTSCTS
c_lflag:
ISIG		ICANON		XCASE		ECHO		ECHOE
ECHONL		ECHOPRT		TOSTOP
c_cc[NCCS]
VINTR		VEOL		VQUIT		VTIME		VEOF
VERASE		VSTOP		VKILL		VSTART		VMIN
optional_actions 用于控制修改起作用的时间
TCSANOW		TCSADRAIN		TCSAFLUSH
termios_p 保存了要修改的参数
-----------------------------
密码输入关闭回显的两种方法
1:使用curses库
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
char passwd[20];
void init()
{
	initscr();
	cbreak();
	noecho();
	intrflush(stdscr,FALSE);
	keypad(stdscr,TRUE);
	refresh;
}
int getpasswd(char *passswd,int size)
{
	int c;
	int n=0;
	printf("input password\n");
	do
	{
		c=getchar();
		if(c!='\n')
		{
			echochar('*');
			passwd[n++]=c;
		}
	}while(c!='\n' && n <(size-1));
	passwd[n]='\0';
	return n;
}
int main()
{
	int n;
	init();
	n=getpasswd(passwd,sizeof(passwd));
	printf("\n your passwd is %s\n",passwd);
	printf("press any key to continue...\n");
	refresh();
	getchar();
	endwin();
	return 0;
}
----------------------------
2使用tcgetattr tcsetattr
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#define  ECHOFLAGS (ECHO | ECHOE |ECHOK |ECHONL)
int set_disp_mode(int fd,int option)
{
	int err;
	struct termios term;
	if(tcgetattr(fd,&term)==-1)
	{perror("cannot get the attribution of the terminal\n"); return 1;}
	if(option) term.c_lflag|=ECHOFLAGS;
	else term.c_lflag &=~ECHOFLAGS;
	err=tcsetattr(fd,TCSAFLUSH,&term);
	if(err==-1 && err==EINTR)
	{perror("cannot set the attribution  of the terminal\n"); return 1;}
	return 0;
}
int getpasswd(char* passwd,int size)
{
	int c;
	int n=0;
	printf("lease input passwd:\n");
	do
	{
		c=getchar();
		if(c!='\n'|c!='\r') {passwd[n++]=c;}
	}while(c!='\n' && c!='\r' && n<(size-1));
	passwd[n]='\0';
	return n;
}
int main()
{
	char passwd[20];
	set_disp_mode(STDIN_FILENO,0);
	getpasswd(passwd,sizeof(passwd));
	printf("\nyour passwd is %s\n",passwd);
	printf("press any key to continue\n");
	set_disp_mode(STDIN_FILENO,1);
	getchar();
	return 0;
}
----------------------------------
	串口通信
串口再数据通信中,一次只传输一个bit的数据。
串口通信设备也被称为数据通讯设备(DCE,Data Communication Equipment)
或数据终端设备(DTE,Data Terminal Equipment)
串口一般用于ascii的传输,
打开串口fd=open("dev/ttyS0",O_RDWR|O_NOCTTY);
设置串口通信参数
波特率的设置
cfgetispeed() cfgetospeed()
head	<termios.h>
	<unistd.h>
define	speed_t cfgetispeed(const struct termios *termios_p);
	speed_t cfgetospeed(const struct termios *termios_p);
return 	suc:返回termios_p结构中的输入输出端口的波特率 fail:-1 	set errno:yes
cfsetispeed(),cfsetospeed()
head	<termios.h>
	<unistd.h>
define	int cfsetispeed(struct termios *termios_p,speed_t speed);
	int cfsetospeed(struct termios *termios_p,speed_t speed);
return	suc:返回termios_p结构中的输入、输出端口的波特率 fail:-1		set errno:yes
eg:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
.............
struct termios opt;
tcgetattr(fd,&opt);
cfsetispeed(fd,B9600);
cfsetospeed(fd,B9600);
tcsetattr(fd,TCANOW,&opt);
..........
数据位的设置:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
........
struct termios opt;
tcgetattr(fd,&opt);
opt.c_cflag&=~CSIZE;
opt.c_cflag|=CS8;
.........
tcsetattr(fd,TCANOW,&opt);
..............
奇偶校验位
设置		代码
无校验		opt.c_cflag&=~PARENB;
奇校验		opt.c_cflag|=(PARODD|PARENB);
偶校验		opt.c_cflag&=~PARENB;
		opt.c_cflag&=~PARODD;
空格		opt.c_cflag&=~PARENB;
		opt.c_cflag&=~CSTOPB;
数据流控制
不使用数据流控制		opt.c_cflag&=~CRTSCTS
硬件				opt.c_cflag|=CRTSCTS
软件				opt.c_cflag|=IXON|IXOFF|IXANY
串口读写实例
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
int open_port(char* port)
{
	int fd;
	if((fd=open(port,O_RDWR|O_NOCTTY|O_NONBLOCK))==-1) {perror("cannot open the expected port"); return 1;}
	return fd;
}
void close_port(int fd) {close(fd);}
int get_baud_rate(unsigned long int baud_rate)
{
	switch(baud_rate)
	{
		case 0	:	return B0;
		case 50	:	return B50;
		case 75 :	return B75;
		case 110:	return B110;
		case 134:	return B134;
		case 150:	return B150;
		case 200:	return B200;
		case 300:	return B300;
		case 600:	return B600;
		case 1200:	return B1200;
		case 1800:	return B1800;
		case 2400:	return B2400;
		case 4800:	return B4800;
		case 9600:	return B9600;
		case 19200:	return B19200;
		case 38400:	return B38400;
		case 57600:	return B57600;
		case 115200:	return B115200;
		case 230400:	return B230400;
		default:	return -1;
	}
}
typedef struct port_info
{
	int baud_rate;
	int port_fd;
	char parity;
	char stop_bit;
	char flow_ctrl;
	char data_bits;
}*pport_info;
int set_port(pport_info p_info)
{
	struct termios old_opt,new_opt;
	int baud_rate,parity;
	memset(&old_opt,0,sizeof(old_opt));
	memset(&new_opt,0,sizeof(new_opt));
	cfmakeraw(&new_opt);
	tcgetattr(p_info->port_fd,&old_opt);
	baud_rate=get_baud_rate(p_info->baud_rate);
	cfsetispeed(&new_opt,baud_rate);
	cfsetospeed(&new_opt,baud_rate);
	new_opt.c_cflag |=CLOCAL;
	new_opt.c_cflag |=CREAD;
	switch(p_info->flow_ctrl)
	{
		case '0': new_opt.c_cflag &=~CRTSCTS; break;
		case '1': new_opt.c_cflag |=CRTSCTS; break;
		case '2': new_opt.c_cflag |=IXON | IXOFF | IXANY; break;
	}
	new_opt.c_cflag &=~CSIZE;
	switch(p_info->data_bits)
	{
		case '5': new_opt.c_cflag |=CS5; break;
		case '6': new_opt.c_cflag |=CS6; break;
		case '7': new_opt.c_cflag |=CS7; break;
		case '8': new_opt.c_cflag |=CS8; break;
		default: new_opt.c_cflag |=CS8;
	}
	switch(p_info->parity)
	{
		case '0': new_opt.c_cflag &=~PARENB; break;
		case '1': new_opt.c_cflag |=PARENB;
			  new_opt.c_cflag &=~PARODD; break;
		case '2': new_opt.c_cflag |=PARENB;
			  new_opt.c_cflag |=PARODD; break;
	}
	if(p_info->stop_bit=='2') new_opt.c_cflag |=CSTOPB;
	else new_opt.c_cflag &=~CSTOPB;
	new_opt.c_oflag &=~OPOST;
	new_opt.c_cc[VMIN]=1;
	new_opt.c_cc[VTIME]=1;
	tcflush(p_info->port_fd,TCIFLUSH);
	int result;
	result=tcsetattr(p_info->port_fd,TCSANOW,&new_opt);
	if(result==-1) {perror("cannot set the serial port parameters\n"); return -1;}
	tcgetattr(p_info->port_fd,&old_opt);
	return result;
}
int send_data(int fd,char *data,int data_len)
{
	int len;
	len=0;
	len=write(fd,data,data_len);
	if(len==data_len) return len;
	else {tcflush(fd,TCOFLUSH); return -1;}
}
int recv_data(int fd,char *data,int data_len)
{
	int len ,fs_sel;
	fd_set fs_read;
	struct timeval time;
	FD_ZERO(&fs_read);
	FD_SET(fd,&fs_read);
	time.tv_sec=10;
	time.tv_usec=0;
	fs_sel=select(fd+1,&fs_read,NULL,NULL,&time);
	if(fs_sel)
	{
		len=read(fd,data,data_len);
		return len;
	} else return -1;
int main(int argc,char* argv[])
{
	int port_fd;
	int len;
	char recv_buf[9];
	int i;
	if(argc!=3)
	{
	printf("usage: %s /dev/ttySn 0(send data)/1(receive data)\n",argv[0]); return -1;
	}
	port_fd=open_port(argv[1]);
	if(port_fd==-1)
	{
		printf("program exit \n");
		return -1;
	}
	struct port_info info;
	info.baud_rate=9600;
	info.data_bits=8;
	info.flow_ctrl=2;
	info.port_fd=port_fd;
	info.stop_bit=1;
	info.parity=0;
	if(set_port(&info)==-1)
	{
		printf("program exit \n");
		return -1;
	}
	if(strcmp(argv[2],"0")==0)
	{
		for(i=0;i<10;i++)
		{
			len=send_data(port_fd,"test data",9);
			if(len>0) printf("%d send data successfully\n",i);
			else printf("send data failed\n");
			sleep(2);
		}
		close_port(port_fd);
	}
	else
	{
	while(1)
	{
		len=recv_data(port_fd,recv_buf,9);
		if(len>0)
		{
			for(i=0;i<len;i++)
			printf("receive data is %s \n",recv_buf);
		}
		else printf("cannot receive data \n"); sleep(2);
	}
	} return 0;
}
}
--------------------
音频设备文件编程基础
	linux下的音频设备文件
/dev/console 	与扬声器有关
/dev/dsp 	与声卡设备上的数字信号处理器(DSP) 声卡设备通过DSP实现A/D转换,
		由于声卡驱动的原因,应用程序只能以只读只写的方式打开,某些例外。
/dev/audio	使用编码方式是mu-law。
/dev/mixer	声卡混音器软件接口,混音器的作用是将多个声音信号组合或叠加,
/dev/sequencer 设备文件用于提供对声卡中的波表合成器的支持。
ioctl() 对设备的特性进行控制,
head	<sys/ioctl.h>
define	int ioctl(int d,int request,...);
return 	suc:0	fail:-1		set errno:yes
d:文件描述符	request:对设备的控制命令
让扬声器发声
形式为:ioctl(fd,KIOCSOUND,(int)tone);
fd:打开扬声器获得的文件描述符,KIOCSOUND对扬声器音频进行控制,tone表示要输出的扬声器音频值。
usleep() 控制扬声器发生时间的长短
head	<unistd.h>
define	void usleep(unsigned long usec);
return	suc:0		fail:-2		set errno:yes
usec:毫秒
eg:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#define SPEAKER_DEVICE "/dev/console"
int main(int argc,char* argv[])
{
	int fd;
	int i;
	int freq;
	if(argc!=2) {printf("usage:%s frequence \n"),argv[0]; return 1;}
	freq=atoi(argv[1]);
	if(freq<=0 || freq>10000) {printf("the freq must be int range from 0 to 10000\n"); return 1;}
	fd=open(SPEAKER_DEVICE,O_WRONLY);
	if(fd==-1) {perror("cannot open the speaker device\n"); return 1;}
	for(i=0;i<10;i++)
	{
		int set_freq=1190000/freq;
		ioctl(fd,KIOCSOUND,set_freq);
		usleep(200);
		ioctl(fd,KIOCSOUND,0);
		usleep(100);
	}
	return 0;
}
-------------------------
linux下声卡编程
播放指定音频文件
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/soundcard.h>
#define Audio_Device "/dev/dsp"
#define Sample_Size 16
#define Sample_Rate 8000
int play_sound(char *filename)
{
	struct stat stat_buf;
	unsigned char *buf=NULL;
	int handler,fd;
	int result;
	int arg,status;
	if((fd=open(filename,O_RDONLY))<0) return -1;
	if(fstat(fd,&stat_buf)) {close(fd); return -1;}
	if(!stat_buf.st_size) {close(fd); return -1;}
	buf=malloc(stat_buf.st_size);
	if(!buf) {close(fd); return -1;}
	if(read(fd,buf,stat_buf.st_size)<0)
	{
		free(buf);
		close(fd);
		return -1;
	}
	handler=open(Audio_Device,O_WRONLY);
	if(handler==-1)  {perror("open Audio_Device fail\n"); return -1;}
	arg=Sample_Rate;
	status=ioctl(handler,SOUND_PCM_WRITE_RATE,&arg);
	if(status==-1) {perror("error from SOUND_PCM_WRITE_RATE ioctl\n"); return -1;}
	arg=Sample_Size;
	status=ioctl(handler,SOUND_PCM_WRITE_BITS,&arg);
	if(status==-1) {perror("error from SOUND_PCM_WRITE_BITS ioctl\n"); return -1;}
	result=write(handler,buf,stat_buf.st_size);
	if(result==-1) {perror("fail to play sound\n"); return -1;}
	free(buf);
	close(fd);
	close(handler);
	return result;
}
int main(int argc,char *argv[])
{
	if(argc!=2)
	{printf("usage:%s soundfilename\n",argv[1]); return -1;}
	play_sound(argv[1]);
	return 0;
}
-------------------------
录制音频文件
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
#define	LENGTH 3
#define RATE 8000
#define SIZE 16
#define CHANNELS 2
unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];
int main(void)
{
	int fd;
	int arg;
	int status;
	fd=open("/dev/dsp",O_RDWR);
	if(fd<0) {perror("cannot open /dev/dsp device\n"); return 1;}
	arg=SIZE;
	status=ioctl(fd,SOUND_PCM_WRITE_BITS,&arg);
	if(status==-1) {perror("cannot set SOUND_PCM_WRITE_BITS\n"); return 1;}
	arg=CHANNELS;
	status=ioctl(fd,SOUND_PCM_WRITE_CHANNELS,&arg);
	if(status==-1) {perror("cannot set SOUND_PCM_WRITE_CHANNELS\n"); return 1;}
	arg=RATE;
	status=ioctl(fd,SOUND_PCM_WRITE_RATE,&arg);
	if(status==-1) {perror("cannot set SOUND_PCM_WRITE_RATE\n"); return 1;}
	/*start to record section*/
	while(1)
	{
		printf("Recording...:\n");
		status=read(fd,buf,sizeof(buf));
		if(status!=sizeof(buf)) {perror("read wrong number of bytes\n");}
		printf("Play...:\n");
		status=write(fd,buf,sizeof(buf));
		if(status!=sizeof(buf)) perror("wrote wrong number of bytes\n");
		status=ioctl(fd,SOUND_PCM_SYNC,0);
		if(status==-1) perror("cannot set SOUND_PCM_SYNC");
	}
	return 0;
}
---------------------------------------------end

汶川大地震

the first earthquake experience in my life happened on 2008.5.12 in Chongqing~囧,so scared of the NATURE

NOW nearly seven thousand people have been killed by the earthquake

总的感觉就好想所有的楼房成了马蜂窝,人成了马蜂,地震是马蜂的人,捅一下,全部出来了~ 异常的壮观,

对于很多人来说都是第一次经历地震,MS重庆没有震过。

查了下资料最近的重庆一次地震是在150年前的黔江,大小是6.5级

通过这次地震让 俺知道了,生命很脆,很弱。自然之不可以抗拒啊。。

讲讲我的经历:
下午2点20的时候俺翘课,在寝室上网,突然发现寝室在晃动,于是我的第一感觉是,可以是风太大了,让宿舍楼产生了共振,看到外面有人跑了,我衣服都没有穿从9楼跑到了底楼,然后过了一会儿,没有震了,当时心想:遭了,我手机,DC,移动硬盘,笔记本还没有拿出来啊,然后又冲到了9楼,拿了书和笔,准备去上课,打电话问同学在哪个教学楼上课,结果没有一个人打通了,然后一群群的人就从1,2,3,4教学楼出来了,如蜂群。如洪流。才意识到不知道我们寝室遭了,原来大家都在“共振”。。

后来上news.sina.com.cn才知道发生了什么,到了4点钟的时候生活老师叫我们下去,听说4:30的时候还要来余震,拿些值钱的东西就到后门吃饭去了。

回来5点钟到12点的时候好像发生余震,不过没有下楼,太累了。

晚上没有熄灯,我上网到4点10左右的时候又开始震了,我叫我们寝室的起来,逃命,然后又下了从九楼来到一楼。

然后又回到9楼,实在是来不起了,洗洗睡了,一睡就到了10:10,靠,岂不是要上课了,写下此文,然后就闪人上课去了。

最后一句:珍惜生命,因为它确实太脆弱了。

默默的为那些人们祈祷。

linux-programming-note-3(文件i/o操作)

<本笔记基于《LINUX编程技术详解》(人民邮电出版社)>
author:tunpishuang (tunpishuang at gmail dot com)
chapter5-------------文件i/o操作
-----------------------------
open() 打开文件设备
head	<sys/types.h>
	<sys/stat.h>
	<fcntl.h>
define 	int open(const char *pathname,int flags);
	int open(const char *pathname,int flags,mode_t mode);
return	success	file discripter		fail:-1		set errno:yes
flag参数:
O_RDONLY	O_WRONLY	O_RDWR		O_APPEND	O_ASYNC		O_CREAT
O_DIRECTORY	O_EXCL		O_LARGEFILE	O_NOATIME	O_TRUNC		O_DIRECT
mode参数:
S_IRWXU		S_IRUSR		S_IWUSR		S_IXUSR
S_IRWXG		S_IRGRP		S_IWGRP		S_IXGRP
S_IRWXO		S_IROTH		S_IWOTH		S_IXOTH
eg:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
	int fd1;
	if(fd1=open("openfunctiontest",O_CREAT |O_RDWR,0777)==-1)
	{perror("cannot creat file openfunctiontest");	return 1;}
	close(fd1);
	return 0;
}
---------------------
close() 关闭文件设备 open后必须的操作,否者会造成资源和程序安装的问题。
head	<unistd.h>
define	int close(int fd);
return 	success:o 	fail:-1 	set errno:yes
-----------------------
creat() 创建文件
head 	<sys/types.h>
	<sys/stat.h>
	<fcntl.h>
define 	int creat(const char *pathname,mode_t mode);
return	success:file discripter		fail:-1	set errno:yes
等于int open(const char *pathname,O_CREAT|O_WRONLY|O_TRUNC,mode_t mode);
-----------------------------------
read() 读文件
head	<unistd.h>
define	ssize_t	read(int fd,void *buf,size_t count);
return	suc:读取的字符数,0表示读取到了文件结束位置 	fail:-1		set errno:yes
eg:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
	int fd;
	char buffer[100];
	int num;
	if(argc!=2) {printf("USage:%s filename\n",argv[0]);  return 1;}
	if((fd=open(argv[1],O_RDONLY))==-1) {perror("cannot open"); return 1;}
	while((num=read(fd,buffer,99))>0)
	{
	buffer[num]='\0';
	printf("%s\n",buffer);
	}
	close(fd);
	return 0;
}
--------------------------------
write() 写文件
head	<unistd.h>
define	ssize_t write(int fd,const void *buf,size_t count);
return	suc:写入字符数,	fail:-1		set errno:yes
eg: 	cp.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
	char buffer[100];
	int fd1,fd2,num;
	if(argc!=3) printf("usage:%s source dest\n",argv[0]);
	if((fd1=open(argv[1],O_RDONLY))==-1) {perror("cannot open\n"); return 1;}
	if((fd2=open(argv[2],O_CREAT|O_WRONLY,0777))==-1) {perror("cannot creat dest\n"); return 1;}
	while((num=read(fd1,buffer,100))>0)
	{
		write(fd2,buffer,num);
	}
	close(fd1);
	close(fd2);
	return 0;
}
--------------------------------------------------
lseek() 改变写入文件位置
head	<sys/types.h>
	<unistd.h>
define	off_t lseek(int fildes,off_t offset,int whence);
return	suc:从文件开始位置最后的偏移量 		fail:-1		set errno:yes
offset 偏移量
whence 文件偏移量的具体计算:
SEEK_SET	SEEK_CUR	SEEK_END
eg:用lseek实现grep功能:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
int main(int argc,char * argv[])
{
	int len;
	int fd;
	long offset=0;
	char buffer[1024];
	int flag=0;
	if(argc!=3) {printf("usage: %s \"string\" filename\n"); return 1;}
	len=strlen(argv[1]);
	fd=open(argv[2],O_RDONLY);
	while(1)
	{
		if(lseek(fd,offset,SEEK_SET)==-1) {perror("cannot move the file pointer\n"); return 1;}
		if(read(fd,buffer,len)<len) break;
		buffer[len]='\0';
		if(strcmp(argv[1],buffer)==0) flag++;
		offset++;
	}
	if(flag>0) printf("find the string: %s in file %s %d times\n",argv[1],argv[2],flag);
	close(fd);
	return 0;
}
--------------------------------------
dup() dup2() 输入输出从定向
head	<unistd.h>
define	int dup(int oldfd);
	int dup2(int oldfd,int newfd);
return 	suc:new fd	fail:-1 	set errno:yes
STDIN_FILENO	标准输入,0
STDOUT_FILENO 	标准输入,1
STDERR_FILENO	标准错误,2
eg:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
	int fd1;
	if(argc!=2) {printf("usage: %s filename\n"); return 1;}
	if((fd1=open(argv[1],O_CREAT|O_RDWR,0777))==-1) {perror("cannot creat\n"); return 1;}
	close(STDOUT_FILENO);
	if(dup(fd1)==-1) {perror("cannot reserved the stdout fd\n"); return 1;}
	printf("write the file\n");
	close(fd1);
	return 0;
}
----------------------------------------如果改为dup2:
dup2(fd1,STDOUT_FILENO);
END

linux-programming-note-2(linux文件和目录)

<本笔记基于《LINUX编程技术详解》(人民邮电出版社)>
author:tunpishuang
chapter4-------------Linux文件和目录
和unix类似,linux不是通过设备标示符来访问文件系统的。
vfs(virtual filesystem):为了屏蔽底层文件系统的实现细节和差异
最早由sun提出,其目的是实现nfs,
getcwd() 获得当前工作目录
head:   <unistd.h>
define: char * getcwd(char *buffer,size_t size)
return: 成功:返回指向当前工作目录字符串的指针 失败:null 设置errno:是
错误信息:
EINVAL
ERANGE
EACCES
eg:
----------------------------------code start
/*getcwd.cxx*/
#include <iostream>
#include <limits.h>
#include <unistd.h>
#ifndef PATH_MAX
#define PATH_MAX 256
#endif
int main(void){
char cur_work_dir[PATH_MAX];
std::cout<<"current max path length is:"<<PATH_MAX<<std::endl;
if(getcwd(cur_work_dir,PATH_MAX)==NULL)
{
 perror("couldn't get cwd!");
 return 1;
}
std::cout<<"current dir is :"<<cur_work_dir<<std::endl;
return 0;
}
---------------------------------code end
pathconf() 获得系统目录最大长度
head <unistd.h>
long pathconf(char *path,int name)
return 成功:返回目录长度极限值 失败:-1  设置errno:是
name可以取值:               错误信息:
_PC_LINK_MAX 		     EINVAL
_PC_MAX_CANON		     ELOOP
_PC_NAME_MAX
_PC_PATH_MAX
_PC_CHOWN_RESTRICTED
_PC_NO_TRUNC
_PC_VDISABLE
eg:
/*pathconf.cxx*/
#include <iostream>
#include <unistd.h>
int main(void)
{
	long cur_path_len;
	char* cur_work_dir;
	/*get the max length of the directory*/
	if(cur_path_len=pathconf(".",_PC_PATH_MAX)==-1)
	{perror("couldn't get current working path length"); return 1;}
	std::cout<<"current path length is "<<cur_path_len<<std::endl;
	/*memory allocate according to the length of the dir*/
	if((cur_work_dir=(char *)malloc(cur_path_len))==NULL)
	{perror("couldn't allocate memory for the pathname"); return 1;}
	/*get current working dir*/
	if(getcwd(cur_work_dir,cur_path_len)==NULL)
	{perror("couldn't get current working dir"); return 1;}
	std::cout<<"curren working dir is"<<cur_work_dir<<std::endl;
	return 0;
}
--------------------------------------------------
chdir,fchdir 更改当前工作目录
功能类似cd,
head 	<unistd.h>
define  int chdir(const char* path); 参数是指向目录的字符串指针
	int fchdir(int fd);          参数是目录的文件描述符
return  sucess:0 fail:-1 set errno:yes
error info:
EFAULT
ENAMETOOLONG
ENOENT
ENOMEM
ENOTDIR
EACCES
ELOOP
EIO
EBADF
eg:
-------------------------------code
/*file name: chdir.cxx*/
#include <iostream>
#include <unistd.h>
int main(void)
{
	long cur_path_len;
	char* cur_work_dir;
	/*get the max length of the directory*/
	if(cur_path_len=pathconf(".",_PC_PATH_MAX)==-1)
	{perror("couldn't get current working path length"); return 1;}
	std::cout<<"current path length is "<<cur_path_len<<std::endl;
	/*memory allocate according to the length of the dir*/
	if((cur_work_dir=(char *)malloc(cur_path_len))==NULL)
	{perror("couldn't allocate memory for the pathname"); return 1;}
	/*get current working dir*/
	if(getcwd(cur_work_dir,cur_path_len)==NULL)
	{perror("couldn't get current working dir"); return 1;}
	std::cout<<"curren working dir is"<<cur_work_dir<<std::endl;
	/*chang to dir PARENT directory*/
	if(chdir("..")==-1)
	{perror("couldn't change cwd"); return 1;}
	if(getcwd(cur_work_dir,cur_path_len)==NULL)
	{perror("couldn't et cwd"); return 1;	}
	std::cout<<"after cwd,the cwd is"<<cur_work_dir<<std::endl;
	return 0;
}
-----------------------------
mkdir(),rmdir() 创建,删除目录
head	<sys/stat.h>
	<sys/types.h>
define  int mkdir(const char *pathname,mode_t mode);
return	success:0	fail:-1 set errno:yes
创建目录的权限由mode&~unmask&0777来指定,umask是默认权限,也称为剥夺权限。
error info:
EPERM
EEXIST
EFAULT
EACCES
ENAMETOOLONG
ENOENT
ENOTDIR
ENOMEM
EROFS
ELOP
ENOSPC
ENOSPC
eg:
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
int main(void)
{
	char* pathname="/root/program/mkdirtest";
	if(mkdir(pathname,0700)==-1)
	{perror("counldn't mkdir"); return 1;}
	return 0;
}
-------------------------------
rmdir()
head	<unistd.h>
define	int rmdir(const char *pathname);
return 	sucess:0	fail:-1 	set errno:yes
-----------------------------
4.2.2 文件描述符和文件指针
linux为了统一对文件和设备的操作,提供了open,read,close等操作函数,
使用文件描述符来实现对文件的操作。
文件描述符实际上是个整数,man 2 open,read,write,lseek,fcntl
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
char test;
int fd;
if(fd=open("fd.dat",O_RDONLY)==-1)
{perror("cannot open the fd.dat file"); return 1;}
if(fork()==-1)
{
perror("cannot create the child process");
return 1;
}
/*read the first char in fd.dat file*/
read(fd,&test,1);
printf("process id: %ld read the char :%c\n",(long)getpid(),test);
close(fd);
return 0;
}
--------------------------------------
4.2.3 文件访问权限
4.2.4 stat(),fstat(),lstat()  获取文件信息
head	<sys/types.h>
	<sys/stat.h>
	<unistd.h>
define	int stat(const char *path,struct stat *buf);
	int fstat(int filedes,struct stat *buf);
	int lstat(const char *path,struct stat *buf);
return	sucess:0	fail:-1		 set errno:yes
几十没有对文件有读取权限,也可以获得文件信息。
lstat和stat一样,除了当path为链接时,获得的将是符号链接的信息,而不是符号链接指向的文件信息.
fstat和stat一样,除了第一个参数时文件描述符。
0x1ff=0777
struct stat {
	dev_t st_dev;
	ino_t st_ino;
	mode_t st_mode;
	nlink_t st_nlink;
	uid_t st_uid;
	gid_t st_gid;
	dev_t st_rdev;
	off_t st_size;
	blksize_t st_blksize;
	blkcnt_t st_blocks;
	time_t	st_atime;
	time_t	st_mtime;
	time_t 	st_ctime;
};
POSIX中定义的检查文件类型的宏说明
st_mode中定义的相关宏
-----------------------
4.2.5 chmod(),fchmod() 修改文件权限
head	<sys/types.h>
	<sys/stat.h>
define	int chmod(const char *path,mode_t mode);
	int fchmod(int fides,mode_t mode);
return success:0	fail:-1	set errno:yes
chmod fchmod中使用的宏详见man 2 chmod
-------------------------
4.2.6 chown(),fchown(),lchown() 修改文件属主
head	<sys/types.h>
	<unistd.h>
define	int chown(const char *path,uid_t owner,gidd_t group);
	int fchown(int fd,uid_t owner,gid_t group);
	int lchown(const char *path,uid_t owner,gid_t group);
return	success:0 	fail:-1 set errno:yes
--------------------------
4.2.7 umask()
umask影响新建文件的默认权限,如果umask的值为022,则新创建的文件的权限
为666-022=755
umask的目的是修改umask的值,以确定程序创建文件的权限,
head	<sys/types.h>
	<unistd.h>
define mode_t umask(mode_t mask);
return success:修改前的umask值, 失败:系统调用总是成功 set errno:no
umask的值一般为S_IWGRP|S_IWOTH (022)
eg:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
	int fd1,fd2;
	fd1=open("test1",O_CREAT|O_RDWR,0777);
	if(fd1<0) {perror("cannot create file test1"); return 1;}
	close(fd1);
	struct stat file_stat;
	if(stat("test1",&file_stat)==-1)
	{perror("cannot get the inf of the test1\n"); return 1;}
	printf("test1 permission is :%o\n",file_stat.st_mode & 0x1ff);
	/*call umask to change the umask value to 077*/
	umask(077);
	if((fd2=open("test2",O_CREAT|O_RDWR,0777))==-1)
	{perror("cannot get the inf of test2 \n"); return 1;}
	close(fd2);
	if(stat("test2",&file_stat)==-1)
	{perror("cannot get the inf of test2 \n"); return 1;}
	printf("after modification the permission is:%o\n",file_stat.st_mode & 0x1ff);
	return 0;
}
---------------------------------
4.3 硬链接 and 符号链接
创建硬链接ln test test.link,我发现test and test.link具有相通的inode
只有文件可以创建硬链接,不能跨文件系统
软连接:touch link.symbol
	ln -s link.sybol link2
4.3.3 创建,删除链接
link() 创建hard link
head	<unistd.h>
define int link(const char *oldpath,const char *newpath);
return successs:0 fail:-1	set errno:yes
unlink() remove the hard link
head	<unstd.h>
define	int unlink(const char *pathname);
return	success:0	fail:-1 set errno:yes
创建符号链接
symlink()
head	<unistd.h>
int symlink(const char *oldpath,const char *newpath);
return	success:0	fail:-1 set errno:yes
------------------------------------
opendir() 打开参数name指定目录
head	<sys/types.h>
	<dirent.h>
define	DIR *opendir(const char *name);
return	成功:指向dir结构的目录指针	失败:NULL	set errno:yes
readdir 获取打开目录下的具体内容
head	<sys/types.h>
	<dirent.h>
define	 sturct dirent *readdir(DIR *dir);
return 	成功:返回指向dirent结构体的指针  失败:NULL set errno:yes
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(void)
{
	DIR* dir;
	struct dirent* drt;
	dir=opendir("/etc/");
	if(dir==NULL) {perror("cannot open the desired dir"); return 1;}
	while((drt=readdir(dir))!=NULL)
	{printf("filename or dir:%s\n",drt->d_name);}
	closedir(dir);
	return 0;
}
-----------------------------------
实例:ls
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
	const int N_BITS=3;
	typedef struct dir_lnk{
		char d_name[256];
		struct dir_lnk *next;
		}dirlnk;
	typedef struct item_info{
		unsigned long inode;
		char permission[11];
		int owner;
		int group;
		off_t size;
		time_t mod_time;
		char name[256];
		}info;
	dirlnk* get_dir_detail(char* dirname)
	{
	DIR* dir;
	struct dirent* drt;
	dir=opendir(dirname);
	if(dir==NULL) {perror("cannot open the dir"); return NULL;}
	dirlnk* dir_head=NULL;
	dirlnk* cur_item=NULL;
	dirlnk* next_item=(dirlnk*)malloc(sizeof(dirlnk));
	while((drt=readdir(dir))!=NULL)
		{
		 if(strcmp(drt->d_name,".")||strcmp(drt->d_name,".."));
		 continue;
		}
	if(cur_item=NULL)
	   cur_item=next_item;
	else
	   cur_item->next=next_item;
	   cur_item->next_item;
	if(dir_head=NULL) dir_head=cur_item;
	strcpy(cur_item->d_name,drt->d_name);
	}
	void print_file_info(dirlnk* dir_head)
	{
	 static char* perm[]={"---","-w-","-wx","r--","r-x","rw-","rwx"};
	 unsigned int mask=0700;
	struct stat file_stat;
	dirlnk* cur_dir=dir_head;
	info file_info;
	while(cur_dir!=NULL)
	{
	  mask=0700;
	  if(stat(cur_dir->d_name,&file_stat)==-1)
		{
		  perror("cannot get the info of the file!");
		  cur_dir=cur_dir->next;
		  continue;
		}
	  if(S_ISREG(file_stat.st_mode))  file_info.permission[0]='-';
	  if(S_ISDIR(file_stat.st_mode))  file_info.permission[0]='d';
	 int i=3;
	 int j=0;
	while(i>0)
	file_info.permission[1+j*3]=perm[(file_stat.st_mode & mask)>>(i-1)*N_BITS][0];
	file_info.permission[2+j*3]=perm[(file_stat.st_mode & mask)>>(i-1)*N_BITS][1];
	file_info.permission[3+j*3]=perm[(file_stat.st_mode & mask)>>(i-1)*N_BITS][2];
	j++;
	i--;
	mask>>=N_BITS;
	}
	 file_info.permission[10]='\0';
	 file_info.owner=file_stat.st_uid;
	 file_info.group=file_stat.st_gid;
	 file_info.mod_time=file_stat.st_atime;
	 file_info.size=file_stat.st_size;
	 strcpy(file_info.name,cur_dir->d_name);
	 file_info.inode=file_stat.st_ino;
	printf("%u ",file_info.inode);
	printf("%s ",file_info.permission);
	printf("%d ",file_info.owner);
	printf("%d ",file_info.group);
	printf("%u ",file_info.size);
	printf("%s ",ctime(&file_info.mod_time));
	printf("%s  \n",file_info.name);
	cur_dir=cur_dir->next;
	}
	int main(int argc, char* argv[])
	{
	 dirlnk* head=get_dir_detail(".");
	 printf_file_info(head);
	}
---------------还有个错误正在sebug