标签 linux 下的文章

stat结构体如下:

struct stat:
dev_t        st_dev        /*id device containing file*/
ino_t        st_ino        /*inode number*/
mode_t        st_mdoe        /*protection*/
nlink_t        st_nlink    /*number of hard link*/
uid_t        st_uid        /*user id of owner*/
gid_t        st_gid        /*group id of owner*/
dev_t        st_rdev        /*device ID(if specical file)*/
off_t        st_size        /*total size in bytes*/
blksize_t    st_blksize    /*blocksize for filesystem I/O*/
blkcnt_t    st_blokcs    /*number of blocks allocated*/
time_t        st_atime    /*time to last access*/
time_t        st_mtime    /*time to last modification*/
time_t        st_ctime    /*time to last satus change*/

struct stat常用字段:

st_mode:文件的访问权限和文件类型。您可以使用宏(如 S_ISREG()、S_ISDIR())来检查文件类型和权限。
st_size:文件的大小(以字节为单位)。
st_uid:文件所有者的用户ID。
st_gid:文件所属组的组ID。
st_atime:最后访问时间(上次读取文件的时间)。
st_mtime:最后修改时间(上次修改文件的时间)。
st_ctime:文件状态改变时间(上次修改文件权限、所有者等的时间)。

自定义命令的显示写法(开源项目里命令使用提示类似linux那种自带提示):

if(argc != 2){printf("Usage : stat <pathname>\n");exit(-1);}

argc处的2可以为任意num,判断的是用户输入的参数是否数量对应,不对应就显示Usage提示并退出

实例

综上,可以写出类ls命令的自定义stat命令实例,代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>

int main(int argc,char ** argv)
{
  struct stat buf;
  
  if(argc != 2){
  printf("Usage : stat <pathname>\n");exit(-1);
    }
  if(stat(argv[1],&buf) != 0){
  printf("stat error!\n");exit(-1);
 }
  printf("#DEV_ID       :\n",(int)buf.st_dev);
  printf("#i-node       :\n",(int)buf.st_ino);
  printf("#link         :\n",(long)buf.st_nlink);
  printf("#UID          :\n",(int)buf.st_uid);
  printf("#GID          :\n",(int)buf.st_gid);
  printf("#size         :\n",(long)buf.st_size);
  printf("#modify_time  :\n",(long)buf.st_mtime);
  printf("#change_time  :\n",(long)buf.st_ctime);
  exit(0);
    }

在linux项目中,源码的编译一般分为手动和自动,两种方法都是基于gcc实现的。但在修改和重新编译的便捷程度上来说,手动不如自动,而自动编译一般是基于makefile来实现的编译。

makefile尤其是在中大型C Project中是非常有用的,实现了代码修改和编译的解耦合。实例如下:

code.c

//code.c
#include "code.h"
int myfun(int in){
  return in + 1;
}

code.h

//code.h
extern int myfun(int);

prog.c

//prog.c
#include<stdio.h>
#include "code.h"
int main(void){
  int i = 1;
  printf("myfun(i) = %d\n",myfun(i));
}

如上实例其实比较简单,手动编译的话其实也只需要三行命令实现,如下:

gcc -c code.c -o code.o
gcc -c prog.c -o prog.o
gcc prog.o code.o -o test

但是如果我们通过makefile,其实可以只通过更为简短好记的命令完成编译:

Makefile

test: prog.o code.o
    gcc prog.o code.o -o test
    ./test
prog.o: prog.c code.h
    gcc -c prog.c -o prog.o
code.o: code.c code.h
    gcc -c code.c -o code.o
clean:
    rm -f *.o test

命令:

make test    //实现编译并运行
make clearn    //清除中间文件和编译后的可执行文件

通过比较手动和自动,不难发现基于makefile的自动编译省去了敲命令的时间,还减少了gcc命令的输入错误和输入时间,有助于后期项目的修改和维护。

详解Makefile文件逻辑

makefile的撰写逻辑其实是非常清晰的,想象有一颗倒过来的树,树的顶端就是你最终想要实现的可运行的文件,而依次往下就是你要编译的文件,得到的图解就会如下图所示:(基于上面的实例做示范)

make工作树
借助工作树,可以帮助你更好的理解项目的依赖和编译过程.与此同时它也可以辅助你快速的写出项目的makefile文件实现项目的自动编译。

