diff options
author | Tudor Florea <tudor.florea@enea.com> | 2014-10-10 03:49:30 +0200 |
---|---|---|
committer | Tudor Florea <tudor.florea@enea.com> | 2014-10-10 03:49:30 +0200 |
commit | ede215cf93ba81c963ae62d665d0f32c9407551c (patch) | |
tree | 4a6dc80f259bccb8ff8b76d31e6cc8794bd97a2b /tcf/terminals_agent.patch | |
download | eclipse-poky-kepler-daisy-140929.tar.gz |
initial commit for Enea Linux 4.0-140929daisy-140929
Migrated from the internal git server on the daisy-enea-point-release branch
Signed-off-by: Tudor Florea <tudor.florea@enea.com>
Diffstat (limited to 'tcf/terminals_agent.patch')
-rw-r--r-- | tcf/terminals_agent.patch | 1042 |
1 files changed, 1042 insertions, 0 deletions
diff --git a/tcf/terminals_agent.patch b/tcf/terminals_agent.patch new file mode 100644 index 0000000..d9ca505 --- /dev/null +++ b/tcf/terminals_agent.patch | |||
@@ -0,0 +1,1042 @@ | |||
1 | Index: org.eclipse.tm.tcf.terminals.agent/terminals.c | ||
2 | =================================================================== | ||
3 | --- org.eclipse.tm.tcf.terminals.agent/terminals.c (revision 0) | ||
4 | +++ org.eclipse.tm.tcf.terminals.agent/terminals.c (revision 0) | ||
5 | @@ -0,0 +1,860 @@ | ||
6 | +/******************************************************************************* | ||
7 | + * Copyright (c) 2008 Wind River Systems, Inc. and others. | ||
8 | + * All rights reserved. This program and the accompanying materials | ||
9 | + * are made available under the terms of the Eclipse Public License v1.0 | ||
10 | + * and Eclipse Distribution License v1.0 which accompany this distribution. | ||
11 | + * The Eclipse Public License is available at | ||
12 | + * http://www.eclipse.org/legal/epl-v10.html | ||
13 | + * and the Eclipse Distribution License is available at | ||
14 | + * http://www.eclipse.org/org/documents/edl-v10.php. | ||
15 | + * | ||
16 | + * Contributors: | ||
17 | + * Wind River Systems - initial API and implementation | ||
18 | + * Intel - implemented terminals service | ||
19 | + *******************************************************************************/ | ||
20 | + | ||
21 | +/* | ||
22 | + * Sample TCF service implementation. | ||
23 | + */ | ||
24 | + | ||
25 | +#include <config.h> | ||
26 | +#include <stdlib.h> | ||
27 | +#include <stdio.h> | ||
28 | +#include <string.h> | ||
29 | +#include <errno.h> | ||
30 | +#include <fcntl.h> | ||
31 | +#include <signal.h> | ||
32 | +#include <assert.h> | ||
33 | +#include <termios.h> | ||
34 | +#ifndef TIOCGWINSZ | ||
35 | +#include <sys/ioctl.h> | ||
36 | +#endif | ||
37 | +#include <framework/myalloc.h> | ||
38 | +#include <framework/protocol.h> | ||
39 | +#include <framework/trace.h> | ||
40 | +#include <framework/context.h> | ||
41 | +#include <framework/json.h> | ||
42 | +#include <framework/asyncreq.h> | ||
43 | +#include <framework/exceptions.h> | ||
44 | +#include <framework/waitpid.h> | ||
45 | +#include <framework/signames.h> | ||
46 | +#include <services/streamsservice.h> | ||
47 | +#include <terminals.h> | ||
48 | + | ||
49 | +#define TERMINALS_DEBUG 1 | ||
50 | + | ||
51 | +#define TERMINALS_NO_LOGIN 0 | ||
52 | + | ||
53 | +static const char * TERMINALS = "Terminals"; | ||
54 | + | ||
55 | +#if defined(WIN32) | ||
56 | +# include <tlhelp32.h> | ||
57 | +# ifdef _MSC_VER | ||
58 | +# pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union (in winternl.h) */ | ||
59 | +# include <winternl.h> | ||
60 | +# else | ||
61 | +# include <ntdef.h> | ||
62 | +# endif | ||
63 | +# ifndef STATUS_INFO_LENGTH_MISMATCH | ||
64 | +# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) | ||
65 | +# endif | ||
66 | +# ifndef SystemHandleInformation | ||
67 | +# define SystemHandleInformation 16 | ||
68 | +# endif | ||
69 | +# error("unsupported WIN32!") | ||
70 | +#elif defined(_WRS_KERNEL) | ||
71 | +# include <symLib.h> | ||
72 | +# include <sysSymTbl.h> | ||
73 | +# include <ioLib.h> | ||
74 | +# include <ptyDrv.h> | ||
75 | +# include <taskHookLib.h> | ||
76 | +# error("unsupported WRS!") | ||
77 | +#else | ||
78 | +# include <sys/stat.h> | ||
79 | +# include <unistd.h> | ||
80 | +# include <dirent.h> | ||
81 | +# if TERMINALS_NO_LOGIN | ||
82 | +# define TERM_LAUNCH_EXEC "/bin/bash" | ||
83 | +# define TERM_LAUNCH_ARGS {TERM_LAUNCH_EXEC, NULL} | ||
84 | +# else | ||
85 | +# define TERM_LAUNCH_EXEC "/bin/login" | ||
86 | +# define TERM_LAUNCH_ARGS {TERM_LAUNCH_EXEC, "-p", NULL} | ||
87 | +# endif | ||
88 | +#endif | ||
89 | + | ||
90 | +#define PIPE_SIZE 0x1000 | ||
91 | +#define TERM_PROP_DEF_SIZE 256 | ||
92 | + | ||
93 | +typedef struct Terminal | ||
94 | +{ | ||
95 | + LINK link; | ||
96 | + int pid; /*pid of the login process of the terminal*/ | ||
97 | + TCFBroadcastGroup * bcg; | ||
98 | + int inp; | ||
99 | + int out; | ||
100 | + int err; | ||
101 | + struct TerminalInput * inp_struct; | ||
102 | + struct TerminalOutput * out_struct; | ||
103 | + struct TerminalOutput * err_struct; | ||
104 | + char inp_id[256]; | ||
105 | + char out_id[256]; | ||
106 | + char err_id[256]; | ||
107 | + | ||
108 | + char pty_type[TERM_PROP_DEF_SIZE]; | ||
109 | + char encoding[TERM_PROP_DEF_SIZE]; | ||
110 | + unsigned long width; | ||
111 | + unsigned long height; | ||
112 | + long exit_code; | ||
113 | + | ||
114 | + Channel *channel; | ||
115 | +} Terminal; | ||
116 | + | ||
117 | +typedef struct TerminalOutput | ||
118 | +{ | ||
119 | + Terminal * prs; | ||
120 | + AsyncReqInfo req; | ||
121 | + int req_posted; | ||
122 | + char buf[PIPE_SIZE]; | ||
123 | + size_t buf_pos; | ||
124 | + int eos; | ||
125 | + VirtualStream * vstream; | ||
126 | +} TerminalOutput; | ||
127 | + | ||
128 | +typedef struct TerminalInput | ||
129 | +{ | ||
130 | + Terminal * prs; | ||
131 | + AsyncReqInfo req; | ||
132 | + int req_posted; | ||
133 | + char buf[PIPE_SIZE]; | ||
134 | + size_t buf_pos; | ||
135 | + size_t buf_len; | ||
136 | + int eos; | ||
137 | + VirtualStream * vstream; | ||
138 | +} TerminalInput; | ||
139 | + | ||
140 | +#define link2term(A) ((Terminal *)((char *)(A) - offsetof(Terminal, link))) | ||
141 | + | ||
142 | +static LINK terms_list; | ||
143 | +#if defined(_WRS_KERNEL) | ||
144 | +static SEM_ID prs_list_lock = NULL; | ||
145 | +#endif | ||
146 | + | ||
147 | +static Terminal * find_terminal(int pid) | ||
148 | +{ | ||
149 | + LINK * qhp = &terms_list; | ||
150 | + LINK * qp = qhp->next; | ||
151 | + | ||
152 | + while (qp != qhp) { | ||
153 | + Terminal * prs = link2term(qp); | ||
154 | + if (prs->pid == pid) | ||
155 | + return prs; | ||
156 | + qp = qp->next; | ||
157 | + } | ||
158 | + return NULL; | ||
159 | +} | ||
160 | + | ||
161 | +static char * tid2id(int tid) | ||
162 | +{ | ||
163 | + static char s[64]; | ||
164 | + char * p = s + sizeof(s); | ||
165 | + unsigned long n = (long) tid; | ||
166 | + *(--p) = 0; | ||
167 | + do { | ||
168 | + *(--p) = (char) (n % 10 + '0'); | ||
169 | + n = n / 10; | ||
170 | + } while (n != 0); | ||
171 | + | ||
172 | + *(--p) = 'T'; | ||
173 | + return p; | ||
174 | +} | ||
175 | + | ||
176 | +static int id2tid(const char * id) | ||
177 | +{ | ||
178 | + int tid = 0; | ||
179 | + if (id == NULL) | ||
180 | + return 0; | ||
181 | + if (id[0] != 'T') | ||
182 | + return 0; | ||
183 | + if (id[1] == 0) | ||
184 | + return 0; | ||
185 | + tid = (unsigned) strtol(id + 1, (char **) &id, 10); | ||
186 | + if (id[0] != 0) | ||
187 | + return 0; | ||
188 | + return tid; | ||
189 | +} | ||
190 | + | ||
191 | +static void write_context(OutputStream * out, int tid) | ||
192 | +{ | ||
193 | + Terminal * prs = find_terminal(tid); | ||
194 | + | ||
195 | + write_stream(out, '{'); | ||
196 | + | ||
197 | + if (prs != NULL) { | ||
198 | + if (*prs->pty_type) { | ||
199 | + json_write_string(out, "PtyType"); | ||
200 | + write_stream(out, ':'); | ||
201 | + json_write_string(out, prs->pty_type); | ||
202 | + write_stream(out, ','); | ||
203 | + } | ||
204 | + | ||
205 | + if (*prs->encoding) { | ||
206 | + json_write_string(out, "Encoding"); | ||
207 | + write_stream(out, ':'); | ||
208 | + json_write_string(out, prs->encoding); | ||
209 | + write_stream(out, ','); | ||
210 | + } | ||
211 | + | ||
212 | + json_write_string(out, "Width"); | ||
213 | + write_stream(out, ':'); | ||
214 | + json_write_ulong(out, prs->width); | ||
215 | + write_stream(out, ','); | ||
216 | + | ||
217 | + json_write_string(out, "Height"); | ||
218 | + write_stream(out, ':'); | ||
219 | + json_write_ulong(out, prs->height); | ||
220 | + write_stream(out, ','); | ||
221 | + | ||
222 | + if (*prs->inp_id) { | ||
223 | + json_write_string(out, "StdInID"); | ||
224 | + write_stream(out, ':'); | ||
225 | + json_write_string(out, prs->inp_id); | ||
226 | + write_stream(out, ','); | ||
227 | + } | ||
228 | + if (*prs->out_id) { | ||
229 | + json_write_string(out, "StdOutID"); | ||
230 | + write_stream(out, ':'); | ||
231 | + json_write_string(out, prs->out_id); | ||
232 | + write_stream(out, ','); | ||
233 | + } | ||
234 | + if (*prs->err_id) { | ||
235 | + json_write_string(out, "StdErrID"); | ||
236 | + write_stream(out, ':'); | ||
237 | + json_write_string(out, prs->err_id); | ||
238 | + write_stream(out, ','); | ||
239 | + } | ||
240 | + } | ||
241 | + | ||
242 | + json_write_string(out, "ID"); | ||
243 | + write_stream(out, ':'); | ||
244 | + json_write_string(out, tid2id(tid)); | ||
245 | + | ||
246 | + write_stream(out, '}'); | ||
247 | +} | ||
248 | + | ||
249 | +static void send_event_terminal_exited(OutputStream * out, Terminal * prs) | ||
250 | +{ | ||
251 | + write_stringz(out, "E"); | ||
252 | + write_stringz(out, TERMINALS); | ||
253 | + write_stringz(out, "exited"); | ||
254 | + | ||
255 | + json_write_string(out, tid2id(prs->pid)); | ||
256 | + write_stream(out, 0); | ||
257 | + | ||
258 | + json_write_ulong(out, prs->exit_code); | ||
259 | + write_stream(out, 0); | ||
260 | + | ||
261 | + write_stream(out, MARKER_EOM); | ||
262 | +} | ||
263 | + | ||
264 | +static void send_event_terminal_win_size_changed(OutputStream * out, | ||
265 | + Terminal * prs) | ||
266 | +{ | ||
267 | + write_stringz(out, "E"); | ||
268 | + write_stringz(out, TERMINALS); | ||
269 | + write_stringz(out, "winSizeChanged"); | ||
270 | + | ||
271 | + json_write_string(out, tid2id(prs->pid)); | ||
272 | + write_stream(out, 0); | ||
273 | + | ||
274 | + json_write_long(out, prs->width); | ||
275 | + write_stream(out, 0); | ||
276 | + | ||
277 | + json_write_long(out, prs->height); | ||
278 | + write_stream(out, 0); | ||
279 | + | ||
280 | + write_stream(out, MARKER_EOM); | ||
281 | +} | ||
282 | + | ||
283 | +static int kill_term(Terminal *term) | ||
284 | +{ | ||
285 | + int err = 0; | ||
286 | + | ||
287 | +#if defined(WIN32) | ||
288 | + HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, term->pid); | ||
289 | + if (h == NULL) | ||
290 | + { | ||
291 | + err = set_win32_errno(GetLastError()); | ||
292 | + } | ||
293 | + else | ||
294 | + { | ||
295 | + if (!TerminateProcess(h, 1)) err = set_win32_errno(GetLastError()); | ||
296 | + if (!CloseHandle(h) && !err) err = set_win32_errno(GetLastError()); | ||
297 | + } | ||
298 | +#else | ||
299 | + if (kill(term->pid, SIGTERM) < 0) | ||
300 | + err = errno; | ||
301 | +#endif | ||
302 | + return err; | ||
303 | +} | ||
304 | + | ||
305 | +static void command_exit(char * token, Channel * c) | ||
306 | +{ | ||
307 | + int err = 0; | ||
308 | + char id[256]; | ||
309 | + unsigned tid; | ||
310 | + Terminal *term = NULL; | ||
311 | + | ||
312 | + json_read_string(&c->inp, id, sizeof(id)); | ||
313 | + if (read_stream(&c->inp) != 0) | ||
314 | + exception(ERR_JSON_SYNTAX); | ||
315 | + if (read_stream(&c->inp) != MARKER_EOM) | ||
316 | + exception(ERR_JSON_SYNTAX); | ||
317 | + | ||
318 | + tid = id2tid(id); | ||
319 | + write_stringz(&c->out, "R"); | ||
320 | + write_stringz(&c->out, token); | ||
321 | + | ||
322 | + if (tid == 0) { | ||
323 | + err = ERR_INV_CONTEXT; | ||
324 | + } else { | ||
325 | + term = find_terminal(tid); | ||
326 | + if (term == NULL) { | ||
327 | + err = ERR_INV_CONTEXT; | ||
328 | + } else { | ||
329 | + err = kill_term(term); | ||
330 | + } | ||
331 | + } | ||
332 | + | ||
333 | + write_errno(&c->out, err); | ||
334 | + write_stream(&c->out, MARKER_EOM); | ||
335 | +} | ||
336 | + | ||
337 | +static void terminal_exited(Terminal * prs) | ||
338 | +{ | ||
339 | + Trap trap; | ||
340 | + | ||
341 | + if (set_trap(&trap)) { | ||
342 | + send_event_terminal_exited(&prs->bcg->out, prs); | ||
343 | + clear_trap(&trap); | ||
344 | + } else { | ||
345 | + trace(LOG_ALWAYS, "Exception sending terminal exited event: %d %s", | ||
346 | + trap.error, errno_to_str(trap.error)); | ||
347 | + } | ||
348 | + | ||
349 | +#if defined(_WRS_KERNEL) | ||
350 | + semTake(prs_list_lock, WAIT_FOREVER); | ||
351 | +#endif | ||
352 | + list_remove(&prs->link); | ||
353 | + close(prs->inp); | ||
354 | + close(prs->out); | ||
355 | + if (prs->out != prs->err) | ||
356 | + close(prs->err); | ||
357 | + if (prs->inp_struct) { | ||
358 | + TerminalInput * inp = prs->inp_struct; | ||
359 | + if (!inp->req_posted) { | ||
360 | + virtual_stream_delete(inp->vstream); | ||
361 | + loc_free(inp); | ||
362 | + } else { | ||
363 | + inp->prs = NULL; | ||
364 | + } | ||
365 | + } | ||
366 | + if (prs->out_struct) | ||
367 | + prs->out_struct->prs = NULL; | ||
368 | + if (prs->err_struct) | ||
369 | + prs->err_struct->prs = NULL; | ||
370 | + loc_free(prs); | ||
371 | +#if defined(_WRS_KERNEL) | ||
372 | + semGive(prs_list_lock); | ||
373 | +#endif | ||
374 | +} | ||
375 | + | ||
376 | +static void terminal_input_streams_callback(VirtualStream * stream, | ||
377 | + int event_code, void * args) | ||
378 | +{ | ||
379 | + TerminalInput * inp = (TerminalInput *) args; | ||
380 | + | ||
381 | + assert(inp->vstream == stream); | ||
382 | + if (!inp->req_posted) { | ||
383 | + if (inp->buf_pos >= inp->buf_len && !inp->eos) { | ||
384 | + inp->buf_pos = inp->buf_len = 0; | ||
385 | + virtual_stream_get_data(stream, inp->buf, sizeof(inp->buf), | ||
386 | + &inp->buf_len, &inp->eos); | ||
387 | + } | ||
388 | + if (inp->buf_pos < inp->buf_len) { | ||
389 | + inp->req.u.fio.bufp = inp->buf + inp->buf_pos; | ||
390 | + inp->req.u.fio.bufsz = inp->buf_len - inp->buf_pos; | ||
391 | + inp->req_posted = 1; | ||
392 | + async_req_post(&inp->req); | ||
393 | + } | ||
394 | + } | ||
395 | +} | ||
396 | + | ||
397 | +static void write_terminal_input_done(void * x) | ||
398 | +{ | ||
399 | + AsyncReqInfo * req = (AsyncReqInfo *) x; | ||
400 | + TerminalInput * inp = (TerminalInput *) req->client_data; | ||
401 | + | ||
402 | + inp->req_posted = 0; | ||
403 | + if (inp->prs == NULL) { | ||
404 | + /* Process has exited */ | ||
405 | + virtual_stream_delete(inp->vstream); | ||
406 | + loc_free(inp); | ||
407 | + } else { | ||
408 | + int wr = inp->req.u.fio.rval; | ||
409 | + | ||
410 | + if (wr < 0) { | ||
411 | + int err = inp->req.error; | ||
412 | + trace(LOG_ALWAYS, "Can't write terminal input stream: %d %s", err, | ||
413 | + errno_to_str(err)); | ||
414 | + inp->buf_pos = inp->buf_len = 0; | ||
415 | + } else { | ||
416 | + inp->buf_pos += wr; | ||
417 | + } | ||
418 | + | ||
419 | + terminal_input_streams_callback(inp->vstream, 0, inp); | ||
420 | + } | ||
421 | +} | ||
422 | + | ||
423 | +static void write_terminal_input(Terminal * prs) | ||
424 | +{ | ||
425 | + TerminalInput * inp = prs->inp_struct = (TerminalInput *) loc_alloc_zero( | ||
426 | + sizeof(TerminalInput)); | ||
427 | + inp->prs = prs; | ||
428 | + inp->req.client_data = inp; | ||
429 | + inp->req.done = write_terminal_input_done; | ||
430 | + inp->req.type = AsyncReqWrite; | ||
431 | + inp->req.u.fio.fd = prs->inp; | ||
432 | + virtual_stream_create(TERMINALS, tid2id(prs->pid), PIPE_SIZE, | ||
433 | + VS_ENABLE_REMOTE_WRITE, terminal_input_streams_callback, inp, | ||
434 | + &inp->vstream); | ||
435 | + virtual_stream_get_id(inp->vstream, prs->inp_id, sizeof(prs->inp_id)); | ||
436 | +} | ||
437 | + | ||
438 | +static void terminal_output_streams_callback(VirtualStream * stream, | ||
439 | + int event_code, void * args) | ||
440 | +{ | ||
441 | + TerminalOutput * out = (TerminalOutput *) args; | ||
442 | + | ||
443 | + assert(out->vstream == stream); | ||
444 | + if (!out->req_posted) { | ||
445 | + int buf_len = out->req.u.fio.rval; | ||
446 | + int err = 0; | ||
447 | + int eos = 0; | ||
448 | + | ||
449 | + if (buf_len < 0) { | ||
450 | + buf_len = 0; | ||
451 | + err = out->req.error; | ||
452 | + } | ||
453 | + if (buf_len == 0) | ||
454 | + eos = 1; | ||
455 | + if (out->prs == NULL) { | ||
456 | + eos = 1; | ||
457 | + err = 0; | ||
458 | + } | ||
459 | + | ||
460 | + assert(buf_len <= (int)sizeof(out->buf)); | ||
461 | + assert(out->buf_pos <= (size_t)buf_len); | ||
462 | + assert(out->req.u.fio.bufp == out->buf); | ||
463 | +#ifdef __linux__ | ||
464 | + if (err == EIO) | ||
465 | + err = 0; | ||
466 | +#endif | ||
467 | + if (err) | ||
468 | + trace(LOG_ALWAYS, "Can't read terminal output stream: %d %s", err, | ||
469 | + errno_to_str(err)); | ||
470 | + | ||
471 | + if (out->buf_pos < (size_t) buf_len || out->eos != eos) { | ||
472 | + size_t done = 0; | ||
473 | + virtual_stream_add_data(stream, out->buf + out->buf_pos, buf_len | ||
474 | + - out->buf_pos, &done, eos); | ||
475 | + out->buf_pos += done; | ||
476 | + if (eos) | ||
477 | + out->eos = 1; | ||
478 | + } | ||
479 | + | ||
480 | + if (out->buf_pos >= (size_t) buf_len) { | ||
481 | + if (!eos) { | ||
482 | + out->req_posted = 1; | ||
483 | + async_req_post(&out->req); | ||
484 | + } else if (virtual_stream_is_empty(stream)) { | ||
485 | + if (out->prs != NULL) { | ||
486 | + if (out == out->prs->out_struct) | ||
487 | + out->prs->out_struct = NULL; | ||
488 | + if (out == out->prs->err_struct) | ||
489 | + out->prs->err_struct = NULL; | ||
490 | + } | ||
491 | + virtual_stream_delete(stream); | ||
492 | + loc_free(out); | ||
493 | + } | ||
494 | + } | ||
495 | + } // end if(!out->req_posted) | ||
496 | +} | ||
497 | + | ||
498 | +static void read_terminal_output_done(void * x) | ||
499 | +{ | ||
500 | + AsyncReqInfo * req = (AsyncReqInfo *) x; | ||
501 | + TerminalOutput * out = (TerminalOutput *) req->client_data; | ||
502 | + | ||
503 | + out->buf_pos = 0; | ||
504 | + out->req_posted = 0; | ||
505 | + terminal_output_streams_callback(out->vstream, 0, out); | ||
506 | +} | ||
507 | + | ||
508 | +static TerminalOutput * read_terminal_output(Terminal * prs, int fd, char * id, | ||
509 | + size_t id_size) | ||
510 | +{ | ||
511 | + TerminalOutput * out = (TerminalOutput *) loc_alloc_zero( | ||
512 | + sizeof(TerminalOutput)); | ||
513 | + out->prs = prs; | ||
514 | + out->req.client_data = out; | ||
515 | + out->req.done = read_terminal_output_done; | ||
516 | + out->req.type = AsyncReqRead; | ||
517 | + out->req.u.fio.bufp = out->buf; | ||
518 | + out->req.u.fio.bufsz = sizeof(out->buf); | ||
519 | + out->req.u.fio.fd = fd; | ||
520 | + virtual_stream_create(TERMINALS, tid2id(prs->pid), PIPE_SIZE, | ||
521 | + VS_ENABLE_REMOTE_READ, terminal_output_streams_callback, out, | ||
522 | + &out->vstream); | ||
523 | + virtual_stream_get_id(out->vstream, id, id_size); | ||
524 | + out->req_posted = 1; | ||
525 | + async_req_post(&out->req); | ||
526 | + return out; | ||
527 | +} | ||
528 | + | ||
529 | +static char **envp_add(char **old_envp, int old_envp_len, char *env) | ||
530 | +{ | ||
531 | + char **new_envp = NULL; | ||
532 | + int i; | ||
533 | + int env_size; | ||
534 | + int old_envp_size; | ||
535 | + | ||
536 | + assert(old_envp || (old_envp==NULL && old_envp_len==0)); | ||
537 | + assert(env); | ||
538 | + assert(*env); | ||
539 | + | ||
540 | + for (i = 0, old_envp_size = 0; i < old_envp_len; i++) { | ||
541 | + old_envp_size += sizeof(char *); //size of env pointer | ||
542 | + old_envp_size += strlen(old_envp[i]) + 1; //size of env string, including trailing '\0' | ||
543 | + } | ||
544 | + assert((old_envp && old_envp[i]==NULL) || (old_envp==NULL)); | ||
545 | + old_envp_size += sizeof(char *);//last null pointer | ||
546 | + | ||
547 | + env_size = strlen(env); //new env string size | ||
548 | + | ||
549 | + new_envp = loc_alloc(old_envp_size + sizeof(char *) + env_size + 1); | ||
550 | + if (new_envp != NULL) { | ||
551 | + new_envp[0] = (char *) new_envp + old_envp_size + sizeof(char *); //setting new env ptr | ||
552 | + strcpy(new_envp[0], env); //copy new env string | ||
553 | + if (old_envp) { | ||
554 | + memcpy(&new_envp[1], old_envp, old_envp_size); //copy old envp | ||
555 | + } else { | ||
556 | + new_envp[1] = NULL; | ||
557 | + } | ||
558 | + } | ||
559 | + return new_envp; | ||
560 | +} | ||
561 | + | ||
562 | +static int start_terminal(Channel * c, char *pty_type, char *encoding, | ||
563 | + char ** envp, int envp_len, char * exe, char ** args, int *pid, | ||
564 | + Terminal ** prs) | ||
565 | +{ | ||
566 | + int err = 0; | ||
567 | + int fd_tty_master = -1; | ||
568 | + char * tty_slave_name = NULL; | ||
569 | + struct winsize size; | ||
570 | + char **newenvp = envp; | ||
571 | + | ||
572 | + memset(&size, 0, sizeof(struct winsize)); | ||
573 | + fd_tty_master = posix_openpt(O_RDWR | O_NOCTTY); | ||
574 | + if (fd_tty_master < 0 || grantpt(fd_tty_master) < 0 || unlockpt( | ||
575 | + fd_tty_master) < 0) | ||
576 | + err = errno; | ||
577 | + if (!err) { | ||
578 | + tty_slave_name = ptsname(fd_tty_master); | ||
579 | + if (tty_slave_name == NULL) | ||
580 | + err = EINVAL; | ||
581 | + } | ||
582 | + | ||
583 | + if (ioctl(fd_tty_master, TIOCGWINSZ, (char *) &size) < 0) | ||
584 | + err = errno; | ||
585 | + | ||
586 | + if (!err && fd_tty_master < 3) { | ||
587 | + int fd0 = fd_tty_master; | ||
588 | + if ((fd_tty_master = dup(fd_tty_master)) < 0 || close(fd0)) | ||
589 | + err = errno; | ||
590 | + } | ||
591 | + | ||
592 | + if (!err) { | ||
593 | + *pid = fork(); | ||
594 | + if (*pid < 0) | ||
595 | + err = errno; | ||
596 | + if (*pid == 0) { | ||
597 | + int fd = -1; | ||
598 | + int fd_tty_slave = -1; | ||
599 | + char env_term[TERM_PROP_DEF_SIZE]; | ||
600 | + | ||
601 | + if (*pty_type) { | ||
602 | + snprintf(env_term, sizeof(env_term), "TERM=%s", pty_type); | ||
603 | + newenvp = envp_add(envp, envp_len, env_term); | ||
604 | + if (newenvp == NULL) { | ||
605 | + err = ENOMEM; | ||
606 | + } else if (envp) { | ||
607 | + loc_free(envp); | ||
608 | + envp = NULL; | ||
609 | + } | ||
610 | + } | ||
611 | + | ||
612 | + if (!err && *encoding) { | ||
613 | + envp = newenvp; | ||
614 | + envp_len += 1; | ||
615 | + snprintf(env_term, sizeof(env_term), "LANG=%s", encoding); | ||
616 | + newenvp = envp_add(envp, envp_len, env_term); | ||
617 | + if (newenvp == NULL) { | ||
618 | + err = ENOMEM; | ||
619 | + } else if (envp) { | ||
620 | + loc_free(envp); | ||
621 | + envp = NULL; | ||
622 | + } | ||
623 | + } | ||
624 | + | ||
625 | + setsid(); | ||
626 | + | ||
627 | + if (!err && (fd = sysconf(_SC_OPEN_MAX)) < 0) | ||
628 | + err = errno; | ||
629 | + if (!err && (fd_tty_slave = open(tty_slave_name, O_RDWR)) < 0) | ||
630 | + err = errno; | ||
631 | +#if defined(TIOCSCTTY) | ||
632 | + if (!err && (ioctl(fd_tty_slave, TIOCSCTTY, (char *) 0)) < 0) | ||
633 | + err = errno; | ||
634 | +#endif | ||
635 | + if (!err && dup2(fd_tty_slave, 0) < 0) | ||
636 | + err = errno; | ||
637 | + if (!err && dup2(fd_tty_slave, 1) < 0) | ||
638 | + err = errno; | ||
639 | + if (!err && dup2(fd_tty_slave, 2) < 0) | ||
640 | + err = errno; | ||
641 | + while (!err && fd > 3) | ||
642 | + close(--fd); | ||
643 | + if (!err) { | ||
644 | + execve(exe, args, newenvp); | ||
645 | + err = errno; | ||
646 | + } | ||
647 | + if (newenvp) | ||
648 | + loc_free(newenvp); | ||
649 | + err = 1; | ||
650 | + if (err < 1) | ||
651 | + err = EINVAL; | ||
652 | + else if (err > 0xff) | ||
653 | + err = EINVAL; | ||
654 | + exit(err); | ||
655 | + } | ||
656 | + } | ||
657 | + | ||
658 | + if (!err) { | ||
659 | + *prs = (Terminal *) loc_alloc_zero(sizeof(Terminal)); | ||
660 | + (*prs)->inp = fd_tty_master; | ||
661 | + (*prs)->out = fd_tty_master; | ||
662 | + (*prs)->err = fd_tty_master; | ||
663 | + (*prs)->pid = *pid; | ||
664 | + (*prs)->bcg = c->bcg; | ||
665 | + (*prs)->channel = c; | ||
666 | + if (*pty_type) | ||
667 | + snprintf((*prs)->pty_type, sizeof((*prs)->pty_type), "%s", pty_type); | ||
668 | + if (*encoding) | ||
669 | + snprintf((*prs)->encoding, sizeof((*prs)->encoding), "%s", encoding); | ||
670 | + (*prs)->width = size.ws_row; | ||
671 | + (*prs)->height = size.ws_col; | ||
672 | + list_add_first(&(*prs)->link, &terms_list); | ||
673 | + } | ||
674 | + | ||
675 | + if (!err) | ||
676 | + return 0; | ||
677 | + errno = err; | ||
678 | + return -1; | ||
679 | +} | ||
680 | + | ||
681 | +static void command_get_context(char * token, Channel * c) | ||
682 | +{ | ||
683 | + int err = 0; | ||
684 | + char id[256]; | ||
685 | + int tid; | ||
686 | + Terminal *term; | ||
687 | + | ||
688 | + json_read_string(&c->inp, id, sizeof(id)); | ||
689 | + if (read_stream(&c->inp) != 0) | ||
690 | + exception(ERR_JSON_SYNTAX); | ||
691 | + if (read_stream(&c->inp) != MARKER_EOM) | ||
692 | + exception(ERR_JSON_SYNTAX); | ||
693 | + | ||
694 | + tid = id2tid(id); | ||
695 | + write_stringz(&c->out, "R"); | ||
696 | + write_stringz(&c->out, token); | ||
697 | + | ||
698 | + if (tid == 0) { | ||
699 | + err = ERR_INV_CONTEXT; | ||
700 | + } else { | ||
701 | + term = find_terminal(tid); | ||
702 | + if (term == NULL) { | ||
703 | + err = ERR_INV_CONTEXT; | ||
704 | + } else { | ||
705 | + write_context(&c->out, tid); | ||
706 | + write_stream(&c->out, 0); | ||
707 | + } | ||
708 | + } | ||
709 | + | ||
710 | + write_errno(&c->out, err); | ||
711 | + write_stream(&c->out, MARKER_EOM); | ||
712 | +} | ||
713 | + | ||
714 | +static void command_launch(char * token, Channel * c) | ||
715 | +{ | ||
716 | + int pid = 0; | ||
717 | + int err = 0; | ||
718 | + char encoding[TERM_PROP_DEF_SIZE]; | ||
719 | + char pty_type[TERM_PROP_DEF_SIZE]; | ||
720 | + char *args[] = TERM_LAUNCH_ARGS; | ||
721 | + | ||
722 | + char ** envp = NULL; | ||
723 | + int envp_len = 0; | ||
724 | + | ||
725 | + Terminal * prs = NULL; | ||
726 | + Trap trap; | ||
727 | + | ||
728 | + if (set_trap(&trap)) { | ||
729 | + json_read_string(&c->inp, pty_type, sizeof(pty_type)); | ||
730 | + if (read_stream(&c->inp) != 0) | ||
731 | + exception(ERR_JSON_SYNTAX); | ||
732 | + json_read_string(&c->inp, encoding, sizeof(encoding)); | ||
733 | + if (read_stream(&c->inp) != 0) | ||
734 | + exception(ERR_JSON_SYNTAX); | ||
735 | + envp = json_read_alloc_string_array(&c->inp, &envp_len); | ||
736 | + if (read_stream(&c->inp) != 0) | ||
737 | + exception(ERR_JSON_SYNTAX); | ||
738 | + if (read_stream(&c->inp) != MARKER_EOM) | ||
739 | + exception(ERR_JSON_SYNTAX); | ||
740 | + | ||
741 | + if (err == 0 && start_terminal(c, pty_type, encoding, envp, envp_len, | ||
742 | + TERM_LAUNCH_EXEC, args, &pid, &prs) < 0) | ||
743 | + err = errno; | ||
744 | + if (prs != NULL) { | ||
745 | + write_terminal_input(prs); | ||
746 | + prs->out_struct = read_terminal_output(prs, prs->out, prs->out_id, | ||
747 | + sizeof(prs->out_id)); | ||
748 | + if (prs->out != prs->err) | ||
749 | + prs->err_struct = read_terminal_output(prs, prs->err, | ||
750 | + prs->err_id, sizeof(prs->err_id)); | ||
751 | + } | ||
752 | + if (!err) { | ||
753 | + add_waitpid_process(pid); | ||
754 | + } | ||
755 | + //write result back | ||
756 | + { | ||
757 | + write_stringz(&c->out, "R"); | ||
758 | + write_stringz(&c->out, token); | ||
759 | + write_errno(&c->out, err); | ||
760 | + if (err || pid == 0) { | ||
761 | + write_stringz(&c->out, "null"); | ||
762 | + } else { | ||
763 | + write_context(&c->out, pid); | ||
764 | + write_stream(&c->out, 0); | ||
765 | + } | ||
766 | + write_stream(&c->out, MARKER_EOM); | ||
767 | + } | ||
768 | + clear_trap(&trap); | ||
769 | + } | ||
770 | + | ||
771 | + loc_free(envp); | ||
772 | + | ||
773 | + if (trap.error) | ||
774 | + exception(trap.error); | ||
775 | +} | ||
776 | + | ||
777 | +static void command_set_win_size(char * token, Channel * c) | ||
778 | +{ | ||
779 | + int err = 0; | ||
780 | + struct winsize size; | ||
781 | + char id[256]; | ||
782 | + unsigned tid; | ||
783 | + Terminal *term = NULL; | ||
784 | + | ||
785 | + json_read_string(&c->inp, id, sizeof(id)); | ||
786 | + if (read_stream(&c->inp) != 0) | ||
787 | + exception(ERR_JSON_SYNTAX); | ||
788 | + size.ws_col=json_read_ulong(&c->inp); | ||
789 | + if (read_stream(&c->inp) != 0) | ||
790 | + exception(ERR_JSON_SYNTAX); | ||
791 | + size.ws_row=json_read_ulong(&c->inp); | ||
792 | + if (read_stream(&c->inp) != 0) | ||
793 | + exception(ERR_JSON_SYNTAX); | ||
794 | + if (read_stream(&c->inp) != MARKER_EOM) | ||
795 | + exception(ERR_JSON_SYNTAX); | ||
796 | + | ||
797 | + tid = id2tid(id); | ||
798 | + | ||
799 | + if(tid==0 || (term=find_terminal(tid))==NULL) { | ||
800 | + err=ERR_INV_CONTEXT; | ||
801 | + }else if (term->width != size.ws_col || term->height != size.ws_row) { | ||
802 | + if(ioctl(term->inp,TIOCSWINSZ,&size)<0) { | ||
803 | + err=errno; | ||
804 | + } | ||
805 | + if(!err) { | ||
806 | + term->width=size.ws_col; | ||
807 | + term->height=size.ws_row; | ||
808 | + send_event_terminal_win_size_changed(&term->channel->out,term); | ||
809 | + } | ||
810 | + } | ||
811 | + | ||
812 | + write_stringz(&c->out, "R"); | ||
813 | + write_stringz(&c->out, token); | ||
814 | + write_errno(&c->out, err); | ||
815 | + write_stream(&c->out, MARKER_EOM); | ||
816 | + | ||
817 | +} | ||
818 | + | ||
819 | +static void waitpid_listener(int pid, int exited, int exit_code, int signal, | ||
820 | + int event_code, int syscall, void * args) | ||
821 | +{ | ||
822 | + if (exited) { | ||
823 | + Terminal * prs = find_terminal(pid); | ||
824 | + if (prs) { | ||
825 | + if (signal != 0) | ||
826 | + prs->exit_code = -signal; | ||
827 | + else | ||
828 | + prs->exit_code = exit_code; | ||
829 | + terminal_exited(prs); | ||
830 | + } | ||
831 | + } | ||
832 | +} | ||
833 | + | ||
834 | +static void channel_close_listener(Channel * c) | ||
835 | +{ | ||
836 | + LINK * l = NULL; | ||
837 | + | ||
838 | + for (l = terms_list.next; l != &terms_list;) { | ||
839 | + Terminal * term = link2term(l); | ||
840 | + l = l->next; | ||
841 | + if (term->channel == c) { | ||
842 | + trace(LOG_ALWAYS, "Terminal is left launched: T%d", term->pid); | ||
843 | + kill_term(term); | ||
844 | + } | ||
845 | + } | ||
846 | +} | ||
847 | + | ||
848 | +void ini_terminals_service(Protocol * proto) | ||
849 | +{ | ||
850 | +#if defined(_WRS_KERNEL) | ||
851 | + prs_list_lock = semMCreate(SEM_Q_PRIORITY); | ||
852 | + if (prs_list_lock == NULL) check_error(errno); | ||
853 | + if (taskCreateHookAdd((FUNCPTR)task_create_hook) != OK) check_error(errno); | ||
854 | + if (taskDeleteHookAdd((FUNCPTR)task_delete_hook) != OK) check_error(errno); | ||
855 | +#endif | ||
856 | + list_init(&terms_list); | ||
857 | + | ||
858 | + add_waitpid_listener(waitpid_listener, NULL); | ||
859 | + add_channel_close_listener(channel_close_listener); | ||
860 | + | ||
861 | + add_command_handler(proto, TERMINALS, "getContext", command_get_context); | ||
862 | + add_command_handler(proto, TERMINALS, "launch", command_launch); | ||
863 | + add_command_handler(proto, TERMINALS, "exit", command_exit); | ||
864 | + add_command_handler(proto, TERMINALS, "setWinSize", command_set_win_size); | ||
865 | +} | ||
866 | Index: org.eclipse.tm.tcf.terminals.agent/main/services-ext.h | ||
867 | =================================================================== | ||
868 | --- org.eclipse.tm.tcf.terminals.agent/main/services-ext.h (revision 0) | ||
869 | +++ org.eclipse.tm.tcf.terminals.agent/main/services-ext.h (revision 0) | ||
870 | @@ -0,0 +1,26 @@ | ||
871 | +/******************************************************************************* | ||
872 | + * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. | ||
873 | + * All rights reserved. This program and the accompanying materials | ||
874 | + * are made available under the terms of the Eclipse Public License v1.0 | ||
875 | + * and Eclipse Distribution License v1.0 which accompany this distribution. | ||
876 | + * The Eclipse Public License is available at | ||
877 | + * http://www.eclipse.org/legal/epl-v10.html | ||
878 | + * and the Eclipse Distribution License is available at | ||
879 | + * http://www.eclipse.org/org/documents/edl-v10.php. | ||
880 | + * | ||
881 | + * Contributors: | ||
882 | + * Wind River Systems - initial API and implementation | ||
883 | + * Intel - implemented terminals service | ||
884 | + *******************************************************************************/ | ||
885 | + | ||
886 | +/* | ||
887 | + * Services initialization code extension point. | ||
888 | + * If the agent is built with additional user-defined services, | ||
889 | + * a customized version of services-ext.h file can be added to compiler headers search paths. | ||
890 | + */ | ||
891 | + | ||
892 | +#include "terminals.h" | ||
893 | + | ||
894 | +static void ini_ext_services(Protocol * proto, TCFBroadcastGroup * bcg) { | ||
895 | + ini_terminals_service(proto); | ||
896 | +} | ||
897 | Index: org.eclipse.tm.tcf.terminals.agent/terminals.h | ||
898 | =================================================================== | ||
899 | --- org.eclipse.tm.tcf.terminals.agent/terminals.h (revision 0) | ||
900 | +++ org.eclipse.tm.tcf.terminals.agent/terminals.h (revision 0) | ||
901 | @@ -0,0 +1,28 @@ | ||
902 | +/******************************************************************************* | ||
903 | + * Copyright (c) 2008 Wind River Systems, Inc. and others. | ||
904 | + * All rights reserved. This program and the accompanying materials | ||
905 | + * are made available under the terms of the Eclipse Public License v1.0 | ||
906 | + * and Eclipse Distribution License v1.0 which accompany this distribution. | ||
907 | + * The Eclipse Public License is available at | ||
908 | + * http://www.eclipse.org/legal/epl-v10.html | ||
909 | + * and the Eclipse Distribution License is available at | ||
910 | + * http://www.eclipse.org/org/documents/edl-v10.php. | ||
911 | + * | ||
912 | + * Contributors: | ||
913 | + * Wind River Systems - initial API and implementation | ||
914 | + * Intel - implemented terminals service | ||
915 | + *******************************************************************************/ | ||
916 | + | ||
917 | +/* | ||
918 | + * TCF terminals service header file. | ||
919 | + */ | ||
920 | + | ||
921 | +#ifndef TERMINALS_H_ | ||
922 | +#define TERMINALS_H_ | ||
923 | + | ||
924 | +#include <config.h> | ||
925 | +#include <framework/protocol.h> | ||
926 | + | ||
927 | +extern void ini_terminals_service(Protocol * proto); | ||
928 | + | ||
929 | +#endif /*TERMINALS_H_*/ | ||
930 | Index: org.eclipse.tm.tcf.terminals.agent/config.h | ||
931 | =================================================================== | ||
932 | --- org.eclipse.tm.tcf.terminals.agent/config.h (revision 0) | ||
933 | +++ org.eclipse.tm.tcf.terminals.agent/config.h (revision 0) | ||
934 | @@ -0,0 +1,64 @@ | ||
935 | +/******************************************************************************* | ||
936 | + * Copyright (c) 2008 Wind River Systems, Inc. and others. | ||
937 | + * All rights reserved. This program and the accompanying materials | ||
938 | + * are made available under the terms of the Eclipse Public License v1.0 | ||
939 | + * and Eclipse Distribution License v1.0 which accompany this distribution. | ||
940 | + * The Eclipse Public License is available at | ||
941 | + * http://www.eclipse.org/legal/epl-v10.html | ||
942 | + * and the Eclipse Distribution License is available at | ||
943 | + * http://www.eclipse.org/org/documents/edl-v10.php. | ||
944 | + * | ||
945 | + * Contributors: | ||
946 | + * Wind River Systems - initial API and implementation | ||
947 | + * Intel - implemented terminals service | ||
948 | + *******************************************************************************/ | ||
949 | + | ||
950 | +/* | ||
951 | + * This file contains "define" statements that control agent configuration. | ||
952 | + * SERVICE_* definitions control which service implementations are included into the agent. | ||
953 | + * | ||
954 | + * This is example agent configuration. It includes only few standard services, | ||
955 | + * and one example service: Day Time. | ||
956 | + */ | ||
957 | + | ||
958 | +#ifndef D_config | ||
959 | +#define D_config | ||
960 | + | ||
961 | +#include <framework/mdep.h> | ||
962 | + | ||
963 | +#if defined(WIN32) || defined(__CYGWIN__) | ||
964 | +# define TARGET_UNIX 0 | ||
965 | +#elif defined(_WRS_KERNEL) | ||
966 | +# define TARGET_UNIX 0 | ||
967 | +#else | ||
968 | +# define TARGET_UNIX 1 | ||
969 | +#endif | ||
970 | + | ||
971 | +#define SERVICE_Locator 1 | ||
972 | +#define SERVICE_Processes 1 | ||
973 | +#define SERVICE_Streams 1 | ||
974 | +#define SERVICE_FileSystem 1 | ||
975 | +#define SERVICE_SysMonitor TARGET_UNIX | ||
976 | + | ||
977 | +#define ENABLE_ZeroCopy 1 | ||
978 | + | ||
979 | +#if !defined(ENABLE_Splice) | ||
980 | +# if ENABLE_ZeroCopy | ||
981 | +# include <fcntl.h> | ||
982 | +# if defined(SPLICE_F_MOVE) | ||
983 | +# define ENABLE_Splice 1 | ||
984 | +# else | ||
985 | +# define ENABLE_Splice 0 | ||
986 | +# endif | ||
987 | +# else | ||
988 | +# define ENABLE_Splice 0 | ||
989 | +# endif | ||
990 | +#endif | ||
991 | + | ||
992 | +#define ENABLE_SSL 0 | ||
993 | + | ||
994 | +#define ENABLE_Trace 1 | ||
995 | +#define ENABLE_Discovery 1 | ||
996 | + | ||
997 | + | ||
998 | +#endif /* D_config */ | ||
999 | Index: org.eclipse.tm.tcf.terminals.agent/Makefile | ||
1000 | =================================================================== | ||
1001 | --- org.eclipse.tm.tcf.terminals.agent/Makefile (revision 0) | ||
1002 | +++ org.eclipse.tm.tcf.terminals.agent/Makefile (revision 0) | ||
1003 | @@ -0,0 +1,39 @@ | ||
1004 | +TCF_AGENT_DIR=../agent | ||
1005 | + | ||
1006 | +include $(TCF_AGENT_DIR)/Makefile.inc | ||
1007 | + | ||
1008 | +override CFLAGS += $(foreach dir,$(INCDIRS),-I$(dir)) $(OPTS) | ||
1009 | + | ||
1010 | +HFILES := $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.h)) $(HFILES) | ||
1011 | +CFILES := $(sort $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)) $(CFILES)) | ||
1012 | + | ||
1013 | +#no using SSL | ||
1014 | +LIBS = -lpthread -lrt | ||
1015 | + | ||
1016 | +EXECS = $(BINDIR)/agent$(EXTEXE) | ||
1017 | + | ||
1018 | +all: $(EXECS) | ||
1019 | + | ||
1020 | +$(BINDIR)/libtcf$(EXTLIB) : $(OFILES) | ||
1021 | + $(AR) rcs $@ $^ | ||
1022 | + | ||
1023 | +$(BINDIR)/agent$(EXTEXE): $(BINDIR)/main/main$(EXTOBJ) $(BINDIR)/libtcf$(EXTLIB) | ||
1024 | + $(CC) $(CFLAGS) -o $@ $(BINDIR)/main/main$(EXTOBJ) $(BINDIR)/libtcf$(EXTLIB) $(LIBS) | ||
1025 | + | ||
1026 | +$(BINDIR)/%$(EXTOBJ): %.c $(HFILES) Makefile | ||
1027 | + @mkdir -p $(dir $@) | ||
1028 | + $(CC) $(CFLAGS) -c -o $@ $< | ||
1029 | + | ||
1030 | +$(BINDIR)/%$(EXTOBJ): $(TCF_AGENT_DIR)/%.c $(HFILES) Makefile | ||
1031 | + @mkdir -p $(dir $@) | ||
1032 | + $(CC) $(CFLAGS) -c -o $@ $< | ||
1033 | + | ||
1034 | +install: all | ||
1035 | + install -d -m 755 $(INSTALLROOT)$(SBIN) | ||
1036 | + install -d -m 755 $(INSTALLROOT)$(INIT) | ||
1037 | + install -c $(BINDIR)/agent -m 755 $(INSTALLROOT)$(SBIN)/tcf-agent | ||
1038 | + install -c $(TCF_AGENT_DIR)/main/tcf-agent.init -m 755 $(INSTALLROOT)$(INIT)/tcf-agent | ||
1039 | + | ||
1040 | +clean: | ||
1041 | + rm -rf $(BINDIR) | ||
1042 | + | ||