我使用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上运行。
如果有人有想法,请问我能做些什么。对此,我真的非常感激。我需要尽快。感谢
答案 0 :(得分:3)
看了一下这个,并编写了以下示例,没有保修,但是对于我来说,对于我的数千次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);
}
}
克里斯苏特所说的已经死了。调用AuthorizationExecuteWithPrivileges时会发生的事情是fork()是你的进程,然后exec()从子进程执行请求的进程(在本例中为chmod)。在有人调用wait()之前,不会获得子进程,但这很难,因为我们没有从AuthorizationExecuteWithPrivileges获取子进程的PID(它将由fork()返回)。正如他所说,如果你确定没有其他线程同时产生进程(即你的线程是唯一一个创建子进程的线程),那么你可以只调用wait()的非PID特定版本我在这个例子中做。
如果你不调用wait(),那么你会积累这些等待收获的僵尸子进程。最终操作系统说“不再”。
我感觉有点不好发布这个,因为它只是对Chris Suter所说的翻新;我赞成他的回答。
为了完整性,这里是该示例的重写版本,通过忽略SIGCHLD而不是调用wait来实现目标。它也没有保修,但对我有用。
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);
}
}
答案 1 :(得分:2)
你要做的不是一个好主意。
我猜你的代码中还有一个bug,也许是在监视管道时。我们需要看到你的其余代码。
如果您采用这种方法,则需要注意并确保清理僵尸进程,这在使用AuthorizationExecuteWithPrivileges时可能会很尴尬,因为您没有获得子进程ID。您可能需要忽略SIGCHLD
,或者如果您可以确定没有其他线程同时处理进程,您可以只调用wait
。
您还必须确保清理管道,否则您将耗尽文件描述符。
系统对于泄漏文件描述符或进程的能力远不如泄漏内存那么宽容。
解决问题的正确方法可能是编写一个帮助工具,然后与帮助工具通信,要求它代表您执行特权操作。这样你只需运行一次辅助工具。您应该能够在Apple的文档中阅读更多相关信息。
答案 2 :(得分:1)
您应该初始化err(由于第一个IF语句),因为它不能保证为0.但是,它可能是,因此您正在跳过AuthorizationCreate,因此不会创建授权会话。
基本上你将authorizationRef未初始化传递给AuthorizationExecuteWithPrivileges,这可能是个问题。
再加上其他人,我会把AuthorizationFree(authorizationRef,kAuthorizationFlagDefaults);最后,当您使用AuthorizationCreate释放内存时。
另外值得注意的是,从OS X v10.7开始,不推荐使用AuthorizationExecuteWithPrivileges,但我想你知道,因为你说你试图在10.5上运行
编辑:您可能希望在运行AuthorizationCreate
后检查错误的状态if ( err != errAuthorizationSuccess ) {
return;
}
...你也应该在AuthorizationExecuteWithPrivileges之后检查错误。
答案 3 :(得分:0)
我想我可能知道这里发生了什么:尝试正确处理管道(即不要传递NULL,并确保关闭它)。如果你没有给它一个STDIN管道,NSTask也会发生像这样奇怪的事情。 cocoadev.com上的This page解释说:
如果执行,NSTask将完全破坏Xcode的调试日志 任何与sh或bash(包括脚本)相关的东西。 printf,NSLog; 一旦任务启动,所有这些都将停止运作。甚至 右键单击调试器中的对象之类的东西会产生 什么都没有(直接GDB仍打印)。 ......我想通了 问题在于标准输入,所有事情。快速修复此问题 将标准输入设置为随机的,例如a 管道,并没有做任何事情。
这让我困扰了好几个小时(与NSTask合作而不是AS)。如果您所看到的奇怪行为与此无关,我会感到惊讶。确保你没有传递NULL,然后通过调用fclose等确保你正在清理AuthorizationExecuteWithPrivileges为你创建的文件句柄。
我不是百分百肯定,但“NSLog停止工作”症状引起了我的注意。