linux whoami cp mv mesg 命令 c语言实现(部分功能)

命令没有实现全部功能,只是初学时为了练习linux中的C语言函数。(有错误请指出,我会及时改正。有不足之处请说明)

whoami实现

#include<stdio.h>
#include<pwd.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
	uid_t id;
	struct passwd * pa;
	id=geteuid();
	pa=getpwuid(id);
	printf("%d\n",id);
	printf("%s\n",pa->pw_name);
	return 0;
}
cp实现

/*
#define S_ISDIR(x)  (((x)&STAT_MASK)==STAT_DIR_FLAG)
STAT_MASK         001000001010
STAT_DIR_FLAG   001000000000
*/
#include<stdio.h>
#include<unistd.h> //close
#include<fcntl.h> //open
#include <sys/stat.h>
#include <string.h>

#include<utime.h>
//use to change time
//int utime(const char *filename,struct utimbuf *buf);

#define BUFSIZE 4096
#define COPYMODE 0644 //文件许可位 permission bit 
void oops(char * sl,char * s2) 
{
	fprintf(stderr,"Error: %s ",sl);
	perror(s2);  //传来一个文件地址,然后让它判断错误原因。
	exit(1);
}
main(int ac,char *av[])
{
	int in_fd,out_fd,n_chars;
	char buf[BUFSIZE];
	struct stat st;
	struct utimbuf  utbuf;
	if(ac!=3)
	{
		fprintf(stderr,"usage: %s source destination\n",*av);
		printf("your parameters are not enough\n");
		exit(1);
	}
	if( (in_fd=open(av[1],O_RDONLY)) == -1 )
	{
		oops("Cannot open ",av[1]);
	}
	
	if( (out_fd=creat(av[2],COPYMODE)) == -1 )
	{
		//实现了输入目录也可以复制。 但是字符串的截取复杂****************
		
		if(stat(av[2],&st)!=-1)
		{
			if(S_ISDIR(st.st_mode))
			{
				
				char tp[100];
				int i,j=0;
				for(i=strlen(av[1])-1;i>=0;i--)
				{
					if(av[1][i]=='/')break;
				}
				for(i++;i<strlen(av[1]);i++)
				{
					tp[j++]=av[1][i];
				}
				tp[j]='\0';
				//strncpy(av[2]+strlen(av[2]),"/\0",2);
				//strcpy(av[2]+strlen(av[2]),av[1] );
				strcpy(av[2]+strlen(av[2]),tp);
				strncpy(av[2]+strlen(av[2]),"\0",1);
				if( (out_fd=creat(av[2],COPYMODE)) == -1 )
				{
				     oops("Cannot creat ",av[2]);
				}
				
				
			}
			
		}
		else  oops("Cannot creat ",av[2]);
	}
	
	if(stat(av[1],&st)==-1)
	{
		oops("Cannot read ",av[1]);
	}


	while( (n_chars = read(in_fd,buf,BUFSIZE))>0 )
	{
		if( write(out_fd,buf,n_chars)!=n_chars )
		{
			oops("write error to",av[2]);
		}
	}
	
	if( n_chars == -1)
	{
		oops("Read error from",av[1]);
	}
	
	if((close(out_fd) == -1) | (close(in_fd)== -1))
	{
		oops("Error closing files ","");
	}
	
	utbuf.actime=st.st_atime;
	utbuf.modtime=st.st_mtime;
	if(-1==utime(av[2],&utbuf))
	{
		oops("Error changing time ","");
	}

        printf("Copy has finished,you can use 'ls' to see it\n");
	
}
/*
st_atime  文件数据的最后存取时间       read            -u
 st_mtime  文件数据的最后修改时间       write           缺省
 st_ctime  文件属性的最后更改时间       chown,chmod     -c

*/


mv实现:

