文件系统2

  1. 系统数据文件信息
    /etc/passwd hh: x:1000:1000:,:/home/hh:/bin/bash
  • struct passwd * getpwuid(uid_t uid); 根据用户号查询用户信息
  • struct passwd * getpwuid(const char* name); 根据用户名获取用户信息
    id和用户名的转换,用这个命令/函数实现
// 根据用户号查询用户名代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pwd.h>


int main(int argc, char ** argv)
{
    if (argc < 2)
    {
        fprintf(stderr, "usage");
        exit(1);
    }
	
	// 传递用户号 uid  使用atoi转换
    struct passwd * pwdline = getpwuid(atoi(argv[1]));
    puts(pwdline->pw_name);  
    return 0;
}

/etc/group

  • struct group *getgrnam(const char *name); // 通过组名获取组的信息
  • struct group *getgrgid(gid_t gid);// 通过组号获取组的信息

/etc/shadow
struct spwd* getspnam(const char *name);
char * crypt(const char *phrase, const char *setting); // 原串,杂字串
注意:ubuntu下gcc的连接过程中是从左到右,该代码中使用了crypt, -lcrypt 写在源文件名右边,链接器就可以在crypt库中找到crypt函数的定义,gcc checkpass.c -lcrypt
sudo ./a.out hh

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

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        fprintf(stderr, "usage");
        exit(1);
    }

    // 获取口令原文
    // getpass(); // 作为口令输入
    char* input_pass = getpass("PassWord:");
    struct spwd * shadowline = getspnam(argv[1]);
    char * crypted_pass = crypt(input_pass, shadowline->sp_pwdp); // 加密  口令原文,
    if (strcmp(shadowline->sp_pwdp, crypted_pass) == 0)
    {
        puts("ok");
    }
    else
    {
        puts("failed");
    }
    return 0;
}

时间戳 time_t
st_atime
st_mtime
st_ctime
在这里插入图片描述

  • time_t time() || time(time_t);
  • struct tm* localtime(const time_t * times);
  • time_t mktime(struct tm * times); 会先进行校验合法,如果溢出,会自动进位
  • size_t strftime(**char *s, size_t max,** const char *format,const struct tm *tm); ``top 2 parametes 共同决定了一块缓冲区; const char *format提取的格式化,一般使用%Y-%m-%d %h:%M:%sconst struct tm *tm源时间,
 struct tm {
               int tm_sec;    /* Seconds (0-60) */
               int tm_min;    /* Minutes (0-59) */
               int tm_hour;   /* Hours (0-23) */
               int tm_mday;   /* Day of the month (1-31) */
               int tm_mon;    /* Month (0-11) */
               int tm_year;   /* Year - 1900 */
               int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
               int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
               int tm_isdst;  /* Daylight saving time */
           };

在out文件中,每隔一秒输出一行当前时间
涉及文件读写,追加读写,时间戳格式化,全缓冲刷新流

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define FEILNAEM "/tmp/out"
#define BUFFSIZE 1024

int main()
{
    FILE* fp = fopen(FEILNAEM, "a+"); // 追加读写
    if (fp == NULL)
    {
        perror("fopen()");
        exit(1);
    }

    int count = 0; // 有多少行
    char buf[BUFFSIZE];
    // 读内容 有多少行
    while (fgets(buf, BUFFSIZE, fp) != NULL)
    {
        count++;
    }

    time_t stamp;
    while (1)
    {
        time(&stamp); // 获取时戳
        struct tm* tm = localtime(&stamp); // 转换
        // 文件是全缓冲模式,\n 已经无法进行刷新,需要手动刷新fflush
        fprintf(fp, "%-4d%d-%d-%d %d:%d:%d\n", ++count,\
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, \  
                tm->tm_hour, tm->tm_min, tm->tm_sec); // 写入
        // 年从1900开始计算,月从0 开始计算,需要+1900 +1
        fflush(fp);
        sleep(1);
    }

    fclose(fp);

    // tail -f /tmp/out   实时查看文件
    return 0;
}

案例:输出今天的时间和100天后的时间

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define timestrsize 1024

int main()
{
    time_t stamp;
    stamp = time(NULL);
    char timestr[timestrsize];
    struct tm *tm;

    tm = localtime(&stamp);
    strftime(timestr, timestrsize, "Now: %Y-%m-%d", tm);
    puts(timestr); // 今天

    tm->tm_mday += 100;
    (void)mktime(tm); // 使用mktime的副作用,校验合法进位的作用

    strftime(timestr, timestrsize, "100days : %Y-%m-%d", tm);
    puts(timestr);

    return 0; // 给父进程的
}
  1. 进程环境
  • main函数
    int main(int argc, char** argv)
  • 进程的终止
    正常终止: 从main函数返回; 调用exit函数;调用_exit()或者_Exit();最后一个线程从其启动例程返回;最后一个线程调用了pthead_exit()函数
    异常终止:在程序中调用abort();接到一个信号并终止;最后一个线程对其取消请求做出响应
  • 命令行参数的分析
    int getopt(argc, argv, const char* optstring);
    getopt_long();
