Annotation of src/usr.bin/tmux/job.c, Revision 1.9
1.9 ! nicm 1: /* $OpenBSD: job.c,v 1.8 2009/10/21 18:20:16 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: /* Destroy a job tree. */
52: void
53: job_tree_free(struct jobs *jobs)
54: {
55: struct job *job;
56:
57: while (!RB_EMPTY(jobs)) {
58: job = RB_ROOT(jobs);
59: RB_REMOVE(jobs, jobs, job);
60: job_free(job);
61: }
62: }
63:
64: /* Find a job and return it. */
65: struct job *
66: job_get(struct jobs *jobs, const char *cmd)
67: {
68: struct job job;
69:
70: job.cmd = (char *) cmd;
71: return (RB_FIND(jobs, jobs, &job));
72: }
73:
74: /* Add a job. */
75: struct job *
1.9 ! nicm 76: job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd,
1.1 nicm 77: void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
78: {
79: struct job *job;
80:
81: job = xmalloc(sizeof *job);
82: job->cmd = xstrdup(cmd);
1.2 nicm 83: job->pid = -1;
1.9 ! nicm 84: job->status = 0;
1.1 nicm 85:
86: job->client = c;
87:
88: job->fd = -1;
89: job->out = buffer_create(BUFSIZ);
90:
91: job->callbackfn = callbackfn;
92: job->freefn = freefn;
93: job->data = data;
94:
1.9 ! nicm 95: job->flags = flags|JOB_DONE;
1.3 nicm 96:
1.4 nicm 97: if (jobs != NULL)
98: RB_INSERT(jobs, jobs, job);
1.2 nicm 99: SLIST_INSERT_HEAD(&all_jobs, job, lentry);
1.9 ! nicm 100:
1.1 nicm 101: return (job);
1.9 ! nicm 102: }
! 103:
! 104: /* Remove job from tree and free. */
! 105: void
! 106: job_remove(struct jobs *jobs, struct job *job)
! 107: {
! 108: if (jobs != NULL)
! 109: RB_REMOVE(jobs, jobs, job);
! 110: job_free(job);
1.1 nicm 111: }
112:
113: /* Kill and free an individual job. */
114: void
115: job_free(struct job *job)
116: {
117: job_kill(job);
118:
1.5 nicm 119: SLIST_REMOVE(&all_jobs, job, job, lentry);
1.1 nicm 120: xfree(job->cmd);
1.4 nicm 121:
122: if (job->freefn != NULL && job->data != NULL)
123: job->freefn(job->data);
1.1 nicm 124:
125: if (job->fd != -1)
126: close(job->fd);
127: if (job->out != NULL)
128: buffer_destroy(job->out);
129:
130: xfree(job);
131: }
132:
133: /* Start a job running, if it isn't already. */
134: int
135: job_run(struct job *job)
136: {
137: int nullfd, out[2], mode;
138:
1.3 nicm 139: if (!(job->flags & JOB_DONE))
1.1 nicm 140: return (0);
1.3 nicm 141: job->flags &= ~JOB_DONE;
1.1 nicm 142:
143: if (pipe(out) != 0)
144: return (-1);
145:
146: switch (job->pid = fork()) {
147: case -1:
148: return (-1);
149: case 0: /* child */
150: sigreset();
151: /* XXX environ? */
152:
1.7 nicm 153: if (dup2(out[1], STDOUT_FILENO) == -1)
1.6 nicm 154: fatal("dup2 failed");
1.7 nicm 155: if (out[1] != STDOUT_FILENO)
156: close(out[1]);
157: close(out[0]);
1.6 nicm 158:
1.7 nicm 159: nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
1.1 nicm 160: if (nullfd < 0)
161: fatal("open failed");
162: if (dup2(nullfd, STDIN_FILENO) == -1)
163: fatal("dup2 failed");
164: if (dup2(nullfd, STDERR_FILENO) == -1)
165: fatal("dup2 failed");
166: if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
167: close(nullfd);
168:
169: execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
170: fatal("execl failed");
171: default: /* parent */
1.7 nicm 172: close(out[1]);
1.1 nicm 173:
1.7 nicm 174: job->fd = out[0];
1.1 nicm 175: if ((mode = fcntl(job->fd, F_GETFL)) == -1)
176: fatal("fcntl failed");
177: if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
178: fatal("fcntl failed");
179: if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
180: fatal("fcntl failed");
181:
182: if (BUFFER_USED(job->out) != 0)
183: buffer_remove(job->out, BUFFER_USED(job->out));
184:
185: return (0);
186: }
187: }
188:
189: /* Kill a job. */
190: void
191: job_kill(struct job *job)
192: {
193: if (job->pid == -1)
194: return;
195: kill(job->pid, SIGTERM);
196: job->pid = -1;
197: }