2017-04-04 11:29:03 u012417380 阅读数 2570

本文参考自腾讯游戏安全实验室,感谢腾讯游戏安全实验室的技术分享,如有侵权,请联系我@@

linux进程空间中有较多的模块信息,模块信息一般包括:动态加载的链接库和可执行文件的信息。通过遍历模块可获取的进程信息包括:模块基地址和模块路径等。
下面我们以HelloWord 程序来讲讲解linux上进程模块信息的获取。该程序用C语言完成,调用了C语言标准库中的printf函数,源码如下:

#include <stdio.h>**重点内容**
int main(int argc,char ** argv){
     printf("Hello World!\n");
     getchar();
     return 0;
}

编译输出:

user1@user-virtual-machine:~/gamesafeTest$ gcc helloworld.c -o helloworld
user1@user-virtual-machine:~/gamesafeTest$ ./helloworld
Hello World!
|

一、Linux内存模块遍历的原理

proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。
进程内存模块的信息存放在proc文件系统下以pid为目录名称的maps文件中,通过读取cat /proc/<pid>/maps来读取内存的相关信息
另开一个shell,查看helloword程序的进程信息:

user1@user-virtual-machine:~$ ps -aux | grep helloworld
user1      5059  0.0  0.0   4196   356 pts/0    S+   00:13   0:00 ./helloworld
user1      5082  0.0  0.0  15952   940 pts/4    S+   00:14   0:00 grep --color=auto helloworld

user1@user-virtual-machine:~$ cat /proc/5059/maps
00400000-00401000 r-xp 00000000 08:05 149801                             /home/user1/gamesafeTest/helloworld
00600000-00601000 r--p 00000000 08:05 149801                             /home/user1/gamesafeTest/helloworld
00601000-00602000 rw-p 00001000 08:05 149801                             /home/user1/gamesafeTest/helloworld
7f883df80000-7f883e13b000 r-xp 00000000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e13b000-7f883e33a000 ---p 001bb000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e33a000-7f883e33e000 r--p 001ba000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e33e000-7f883e340000 rw-p 001be000 08:02 408879                     /lib/x86_64-linux-gnu/libc-2.19.so
7f883e340000-7f883e345000 rw-p 00000000 00:00 0 
7f883e345000-7f883e368000 r-xp 00000000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so
7f883e54c000-7f883e54f000 rw-p 00000000 00:00 0 
7f883e563000-7f883e567000 rw-p 00000000 00:00 0 
7f883e567000-7f883e568000 r--p 00022000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so
7f883e568000-7f883e569000 rw-p 00023000 08:02 408793                     /lib/x86_64-linux-gnu/ld-2.19.so
7f883e569000-7f883e56a000 rw-p 00000000 00:00 0 
7ffe737f7000-7ffe73818000 rw-p 00000000 00:00 0                          [stack]
7ffe7391e000-7ffe73920000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
user1@user-virtual-machine:~$ 

map文件中每份模块的每列信息含义如下:

  • 第1列:模块内容在内存中的地址范围,以16进制显示。
  • 第2列:模块内容在内存中的读取权限,r代表可读,w代表可写,x代表可执行,p代表私有,s代表共享。
  • 第3列:模块内容在对应模块文件中的偏移。
  • 第4列:模块文件在文件系统中的主次设备号。
  • 第5列:模块文件在文件系统中的节点号。
  • 第6列: 模块文件在文件系统中的路径。

每列信息对应Linux内核中mm.h(最新版本在 mm_types.h文件中定义该结构)文件的vm_area_struct数据结构内容。关于虚拟内存最基本的管理单元为 struct vm_area_struct信息,它描述的是一段连续的具有相同访问属性的虚存空间。该虚存空间的大小为物理内存页面的整数倍