#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<string.h>
#include<stdlib.h>
char * getFileName(char * fileName){
	char tp[100],*nm=(char*)malloc(sizeof(char));
	int i,j=0;
	for(i=strlen(fileName)-1;i>=0;i--)
	{
		if(fileName[i]=='/')break;
	}
	for(i++;i<strlen(fileName);i++)
	{
		tp[j++]=fileName[i];
	}
	tp[j]='\0';
	strcpy(nm,tp);
	/* 
	strcpy(nm,fileName);
	strcpy(nm+strlen(nm),tp);
	strncpy(nm+strlen(nm),"\0",1);
	*/
	return nm;
}
int main(int ac,char * av[]){
	struct stat st;
	if(ac!=3){
		fprintf(stderr,"usage: %s source destination not found\n",*av);
	}
	
	if(stat(av[1],&st)==-1 || S_ISDIR(st.st_mode)){
		printf("source is not a file");
		exit(1);
	}
	if(stat(av[2],&st)!=-1){//查看是不是目录 
		if(S_ISDIR(st.st_mode)){
			strcpy(av[2]+strlen(av[2]),"/");
			strcpy(av[2]+strlen(av[2]),getFileName(av[1]));
			strcpy(av[2]+strlen(av[2]),"\0");
		}else{
			printf("destination file is already exist\n");
			//exit(1);  不可以退出,真正的linux也不会出现提示。**********************已改
		}
	}
	/*
	光下面一个函数就可以实现  复制包含目录的文件,但是如果 第二个参数是目录的话会失败的,所以要处理 .
用link如果目标目录文件存在就会失败,不许创建而linux中mv与cp都是可以覆盖目标文件的。
	*/
	if(rename(av[1],av[2])==-1){
		printf("error!\n");
	}
/*
	if(link(av[1],av[2])!=-1) {
		unlink(av[1]);
	}else{
		printf("link error\n");
	}
*/
	return 1;
}


mesg实现

#include    <unistd.h>
#include    <sys/stat.h>
#include    <stdio.h>
#include    <errno.h>
#include    <string.h>
#include    <stdlib.h>
int main(int argc, char *argv[])
{
    struct stat    st;
    char    *tty;
    tty = ttyname(STDERR_FILENO);
    if(tty == NULL){
        exit(1);
    }
    if(stat(tty, &st) == -1){
        exit(1);
    }
    if(argc == 1){
        if(st.st_mode & S_IWGRP)
            printf("is y\n");
        else
            printf("is n\n");
        return 0;
    }
    switch(argv[1][0]){
    case 'y':
        if(chmod(tty, st.st_mode | S_IWGRP) == -1)
            fprintf(stderr, "cannot set '%s': %s\n",tty, strerror(errno));
        break;
    case 'n':
        if(chmod(tty, st.st_mode & ~S_IWGRP) == -1)
            fprintf(stderr, "cannot set '%s': %s\n", tty, strerror(errno));
        break;
    default: ;
    }
    return 0;    
}    

