Unix/Linux 编程笔记

笔记来源于阅读《Unix/Linux 编程实践教程》(UUAP)时的所思所想

day 1

/dev/tty

如果用管道“|”,那么实际上就是把前一个的输出作为下一个的标准输入,然后键盘输入也是标准输入,也就是说如果编程要用getchar()这样的函数来读取键盘输入是不可行的,因为实际上有可能用的是前一个的输出。解决办法就是用/dev/tty

文件/dev/tty是键盘和显示器的设备描述文件,向这个文件写相当于显示在用户的屏幕上,读相当于从键盘获取用户的输入。即使程序的输入/输出被“<”或“>”重定向,程序还是可以通过这个文件与终端交换数据

UUAP
FILE *fp_tty;                                                                                                                                                            
fp_tty = fopen("/dev/tty", "r"); 

因为是文件,跟stdin、stout和普通的文件是一样操作

问题

在尝试着把结构体中的time_t值转化为年月日(使用ctime函数),发现一个问题

printf("%12.12s",ctime(&(utbufp->ut_time))+4);

output:
root     tty7     Nov  9 10:12 (:0)

但实际上如果先用一个long值赋值,就会得到正确的值

long tmp = utbufp->ut_time;
printf("%12.12s",ctime(&(tmp))+4);

output:
root     tty7     Jun 22 19:33 (:0)

这就很迷了,如果是在windows下我还可以用强大的visual studio一探究竟,在linux下我就不知道咋办了。试了一下gdb的tui,搞不懂啊实在是

不过考虑到ctime的参数要求是const,可能是这个的原因?

day 2

感觉这个没啥好更的。总不能贴很傻逼的C语言代码吧。

不过这两天感受到了man手册的好处,各种介绍都非常的详细(甚至好多函数都有非常详实的demo),感觉如果有人要来问我linux咋学的话,我肯定会狠狠地推荐man。(虽然好像我也不大懂linux)

刚才在看文件的set-user-id位。一开始理解错了,我还以为是一个文件A(0600),加了这个权限(4600)就可以通过那个用户创建的程序去read或者write文件A。

结果我想错了,它的意思是,给一个程序加上set-user-id位,在运行这个程序的时候就会当做是创建者的身份运行

一个很有意思的小知识hhh,毕竟像passwd就是这样的东西

有set-user-id位的文件还会标红欸,是不是说这东西很危险啊hhh

有set-user-id位的文件还是很多的

话说为啥root用户下的终端都这么索然无味

看看普通用户的!

这明显好看很多吧

day 3

今天看了看unix/linux文件方面的内容。不过没学过其它操作系统的文件系统,不太好比较,单只是觉得unix的文件好像很。。很奇妙的感觉(毕竟在windows里只看到过快捷方式,没看到过一个一模一样的同一个文件可以同时出现在目录的很多个地方)

linux中的目录就是一棵“指针”组成的树而已。每个文件在硬盘上的位置和在目录中的位置是没有一点关联的,在硬盘中的每个文件都有自己的inode(也只有这个,没有名字),在每个文件系统中都是唯一的。

树上的每个节点的结构包含inode和字串(名字),对应一个硬盘中的文件。所以,一棵树上可以有一堆一模一样的文件(真的就是同一个文件)然后还拥有不同的名字。

这么一搞的话,文件的移动就会变得非常方便快捷(刚刚看了下,好像在windows中也是这样的?),移动一个文件需要做的仅仅就是把树上的结点移动一下罢了

以及linux中的挂载点,就是把一个文件系统的树根接到一棵树上罢了,就感觉很神奇

这本书还讲了讲硬盘上的大文件是怎么储存的,其实就是类似内存的那样,有一块存储指向一个个数据块的结构,然后inode指向这个结构,这样就能索引文件了。(这是二级间接块,小文件可以没有这个,大文件可以有更多的层级)

day 7 ?

