gpt4 book ai didi

c - C方法ID和getpwnam(3)

转载 作者:行者123 更新时间:2023-11-30 20:33:54 25 4
gpt4 key购买 nike

对于我在学校的IT,我必须编写一个程序来输出用户ID和用户组ID,就像命令“ id”一样,而没有组。
这对我来说很好,但是现在我必须使用方法getpwnam对其进行扩展:
它应用作./id_extended USERNAME,然后应输出该用户的uid和gid。我看了getpwnam(3)的观点,因为这课告诉我要去那里做。现在有一个将getpwnam_r与缓冲区等配合使用的示例,但这不是我们应该采用的方式;我们必须使用简单的getpwnam

我知道getpwnam返回一个指针,但是该指针如何用于用户组ID和用户ID?

最佳答案

OP应该在问题中包含其代码。让我们对其进行部分检查:

#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>


由于这是POSIX.1 C代码,因此代码应以例如 #define _POSIX_C_SOURCE 200809L告诉C库头文件我们需要POSIX.1-2008功能。

getpwnam()需要 #include <pwd.h>,但还需要 #include <sys/types.h>(未列出)。

如果使用了 getuid()getgid(),则需要 #include <unistd.h>(已列出)。

标准I / O需要 #include <stdio.h>,而 #include <errno.h>提供 errno和错误代码。我个人也将 #include <string.h>用作 strerror(),因为我喜欢使用 fprintf()以自己的格式打印错误消息(而不是使用例如 perror()<stdio.h> GNU扩展名的 %m

下一部分,

struct passwd *getpwnam(const char *name);
uid_t getuid(void);
uid_t geteuid(void);
struct passwd pass;


有很多问题:首先,您不需要声明C库函数;头文件已经为我们声明了它们。其次, getpwnam()的返回值是指向 struct passwd的指针-这就是 struct passwd *的含义! -,因此声明 struct passwd pass为零。第三,如果仅在 pass中使用 main(),则应在 main()中将其声明为局部变量,而不是全局变量(在任何函数之外)。

在最后一部分,

int main(int argc,char* argv[]) {
if(argc == 1){
printf("user: %d\ngroup: %d\n",getuid(),getgid());
}
if(argc == 2){
pass = getpwnam(argv[1]);
printf("%s %ld",pass.pw_uid,pass.pw_gid );
}
}


我们看到正确定义了 main()(采用 int argcchar *argv[]);但是,没有声明要求的 return (some int)语句。最好通过在末尾添加 return EXIT_SUCCESS;来解决。

由于 pass仅在 main()中使用,因此它应该是局部变量,因此 main()的主体应以其正确的声明开始: struct passwd *pass;

如果提供两个或多个参数,则该程序不执行任何操作。这是非常令人惊讶的,也是不希望的。在参数过多的情况下显示错误消息的 if (argc == 1) { /* no arguments */ } else if (argc == 2) { /* one argument */ } else { /* two or more arguments */ }在这里是更明智的选择。

在一个参数的情况下( argc == 2-请记住, argc包括 argv[0],这是用于执行该程序的名称),存在两个独立的问题:首先, pass不是指针(可以如上所示通过声明对其进行修复)。其次,更重要的一点是,没有检查 getpwnam()是成功还是失败。

如果发生错误, man 3 getpwnam告诉我们,如果发生错误, getpwnam()将返回 NULL,其中 errno描述该错误。这意味着如果正确声明了 pass,则应使用例如

    pass = getpwnam(argv[1]);
if (!pass) {
fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}

/* pass->pw_uid has user ID,
pass->pw_gid has group ID,
pass->pw_name has user name,
and so on. */


请注意, if (!pass)等效于POSIX.1 C中的 if (pass == NULL)

(使用较短的格式只是我个人的喜好。因为 !是not运算符,所以我实际上将第一个读为“如果没有 pass”;而我将第二个读为“如果 pass为NULL” 。前者对我来说更轻松/更快/更舒适。)

另请注意,没有 uid_tgid_t的printf格式说明符。虽然大多数代码使用 int%d)并假定编译器将正确处理升级,但我个人更喜欢使用 long%ld)并将结果显式转换为 long;例如,

    printf("uid=%ld (%s)\n", (long)(pass->pw_uid), pass->pw_name);


(大多数情况下,您会看到强制转换写为 (long)pass->pw_uid,但是除非您还记得C语言中的运算符优先级规则,否则可能不清楚将表达式的哪一部分强制转换为 long。阅读代码-编译器绝对不在乎--我偶尔会写为 (long)(pass->pw_uid),因为强制转换项显然是 (pass->pw_uid),即结构中 pw_uid字段的值指向通过 pass。)

最后,我想建议一下程序逻辑中的两个更改。

如果没有指定用户名,则不使用 struct passwd *pass,而是在未指定用户名的情况下也使用它,以使用 getpwuid(getuid())获取当前用户信息。然后,以 pass所指向的结构打印信息的代码可能会停留在 if (argc == ..)子句的主体之外。这样,只有一个 printf()可以打印信息,并且无论信息是为当前用户打印还是由名称指定的其他用户打印,其格式始终相同。

getuid()getgid()在POSIX.1中总是成功的;它们不会失败。这就是为什么可以使用它们而不进行任何错误检查的原因。)

第二个更改更像是附加项。您可以使用 getgrgid(pass->pw_uid)getgrgid(getgid())来获取指向 struct group的指针,该指针在用户组上提供相似的信息。特别是 ->gr_name,这是组的名称。
要使用 getgrgid(),还应该在文件开头附近使用 #include <grp.h>。 (它也需要 #include <sys/types.h>,但是您已经应该拥有它,因为 getpwnam()getpwuid()都需要它。)

以上信息应足以根据规定的要求编写一个可以正常运行的程序。但是,我不会列出完整的固定/修改程序,因为您会学到更多,并且会满意地自己完成自己的工作-而且我们都避免通过将我们的工作作为自己的工作来帮助自由登载者利用我们的努力拥有。

关于c - C方法ID和getpwnam(3),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43768015/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com