我正在尝试获取学校Mac OS的主机名。我不能使用Mac手册页第3节中的gethostname(),而不是第2节中的内容。是否有不使用gethostname()的另一种获取主机名的方法?只允许在libc中使用man 2 section函数。

最佳答案

gethostname只是一个sysctl,而sysctl只是一个syscall
syscall在手册的第2节中(按定义)。

因此,抓住您最喜欢的反汇编程序(如果没有,则为otool -tV),在nm中的/usr/lib/system库中找出导出_gethostname_sysctl的库,然后开始工作(或查找源代码: P)。

下面,我使用gethostname重新实现sysctl,并使用sysctl重新实现syscall

#include <sys/syscall.h>    // SYS_sysctl
#include <sys/sysctl.h>     // CTL_KERN, KERN_HOSTNAME
#include <unistd.h>         // syscall

int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
{
    return syscall(SYS_sysctl, name, namelen, oldp, oldlenp, newp, newlen);
}

int gethostname(char *buf, size_t buflen)
{
    int name[] = { CTL_KERN, KERN_HOSTNAME };
    size_t namelen = 2;

    return sysctl(name, namelen, buf, &buflen, NULL, 0);
}

int puts(const char *s)
{
    // left as an exercise to the reader ;)
}

int main(void)
{
    #define BUFSIZE 256
    char buf[BUFSIZE];
    size_t buflen = BUFSIZE;

    if(gethostname(buf, buflen) == 0)
    {
        puts(buf);
    }

    return 0;
}


sysctl的实现不是太复杂。您实际上只是在其他参数前面打了SYS_sysctl(来自sys/syscall.h),然后将它们全部传递给syscall

要了解gethostname的实现,您必须知道sysctl的工作方式:


oldp是查询值的存储位置。
newp是将从中读取新值的位置。由于我们未设置任何新值,因此此处为NULL
name或多或少是sysctl的实际参数列表,其内容取决于要查询的实际sysctl

CTL_KERN表示我们需要内核提供的东西。
KERN_HOSTNAME表示我们要检索主机名。
而且由于KERN_HOSTNAME不接受任何参数,因此仅此而已。

仅出于演示目的,如果您调用了KERN_PROCARGS,则name将需要一个附加参数,即应检索其参数的进程ID。
在这种情况下,name将如下所示:

int name[] = { CTL_KERN, KERN_PROCARGS, pid };


namelen必须相应地设置为3


现在,在上述实现中,我已经使用了puts,显然您是不允许这样做的,但是我相信您可以弄清楚如何重新实现strlen并使用write syscall。 ;)

关于c - 如何在C中获取Mac OS的主机名,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39146754/

10-12 18:19