-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvenowm_control.c
210 lines (169 loc) · 5.54 KB
/
venowm_control.c
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "venowm_control.h"
#include "logmsg.h"
#include "venowm.h"
#include "workspace.h"
#include "split.h"
#include "protocol/venowm-shell-protocol.h"
static void venowm_control_focus_up(struct wl_client *client,
struct wl_resource *resource){
(void)client;
venowm_control_t *vc = wl_resource_get_user_data(resource);
split_t *new = split_move_up(g_workspace->focus);
workspace_focus_frame(g_workspace, new);
be_repaint(vc->be);
}
static void venowm_control_focus_down(struct wl_client *client,
struct wl_resource *resource){
(void)client;
venowm_control_t *vc = wl_resource_get_user_data(resource);
split_t *new = split_move_down(g_workspace->focus);
workspace_focus_frame(g_workspace, new);
be_repaint(vc->be);
}
static void venowm_control_focus_left(struct wl_client *client,
struct wl_resource *resource){
(void)client;
venowm_control_t *vc = wl_resource_get_user_data(resource);
split_t *new = split_move_left(g_workspace->focus);
workspace_focus_frame(g_workspace, new);
be_repaint(vc->be);
}
static void venowm_control_focus_right(struct wl_client *client,
struct wl_resource *resource){
(void)client;
venowm_control_t *vc = wl_resource_get_user_data(resource);
split_t *new = split_move_right(g_workspace->focus);
workspace_focus_frame(g_workspace, new);
be_repaint(vc->be);
}
static void venowm_control_launch(struct wl_client *client,
struct wl_resource *resource, struct wl_array *argv_array,
struct wl_array *argvlen_array){
(void)client;
venowm_control_t *vc = wl_resource_get_user_data(resource);
(void)vc;
uint32_t *argvlen_ptr;
// validity checks on the arg list
size_t argv_sum_len = argv_array->size;
size_t nargs = argvlen_array->size / sizeof(*argvlen_ptr);
// make sure argv is not an empty list
if(argv_sum_len == 0 || nargs == 0){
logmsg("launch arguments are empty, not executing\n");
goto done;
}
// make sure the argv_sum_length is correct
size_t counted_sum_len = 0;
wl_array_for_each(argvlen_ptr, argvlen_array){
counted_sum_len += *argvlen_ptr;
}
if(counted_sum_len != argv_sum_len){
logmsg("launch arguments improperly packed, not executing\n");
goto done;
}
// make sure all args are null-terminated
char *p = argv_array->data;
wl_array_for_each(argvlen_ptr, argvlen_array){
if(p[*argvlen_ptr - 1] != '\0'){
logmsg("launch arguments not null terminated, not executing\n");
goto done;
}
p += *argvlen_ptr;
}
// build the char **argv for execvp, which is NULL terminated.
size_t argv_copy_size = sizeof(char*) * (nargs + 1);
char **argv_copy = malloc(argv_copy_size);
if(!argv_copy){
logmsg("failed to launch %s: %m\n", (char*)argv_array->data);
goto done;
}
// fill argv_copy_size with pointers to argv_array->data
size_t argv_idx = 0;
p = argv_array->data;
wl_array_for_each(argvlen_ptr, argvlen_array){
argv_copy[argv_idx++] = p;
p += *argvlen_ptr;
}
// null-terminate the list
argv_copy[argv_idx] = NULL;
// actually launch the child process
pid_t pid = fork();
if(pid < 0){
logmsg("failed to launch %s: %m\n", (char*)argv_array->data);
goto cu_argv_copy;
}
if(pid == 0){
// child process
// all input/output uses /dev/null (best effort)
int null_fd = open("/dev/null", O_RDWR);
if(null_fd < 0){
perror("opening /dev/null");
}else{
// ignore errors, it'll be fine
close(0);
dup(null_fd);
close(1);
dup(null_fd);
close(2);
dup(null_fd);
}
// actually launch the command
execvp(argv_copy[0], argv_copy);
perror("execvp");
exit(127);
}
cu_argv_copy:
free(argv_copy);
done:
return;
}
static const struct venowm_control_interface venowm_control_impl = {
venowm_control_focus_up,
venowm_control_focus_down,
venowm_control_focus_left,
venowm_control_focus_right,
venowm_control_launch,
};
static void unbind_venowm_control(struct wl_resource *resource){
venowm_control_t *vc = wl_resource_get_user_data(resource);
(void)vc;
logmsg("venowm_control client disconnected\n");
// it seems you should not call wl_resource_destroy here...
}
static void bind_venowm_control(struct wl_client *client, void *data,
uint32_t version, uint32_t id){
venowm_control_t *vc = data;
struct wl_resource *resource;
logmsg("new venowm_control client\n");
resource = wl_resource_create(client, &venowm_control_interface, 1, id);
if(!resource){
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &venowm_control_impl, vc,
unbind_venowm_control);
}
void venowm_control_free(venowm_control_t *vc){
wl_global_destroy(vc->global);
free(vc);
}
venowm_control_t *venowm_control_new(backend_t *be,
struct wl_display *display){
venowm_control_t *vc = malloc(sizeof(*vc));
if(!vc) return NULL;
*vc = (venowm_control_t){
.be=be,
};
vc->global = wl_global_create(display, &venowm_control_interface, 1,
vc, bind_venowm_control);
if(!vc->global) goto fail_malloc;
return vc;
fail_malloc:
free(vc);
return NULL;
}