//Linux/include/linux/mm_types.h

 /*
295  * This struct defines a memory VMM memory area. There is one of these
296  * per VM-area/task.  A VM area is any part of the process virtual memory
297  * space that has a special rule for the page-fault handlers (ie a shared
298  * library, the executable area etc).
299  */
300 struct vm_area_struct {
301         /* The first cache line has the info for VMA tree walking. */
302 
303         unsigned long vm_start;         /* Our start address within vm_mm. */
304         unsigned long vm_end;           /* The first byte after our end address
305                                            within vm_mm. */
306 
307         /* linked list of VM areas per task, sorted by address */
308         struct vm_area_struct *vm_next, *vm_prev;
309 
310         struct rb_node vm_rb;
311 
312         /*
313          * Largest free memory gap in bytes to the left of this VMA.
314          * Either between this VMA and vma->vm_prev, or between one of the
315          * VMAs below us in the VMA rbtree and its ->vm_prev. This helps
316          * get_unmapped_area find a free area of the right size.
317          */
318         unsigned long rb_subtree_gap;
319 
320         /* Second cache line starts here. */
321 
322         struct mm_struct *vm_mm;        /* The address space we belong to. */
323         pgprot_t vm_page_prot;          /* Access permissions of this VMA. */
324         unsigned long vm_flags;         /* Flags, see mm.h. */
325 
326         /*
327          * For areas with an address space and backing store,
328          * linkage into the address_space->i_mmap interval tree.
329          */
330         struct {
331                 struct rb_node rb;
332                 unsigned long rb_subtree_last;
333         } shared;
334 
335         /*
336          * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
337          * list, after a COW of one of the file pages.  A MAP_SHARED vma
338          * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack
339          * or brk vma (with NULL file) can only be in an anon_vma list.
340          */
341         struct list_head anon_vma_chain; /* Serialized by mmap_sem &
342                                           * page_table_lock */
343         struct anon_vma *anon_vma;      /* Serialized by page_table_lock */
344 
345         /* Function pointers to deal with this struct. */
346         const struct vm_operations_struct *vm_ops;
347 
348         /* Information about our backing store: */
349         unsigned long vm_pgoff;         /* Offset (within vm_file) in PAGE_SIZE
350                                            units */
351         struct file * vm_file;          /* File we map to (can be NULL). */
352         void * vm_private_data;         /* was vm_pte (shared mem) */
353 
354 #ifndef CONFIG_MMU
355         struct vm_region *vm_region;    /* NOMMU mapping region */
356 #endif
357 #ifdef CONFIG_NUMA
358         struct mempolicy *vm_policy;    /* NUMA policy for the VMA */
359 #endif
360         struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
361 };
362 

二、Linux内存模块遍历实现

乌班图64系统下获取”libc.so“模块内存加载基址和路径名.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
bool GetModuleBase(long long &ulModBase,pid_t pid,const char * pszModName){
        bool bRet = false;
        FILE * fp = NULL;
        char szMapFilePath[32]={0};
        char szMapFileLine[1024]={0};

        if(pszModName == NULL)
        {
          return bRet; 
        }

        if(pid < 0)
        {
            sprintf(szMapFilePath,"/proc/self/maps");
        }else{
            sprintf(szMapFilePath,"/proc/%d/maps",pid);
        }

        fp = fopen(szMapFilePath,"r");

        if(fp != NULL)
        {
              while(fgets(szMapFileLine,sizeof(szMapFileLine),fp)!=NULL)
              {

                if(strstr(szMapFileLine,pszModName))
                   {
                      char * pszModAddrStart = strtok(szMapFileLine,"-");
                      if(pszModAddrStart)
                      {
                          ulModBase = strtoul(pszModAddrStart,NULL,16);                     

                          if(ulModBase == 0x8000)
                            ulModBase =0;
                bRet = true;
                break;

                       }

                   } 
              }
           fclose(fp);
        }

        return bRet;
}