通过上面的工作树,我们可以得知:makefile里每一次编译动作的执行都需要两个参数(clean动作除外),如:
test: prog.o code.o
对此再进一步总结,就可以得出格式如下:

目标文件:    依赖文件列表
TAB命令
...
TAB命令
...

拓展

以上只是最简单和最基础的makefile的使用,进阶可以参考:
Makefile入门(超详细一文读懂)
全网最牛Linux内核Makefile文件详解

在Linux操作系统中,有几种常见的文件系统类型,其中包括ext1、ext2、ext3和ext4。下面是对它们的区别进行详细描述:

ext1(第一个扩展文件系统):

ext1是最早的扩展文件系统之一,用于早期的Linux系统。它是linux上第一个利用虚拟文件系统实现出的文件系统。它使用简单的文件组织结构,没有日志功能,也没有支持文件系统的日志记录和恢复功能。ext1不支持文件和目录的访问控制列表(ACL)。
由于缺乏日志功能,如果系统崩溃或意外断电,可能会导致数据损坏或丢失。

ext2(第二个扩展文件系统):

ext2是ext1的改进版本,增加了一些功能和性能改进。
ext2 的经典实现为LINUX内核中的ext2fs文件系统驱动,最大可支持2TB的文件系统。在ext2文件系统中,文件由inode(包含有文件的所有信息)进行唯一标识。一个文件可能对应多个文件名,只有在所有文件名都被删除后,该文件才会被删除。此外,同一文件在磁盘中存放和被打开时所对应的inode是不同的,并由内核负责同步。文件系统高效稳定。
ext2仍然不支持访问控制列表(ACL)。

ext3(第三个扩展文件系统):

ext3是ext2的演化版本,向后兼容ext2。
ext3在ext2的基础上增加了日志记录功能,提供了更好的数据一致性和错误恢复能力。
它支持访问控制列表(ACL),可以为文件和目录设置更详细的权限控制。
ext3仍然使用固定的索引节点(inode)大小,限制了文件系统的最大容量和性能。

特性:
1、高可用性:系统使用了ext3文件系统后,即使在非正常关机后,系统也不需要检查文件系统。
2、数据的完整性:避免了意外宕机对文件系统的破坏。
3、文件系统的速度:因为ext3的日志功能对磁盘的驱动器读写头进行了优化。所以,文件系统的读写性能较之Ext2文件系统并来说,性能并没有降低。
4、数据转换 :“由ext2文件系统转换成ext3文件系统非常容易。
5、多种日志模式

ext4(第四个扩展文件系统):

ext4是ext3的进一步改进和升级版本,向后兼容ext2和ext3。
ext4增加了更高的文件系统容量限制和更大的文件大小支持。
它引入了多块分配、延迟分配和无日志写入等功能,提高了文件系统的性能和数据安全性。
ext4支持更快的文件系统检查和修复时间,并提供更灵活的文件系统扩展能力。

特性:

1.与Ext3兼容

2.更大的文件系统和更大的文件:Ext4分别支持1EB(1EB=1024PB,1PB=1024TB)的文件系统,以及16TB 的文件。

3.无限数量的子目录:而Ext4支持无限数量的子目录。

4.Extents:Ext4引入了extents概念,每个 extent 为一组连续的数据块,相比Ext3采用间接块映射,提高了不少效率。

5.多块分配:Ext4 的多块分配器“multiblock allocator”(mballoc) 支持一次调用分配多个数据块。

6.延迟分配

7.快速 fsck

8.日志校验

9.“无日志”(No Journaling)模式

10.在线碎片整理

11.inode 相关特性:较之Ext3默认的inode大小128字节,ext4默认inode大小为256字节


没有ext1的原因:

旧且过时:ext1是最早的扩展文件系统之一,用于早期的Linux系统。随着时间的推移,ext1已被后续的文件系统所取代,并且不再是当前Linux系统的标准选择。

缺乏重要特性:相比后续版本的ext文件系统,ext1缺乏许多重要的特性。它不具备文件系统日志功能,这意味着在系统崩溃或意外断电的情况下,数据完整性和一致性的保护能力较差。此外,ext1也不支持访问控制列表(ACL),这限制了对文件和目录权限的更精细控制。