/*
主要代码参考网址:
http://www.cnblogs.com/mcnns/archive/2012/12/20/2826176.html

所用知识简介
参考网址:
http://baike.baidu.com/view/8031097.htm
http://baike.baidu.com/link?url=o1UFivoW3f4RUs5LpY8SaWYIBSPGyn_FpKdI3jC5HYzbyLoKGA2DSL0zBuDgMF0F
http://blog.csdn.net/novrose/article/details/6947868
http://baike.baidu.com/view/568600.htm
http://baike.baidu.com/view/1229012.htm
http://linux.chinaunix.net/techdoc/system/2009/07/04/1121929.shtml

char *strchr(char* _Str,int _Ch)
头文件:#include <string.h>
功能:查找字符串s中首次出现字符c的位置
说明:返回首次出现c的位置的指针,返回的地址是字符串在内存中随机分配的地址再加上你所搜索的字符在字符串位置,如果s中不存在c则返回NULL。

//
stdin, stdout, stderr类型为 FILE* 
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO类型为 int 

使用stdin的函数主要有:fread、fwrite、fclose等,是文件流方式。属于高级IO,带缓冲的。 

使用STDIN_FILENO的函数有:read、write、close等, 属于低级IO,要自己处理缓冲。 
通常守护进程在后台运行,所以要将它的标准输入输出重定向到/dev/null。 

fd = open("/dev/null", O_RDONLY); 
if(fd != -1){ 
dup2(fd, STDIN_FILENO); 
dup2(fd, STDOUT_FILENO); 
dup2(fd, STDERR_FILENO); 
if(fd > 2){ 就是除了标准输入,输出和错误,其他的都关闭啊
close(fd); 
} 
}
函数名: dup2
功能: 复制文件句柄
用法: int dup2(int oldhandle,int newhandle);
///
头文件
#include<unistd.h>
2函数原型
char * ttyname(int desc);

用法举例
char * file = “/dev/tty”;
fd = open (fiel,O_RDONLY);
if(isatty(fd)){
printf(“is a tty.\n”);
printf(“ttyname = %s \n”,ttyname(fd));
}
else printf(“ is not a tty\n”);
close(fd);


函数名: stat()
功 能: 得到文件的信息,将其保存在buf结构中,buf的地址以参数形式传递给stat。
用 法: int _stat(const char *path,struct _stat *buffer)
参数:
const char *path: 文件名或者目录名
struct _stat *buffer:结构体对象地址
返回值: 返回-1表示失败。

stat 结构定义于:/usr/include/sys/stat.h 文件中

struct stat finfo;
stat( sFileName, &finfo );
int size = finfo. st_size;
struct stat
mode_t st_mode; //文件对应的模式,文件,目录等
ino_t st_ino; //i-node节点号
dev_t st_dev; //设备号码
dev_t st_rdev; //特殊设备号码
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者
gid_t st_gid; //文件所有者对应的组
off_t st_size; //普通文件,对应的文件字节数
time_t st_atime; //文件最后被访问的时间
time_t st_mtime; //文件内容最后被修改的时间
time_t st_ctime; //文件状态(属性)改变时间
blksize_t st_blksize; //文件内容对应的块大小
blkcnt_t st_blocks; //文件内容对应的块数量


函数名称:[1]chmod
函数原型:int chmod( const char *filename, int pmode );
所属库:stdio.h
函数功能:改变文件的读写许可设置,如果改变成功返回0,否则返回-1

chmod函数的定义: 
#include 
#include 
int chmod(const char *path, mode_t mode)
关于mode_t的定义:
#ifndef __mode_t_defined
typedef __mode_t mode_t;
# define __mode_t_defined
#endif
__mode_t的定义:
#define __mode_t __MODE_T_TYPE
#define __MODE_T_TYPE __U32_TYPE
#define __U32_TYPE unsigned int
可以看到mode_t的定义实际就是unsigned int形式的。
   但是函数chmod(const char *path, mode_t mode)在解释mode_t时是将这里的mode当成8进制的去解释。
参数 mode 有下列数种组合
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限 
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
比如要将文件test的权限修改为644,那么可以采用以下几种方法:
chmod("test", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
chmod("test", 0644);
chmod("test", 420);
   第一种方法是将00400和00200和00040和00004进行或运算,最终得到的结果就是0644(八进制),而八进制的0644就等于十进制的420。所以上面三种方法是等效的。
   当我们给chmod函数传递参数时他会将对应的十进制的mode参数转换为相应的八进制进行运算。所以我们要将test文件的权限改为644时传递给函数chmod的参数不能直接是644。而应该是420。这是因为十进制的420就等于八进制的644。
   但是我们使用chmod命令时却可以直接输入644。具体的chmod实现时我认为是将644接收后(接收时可能是以字符串形式接收)认为644是八进制的数据,然后将644转换为对应的十进制,然后直接传递给函数chmod(const char *path, mode_t mode)。
*/
        







评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值