objective-c - Cocoa 中 AuthorizationExecuteWithPriveleges 的非常奇怪的问题

标签 objective-c macos cocoa bash terminal

我正在使用 AuthorizationExecuteWithPriveleges 以管理员权限从我的应用程序执行 bash 命令。我发现了非常奇怪的问题。这是我正在使用的

    FILE *pipe=nil;
    OSStatus err;
    AuthorizationRef authorizationRef;
    char *command= "/bin/chmod";
  
    
    char *args[] = {"644","folderPath", nil};

   if(err!=0)
    {
                                err = AuthorizationCreate(nil,
                                       kAuthorizationEmptyEnvironment,
                                       kAuthorizationFlagDefaults,
                                       &authorizationRef);
    }
    NSLog(@"test");
    err = AuthorizationExecuteWithPrivileges(authorizationRef,
                                             command,
                                             kAuthorizationFlagDefaults,
                                             args,
                                             &pipe);  

调用此函数大约 40 次后,开始响应非常缓慢。之后它就会死掉,并卡住应用程序,我不知道这是怎么回事。在调用大约 40 次后,它没有显示日志“测试”,也没有做任何事情。 使用什么 Bash 命令或什么参数并不重要。它仍然做同样的事情。这有什么问题?我之所以使用它,是因为我的应用程序也需要在 10.5 上运行。

如果有人有想法,我该怎么办。对此,我真的非常感激。我需要尽快。谢谢

最佳答案

仔细研究了这一点,并编写了以下示例,没有任何保证,但对我来说,它可以毫无问题地调用数千次 AuthorizationExecuteWithPrivileges:

void DoOtherStuff(AuthorizationRef auth, char* path);

void DoStuff(char* path)
{
    AuthorizationItem foo;
    foo.name = kAuthorizationRightExecute;
    foo.value = NULL;
    foo.valueLength = 0;
    foo.flags = 0;

    AuthorizationRights rights;
    rights.count = 1;
    rights.items = &foo;

    AuthorizationRef authorizationRef;
    OSStatus err = errAuthorizationSuccess;

    if (errAuthorizationSuccess != (err = AuthorizationCreate(NULL,  kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef)))    
    {
        NSLog(@"Error on AuthorizationCreate: %lu", (long)err);
        return;
    }

    for (NSUInteger i = 0; i < 5000; i++)
    {
        NSLog(@"Doing run: %lu", (long)i+1);
        DoOtherStuff(authorizationRef, "/tmp/foo");
    }

    if (errAuthorizationSuccess != (err = AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults)))
    {
        NSLog(@"Error on AuthorizationFree: %lu", (long)err);
        return;
    }
}

void DoOtherStuff(AuthorizationRef authorizationRef, char* path)
{    
    OSStatus err = errAuthorizationSuccess;
    FILE *pipe = NULL;
    @try
    {
        char *args[] = {"644", path, NULL};
        if (errAuthorizationSuccess != (err = AuthorizationExecuteWithPrivileges(authorizationRef,
                                                 "/bin/chmod", kAuthorizationFlagDefaults, args, &pipe)))
        {
            NSLog(@"Error on AuthorizationExecuteWithPrivileges: %lu", (long)err);
            return;
        }

        int stat;
        wait(&stat);

        NSLog(@"Success! Child Process Died!");
    }
    @finally 
    {        
        if (pipe)
            fclose(pipe);
    }
}

Chris Suter 所说的完全正确。当您调用 AuthorizationExecuteWithPrivileges 时发生的事情是它 fork()s 您的进程,然后 exec()s 从子进程请求的进程(在本例中为 chmod)。在有人调用 wait() 之前,子进程不会被收割,但这很难,因为我们无法从 AuthorizationExecuteWithPrivileges 中获取子进程的 PID(它会由 fork() 返回)。正如他所说,如果您确定没有其他线程同时产生进程(即您的线程是唯一创建子进程的线程),那么您可以调用 wait() 的非 PID 特定版本,例如我在这个例子中这样做。

如果您不调用 wait() ,那么您会累积这些等待收割的僵尸子进程。最终操作系统说“不再”。

我觉得发布这个有点不好,因为它只是对 Chris Suter 所说内容的翻版;我赞成他的回答。

为了完整起见,这里是该示例的修改版本,它通过忽略 SIGCHLD 而不是调用等待来实现目标。它也没有保修,但对我有用。

void DoOtherStuff(AuthorizationRef auth, char* path);

void DoStuff(char* path)
{
    AuthorizationItem foo;
    foo.name = kAuthorizationRightExecute;
    foo.value = NULL;
    foo.valueLength = 0;
    foo.flags = 0;

    AuthorizationRights rights;
    rights.count = 1;
    rights.items = &foo;

    AuthorizationRef authorizationRef;
    OSStatus err = errAuthorizationSuccess;

    struct sigaction oldAction;
    struct sigaction newAction;

    newAction.__sigaction_u.__sa_handler = SIG_IGN;
    newAction.sa_mask = 0;
    newAction.sa_flags = 0;

    if(0 != sigaction(SIGCHLD, &newAction, &oldAction))
    {
        NSLog(@"Couldn't ignore SIGCHLD");
        return;
    }

    @try
    {
        if (errAuthorizationSuccess != (err = AuthorizationCreate(NULL,  kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef)))    
        {
            NSLog(@"Error on AuthorizationCreate: %lu", (long)err);
            return;
        }

        for (NSUInteger i = 0; i < 1000; i++)
        {
            NSLog(@"Doing run: %lu", (long)i+1);
            DoOtherStuff(authorizationRef, "/tmp/foo");
        }

        if (errAuthorizationSuccess != (err = AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults)))
        {
            NSLog(@"Error on AuthorizationFree: %lu", (long)err);
            return;
        }
    }
    @finally 
    {
        const struct sigaction cOldAction = oldAction;
        if(0 != sigaction(SIGCHLD, &cOldAction, NULL))
        {
            NSLog(@"Couldn't restore the handler for SIGCHLD");
            return;
        }

    }
}

void DoOtherStuff(AuthorizationRef authorizationRef, char* path)
{ 
    OSStatus err = errAuthorizationSuccess;
    FILE *pipe = NULL;
    @try
    {
        char *args[] = {"644", path, NULL};
        if (errAuthorizationSuccess != (err = AuthorizationExecuteWithPrivileges(authorizationRef,
                                                 "/bin/chmod", kAuthorizationFlagDefaults, args, &pipe)))
        {
            NSLog(@"Error on AuthorizationExecuteWithPrivileges: %lu", (long)err);
            return;
        }

        NSLog(@"Success!");
    }
    @finally 
    {        
        if (pipe)
            fclose(pipe);
    }
}

关于objective-c - Cocoa 中 AuthorizationExecuteWithPriveleges 的非常奇怪的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8094683/

相关文章:

objective-c - 如何确定两个NSD何时相隔1周?

ios - 如何释放 JSONConnection 对象

python - 使用 python 终端关闭程序

css - Chrome 中我的单选按钮左侧有裁剪

objective-c - 使用 Cocoa 在 NSComboBox 中显示文本

iphone - 以编程方式查找 iphone 的语言环境货币

ios - AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection :completionHandler inactive/invalid connection passed?

windows - 代码如何存储在可执行文件中?

objective-c - Snow Leopard 和 Leopard 的一个代码库

objective-c - 简单的 NSMutable 数组问题