-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCmdivatorCmd.m
105 lines (91 loc) · 3.93 KB
/
CmdivatorCmd.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#import <spawn.h>
#import "CmdivatorCmd.h"
#import "Common.h"
#define LISTENER_NAME_PREFIX @"net.joedj.cmdivator.listener:"
@implementation CmdivatorCmd
- (instancetype)initWithPath:(NSString *)path {
if ((self = [super init])) {
_path = path;
}
return self;
}
- (NSString *)displayName {
return _path.lastPathComponent;
}
- (NSString *)displayPath {
return _path.stringByAbbreviatingWithTildeInPath;
}
- (NSString *)listenerName {
return [LISTENER_NAME_PREFIX stringByAppendingString:_path];
}
- (void)runForEvent:(LAEvent *)event {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static posix_spawn_file_actions_t cmd_spawn_file_actions;
static posix_spawnattr_t cmd_spawnattr;
static dispatch_once_t once;
dispatch_once(&once, ^{
int ret;
if (!(ret = posix_spawnattr_init(&cmd_spawnattr))) {
if ((ret = posix_spawnattr_setflags(&cmd_spawnattr, POSIX_SPAWN_CLOEXEC_DEFAULT))) {
LOG(@"posix_spawnattr_setflags: [%i] %s", ret, strerror(ret));
}
} else {
LOG(@"posix_spawnattr_init: [%i] %s", ret, strerror(ret));
}
if (!(ret = posix_spawn_file_actions_init(&cmd_spawn_file_actions))) {
if ((ret = posix_spawn_file_actions_addinherit_np(&cmd_spawn_file_actions, STDOUT_FILENO))) {
LOG(@"posix_spawn_file_actions_addinherit_np(%i): [%i] %s", STDOUT_FILENO, ret, strerror(ret));
}
if ((ret = posix_spawn_file_actions_addinherit_np(&cmd_spawn_file_actions, STDERR_FILENO))) {
LOG(@"posix_spawn_file_actions_addinherit_np(%i): [%i] %s", STDERR_FILENO, ret, strerror(ret));
}
} else {
LOG(@"posix_spawn_file_actions_init: [%i] %s", ret, strerror(ret));
}
});
NSString *path = _path;
const char * const cmd = path.fileSystemRepresentation;
const char * const cmd_argv[] = { cmd, NULL };
const char * const cmd_envp[] = {
[@"ACTIVATOR_LISTENER_NAME=" stringByAppendingString:self.listenerName].UTF8String,
[@"ACTIVATOR_EVENT_NAME=" stringByAppendingString:event.name].UTF8String,
[@"ACTIVATOR_EVENT_MODE=" stringByAppendingString:event.mode].UTF8String,
NULL
};
pid_t pid;
int ret;
if (!(ret = posix_spawn(&pid, cmd, &cmd_spawn_file_actions, &cmd_spawnattr, (char * const *)cmd_argv, (char * const *)cmd_envp))) {
dispatch_source_t exit_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, dispatch_get_main_queue());
dispatch_source_set_event_handler(exit_source, ^{
int status;
if (waitpid(pid, &status, WNOHANG) == -1) {
LOG(@"waitpid(%i): [%i] %s", pid, errno, strerror(errno));
} else if (WIFEXITED(status)) {
int exitStatus = WEXITSTATUS(status);
if (exitStatus != 0) {
LOG(@"%@ terminated with status: %i", path, exitStatus);
}
} else if (WIFSIGNALED(status)) {
LOG(@"%@ terminated by signal: %i", path, WTERMSIG(status));
}
dispatch_source_cancel(exit_source);
dispatch_release(exit_source);
});
dispatch_resume(exit_source);
} else {
LOG(@"Unable to spawn %@ for event %@: [%i] %s", path, event, ret, strerror(ret));
}
});
}
- (BOOL)isRemovable {
return [NSFileManager.defaultManager isDeletableFileAtPath:_path];
}
- (BOOL)delete {
NSError * __autoreleasing error = nil;
if (![NSFileManager.defaultManager removeItemAtPath:_path error:&error]) {
LOG(@"Unable to delete command %@: %@", _path, error);
return NO;
}
return YES;
}
@end