bool GetModuleFullName(pid_t pid,const char * pszModName,char *pszFullModName,int nBuffSize)
{
       bool bRet = false;
       FILE * fp = NULL;
       char szMapFilePath[32]={0};
       char szMapFileLine[1024]={0};
       char * pszFullName = NULL;

       if(pszModName == NULL|| pszFullModName == NULL||nBuffSize<=0)
       {
            return bRet;
       }

        if(pid<0)
        {
          sprintf(szMapFilePath,"/proc/self/maps");
        }
          else
        {
          sprintf(szMapFilePath,"/proc/%d/maps",pid);
        }

        fp = fopen(szMapFilePath,"r");
        if(fp!=NULL)
        {
           while(fgets(szMapFileLine,sizeof(szMapFileLine),fp)!=NULL)
           { 

             if(strstr(szMapFileLine,pszModName))
             {
                           if(szMapFileLine[strlen(szMapFileLine) -1]=='\n')
                           {
                              szMapFileLine[strlen(szMapFileLine) -1]=0;
                           } 

                           pszFullName = strchr(szMapFileLine,'/');

                           if(pszFullName == NULL)
                           {
                                   continue;
                           }

                           strncpy(pszFullModName,pszFullName,nBuffSize -1); 

                           bRet = true;    
                      }

           } 

           fclose(fp);

        }
        return bRet;

}

int main(int argc,char ** argv)
{
     long long ulCModBase  = 0;
     char szCModPath[256] = {0};

     if(GetModuleBase(ulCModBase,getpid(),"libc-2.19.so"))
     {
        printf("c mod base:0x%llx\n", ulCModBase);
     }

     if (GetModuleFullName(getpid(), "libc-2.19.so", szCModPath, 256))
     {
        printf("c mod full path:%s\n", szCModPath);
     }

     printf("finish \n");
     return 0;
}

编译输出:

user1@user-virtual-machine:~/gamesafeTest$ g++ MapCheck.cpp -o mapcheck
user1@user-virtual-machine:~/gamesafeTest$ ./mapcheck
c mod base:0x7f28c6471000
c mod full path:/lib/x86_64-linux-gnu/libc-2.19.so
finish 
2020-03-16 14:47:52 sweetfather 阅读数 58

首先简单说一下什么是环境变量?环境变量简单的说就是当前环境下的参数或者变量。如果说的专业一点就是指在操作系统中用来指定操作系统的一些参数。 
   
  举个我们最常见的环境变量 —— PATH,它的用途就是当用户要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下寻找此程序外,还要到PATH变量中指定的路径去寻找。用户可以通过设置PATH变量,来更好的运行进程。举个常见的例子,

在Linux系统下配置环境变量最常用的两种方法:
  1、修改家目录下的 .bashrc 文件
  2、修改 /etc/profile 文件
  (注:最后我们会对比两种方法的利弊,大家可以根据自己的情况选用最适合的方法。) 


1、修改家目录下的 .bashrc 文件
  .bashrc 文件主要保存着个人的一些个性化设置,如:命令别名、环境变量等。

  1)先切换回家目录
cd ~
  2)修改 .bashrc 文件
vi .bashrc
  3)在 .bashrc 文件的 最后 加入环境变量
变量名=变量值
...=...
export 变量名 ...
如:JAVA_HOME=/opt/jdk1.8.0_91
  CLASSPATH=.:./bin
  PATH=$JAVA_HOME/bin:$PATH
  export JAVA_HOME CLASSPATH PATH
  4)退出并保存
:wq
  5)立即生效(此时应该在家目录下)
source .bashrc
  注:如果不执行 source 命令,则需重启系统才能生效

2、修改 /etc/profile 文件
  /etc/profile 文件是系统为每个用户设置的环境信息,当用户第一次登录时,该文件被执行。此文件的改变会涉及到系统的环境,也就是有关Linux环境变量的东西。

  1)修改 /etc/profile 文件
sudo vi /etc/profile
  2)在 /etc/profile 文件的 最后 加入环境变量
