`
javasee
  • 浏览: 965273 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Linux环境(四)--临时文件与用户信息

阅读更多
临时文件

通常,程序需要以文件的形式使用临时存储。这也许是存储计算的中间结果,或者是在实际操作之前所做的文件拷贝备份。例如,一个数据程序在删除记录时会使用临时文件。文件会收集需要保存的数据库实体,然后在操作结束时,临时文件会成为新的数据库而原始的会被删除。

临时文件的大量使用隐藏了他的一个缺点。我们必须小心来确保程序会选择一个唯一的名字来使用临时文件。如果不是这样,因为Linux是一个多任务系统,也许会有另一个程序选择了相同的名字,而这两个彼此之间会相互影响。

一个唯一的临时文件名可以由tmpnam函数生成:

#include <stdio.h>
char *tmpnam(char *s);

tmpnam函数会返回一个与现存的文件不同的可用的文件名。如果字符串不为null,文件名也就会被写入其中。后续的tmpnam函数调用会覆盖返回值所用的表态存储区,所以如果tmpnam函数被调用多次,实际上是使用一个字符串参数。这个字符串假定至少为L_tmpnam字符长。一个程序中,tmpnam至多可以被调用TMP_MAX次,而且每次都会生成一个不同的文件名。

如果临时文件被立即使用,那么我们可以同时使用tmpfile函数来对其命名并且打开。这一点很重要,因为另一个程序会使用tmpnam返回的相同的名字创建一个文件。tmpfile函数避免这种情况的发生:

#include <stdio.h>
FILE *tmpfile(void);

tmpfile函数会返回一个指向唯一的临时文件的流指针。这个文件会为读和写打开,而且在所有到文件的引用被关闭以后,这个文件会被自动删除。

如果发生错误,tmpfile会返回一个空指针,并且设置errno变量。

试验--tmpnam与tmpfile

下面让我们实际的看一下这两个函数的使用:

#include <stdio.h>
int main()
{
char tmpname[L_tmpnam];
char *filename;
FILE *tmpfp;
filename = tmpnam(tmpname);
printf(“Temporary file name is: %s\n”, filename);
tmpfp = tmpfile();
if(tmpfp)
printf(“Opened a temporary file OK\n”);
else
perror(“tmpfile”);
exit(0);
}

当我们编译运行程序tmpnam.c时,我们可以看到由tmpnam生成的唯一的文件名:

$ ./tmpnam
Temporary file name is: /tmp/file2S64zc
Opened a temporary file OK

工作原理

这个程序调用tmpnam生成一个唯一文件名的临时文件。如果我们要使用这个临时文件,我们可以立即打开,从而来减小另一个程序会使用同一个文件名打开这个文件的风险。tmpfile调用会同时创建并打开一个临时文件,从而避免了这种风险。实际上,当编译一个使用这个函数的程序时,GNU C编译器也会给出一个使用tmpnam的警告。

老版本Unix系统还有另一个使用mktemp与mkstemp函数来生成临时文件名的方法。这些与被Linux系统支持,并且与tmpnam相似,所不同的是我们可以为临时文件名指定一个模板,这样我们就可以更好的控制其位置与名字:

#include <stdlib.h>
char *mktemp(char *template);
int mkstemp(char *template);

mktemp函数由指定的模板生成一个唯一的文件名。template必须以6个x开始。mktemp函数使用唯一可用的文件名字符来替换这些x字符。他返回一个指向所生成的字符串的指针,如果不可以生成一个唯一的文件名,则会返回一个null指针。

mkstemp函数在创建与打开临时文件方面与tmpfile相类似。文件名由与mktemp相同的方式生成的,但是返回的结果是一个打开的,底层文件描述符。

通常,我们应使用创建与打开函数tmpfile与mkstemp,而不是tmpnam与mktemp。

用户信息

所有了Linux程序,除了init之外,都是由其他程序或用户启动的。我们将会在第11章中了解更多的如何运行程序,或进程,交互等内容。用户通常由一个负责命令的shell来启动程序。我们已经看到,程序可以通过检测其环境变量以及读取系统时钟来确定其环境信息。一个程序也可以查看正使用他的用户信息。

当一个用户登陆进Linux系统时,他就有一个用户名与密码。如果这些通过验证,系统就会用户提供一个shell。通常,用户具有一个称之为UID的唯一的用户标识。Linux运行的所有程序都是运行在用户的行为以及与其相关的UID上的。

我们可以设置一个程序的运行,使其看起来就像是另一个用户启动的。当一个程序具有其UID的权限集合时,他的运行看起来就像是可执行文件的拥有者启动的。当执行su命令时,程序的运行看起来就像是超级用户启动的。然后他会验证用户的访问权限,将其UID改变为目标用户的UID,然后执行目标用户的登陆shell。这会允许一个程序的运行看起来就像是另一个不同的用户启动的,而这通常为系统管理员用来执行维护任务。

因为UID是用户标识的关键,我们就从这里开始讨论。

UID有其自己的类型--uid_t--在sys/types.h中进行了定义。他通常是一个小整数。一些是由系统预先定义的;另一个些是当有新用户要添加到系统时,由系统管理员创建的。通常,用户的UID值大于100。

#include <sys/types.h>
#include <unistd.h>
uid_t getuid(void);
char *getlogin(void);

getuid函数会返回与程序相关的UID值。这通常是启动程序的用户的UID值。

getlogin函数会返回与当前用户相关联的登陆名。

系统文件/etc/passwd包含一个处理用户帐户的数据库。每个用户一行,其中包含用户名,加密密码,用户标识UID,组标识GID,全名,主目录,以及默认的shell。下面是其中的一个例子:

neil:zBqxfqedfpk:500:100:Neil Matthew:/home/neil:/bin/bash

如果我们要编写一个程序来确定启动程序的用户UID,我们会对其进行扩展来查看密码文件以查找用户的登陆名与全名。我们并不推荐这样做,因为现在的类Unix系统都由使用简单的密码文件迁移到加强的系统安全。许多系统,包括Linux,有一个选项可以使用影子密码(shadwo password)文件,其中根本就不包含任何有用的加密密码信息(这通常存放在用户不可读取的/etc/shadow中)。正是因为这个原因,系统定义了一系列函数来为用户信息提供标准而高效的程序接口:

#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);

密码数据库结构,passwd,定义在pwd.h中,包含下列成员:

成员 描述
char *pw_name 用户登陆名
uid_t pw_uid UID值
gid_t pw_gid GID值
char *pw_dir 用户主目录
char *pw_gecos 用户全名
char *pw_shell 用户默认shell

一些Unix系统会使用一个不同的名字来表示用户全名域:在一些系统上例如Linux为pw_gecos,而在另一个系统上为pw_comment。这就意味着我们并不推荐使用这个域。

getpwuid与getpwnam函数都会返回一个指向对应于一个用户的密码结构指针。对于getpwuid函数,用户是由UID标识的,而对于getpwnam函数,用户是由登陆来标识的。如果出错,他们都会返回一个空指针并且设置errno变量。

试验--用户信息

这里有一个程序,user.c,这会由密码数据库中得到一些用户信息:

#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
uid_t uid;
gid_t gid;
struct passwd *pw;
uid = getuid();
gid = getgid();
printf(“User is %s\n”, getlogin());
printf(“User IDs: uid=%d, gid=%d\n”, uid, gid);
pw = getpwuid(uid);
printf(“UID passwd entry:\n name=%s, uid=%d, gid=%d, home=%s, shell=%s\n”,
pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);
pw = getpwnam(“root”);
printf(“root passwd entry:\n”);
printf(“name=%s, uid=%d, gid=%d, home=%s, shell=%s\n”,
pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);
exit(0);
}

其程序输出如下所示,也许在不同的系统上其输出结果会略有不同:

$ ./user
User is neil
User IDs: uid=500, gid=100
UID passwd entry:
name=neil, uid=500, gid=100, home=/home/neil, shell=/bin/bash
root passwd entry:
name=root, uid=0, gid=0, home=/root, shell=/bin/bash

工作原理

这个程序会调用getuid函数来得到当前用户的UID值。这个UID会用在getpwuid函数中来得到详细的密码文件信息。作为一个对照,我们演示了如何在getpwnam函数中指定用户名root来得到用户信息。

要遍历密码文件信息,我们可以使用getpwent函数。这会取得连续的文件实体:

#include <pwd.h>
#include <sys/types.h>
void endpwent(void);
struct passwd *getpwent(void);
void setpwent(void);

getpwent函数会依次返回每个用户信息。当到达文件结尾时,他会返回一个空指针。一旦搜索完毕所有的有效实体,我们可以使用endpwent函数来结束处理过程。setpwent函数可以在密码文件中重新设置指针使其指向文件的开头,这样当下次调用getpwent函数时可以重新开始遍历。这些函数的操作与我们在第3章所讨论的目录遍历函数opendir,readdir,closedir相类似。

用户与组标识可由其他的一个通常不用的函数来得到:

#include <sys/types.h>
#include <unistd.h>
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
int setuid(uid_t uid);
int setgid(gid_t gid);

我们可以查看系统手册页来得到关于组标识与有效用户标识的更为详细的内容,尽管我们会发现我们根本就不需要来操作这些函数。
分享到:
评论

相关推荐

    arm-linux-gcc-5.4.0.tar.gz

    总之,`arm-linux-gcc`是进行ARM架构Linux系统交叉编译的重要工具,它的安装和使用涉及到Linux环境变量配置、编译选项选择、库依赖管理等多个方面。熟练掌握这些技能,对于在嵌入式领域开发高效、可靠的应用至关重要...

    mariadb-10.11.2-linux-systemd-x86-64.tar.gz

    这个名为“mariadb-10.11.2-linux-systemd-x86_64.tar.gz”的压缩包文件,显然是针对Linux操作系统,采用Systemd作为初始化系统的x86_64架构的MariaDB 10.11.2版本。 MariaDB的核心特点包括: 1. 兼容性:MariaDB...

    p6880880_112000_Linux-x86-64.zip

    1. 解压缩"p6880880_112000_Linux-x86-64.zip"到一个临时目录,例如 `/tmp/patch`。 2. 打开终端,切换到Oracle软件的主目录,通常是 `/u01/app/oracle/product/11.2.0/dbhome_1`。 3. 使用OPatch执行安装命令,如:...

    arm-linux-gcc-3.3.2_安装交叉编译器

    可以通过`rm -rv usr`命令实现,但这一步需谨慎操作,确保只删除了安装过程中产生的临时文件,避免误删重要系统文件。 **总结** 通过以上步骤,我们可以成功地在Linux环境下安装并配置ARM-Linux-GCC-3.3.2交叉...

    p6880880_112000_Linux-x86-64.zip11.2.0.3.10

    OPI通常包含了补丁文件、安装脚本以及必要的配置信息,以确保补丁的正确应用。 在标签 "p6880880_112000_" 中,"p6880880" 可能是该补丁的唯一标识符,便于Oracle支持团队跟踪和识别特定的补丁。这种格式的标签通常...

    linux临时文件建立代码

    在Linux环境下,程序经常会需要利用文件系统进行临时存储,例如存储计算过程中的中间结果,或是对文件进行拷贝备份操作。这种需要在操作完成后可能要删除的文件被称为临时文件。由于Linux是一个多任务操作系统,所以...

    Linux-Code--Tree.rar_linux_linux 文件目录

    - `/tmp`:存放临时文件,系统重启时会被清空。 - `/usr`:包含非系统运行所需的额外应用程序和库,分为`/usr/bin`、`/usr/lib`等子目录。 - `/var`:存放变量数据,如日志文件、缓存、数据库等,会随时间增长。 ...

    linux-amlogic-toolkit-master-new(封包正常可用)_ROOT_menyjy_unpackamlog

    在开发环境中,它避免了不必要的文件被添加到版本库中,比如编译产生的临时文件、日志文件等。 2. `README.md`:这是项目中的说明文档,通常用Markdown格式编写,用于介绍项目背景、使用方法、注意事项等。在这个...

    计算机软件-商业源码-224 创建临时文件.zip

    此外,临时文件也可以用于存储用户会话信息、缓存计算结果、保存程序崩溃时的现场等,以便后续恢复。 在Windows操作系统中,通常会在`C:\Users\用户名\AppData\Local\Temp`目录下创建临时文件,而在Unix/Linux系统...

    Linux全攻略--文件和磁盘管理(优化版)

    这篇“Linux全攻略--文件和磁盘管理(优化版)”涵盖了广泛的文件系统类型和磁盘操作,以及如何在Linux环境中有效地管理这些资源。 首先,Linux支持多种文件系统,包括JFS、ReiserFS、Ext、Ext2、Ext3、ISO9660、XFS...

    p9352237_112010_Linux-x86-64.zip

    "p9352237_112010_Linux-x86-64.zip" 文件是一个针对Oracle 11g的补丁更新包,专为Linux 64位系统设计,用于提升系统的稳定性和安全性。 Oracle 11g Release 11.2.0.1.1 PSU(Patch Set Update)9352237是一个关键...

    mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz

    1. **安装过程**:在Linux环境下,首先需要将`.tar.gz`文件解压到一个合适的目录,通常是在 `/usr/local/` 下创建一个新的目录如 `/usr/local/mysql`。使用`tar -zxvf mysql-5.7.38-linux-glibc2.12-x86_64.tar.gz`...

    Linux学习之CentOS(3)--初识linux的文件系统以及用户组等概念.docx

    - `/tmp`:临时文件存储区,重启后会被清空。 - `/usr`:非必需的用户应用程序和系统资源,如 `/usr/bin`、`/usr/lib`、`/usr/sbin` 等。 - `/var`:存储可变数据,如日志文件、缓存等。 【用户组和权限】 在...

    安装redhat-linux-5.5-环境与oracle-11g-数据库.pdf

    这里推荐的分区方案包括:`/swap` 分区为 4GB 用于交换空间,`/boot` 分区为 100MB 用于引导文件,`/` 根分区为 20GB,`/home` 分区为 10GB 用于用户数据,以及 `/tmp` 分区为 5GB 用于临时文件。 2. **选择安装...

    Linux基础服务-配置Linux系统网络服务-Linux目录

    - **`/tmp/`**:用于临时存储文件。 - **`/proc/`**:包含系统服务和进程的信息,类似于汽车仪表盘。 - **路径表示形式**: - **绝对路径**:从根目录 `/` 开始的路径,如 `/etc/hostname`。 - **相对路径**:...

    mysql-5.7.21-linux-glibc2.12-x86_64.tar.gz在Linux下安装步骤

    在Linux环境下安装MySQL 5.7.21的详细步骤如下: 1. **安装包准备**:首先,你需要从MySQL的官方网站或者可靠的第三方源下载安装包。在这个例子中,使用的是`mysql-5.7.21-linux-glibc2.12-x86_64.tar.gz`,你可以...

    linux学习笔记--很经典

    - 存放临时文件,这些文件在系统重启时会被清除。 18. **/usr** - 存放用户应用程序和文件的位置。 - **/usr/X11R6**: X Window系统文件。 - **/usr/src**: Linux源代码。 - **/usr/include**: 系统头文件。...

    mysql-5.0.41-linux-i686-glibc23

    让我们深入探讨一下这个版本的MySQL以及它在Linux环境中的部署和使用。 首先,MySQL 5.0.41是MySQL 5.0系列的一个稳定版本,发布于2007年。这个版本引入了多项性能优化、安全改进和新特性,包括增强的查询优化器、...

    node-v0.8.21-linux-arm-pi.tar.gz

    在解压这个文件之后,你会得到一个名为 "node-v0.8.21-linux-arm-pi" 的目录,里面包含了一系列的文件和子目录,这些通常是Node.js的可执行文件、库文件、头文件等,使得用户能够在树莓派或其他基于ARM的Linux系统上...

Global site tag (gtag.js) - Google Analytics