ls -l -i -n -a /etc/tmp
// 测试口令 ./mydate -y 4 -m -d  输出当前时间,年月日,4表示年按照4位输出eg:2023
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

#define timestrsize 1024
#define FMTSTRSIZE 1024
// -y : year
// -m : month
// -d : day
// -H : hour
// -M : minute
// -S : second
int main(int argc, char** argv)
{
    time_t stamp;
    stamp = time(NULL);
    char timestr[timestrsize];
    struct tm *tm;

    tm = localtime(&stamp);

    int c;
    char fmtstr[FMTSTRSIZE]; // 格式化使用参数进行拼接
    fmtstr[0] = '\0';
    while (1)
    {
        c = getopt(argc, argv, "H:MSy:md");// 如果有冒号,那么指针就默认指向有冒号的变量  // 删除冒号可实现MSmd的功能
        if (c < 0)
        {
            break; // 失败跳出
        }
        switch (c)
        {
        case 'H':
            if (strcmp(optarg, "12") == 0)
                strncat(fmtstr, "%I(%P) ", FMTSTRSIZE);
            else if (strcmp(optarg, "24") == 0)
                strncat(fmtstr, "%H ", FMTSTRSIZE);
            else
                fprintf(stderr, "invalid argv");
            break;
        case 'M':
            strncat(fmtstr, "%M ", FMTSTRSIZE);
            break;
        case 'S':
            strncat(fmtstr, "%S ", FMTSTRSIZE);
            break;
        case 'y':
            if (strcmp(optarg, "2") == 0)
                strncat(fmtstr, "%y ", FMTSTRSIZE);
            else if (strcmp(optarg, "4") == 0)
                strncat(fmtstr, "%Y", FMTSTRSIZE);
            else
                fprintf(stderr, "invalid argv -y");
            break;
        case 'm':
            strncat(fmtstr, "%m ", FMTSTRSIZE);
            break;
        case 'd':
            strncat(fmtstr, "%d ", FMTSTRSIZE);
            break;
        default:
            break;
        }
    }

    strftime(timestr, timestrsize, fmtstr, tm); // 缓冲区,大小,格式化,源
    puts(timestr); // 今天
    return 0;
}

测试口令: ./mydate -y 4 -m -d /tmp/out 如果指定文件,将结果输出到文件中,如果未指定文件 ,将结果输出到终端

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

#define timestrsize 1024
#define FMTSTRSIZE 1024
// -y : year
// -m : month
// -d : day
// -H : hour
// -M : minute
// -S : second
int main(int argc, char** argv)
{
    time_t stamp;
    stamp = time(NULL);
    char timestr[timestrsize];
    struct tm *tm;
    tm = localtime(&stamp);

    int c;
    char fmtstr[FMTSTRSIZE]; // 格式化使用参数进行拼接
    fmtstr[0] = '\0';
    FILE* fp = stdout;
    while (1)
    {
        c = getopt(argc, argv, "-H:MSy:md");// 如果有冒号,那么指针就默认指向有冒号的变量
        if (c < 0)
        {
            break; // 失败跳出
        }
        switch (c)
        {
        case 1:
            // 如果给出输出文件,就将结果输出到文件中,否则输出到终端中
            if (fp == stdout)
            {
                fp = fopen(argv[optind - 1], "w"); // man getopt 可以使用与其关联的宏optind  optarg
                if (fp == NULL)
                {
                    perror("fopen");
                    fp = stdout;
                }
            }
            break;
        case 'H':
            if (strcmp(optarg, "12") == 0)
                strncat(fmtstr, "%I(%P) ", FMTSTRSIZE);
            else if (strcmp(optarg, "24") == 0)
                strncat(fmtstr, "%H ", FMTSTRSIZE);
            else
                fprintf(stderr, "invalid argv");
            break;
        case 'M':
            strncat(fmtstr, "%M ", FMTSTRSIZE);
            break;
        case 'S':
            strncat(fmtstr, "%S ", FMTSTRSIZE);
            break;
        case 'y':
            if (strcmp(optarg, "2") == 0)
                strncat(fmtstr, "%y ", FMTSTRSIZE);
            else if (strcmp(optarg, "4") == 0)
                strncat(fmtstr, "%Y", FMTSTRSIZE);
            else
                fprintf(stderr, "invalid argv -y");
            break;
        case 'm':
            strncat(fmtstr, "%m ", FMTSTRSIZE);
            
            break;
        case 'd':
            strncat(fmtstr, "%d ", FMTSTRSIZE);
            
            break;
        default:
            break;
        }
    }

    strncat(fmtstr, "\n", FMTSTRSIZE);
    strftime(timestr, timestrsize, fmtstr, tm); // 缓冲区,大小,格式化,源
    fputs(timestr, fp); // 今天
    
    if (fp != stdout)
        fclose(fp);
    return 0;
}
  • 环境变量
    本质是key=value 命令export
    一般命令在当前路径可以实现 ,因为默认在path环境变量中添加了当前路径
    environ
    在这里插入图片描述
    输出环境变量