变量名=变量值
...=...
export 变量名 ...
如:JAVA_HOME=/opt/jdk1.8.0_91
  CLASSPATH=.:./bin
  PATH=$JAVA_HOME/bin:$PATH
  export JAVA_HOME CLASSPATH PATH
  3)退出并保存
:wq
  4)立即生效
source /etc/profile
  注:如果不执行 source 命令,则需重启系统才能生效

3、对比两种方法
  修改.bashrc文件,它可以把使用这些环境变量的权限控制到用户级别,只是针对某一个特定的用户。而修改 /etc/profile 文件,它是针对于所有的用户,使所有用户都有权使用这些环境变量。 
  相比较起来,第一种方法更加安全,因为如果采用第二种方法,它可能会给系统带来安全性的问题。 

 

2017-11-15 13:08:40 gexiucheng 阅读数 683

Linux服务器下需要监控某些进程的状态. 当进程不存在时, 自动启动, 当进程异常时, 自动重启.

以tomcat为例


1. 编写监控脚本(/data/bin/monitor.sh)

#!/bin/sh
#加载环境变量
#ALL
source /etc/profile

#MINE
source ~/.bash_profile

#进程标识(此处以路径作为标识)
TOMCAT_PATH=/root/tools/server

############重启服务
function restartServer(){
    #杀死进程
    if [ "" != "$1" ]
    then
        echo "kill the process"
        kill -9 $1
        sleep 2
    fi

    #重启进程脚本
    cd "$TOMCAT_PATH/bin"
    echo "restart the process `pwd`/startup.sh"
    sh startup.sh

    #结束
    echo "done!!!"
}

#打印脚本时间
monitorDate=`date "+%Y-%m-%d %H:%M:%S"`
echo -e "\n---------------Monitor at [$monitorDate]"

#获取进程pid
pid=`ps -ef|grep $TOMCAT_PATH|grep java|grep -v grep|awk '{print $2}'`
echo "PID: $pid"
if [ "" == "$pid" ]
then
    echo "ERROR: pid not found"

    #启动服务
    restartServer
    exit
else
    # 进程存在的情况下的处理
    # restartServer $pid
fi

添加执行权限 

chmod +x monitor.sh


2. 部署crontab(定时执行, 每5分钟执行一次)

crontab -e

*/5 * * * * /data/bin/monitor.sh >> /data/bin/minitor.log 2>&1


3. 观察日志文件是否有报错

tail -100f /data/bin/minitor.log


2018-03-25 09:55:15 guaiguaihenguai 阅读数 235
当没有指定查找路径时
Windows 会默认在当前路径下查找
Linux 默认在系统规定的目录(规定的目录是在PATH里边写死的)去查找,是不会在当前路径里边查找的
要想在当前目录下查找,必须把当前路径配到PATH里边去

如何将进程的空间的替换掉?------加载程序
加载器----exec系列的函数----将磁盘中的内容映射到内存中

exec系列函数的原型


int execve(const char* filename , char* const argv[] , char* const envp[]);
        ------操作系统只提供了这一个函数,其他的都是C语言库在它的基础上封装的。

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 ,const char*  argv[]);
int execvp(const char* file,const char*  argv[])

execl/execv          函数名中带p的是file ,因为那个p 就是path,代表文件路径
execlp/execvp      函数名不带p的是path,不仅要给出文件,还要给出文件里的路径。

execl ----不带e会将当前的进程的环境变量拿去用
execle ----e代表环境变量  不要原来的环境变量,要自己组装环境变量

如果既想使用execle 又想使用当前进程的环境变量,怎么实现呢?

系统里边定义了一个全局变量:char** environ   
可以使用 extern  char** environ  ,然后通过environ访问系统的环境变量

#include <stdio.h>
#include <stdlib.h> 
#include <unistd.h>
#include <string.h>

extern char* environ
int main()
{
        int i =0;
        for(i = 0; environ[i] != NULL ;i++)
            printf("%s\n",environ[i]);
        if(execle("./hello","hello",NULL,environ ) == -1)
            perror("exec"),exit(1);
}


