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