1. 程式人生 > >Unix/Linux程式設計實踐教程–chmod在Centos7.3的實現

Unix/Linux程式設計實踐教程–chmod在Centos7.3的實現

環境: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 aaa
ls -l aaa > bbb
./a.out 644 aaa
ls -l aaa >> bbb
./a.out 0000 aaa
ls -l aaa >> bbb
./a.out u=rwxst aaa
ls -l aaa >> bbb
./a.out g=rwxst aaa
ls -l aaa >> bbb
./a.out o=rwxst aaa
ls -l aaa >> bbb
./a.out 0000 aaa
ls -l aaa >> bbb
./a.out a=rwxst aaa
ls -l aaa >> bbb
./a.out 0000 aaa
ls -l aaa >> bbb
./a.out a=rw aaa
ls -l aaa >> bbb
./a.out 0000 aaa
ls -l aaa >> bbb
./a.out ug=rw aaa
ls -l aaa >> bbb
./a.out o+rw aaa
ls -l aaa >> bbb
./a.out u+x aaa
ls -l aaa >> bbb
./a.out u+s aaa
ls -l aaa >> bbb
./a.out u-x aaa
ls -l aaa >> bbb
./a.out a-r aaa
ls -l aaa >> bbb
./a.out a+t aaa
ls -l aaa >> bbb

chmod 7777 aaa
ls -l aaa > ccc
chmod 644 aaa
ls -l aaa >> ccc
chmod 0000 aaa
ls -l aaa >> ccc
chmod u=rwxst aaa
ls -l aaa >> ccc
chmod g=rwxst aaa
ls -l aaa >> ccc
chmod o=rwxst aaa
ls -l aaa >> ccc
chmod 0000 aaa
ls -l aaa >> ccc
chmod a=rwxst aaa
ls -l aaa >> ccc
chmod 0000 aaa
ls -l aaa >> ccc
chmod a=rw aaa
ls -l aaa >> ccc
chmod 0000 aaa
ls -l aaa >> ccc
chmod ug=rw aaa
ls -l aaa >> ccc
chmod o+rw aaa
ls -l aaa >> ccc
chmod u+x aaa
ls -l aaa >> ccc
chmod u+s aaa
ls -l aaa >> ccc
chmod u-x aaa
ls -l aaa >> ccc
chmod a-r aaa
ls -l aaa >> ccc
chmod a+t aaa
ls -l aaa >> ccc

diff bbb ccc