这样一系列函数的使用都差不多,在这里就演示一下 execvp 的使用

为了方便验证,在这里将替换程序写简单一点。


被替换的程序




从结果可以看出,exec.c里边的 after execvp 并没有输出,这是为什么呢?
因为execvp函数已经使用可执行程序hello将后边的内容替换掉了。
如果替换失败,返回-1,后续代码依然会继续执行
exec系列函数

注:在哪个进程里边调用了exec就替换哪个进程的空间,并不需要创建一个子进程。
exec系列函数执行失败返回-1,原空间里边的内容会继续执行
执行成功地话是不会返回的,因为原来的空间已经被替换掉了,返回也没地接收了,所以不返回。
执行成功是不会返回的,因为执行成功了的话,原来的代码都不存在了,返回值也没地接收了,所以不返回。
2019-09-09 08:47:50 long_un 阅读数 21

linux 指令

命令

●内部命令,随Shell启动,常驻内存
●外部命令,需要找到文件加载进程,查找路径就是$PATH
。hash, 外部命令路径可以保存在一个hash表中

命令格式

命令本身可以接受选项和参数,而选项可以有自己的参数。
●短选项: -h使用-加一个字母,短选项可以合并,但是如果选项需要提供参数,必须放后面。 短选项往往都是最常用的选项,为了简化而提供
●长选项: -all使用–加单词,长选项不可以合并写
●Ctl+ c可以结束正在运行的命令
●\ 命令续行符
●;一行多个命令使用分号分割
●使用tab键补全,tab 2次可以提示补全的候选

命令扩展

在这里插入图片描述

常用命令

●查帮助

​ 。help 内部命令
​ 。man查看Man文档
​ 。命令h或命令–helpI

●命令

​ 。type命令类型 wc -l 统计条数
​ 。hostname 主机名
​ 。who登录信息, who am i或whoami, w
​ 。whatis 命令有什么功能
​ 。which 命令在哪里
​ 。whereis 命令程序二进制文件、man文档
​ 。 uname -a查看操作系统信息,比如内核版本-r
​ 。alias别名 。强制执行文件 bash+文件
​ 。echo 回显字符
​ ■-n取消自动附加最后的换行符
​ ■-e使用解释功能,$ echo -e “a\tb\nc"使用转义符
​ 。 date日期
​ ■date +”%Y%m%d %H:%M:%S"
​ ■date [MDDhhmm[[CC]YY][.ss]][.ss]]修改时间

●开关机

。halt, poweroff
。reboot重启
。shutdown [optionl... TIME
	■-r重启
	■-h关机
	■TIME: now立即执行; +3几分钟后执行; hh:mm几点几分开始执行
	■-c末执行前,还可以取消

●网络

​ 。 ping -c 20 -w 5 www. magedu. com
​ 。ip a
​ 。ss -tanlp

绝对路径和相对路径

●相对路径,不以/开始的路径
●绝对路径, 以/开始的路径
●因为常常当前工作路径会变化,有时候从当前路径为参照,找其它路径中的文件会出错,往往就从根开始写
绝对路径,减少路径错误
●相对路径用在相对于当前路径的某个文件, 相对关系不变的情况
●basename基名和dirname目录名

dirname /etc/ sysconfig/ network-scripts/ifcfg- ens33
/etc/sysconfig/ network-scripts

basename /etc/sysconfig/network-scripts/ ifcfg-ens33
ifcfg-ens33

文件类型

●-或f 普通文件
●d目录directory
●I 符号链接或软链接symbolic link,相当于快捷方式
●b块设备block device, 随机访问,磁盘
●c字符设备character device, 线性访问,键盘
●p管道pipe
●s socket文件

通配符Wildcard

● * 匹配0个或多个字符
● ?匹配一个字符
● [a-z]、 [A-Z]、 [0-9]、 [acdf]匹配一 个字符; 【^a-z】匹配a-z之外的任意- 个字符
● [:space:]空白字符; [:digit:]表示0-9; [:lower:]小写; [:upper:]大写; [:alpha:]字母; [:alnum:]字 母和数字等。
。当一个字符用,所以test[:alnum:]]

