Annotation of src/usr.bin/tmux/job.c, Revision 1.5
1.5 ! nicm 1: /* $OpenBSD: job.c,v 1.4 2009/10/11 07:30:07 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <fcntl.h>
22: #include <paths.h>
23: #include <string.h>
24: #include <unistd.h>
25:
26: #include "tmux.h"
27:
28: /*
29: * Job scheduling. Run queued commands in the background and record their
30: * output.
31: */
32:
1.2 nicm 33: /* All jobs list. */
34: struct joblist all_jobs = SLIST_HEAD_INITIALIZER(&all_jobs);
35:
1.1 nicm 36: RB_GENERATE(jobs, job, entry, job_cmp);
37:
38: int
39: job_cmp(struct job *job1, struct job *job2)
40: {
41: return (strcmp(job1->cmd, job2->cmd));
42: }
43:
44: /* Initialise job tree. */
45: void
46: job_tree_init(struct jobs *jobs)
47: {
48: RB_INIT(jobs);
49: }
50:
51: /* Count the number of jobs in a tree. */
52: u_int
53: job_tree_size(struct jobs *jobs)
54: {
55: struct job *job;
56: u_int n;
57:
58: n = 0;
59: RB_FOREACH(job, jobs, jobs)
60: n++;
61: return (n);
62: }
63:
64: /* Destroy a job tree. */
65: void
66: job_tree_free(struct jobs *jobs)
67: {
68: struct job *job;
69:
70: while (!RB_EMPTY(jobs)) {
71: job = RB_ROOT(jobs);
72: RB_REMOVE(jobs, jobs, job);
73: job_free(job);
74: }
75: }
76:
77: /* Find a job and return it. */
78: struct job *
79: job_get(struct jobs *jobs, const char *cmd)
80: {
81: struct job job;
82:
83: job.cmd = (char *) cmd;
84: return (RB_FIND(jobs, jobs, &job));
85: }
86:
87: /* Add a job. */
88: struct job *
89: job_add(struct jobs *jobs, struct client *c, const char *cmd,
90: void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
91: {
92: struct job *job;
93:
94: job = xmalloc(sizeof *job);
95: job->cmd = xstrdup(cmd);
1.2 nicm 96: job->pid = -1;
1.1 nicm 97:
98: job->client = c;
99:
100: job->fd = -1;
101: job->out = buffer_create(BUFSIZ);
102:
103: job->callbackfn = callbackfn;
104: job->freefn = freefn;
105: job->data = data;
106:
1.3 nicm 107: job->flags = JOB_DONE;
108:
1.4 nicm 109: if (jobs != NULL)
110: RB_INSERT(jobs, jobs, job);
1.2 nicm 111: SLIST_INSERT_HEAD(&all_jobs, job, lentry);
1.1 nicm 112:
113: return (job);
114: }
115:
116: /* Kill and free an individual job. */
117: void
118: job_free(struct job *job)
119: {
120: job_kill(job);
121:
1.5 ! nicm 122: SLIST_REMOVE(&all_jobs, job, job, lentry);
1.1 nicm 123: xfree(job->cmd);
1.4 nicm 124:
125: if (job->freefn != NULL && job->data != NULL)
126: job->freefn(job->data);
1.1 nicm 127:
128: if (job->fd != -1)
129: close(job->fd);
130: if (job->out != NULL)
131: buffer_destroy(job->out);
132:
133: xfree(job);
134: }
135:
136: /* Start a job running, if it isn't already. */
137: int
138: job_run(struct job *job)
139: {
140: int nullfd, out[2], mode;
141:
1.3 nicm 142: if (!(job->flags & JOB_DONE))
1.1 nicm 143: return (0);
1.3 nicm 144: job->flags &= ~JOB_DONE;
1.1 nicm 145:
146: if (pipe(out) != 0)
147: return (-1);
148:
149: switch (job->pid = fork()) {
150: case -1:
151: return (-1);
152: case 0: /* child */
153: sigreset();
154: /* XXX environ? */
155:
156: nullfd = open(_PATH_DEVNULL, O_RDONLY, 0);
157: if (nullfd < 0)
158: fatal("open failed");
159: if (dup2(nullfd, STDIN_FILENO) == -1)
160: fatal("dup2 failed");
161: if (dup2(nullfd, STDERR_FILENO) == -1)
162: fatal("dup2 failed");
163: if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
164: close(nullfd);
165:
166: close(out[1]);
167: if (dup2(out[0], STDOUT_FILENO) == -1)
168: fatal("dup2 failed");
169: if (out[0] != STDOUT_FILENO)
170: close(out[0]);
171:
172: execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
173: fatal("execl failed");
174: default: /* parent */
175: close(out[0]);
176:
177: job->fd = out[1];
178: if ((mode = fcntl(job->fd, F_GETFL)) == -1)
179: fatal("fcntl failed");
180: if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
181: fatal("fcntl failed");
182: if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
183: fatal("fcntl failed");
184:
185: if (BUFFER_USED(job->out) != 0)
186: buffer_remove(job->out, BUFFER_USED(job->out));
187:
188: return (0);
189: }
190: }
191:
192: /* Kill a job. */
193: void
194: job_kill(struct job *job)
195: {
196: if (job->pid == -1)
197: return;
198: kill(job->pid, SIGTERM);
199: job->pid = -1;
200: }