不推荐使用:由于缺乏关键特性和相对较低的可靠性,Linux社区已经不再推荐使用ext1文件系统。后续的ext2、ext3和ext4文件系统提供了更多的功能和改进,可以更好地满足现代系统的需求。


相关资料:

Ext4 - Ubuntu Wiki: 这是Ubuntu操作系统的官方Wiki页面,涵盖了对ext4文件系统的详细介绍,包括特性、性能、格式化、调优和备份等方面的内容。
链接:https://wiki.ubuntu.com/Ext4

The Linux Kernel Documentation: ext4优化
链接:https://www.kernel.org/doc/html/latest/filesystems/ext4/

1. 静态库&动态库

1静态链接库的优点

(1)代码装载速度快,执行速度略比动态链接库快;

(2)只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题。

2动态链接库的优点

(1)更加节省内存并减少页面交换;

(2) DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;

(3)不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;

(4)适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。

3不足之处

(1)使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;

(2)使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,统统撕掉。这在早期Windows中很常见

2. Mask&Umask

Linux中的权限有r(读) w(写) x(执行),分别用数字4,2,1代表。
Umask是设置系统创建文件时的默认权限,是创建文件权限补码,对文件来说最大值是6
Umask设为为244,则创建的文件默认权限是422,文件的第一位是‘-’也就是-r—w–w-

3. 子进程&父进程

子进程继承父进程
    用户号UIDs和用户组号GIDs
    环境Environment
    堆栈
    共享内存
    打开文件的描述符
    执行时关闭(Close-on-exec)标志
    信号(Signal)控制设定
    进程组号
    当前工作目录
    根目录
    文件方式创建屏蔽字
    资源限制
    控制终端
子进程独有
    进程号PID
    不同的父进程号
    自己的文件描述符和目录流的拷贝
    子进程不继承父进程的进程正文(text),数据和其他锁定内存(memory locks)
    不继承异步输入和输出
父进程和子进程拥有独立的地址空间和PID参数。
子进程从父进程继承了用户号和用户组号,用户信息,目录信息,环境(表),打开的文件描述符,堆栈,(共享)内存等。
经过fork()以后,父进程和子进程拥有相同内容的代码段、数据段和用户堆栈,就像父进程把自己克隆了一遍。事实上,父进程只复制了自己的PCB块。而代码段,数据段和用户堆栈内存空间并没有复制一份,而是与子进程共享。只有当子进程在运行中出现写操作时,才会产生中断,并为子进程分配内存空间。由于父进程的PCB和子进程的一样,所以在PCB中断中所记录的父进程占有的资源,也是与子进程共享使用的。这里的“共享”一词意味着“竞争”

4. EXT文件

ext
第一代扩展文件系统,一种文件系统,于1992年4月发表,是linux核心所做的第一个文件系统。采用Unix文件系统(UFS)的元数据结构,以克服MINIX文件系统性能不佳的问题。

ext2
第二代扩展文件系统是LINUX内核所用的文件系统,用以代替ext。

ext3
EXT3是第三代扩展文件系统。Ext3文件系统是从Ext2文件系统发展而来,目前已经非常稳定可靠。它完全兼容ext2文件系统。

ext4
EXT4是第四代扩展文件系统,是ext3文件系统的后继版本。Ext4是Ext3的改进版,修改了Ext3中部分重要的数据结构,Ext4可以提供更佳的性能和可靠性,还有更为丰富的功能

详细内容可阅读:ext文件系统笔记

5. nohup命令

如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用 nohup 命令。该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。nohup 就是不挂起的意思( no hang up )

6. 常见退出命令

Esc:在vi的插入模式或者底行命令模式下进入命令模式
q:用来退出 man 手册查看命令或者配置文件的状态,或者more、less等命令查看文件的状态
exit:一般用于退出会话式程序或者交互式命令行,如ssh远程连接,切换 shell(Linux中)
quit:一般用于图形界面的退出

7. git合并

( 1 ) git merge
( 2 ) git pull
( 3 ) git cherry-pick

8. 与或非符号

! 为非运算

-a (and)表示并且,与运算

-o (or)表示或,或运算

9. Select 与 Epoll

select 和 epoll效率差异的原因:select采用轮询方式处理连接,epoll是触发式处理连接。

Select:

  1. Socket 数量限制:该限制可操作的 Socket 数由 FD_SETSIZE 决定,内核默认32*32=1024.