grep -E [a-z]+ 同等于 egrep [a-z]+

grep -v ^# -v:除什么之外 ^:以什么开头

文件系统命令

● Is列出目录内容

​ 。-a显示所有文件,包括隐藏文件,即以开头的文件
​ 。-l长格式显示。别名ll即Is -l。 显示了stat的部分内容
​ 。-h, -human-readable配合-I,人可阅读的,size显示为K、M、G等
​ 。-R递归目录
​ 。-d或-ld 显示目录自身
​ 。-i显示inode号

●stat 显示文件的信息(元数据metadata)

​ 。access time, atime,读取文件内容则设置
​ 。modify time, mtime,改变文件自身内容则设置。Is -I显示的时间就是mtime
​ 。change time, ctime, 元数据发生变化则设置

●cd 切换目录change directory

​ 。cd或cd ~回家
​ 。cd -最后两次目录切换

●pwd显示当前工作路径; basename基名,路径中最后-部分; dirname目录名
●file 显示文件格式
●cat 读取文件或stdin到stdout; tac每个文件倒着读取行
●more, less比more功能更强

​ 。回车向后- -行,y向前一-行
​ 。空格向后-页,b向前-页
​ 。d向后半页, u向前半页
​ 。g首行,G末行
​ 。u向前
​ 。/或?搜索
​ 。q退出
●head -n 20 /etc/passwd
●tail-n10 /etc/passwd; tail -f /var/log/messages
touch没有文件创建空文件,如果文件存在,改变时间戳
​ 。-a改变atime、 ctime
​ 。-m改变mtime、 ctime
​ 。-c如果文件不存在,则不创建
mkdir 创建目录
​ 。-p创建父目录
​ 。-v详情
tree递归显示目录树
​ 。-d只显示目录
​ 。-L n显示的最大层数
rmdir删除空录
rm慎用!!!
​ 。-i交互式提醒; -f强制不提醒
​ 。-r递归删除
​ 。rm -rf
In创建链接文件
​ 。-S 创建符号链接
​ 。-v详情
cp复制目录或文件,从源复制到目标。默认不递归复制
​ 。如果源是文件
​ ■目标是文件,目标不存在,直接创建指定名称文件。如果目标存在,覆盖
​ ■目标是路径,复制到指定的路径下,不存在新建,存在则覆盖
​ 。如果源是目录
​ ■目标是文件,不可以
​ ■目标是目录
​ ■如果目标目录存在,就在该目标目录下复制源目录内容
​ ■如果不存在,创建目标目录,复制源的内容
​ 。如果有多个源,目标只能是目录了,且目标必须存在
​ 。-i交互式提醒; -f强制覆盖不提示
​ 。-R-r递归复制
​ 。-perserv 保留指定的元数据信息,all保留所有即包含权限、属主、属组等
​ 。-d表示–no-dereference -preserv=links不复制源文件,只复制链接名
​ 。-a归档,相当于-dR --reserv=all, 递归复制所有文件包括软链接,但不跟踪软链接
mv移动或重命名
​ 。和cp很像
find [指定目录][指定条件] [指定动作] [指定动作]
​ 。find / -name *.py

符号链接

$ ln -sv test test.link
$ stat test
$ stat test.link
$ stat -L test.link
使用In命令加上-s选项就可以创建符号链接,也称软链接。软链接也是文件,60个字符以内,在软链接的inode entry中记录着链接到的文件的路径(相对或绝对路径字符串)。而大多数软链接记录的路径字符串长度都小于60,应当尽量避免为软链接分配块,太浪费空间了。
软链接里面记录着路径字符串,所以软链接的size就是路径字符串的长度。
stat的-L选项跟进符号链接。

