Annotation of src/usr.bin/tmux/job.c, Revision 1.3
1.2 nicm 1: /* $OpenBSD: job.c,v 1.1 2009/10/10 15:03:01 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);
1.2 nicm 73: SLIST_REMOVE(&all_jobs, job, job, lentry);
1.1 nicm 74: job_free(job);
75: }
76: }
77:
78: /* Find a job and return it. */
79: struct job *
80: job_get(struct jobs *jobs, const char *cmd)
81: {
82: struct job job;
83:
84: job.cmd = (char *) cmd;
85: return (RB_FIND(jobs, jobs, &job));
86: }
87:
88: /* Add a job. */
89: struct job *
90: job_add(struct jobs *jobs, struct client *c, const char *cmd,
91: void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
92: {
93: struct job *job;
94:
95: job = xmalloc(sizeof *job);
96: job->cmd = xstrdup(cmd);
1.2 nicm 97: job->pid = -1;
1.1 nicm 98:
99: job->client = c;
100:
101: job->fd = -1;
102: job->out = buffer_create(BUFSIZ);
103:
104: job->callbackfn = callbackfn;
105: job->freefn = freefn;
106: job->data = data;
107:
1.3 ! nicm 108: job->flags = JOB_DONE;
! 109:
1.1 nicm 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:
122: xfree(job->cmd);
123:
124: if (job->fd != -1)
125: close(job->fd);
126: if (job->out != NULL)
127: buffer_destroy(job->out);
128:
129: xfree(job);
130: }
131:
132: /* Start a job running, if it isn't already. */
133: int
134: job_run(struct job *job)
135: {
136: int nullfd, out[2], mode;
137:
1.3 ! nicm 138: if (!(job->flags & JOB_DONE))
1.1 nicm 139: return (0);
1.3 ! nicm 140: job->flags &= ~JOB_DONE;
1.1 nicm 141:
142: if (pipe(out) != 0)
143: return (-1);
144:
145: switch (job->pid = fork()) {
146: case -1:
147: return (-1);
148: case 0: /* child */
149: sigreset();
150: /* XXX environ? */
151:
152: nullfd = open(_PATH_DEVNULL, O_RDONLY, 0);
153: if (nullfd < 0)
154: fatal("open failed");
155: if (dup2(nullfd, STDIN_FILENO) == -1)
156: fatal("dup2 failed");
157: if (dup2(nullfd, STDERR_FILENO) == -1)
158: fatal("dup2 failed");
159: if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
160: close(nullfd);
161:
162: close(out[1]);
163: if (dup2(out[0], STDOUT_FILENO) == -1)
164: fatal("dup2 failed");
165: if (out[0] != STDOUT_FILENO)
166: close(out[0]);
167:
168: execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
169: fatal("execl failed");
170: default: /* parent */
171: close(out[0]);
172:
173: job->fd = out[1];
174: if ((mode = fcntl(job->fd, F_GETFL)) == -1)
175: fatal("fcntl failed");
176: if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
177: fatal("fcntl failed");
178: if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
179: fatal("fcntl failed");
180:
181: if (BUFFER_USED(job->out) != 0)
182: buffer_remove(job->out, BUFFER_USED(job->out));
183:
184: return (0);
185: }
186: }
187:
188: /* Kill a job. */
189: void
190: job_kill(struct job *job)
191: {
192: if (job->pid == -1)
193: return;
194: kill(job->pid, SIGTERM);
195: job->pid = -1;
196: }