diff --git a/C13-Linux系统编程/C13-Linux系统编程学习笔记.md b/C13-Linux系统编程/C13-Linux系统编程学习笔记.md index d2a10e9..f575d79 100644 --- a/C13-Linux系统编程/C13-Linux系统编程学习笔记.md +++ b/C13-Linux系统编程/C13-Linux系统编程学习笔记.md @@ -411,6 +411,11 @@ p1->read -> p2->write ### 程序中的重定向:`dup`, `dup2` ```c +/** + * dup 和 dup2 都是复制文件描述符 + * dup2 可以指定新的文件描述符 + * dup 会返回一个新的文件描述符 + */ int dup(int oldfd); int dup2(int oldfd, int newfd); ``` @@ -687,7 +692,214 @@ long telldir(DIR *dirp); ## 系统数据文件和信息 +> 不同环境可能有区别,以具体查询为准,这里以Linux为例 + +1. `/etc/passwd` +```c +/** + * 通过用户名获取用户信息 +*/ +struct passwd *getpwuid(uid_t uid); + +/** + * 通过用户ID获取用户信息 +*/ +struct passwd *getpwnam(const char *name); + +struct passwd { + char *pw_name; /* username */ + char *pw_passwd; /* user password */ + uid_t pw_uid; /* user ID */ + gid_t pw_gid; /* group ID */ + char *pw_gecos; /* user information */ + char *pw_dir; /* home directory */ + char *pw_shell; /* shell program */ +}; +``` + +2. `/etc/group` +```c +/** + * 通过组ID获取组信息 +*/ +struct group *getgrgid(gid_t gid); + +/** + * 通过组名获取组信息 +*/ +struct group *getgrnam(const char *name); + +struct group { + char *gr_name; /* group name */ + char *gr_passwd; /* group password */ + gid_t gr_gid; /* group ID */ + char **gr_mem; /* group members */ +}; +``` + +3. `/etc/shadow` +ll显示root用户也不可读写,但是只有root用户才可读写 +这样是提醒你,即便是root用户,也不要随便读写这个文件 + +> 密码 +> hash - 混淆,不可逆 +> 如果原串一样,hash值也一样 +> 防备管理员监守自盗 +> +> 加密 - 解密 +> +> 加密为了安全,攻击成本大于收益 +> 安全?穷举:口令随机校验(第一遍明明对了给你报错,让你连续两遍成功输入正确) +> +> 推荐书籍:《应用密码学》 + +```c +/** + * 获得用户的密码信息 +*/ +struct *spwd getspnam(const char *name); + +/** + * 加密密码 + * + * @prarm: key 密码 + * @prarm: salt 盐 杂字串 + * + * 默认 md5 加密方式 +*/ +char *crypt(const char *key, const char *salt); + +struct spwd { + char *sp_namp; /* login name */ + char *sp_pwdp; /* encrypted password */ + long sp_lstchg; /* last change */ + long sp_min; /* min days between changes */ + long sp_max; /* max days between changes */ + long sp_warn; /* warning days before password + expires */ + long sp_inact; /* days before account inactive */ + long sp_expire; /* days since 1970-01-01 until account + expires */ + unsigned long sp_flag; /* reserved */ +}; + +/** + * 输入提示符 +*/ +char *getpass(const char *prompt); +``` + +4. 时间戳 +机器喜欢大整数 `time_t` +人类喜欢字符串 `char *` +程序员喜欢结构体 `struct tm` + +```c + +/** + * 从内核获取以秒为单位的一个时戳 + * 从 UTC 1970年1月1日0时0分0秒 到现在的秒数 +*/ +time_t time(time_t *t); + +// eg: 两种用法 +time_t stamp; +time(&stamp); +stamp=time(NULL); + +/** + * 将时间戳转换为结构体 +*/ +struct tm *gmtime(const time_t *timep); +struct tm *localtime(const time_t *timep); + +sturct tm { + int tm_sec; /* seconds */ + int tm_min; /* minutes */ + int tm_hour; /* hours */ + int tm_mday; /* day of the month */ + int tm_mon; /* month */ + int tm_year; /* year */ + int tm_wday; /* day of the week */ + int tm_yday; /* day in the year */ + int tm_isdst; /* daylight saving time */ + /* daylight 夏令时调整 */ +}; + +/** + * 将结构体转换为时间戳 + * ! 没有 const,可能更改 tm +*/ +time_t mktime(struct tm *tm); + +/** + * 格式化输出时间 +*/ +size_t strftime(char *s, size_t max, const char *format, + const struct tm *tm); + +// eg +strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); +``` ## 进程环境 +### `main`函数 +```c +int main(int argc, char *argv[]); +``` + +### 进程的终止 +1. 正常终止: + - 从`main`函数返回 + - 调用`exit` + `void exit(int status);` + status & 0377 有符号的char -128~127 + + - 调用`_exit`或者`_Exit`(系统调用) + > `exit`与`_exit _Exit`的区别 + > `_exit`不执行`atexit`注册的函数,不刷新`stdio`缓冲区 + > 这样可以防止错误扩散 + - 最后一个线程从其启动例程返回 + - 最后一个线程调用了`pthread_exit` + +2. 异常终止 + - 调用`abort` + - 接到一个信号并终止 + - 最后一个线程对其取消请求作出响应 + + +```c +/** + * 注册一个函数,当进程终止时调用 + * + * 钩子函数:逆序执行 + * 可以进行资源释放 +*/ +int atexit(void (*function)(void));// 钩子函数 +``` + +### 命令行参数的分析 +```c +#include + +extern char *optarg; // 选项参数 +// optind: 下一个要处理的参数的索引 +extern int optind, opterr, optopt; + +int getopt(int argc, char *const argv[], const char *optstring); + +int getopt_long(int argc, char *const argv[], const char *optstring, + const struct option *longopts, int *longindex); +``` + +### 环境变量 + +### C程序的存储空间布局 + +### 库 + +### 函数之间正常的跳转 + +### 资源的获取及控制 diff --git a/C13-Linux系统编程/fs/100days.c b/C13-Linux系统编程/fs/100days.c new file mode 100644 index 0000000..134e562 --- /dev/null +++ b/C13-Linux系统编程/fs/100days.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#define TIMESTRSIZE 128 + +/** + * @brief 找出100天以后是哪一天 + * @details + * + * @param argc + * @param argv + * + * @return int + */ +int main(int argc, char **argv) +{ + time_t stamp; + struct tm *tm; + char timestr[TIMESTRSIZE]; + + time(&stamp); + tm = localtime(&stamp); + strftime(timestr, TIMESTRSIZE, "Now: %Y-%m-%d", tm); + puts(timestr); + + tm->tm_mday += 100; + // mktime 会先调整tm溢出的情况 + mktime(tm); + strftime(timestr, TIMESTRSIZE, "100 days later: %Y-%m-%d", tm); + puts(timestr); + + exit(0); +} \ No newline at end of file diff --git a/C13-Linux系统编程/fs/atexit.c b/C13-Linux系统编程/fs/atexit.c new file mode 100644 index 0000000..f3d9dbc --- /dev/null +++ b/C13-Linux系统编程/fs/atexit.c @@ -0,0 +1,37 @@ +#include +#include + +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(int argc, char **argv) +{ + puts("Begin!"); + + atexit(f1); + atexit(f2); + atexit(f3); + + puts("End!"); + + exit(0); +} +// out: +// *[main][~/Linux-C-Notes/C13-Linux系统编程/fs]$ ./atexit +// Begin! +// End! +// f3() is working! +// f2() is working! +// f1() is working! \ No newline at end of file diff --git a/C13-Linux系统编程/fs/check.c b/C13-Linux系统编程/fs/check.c new file mode 100644 index 0000000..e3baf66 --- /dev/null +++ b/C13-Linux系统编程/fs/check.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include + +/** + * @brief 加密输入的密码并与shadow文件中的密码进行比较 + * @details + * !!! compile: gcc check.c -o check -lcrypt + * !!! 需要root权限运行 + * + * @param argc + * @param argv [in] 用户名 + * + * @return int + */ +int main(int argc, char **argv) +{ + if (argc < 2) + { + fprintf(stderr, "Usage:...\n"); + exit(1); + } + + char *input_pass; + struct spwd *shadowline; + char *crypt_pass; + + //* getpass()函数在输入密码时不会回显密码 + input_pass = getpass("PassWord: "); + + //* getspnam()函数通过用户名获取shadow文件中的密码 + shadowline = getspnam(argv[1]); + + //* 加密输入的密码 + crypt_pass = crypt(input_pass, shadowline->sp_pwdp); + + if (0 == strcmp(crypt_pass, shadowline->sp_pwdp)) + puts("OK!"); + else + puts("Error!"); + + exit(0); +} \ No newline at end of file diff --git a/C13-Linux系统编程/fs/main1.c b/C13-Linux系统编程/fs/main1.c new file mode 100644 index 0000000..d0ce5f3 --- /dev/null +++ b/C13-Linux系统编程/fs/main1.c @@ -0,0 +1,13 @@ +#include +#include + +int main(int argc, char **argv) +{ + printf("Hello, World!\n"); + + return 0; + /* + * echo $? + * 0 + */ +} \ No newline at end of file diff --git a/C13-Linux系统编程/fs/mydate.c b/C13-Linux系统编程/fs/mydate.c new file mode 100644 index 0000000..934d43a --- /dev/null +++ b/C13-Linux系统编程/fs/mydate.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include + +#define TIMESTRSIZE 1024 +#define FMTSTRSIZE 1024 + +/** + * @brief mydate + * @details + * Usage: + * mydate [-H 12|24] [-y 2|4] [-m] [-d] [-M] [-S] + * Options: + * -y: year 2位,4位 + * -m: month + * -d: day + * -H: hour 12小时制,24小时制 + * -M: minute + * -S: second + * + * @param argc + * @param argv + * + * @return int + */ +int main(int argc, char **argv) +{ + time_t stamp; + struct tm *tm; + char timestr[TIMESTRSIZE]; + int c; + char fmtstr[FMTSTRSIZE]; + fmtstr[0] = '\0'; + FILE *fp = stdout; + + time(&stamp); + tm = localtime(&stamp); + + while (1) + { + //* 选项传参 + // c = getopt(argc, argv, "H:y:MSmd"); + + //* 加'-',接收非选项传参 + c = getopt(argc, argv, "-H:y:MSmd"); + if (c < 0) + break; + + switch (c) + { + //* 非选项传参,返回1 + case 1: + if (stdout == fp) //! 先入为主 + { + fp = fopen(argv[optind - 1], "w"); + if (NULL == fp) + { + perror("fopen()"); + fp = stdout; + } + } + break; + + case 'H': + if (0 == strcmp(optarg, "12")) + strncat(fmtstr, "%I(%P) ", FMTSTRSIZE - 1); + else if (0 == strcmp(optarg, "24")) + strncat(fmtstr, "%H ", FMTSTRSIZE - 1); + else + fprintf(stderr, + "Usage: %s [-H 12|24] [-y 2|4] [-m] [-d] [-M] [-S]\n", + argv[0]); + break; + + case 'M': strncat(fmtstr, "%M ", FMTSTRSIZE - 1); break; + + case 'S': strncat(fmtstr, "%S ", FMTSTRSIZE - 1); break; + + case 'y': + if (0 == strcmp(optarg, "2")) + strncat(fmtstr, "%y ", FMTSTRSIZE - 1); + else if (0 == strcmp(optarg, "4")) + strncat(fmtstr, "%Y ", FMTSTRSIZE - 1); + else + fprintf(stderr, + "Usage: %s [-H 12|24] [-y 2|4] [-m] [-d] [-M] [-S]\n", + argv[0]); + break; + + case 'm': strncat(fmtstr, "%m ", FMTSTRSIZE - 1); break; + + case 'd': strncat(fmtstr, "%d ", FMTSTRSIZE - 1); break; + + default: break; + } + } + + strncat(fmtstr, "\n", FMTSTRSIZE - 1); + strftime(timestr, TIMESTRSIZE, fmtstr, tm); + + fputs(timestr, fp); + + if (fp != stdout) + fclose(fp); + + exit(0); +} \ No newline at end of file diff --git a/C13-Linux系统编程/fs/timelog.c b/C13-Linux系统编程/fs/timelog.c new file mode 100644 index 0000000..7e6bf25 --- /dev/null +++ b/C13-Linux系统编程/fs/timelog.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +#define FNAME "time.log" +#define BUFSIZE 1024 + +/** + * @brief 往文件里面输出时间戳 + * @details + * 实例格式:2019-12-12 12:12:12 + * + * @param argc + * @param argv + * + * @return int + */ +int main(int argc, char **argv) +{ + FILE *fp; + time_t stamp; + struct tm *tm; + char buf[BUFSIZE]; + int count = 0; + + fp = fopen(FNAME, "a+"); + if (fp == NULL) + { + perror("fopen()"); + exit(1); + } + + while (fgets(buf, BUFSIZE, fp) != NULL) + count++; + + while (1) + { + stamp = time(NULL); + + tm = localtime(&stamp); + if (NULL == tm) + { + perror("localtime()"); + exit(1); + } + + strftime(buf, BUFSIZE, "%Y-%m-%d %H:%M:%S", tm); + + fprintf(fp, "%-4d%s\n", ++count, buf); + + /* + * 加了sleep(1)之后就没有输出? + * 全缓冲 + * 因为缓冲区没有满,没有刷新到文件里面 + */ + fflush(fp); + + sleep(1); + } + + fclose(fp); + exit(0); +} + +//! 最终效果 +// *[main][~/Linux-C-Notes/C13-Linux系统编程/fs]$ ./test +// ^C +// *[main][~/Linux-C-Notes/C13-Linux系统编程/fs]$ cat time.log +// 1 2024-05-11 21:53:26 +// 2 2024-05-11 21:53:27 +// 3 2024-05-11 21:53:28 +// 4 2024-05-11 21:53:29 +// 5 2024-05-11 21:53:30 +// *[main][~/Linux-C-Notes/C13-Linux系统编程/fs]$ ./test +// ^C +// *[main][~/Linux-C-Notes/C13-Linux系统编程/fs]$ cat time.log +// 1 2024-05-11 21:53:26 +// 2 2024-05-11 21:53:27 +// 3 2024-05-11 21:53:28 +// 4 2024-05-11 21:53:29 +// 5 2024-05-11 21:53:30 +// 6 2024-05-11 21:53:35 +// 7 2024-05-11 21:53:36 +// 8 2024-05-11 21:53:37 +// 9 2024-05-11 21:53:38 \ No newline at end of file diff --git a/C13-Linux系统编程/fs/username.c b/C13-Linux系统编程/fs/username.c new file mode 100644 index 0000000..7c4bbb5 --- /dev/null +++ b/C13-Linux系统编程/fs/username.c @@ -0,0 +1,29 @@ +#include +#include +#include + +/** + * @brief 用user id获取用户名 + * @details + * + * @param argc + * @param argv + * + * @return int + */ +int main(int argc, char **argv) +{ + if (argc < 2) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + + struct passwd *pwdline; + + pwdline = getpwuid(atoi(argv[1])); + + puts(pwdline->pw_name); + + exit(0); +} \ No newline at end of file