Unix/Linux编程实践教程–chmod在Centos7.3的实现

来源:互联网 发布:淘宝返现卡片 编辑:程序博客网 时间:2024/06/01 08:18

环境:centos 7.3 x86_64

如果搜一下man就会发现,里面有两个chmod,一个是chmod(1),一个是chmod(2)。根据牛顿-莱布尼兹公式,立即推,第一个是用户命令,第二个是系统调用。系统调用里,函数的原型是这样的:

int chmod(const char *pathname, mode_t mode);

所以要实现的chmod命令,无非就是把用户的输入解释成对应的mode_t类型,然后交给chmod系统调用进行处理即可。

目标,支持符号和八进制数两种表示法。符号表示法仅支持[ugoa...][+-=][rwxst...]。八进制表示法支持1-4位八制数,没有设置的位默认为0,同man 1 chmod一致。

Usage: chmod mode file...

程序流程大概是这样的:

  1. 解析mode
  2. 对于每个文件调用chmod进行设置或修改

代码大概是这样的,用了一些位操作去减少代码的长度:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>void oops(const char* str);mode_t parse_mode(const char *mode);void xc_chmod(const char *path, mode_t mode);mode_t modify_mode(mode_t mode);#define USAGE "Usage: chmod mode file...\n"enum{    CW_ADD,    CW_REMOVE,    CW_SET,    CW_COVER}chmod_way;enum{    MOD_READ = 0444,    MOD_WRITE = 0222,    MOD_EXEC = 0111,};enum{    ER_ALL = 0777,    ER_USR = 0700,    ER_GRP = 070,    ER_OTH = 07}effect_range = 0;int mode_read = 0;int mode_write = 0; int mode_exec = 0;int mode_sgid = 0;int mode_sticky = 0;int main(int ac, char *av[]){    mode_t mode;    if(ac < 3){        fprintf(stderr, USAGE);        exit(1);    }    mode = parse_mode(*++av);    ac -= 2;    while(ac--)        xc_chmod(*++av, mode);    return 0;}void xc_chmod(const char *path, mode_t mode){    struct stat info;    if(chmod_way != CW_COVER){        if(stat(path, &info) == -1)            oops("chmod");        mode = info.st_mode;        mode = modify_mode(mode);       }    if(chmod(path, mode) == -1)            oops("chmod");}mode_t modify_mode(mode_t mode){    mode_t amode = mode;    int add_or_remove;    if(chmod_way == CW_SET)    {        if(mode_read){            // printf("MODE_READ: %o & effect_range: %o = %o\n", MOD_READ, effect_range, MOD_READ& effect_range);            amode |= MOD_READ & effect_range;        }        if(mode_write)            amode |= MOD_WRITE & effect_range;        if(mode_exec)            amode |= MOD_EXEC & effect_range;        if(mode_sgid){            if(effect_range & ER_USR)                amode |= S_ISUID;            if(effect_range & ER_GRP)                amode |= S_ISGID;        }        if(mode_sticky  && (effect_range & ER_OTH))            amode |= S_ISVTX;    }else{        add_or_remove = chmod_way == CW_ADD;        if(mode_read)            if(add_or_remove)                amode |= MOD_READ & effect_range;            else                amode &= ~(MOD_READ & effect_range);        if(mode_write)            if(add_or_remove)                amode |= MOD_WRITE & effect_range;            else                amode &= ~(MOD_WRITE & effect_range);        if(mode_exec)            if(add_or_remove)                amode |= MOD_EXEC & effect_range;            else                amode &= ~(MOD_EXEC & effect_range);        if(mode_sgid){            if(effect_range & ER_USR)                if(add_or_remove)                    amode |= S_ISUID;                else                    amode &= ~S_ISUID;            if(effect_range & ER_GRP)                if(add_or_remove)                    amode |= S_ISGID;                else                    amode &= ~S_ISGID;        }        if(mode_sticky && (effect_range & ER_OTH))            if(add_or_remove)                amode |= S_ISVTX;            else                amode &= ~S_ISVTX;    }    return amode;}mode_t parse_mode(const char *mode){    char *p;    mode_t amode;    if(mode[0] >= '0' && mode[0] <= '9'){        /* parse use oct digits */        int len = 0;        int base = 1;        int tmp = 0;        int i;        int legal = 1;        p = mode;        while(*p){            if(!(*p >= '0' && *p <= '7'))                legal = 0;            p++;            len++;        }        if(len > 4)            legal = 0;        if(!legal){            fprintf(stderr, USAGE);            exit(1);        }        sscanf(mode, "%o", &tmp);        amode = tmp;        chmod_way = CW_COVER;    }else{        /* parse use symbolic */        p = mode;        while(*p != '+' && *p != '-' && *p != '='){            switch(*p){                case 'a':                    effect_range |= ER_ALL;                    break;                case 'g':                    effect_range |= ER_GRP;                    break;                case 'o':                    effect_range |= ER_OTH;                    break;                case 'u':                    effect_range |= ER_USR;                    break;                default:                    fprintf(stderr, USAGE);                    exit(1);                    break;            }            p++;        }        switch(*p){            case '+':                chmod_way = CW_ADD;                break;            case '-':                chmod_way = CW_REMOVE;                break;            case '=':                chmod_way = CW_SET;                break;            default:                fprintf(stderr, USAGE);                exit(1);                break;        }        p++;        while(*p){            switch(*p){                case 'r':                    mode_read = 1;                    break;                case 'w':                    mode_write = 1;                    break;                case 'x':                    mode_exec = 1;                    break;                case 's':                    mode_sgid = 1;                    break;                case 't':                    mode_sticky = 1;                    break;                default:                    fprintf(stderr, USAGE);                    exit(1);                    break;            }            ++p;        }    }    return amode;}void oops(const char* str){    perror(str);    exit(1);}