我已经摸鱼了这么多天了?、??不过前两天看的东西也没啥让我想写的欲望。之前的时候看了点对终端的各种设置,例如ICANON、ECHO(回显)什么的,以及一个无阻塞的方式

打算写一个搞新生的题目,让新手运行的时候都不知道怎么退出,嘻嘻

今天看了点中断,这个中断还是有意思啊,不过程序能够自己处理的只有SIGINT,也就是Ctrl+C,也就是说只要Ctrl+\还是能直接关掉程序的。。。想搞一个能阻止SIGKILL的方法,感觉那就有意思多了。(虽然进程可以由守护进程重新开起来,但是应该不能在原来的终端再起了吧?但是也许可以新建终端?)

以及,SIGINT并不都是坏的,也有“善良”的中断,比如有个大型的工作,中断可以用来查看当前的进度。例如下面的代码

#include <stdio.h>
#include<signal.h>
#include<unistd.h>

void view_progress();

static int c = 0;

int main()
{
    signal(SIGINT, view_progress);
    while(1)
    {
        sleep(1);
        c++;
    }
}

void view_progress()
{
    printf("Now c is %d\n", c);
}
[email protected]:~/learning/uulp# ./kindINT 
^CNow c is 1
^CNow c is 4
^CNow c is 5
^CNow c is 6
^CNow c is 7
^CNow c is 8
^CNow c is 9
^CNow c is 10
^CNow c is 11
^CNow c is 12
^CNow c is 13
^CNow c is 14
^CNow c is 15

^CNow c is 18

^CNow c is 19
^\退出

贴个我瞎几把写的东西

其实我只是综合了之前的内容,写了一个看起来很有趣的小玩意罢了,但是好像没什么用

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<termios.h>
#include<stdlib.h>
#include<fcntl.h>

void restore(int);
void self_protect();
void set_tty_state();
void set_nodelay_mode();
void back_door();
void angry(int);

int main()
{
    restore(0);
    self_protect();
    set_tty_state();
    set_nodelay_mode();
    back_door();
}

void restore(int mode)
{
    static struct termios original_state;
    static int original_termflags;
    if(!mode)
    {
        tcgetattr(0, &original_state);
        original_termflags = fcntl(0, F_GETFL);
    }
    else
    {
        tcsetattr(0, TCSANOW, &original_state);  // restore original state
        fcntl(0, F_SETFL, original_termflags);
    }
}

void set_tty_state()
{
    struct termios new_state;
    tcgetattr(0, &new_state);
    new_state.c_lflag &= ~ICANON;
    new_state.c_lflag &=~ECHO;
    new_state.c_cc[VMIN] = 1;
    tcsetattr(0, TCSANOW, &new_state);
}

void set_nodelay_mode()
{
    int termflags;
    termflags = fcntl(0,F_GETFL);
    termflags |= O_NDELAY;
    fcntl(0, F_SETFL, termflags);
}

void self_protect()
{
    signal(SIGINT, angry);
    signal(SIGQUIT, angry);
    signal(SIGTSTP, angry); 
}

void back_door()
{
    int c;
    while(1)
    {
        printf("I don't want to quit. YOU CAN'T KILL ME!\n");
        printf("Do you really want to kill me?QAQ");
        if((c = getchar()) == 'n')
        {
            restore(1);
            exit(1);
        }
        putchar('\n');
    }
}

void angry(int s)
{
    sleep(2);
    printf("\n\e[31;47m U want use Ctrl + C or Ctrl + Z, Ctrl + \\ to kill me? Naive!!! \e[0m\n");
    printf("\e[31;47m Give up, Muggle!\e[0m\n");
    sleep(2);
}

说起来我也忘记我贴上来的这个版本是不是未完成的了

它其实一直在getchar(),是非阻塞模式的,而且没有回显,只有输入“n”才能让它自己退出

说点什么

avatar

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

  Subscribe  
提醒