inoda

每一个文件包括目录都有唯一的一个inode号

目录也是文件,在目录文件本身的数据.上存储着其下的文件的文件名到inode号的映射信息。

一般inode表会占用磁盘空间的1%,所以inode记录数有限制。可能会造成文件太多, inode用完了,可以磁盘还
有空间。因此,小文件多,要适当增加inode空间。inode不跨分区。
查看inode可以使用ls -i
在这里插入图片描述
●假设1个block为4KB
●有15个块指针区, 每个块指针占4个字节
●direct block直接块指针,有12个,那么所有直接块指针最大管理48KB的数据
●single indirecti间接块指针1个,指针占4个字节,1个块就可以存储1 k即1024个指针, 1K * 4KB=4MB, 说明间接块指针可以管理4MB数据
●double indirect二级间接块指针1个,一级指针可以存1K个指针,每一个-级指针有可以保持1K个二级指针,由此可得1K* 1K* 4K=4G,可以管理4G数据
●triple indirect三级间接块指针1个, 4G* 1K= 4T,可以管理4T数据

文件查找

​ /的inode在ext文件系统中是保留的,inode是2。
​ 假设需要查找/d1/f1这个文件,首先找到inode表中查找2对应的块block. /是目录,所以块信息中存储的是它里面的子目录或文件的inode号和文件名。匹配d1文件名后就知道了它的inode号,假设是1234。
​ 再去inode表中找1234对应的inode entry中块信息,然后读取块中信息,由于d1也是目录,从中找出f1和f1的inode。
​ 使用f1的inode去inode表中找到f1的块信息,就可以读取f1的数据了。
注:文件名是目录的数据,也就是说存在目录的块上。

硬链接:如果两个文件没有跨分区,且2个文件指向同一个inode,这就是硬链接,即文件的引用计数。ln test test1来创建文件test1,硬链接数加1。如果硬链接数为0,则文件才被清除了。

进程的状态返回值

​ 每一个进程可以有输入和输出,但是每一个进程还可以有一 个状态返回值, 来表示进程是否成功地执行。
​ 0在绝大多数操作系统中都表示成功;
​ 非0表示进程一定没有成功执行,但非零数表示什么意思,要看不同程序的帮助文档或编程手册。在bash中使用$?查看这个状态返回值。 echo $? 来查看

文件描述符

一切皆文件。每一个打开的文件分配一个文件描述符(Flle Descriptor),负整数。

在这里插入图片描述
管道
使用 |,上一个程序的标准输出通过管道送给下一个命令的标准输入。

重定向
重定向就是改变程序的输入或输出。
●>输出重定向: 相当于 w+ 把标准输出或者文件内容输出给目标 在最后添加 &> c = 2>&1 = 1>&2 在>c前面添加 2>&1 相当于 2 指向1的引用stdout 1也指向stdout 则都只接受stdout id abc > c 2>/dev/null stdout = c stderr = null(黑洞)
●》追加输出重定向:相当于尾部追加
●<输入重定向 :cat < c 原来读取键盘输出内容现在换出读取文件c内容字 符流
●<< Here Document >> cat > test << EOF:直接编辑test文件 buffer 遇到EOF之后结束
输出重定向和输出追加重定向

表示1先指向文件,2指向1,也就指向该文件 >files 2>&1
2>&1 > files表示2指向1即stdout,然后1重新指向一个文件

输入重定向

Here Document

用户和组

*nix(unix)是多用户系统

用户
。管理员
■root用户是必须有的管理员账户,特权用户,无所不能。慎用
■uid为0
■家目录在/root
。系统用户
■普通授权用户,不用登录,- -般不需要家目录
■uid 1-499,CentOS7 1-999
。普通用户
■普通授权用户,交互式登录,需要家目录在/home/
■uid 500+,CentOS 1000+
。用户id为2字节无符号整数,0是root, 其它用户使用1-65535