效果:

这里写图片描述

测试脚本:

gcc chmod.c./a.out 7777 aaals -l aaa > bbb./a.out 644 aaals -l aaa >> bbb./a.out 0000 aaals -l aaa >> bbb./a.out u=rwxst aaals -l aaa >> bbb./a.out g=rwxst aaals -l aaa >> bbb./a.out o=rwxst aaals -l aaa >> bbb./a.out 0000 aaals -l aaa >> bbb./a.out a=rwxst aaals -l aaa >> bbb./a.out 0000 aaals -l aaa >> bbb./a.out a=rw aaals -l aaa >> bbb./a.out 0000 aaals -l aaa >> bbb./a.out ug=rw aaals -l aaa >> bbb./a.out o+rw aaals -l aaa >> bbb./a.out u+x aaals -l aaa >> bbb./a.out u+s aaals -l aaa >> bbb./a.out u-x aaals -l aaa >> bbb./a.out a-r aaals -l aaa >> bbb./a.out a+t aaals -l aaa >> bbbchmod 7777 aaals -l aaa > cccchmod 644 aaals -l aaa >> cccchmod 0000 aaals -l aaa >> cccchmod u=rwxst aaals -l aaa >> cccchmod g=rwxst aaals -l aaa >> cccchmod o=rwxst aaals -l aaa >> cccchmod 0000 aaals -l aaa >> cccchmod a=rwxst aaals -l aaa >> cccchmod 0000 aaals -l aaa >> cccchmod a=rw aaals -l aaa >> cccchmod 0000 aaals -l aaa >> cccchmod ug=rw aaals -l aaa >> cccchmod o+rw aaals -l aaa >> cccchmod u+x aaals -l aaa >> cccchmod u+s aaals -l aaa >> cccchmod u-x aaals -l aaa >> cccchmod a-r aaals -l aaa >> cccchmod a+t aaals -l aaa >> cccdiff bbb ccc
原创粉丝点击