#include <stdio.h>
#include <stdlib.h>

extern char** environ;

int main()
{
    for (int i = 0; environ[i] != NULL; i++)
    {
        puts(environ[i]);
    }
    return 0;
}

char *getenv(const char *name); // 获取环境变量值 根据key获取value

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

int main()
{
    puts((getenv("PATH"))); // 获取path的环境变量
    return 0;
}

int setenv(const char *name, const char *value, int overwrite);

  • c程序的存储空间布局
    在这里插入图片描述
    命令 pmap 进程号 可查看进程空间

  • 动态库,静态库,手工装载库
    #include <dlfcn.h>
    void *dlopen(const char *filename, int flags);
    int dlclose(void *handle);
    dlerror
    链接的时候加上-ldl
  • 函数跳转
    int setjmp(jmp_buf env); 设置跳转点 马上返回的时候,返回0,如果从longjmp返回的时候,返回非0
    void longjmp(jmp_buf env, int val); 跳回到跳转点
    实现跨函数的安全跳转,切换执行环境
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

static jmp_buf save;

static void d(void)
{
    printf("%s():Begin.\n", __FUNCTION__);
    printf("%s(): jump now!",__FUNCTION__);
    longjmp(save, 6); // 带回的值是6  如果设置为0,那么会强制带回1,因为是跳回,必须是非0
    printf("%s():End.\n", __FUNCTION__);
}

static void c(void)
{
    printf("%s():Begin.\n", __FUNCTION__);
    printf("%s():Call d().\n", __FUNCTION__);
    d();
    printf("%s():d() returned.\n", __FUNCTION__);
    printf("%s():End.\n", __FUNCTION__);
}

static void b(void)
{
    printf("%s():Begin.\n", __FUNCTION__);
    printf("%s():Call c().\n", __FUNCTION__);
    c();
    printf("%s():c() returned.\n", __FUNCTION__);
    printf("%s():End.\n", __FUNCTION__);
}

static void a(void)
{
    printf("%s():Begin.\n", __FUNCTION__);
    int ret = setjmp(save);
    if (ret == 0)
    {
        // 设置
        printf("%s():Call b().\n", __FUNCTION__);
        b();
        printf("%s():b() returned.\n", __FUNCTION__);
    }
    else
    {
        // 跳回来的
        printf("%s():jumped back here with code%d\n", __FUNCTION__, ret);
    }
    printf("%s():End.\n", __FUNCTION__);
}

int main()
{
    // __FUNCTION__ gcc提供   还有__line__  __file__
    printf("%s():Begin.\n", __FUNCTION__);
    printf("%s():Call a().\n", __FUNCTION__);
    a();
    printf("%s():a() returned.\n", __FUNCTION__);
    printf("%s():End.\n", __FUNCTION__);
    return 0;
}
  • 资源的获取及控制
    命令:ulimit -a
    int getrlimit(int resource, struct rlimit *rlim);
    int setrlimit(int resource, const struct rlimit *rlim);
struct rlimit {
          rlim_t rlim_cur;  /* Soft limit */
          rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */ // 高限值不可以提高,只能降低(ROOT用户可以升高)
};

atexit(); 钩子函数 register a function to be called at normal process termination 正常终止的时候调用,释放该释放的内容

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

static void f1(void)
{
    puts("f1() is working");
}

static void f2(void)
{
    puts("f2 is working");
}

static void f3(void)
{
    puts("f3 is working");
}

int main()
{
    puts("begin");

    // 钩子函数
    atexit(f1);
    atexit(f2);
    atexit(f3); // 先执行

    puts("end");
    return 0;
}

钩子函数用法

open(f1)
atexit(f1);
open(f2)
atexit(f2);
这意味着当f1 open失败的时候,会调用钩子函数1,当f2 open失败的时候,会先调用f2钩子函数,再调用f1钩子函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值