。用户属于不同的组
。管理员组
■名为root, gid为0
。系统组
■普通组,gid为1-499, CentOS7 1-999
。普通组
■普通组, gid为500+,CentOS 1000+
用户的组
。主要组、基本组primary group
■每一个用户都仅能属于一个组,这个组称为主组,创建用户是指定
。附加组supplementary group
■一个用户可以属于零个或多个附加组

主要配置文件

●/etc/passwd保存用户及id、主组id等属性信息 nologin 不允许登录 bash 登录需要密码
。登录名:密码(shadow中):uid:gid主组:注释:家目录:shell
●/etc/shadow保存用户密码及相关属性
●/etc/group组及属性信息
。组名:组密码(gshadow中):gid:以当前组为附加组的用户列表逗号分隔

用户和组命令

用户、组

​ 。id
​ ■id 当前用户
​ ■id wayne指定用户信息
​ ■-u用户id; -g主组; -G附加组; -n使用名字
​ 。useradd
​ ■-r 创建系统用户,默认没有家目录
​ ■-u UID指定uid
​ ■-g GID指定主组,如果没有指定,则创建与用户名相同的同名主组
​ ■-m系统用户默认不创建家目录,使用该选项创建家目录
​ ■-M非系统用户默认创建家目录,使用该选项则不创建
​ ■-d 指定家目录
​ ■-s 指定shell,查看/etc/shells
​ ■-G g1[g2,…]指定用户的附加组,附加组必须存在 usermod -aG user1 wayne 为wayne加个附加组 user1
​ 。su切换用户
​ ■su- wayne常用,登录式切换,读取该用户的配置文件,并切换到该用户的家目录
​ ■suwayne 用得少,非登录式切换,不读取用户配置文件,也不改变当前工作目录
​ ; # su wayne -C "id"常用,只是为了使用wayne用户启动- 个程序,没必要登录
​ ■当前是root用户, su切换时,无需密码,其它用户切换需要密码
​ 。passwd
​ ■; passwod当前用户修改密码
​ ■# echo 12345678 I passwd - -stdin wayne为wayne用户设置密码
​ ■密码应该足够强,或有过期
​ ■-d删除密码; -I锁定用户; -u解锁用户
​ ■-Xx maxdays密码最大使用期限,超过宽限期后用户将不能自己修改密码
​ ■-w warndays提前多少天警告密码要到期了; i inactivedays超期后修改密码的宽限期
usermod修改用户、userdel 删除用户
groupadd增加组、groupmod修改组、 groupdel删除组

进程的安全上下文

每一个进程启动起来,都有一个用户身份,这个身份决定着进程能访问什么资源。
文件的元数据中定义了权限mode,三部分为属主、属组、其它。
Read Write Execute
r w x
-ord rwx rwx rwx
FileType Owner Group Other Users

当一个进程访问-个资源时,首先进行属主权限匹配,未匹配再进行属组、附加组权限匹配。
如果都没匹配上,那么就是other其它用户,就匹配mode中的最后部分。

文件权限含义

在这里插入图片描述

权限命令
chmod
。-R 目录递归设置,不推荐
。chmod [OPTION… OCTAL-MODE FL…使用3位八进制数修改文件mode
。chmod [OPTION… MODE[MODE]… FILE…
■修改某-组3位权限u、g、o、a
■u=、g=、o=、a=、ug=、 uo=、 go=
■修改组内3位中的某- -位
■u+、g+、o+、a+、+
■u-、g、o-、a-、-
umask
。目录-般有x才能cd进入,文件-一般不要随便给x权限
。默认情况下,管理员umask是022,普通用户是002
。文件666-022=644
。目录为777-022=755
。umask 022修改掩码,非永久有效

在这里插入图片描述
chown
。-R目录递归修改
。| chown [OPTION]… [OINER][: [GROUP]] FILE… 改文件的属主、属组

在这里插入图片描述

Android Init进程

阅读数 424

没有更多推荐了,返回首页