2.操作限制:通过遍历FD_SETSIZE(1024)个 Socket 来完成调度,不管哪个 Socket 是活跃的,都遍历一遍。

Epoll

  1. Socket 数量无限制:该模式下的 Socket 对应的fd列表由一个数组来保存,大小不限制(默认4k)。

2.操作无限制:基于内核提供的反射模式,有活跃 Socket 时,内核访问该 Socket 的 callback ,不需要遍历轮询。

但当所有的 Socket 都活跃的时候,所有的 callback 都被唤醒,会导致资源的竞争。既然都是要处理所有的 Socket ,那么遍历是最简单最有效的实现方式。

10. crond 命令
速记:分食(时)日月粥(周)

crond是linux用来执行周期性任务的进程

crontab基本格式 :
分  时  日 月  周  命令
第1列表示分钟1~59 每分钟用或者 /1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令

时间配置段为 5 部分:f1 f2 f3 f4 f5,其中 f1 是表示分钟(0-59),f2 表示小时(0-23),f3 表示一个月份中的第几日(1-31),f4 表示月份(1-12),f5 表示一个星期中的第几天(0-6)。

当 f1 为 时表示每分钟都要执行,f2 为 时表示每小时都要执行程序,其余类推;
当 f1 为 a-b 时表示从第 a 分钟到第 b 分钟这段时间内要执行,f2 为 a-b 时表示从第 a 到第 b 小时都要执行,其余类推;
当 f1 为 /n 时表示每 n 分钟个时间间隔执行一次,f2 为 /n 表示每 n 小时个时间间隔执行一次,其余类推;
当 f1 为 a, b, c,… 时表示第 a, b, c,… 分钟要执行,f2 为 a, b, c,… 时表示第 a, b, c…个小时要执行,其余类推。

题中 /30 3 表示:每月的 3 号,每 30 分钟执行命令。

11. Linux运行级别

0 : 系统停机状态,系统默认运行级别不能设置为0,否则不能正常启动,机器关闭。

1 : 单用户工作状态,root权限,用于系统维护,禁止远程登陆,就像Windows下的安全模式登录。

2 : 多用户状态,没有NFS支持。

3 : 完整的多用户模式,有NFS,登陆后进入控制台命令行模式。

4 : 系统未使用,保留一般不用,在一些特殊情况下可以用它来做一些事情。例如在笔记本电脑的电池用尽时,可以切换到这个模式来做一些设置。

5 : X11控制台,登陆后进入图形GUI模式,XWindow系统。

6 : 系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动。运行init6机器就会重启

12. 磁盘默认权限

aqouta.user是用户磁盘配额需要的配置文件,而不是可执行文件

aquota.user 的权限是 -rw——,十进制值为 600

13. 常见的解/压缩命令

tar是操作.tar的命令
gzip是压缩.gz压缩包的命令
compress:压缩.Z文件
uncompress:解压缩.Z文件

14. 孤儿进程 & 僵尸进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上 ,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表上面出面处理它的一切善后工作。 因此孤儿进程并不会有什么危害。

有时会刻意使进程成为孤儿。比如 守护进程daemon,nohup命令

15. Linux启动流程

1,BIOS加电自检

2,从硬盘0柱面 0磁道 第一扇区读512字节的MBR主引导记录

3,运行引导程序Grub并根据其配置加载kernel镜像后初始化

4,根据/etc/inittab中系统初始化配置执行/etc/rc.sysinit脚本

5,根据第3步读到的runlevel值启动对应服务

6,运行/etc/rc.local

7,生成终端待用户登录

16. 产生死锁的必要条件

(1) 互斥条件:一个资源每次只能被一个进程使用
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
(3) 不剥夺条件:进程已获得的资源,在使用完之前,不能强行剥夺
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

**产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

17. POSIX互斥锁

POSIX,英文全称Portable Operating System Interface,也就是可移植操作系统接口。

POSIX互斥锁是指统一接口的互斥锁,它有一些相关的函数。

POSIX互斥锁相关函数有以下:

pthread_mutex_init 初始化一个互斥量
pthread_mutex_lock 给一个互斥量加锁
pthread_mutex_trylock 加锁,如果失败不阻塞
pthread_mutex_unlock 解锁
pthread_mutex_destroy 销毁互斥锁