Annotation of src/usr.bin/tmux/job.c, Revision 1.8
1.8 ! nicm 1: /* $OpenBSD: job.c,v 1.7 2009/10/21 07:24:23 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 *
76: job_add(struct jobs *jobs, struct client *c, const char *cmd,
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.1 nicm 84:
85: job->client = c;
86:
87: job->fd = -1;
88: job->out = buffer_create(BUFSIZ);
89:
90: job->callbackfn = callbackfn;
91: job->freefn = freefn;
92: job->data = data;
93:
1.3 nicm 94: job->flags = JOB_DONE;
95:
1.4 nicm 96: if (jobs != NULL)
97: RB_INSERT(jobs, jobs, job);
1.2 nicm 98: SLIST_INSERT_HEAD(&all_jobs, job, lentry);
1.1 nicm 99:
100: return (job);
101: }
102:
103: /* Kill and free an individual job. */
104: void
105: job_free(struct job *job)
106: {
107: job_kill(job);
108:
1.5 nicm 109: SLIST_REMOVE(&all_jobs, job, job, lentry);
1.1 nicm 110: xfree(job->cmd);
1.4 nicm 111:
112: if (job->freefn != NULL && job->data != NULL)
113: job->freefn(job->data);
1.1 nicm 114:
115: if (job->fd != -1)
116: close(job->fd);
117: if (job->out != NULL)
118: buffer_destroy(job->out);
119:
120: xfree(job);
121: }
122:
123: /* Start a job running, if it isn't already. */
124: int
125: job_run(struct job *job)
126: {
127: int nullfd, out[2], mode;
128:
1.3 nicm 129: if (!(job->flags & JOB_DONE))
1.1 nicm 130: return (0);
1.3 nicm 131: job->flags &= ~JOB_DONE;
1.1 nicm 132:
133: if (pipe(out) != 0)
134: return (-1);
135:
136: switch (job->pid = fork()) {
137: case -1:
138: return (-1);
139: case 0: /* child */
140: sigreset();
141: /* XXX environ? */
142:
1.7 nicm 143: if (dup2(out[1], STDOUT_FILENO) == -1)
1.6 nicm 144: fatal("dup2 failed");
1.7 nicm 145: if (out[1] != STDOUT_FILENO)
146: close(out[1]);
147: close(out[0]);
1.6 nicm 148:
1.7 nicm 149: nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
1.1 nicm 150: if (nullfd < 0)
151: fatal("open failed");
152: if (dup2(nullfd, STDIN_FILENO) == -1)
153: fatal("dup2 failed");
154: if (dup2(nullfd, STDERR_FILENO) == -1)
155: fatal("dup2 failed");
156: if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
157: close(nullfd);
158:
159: execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
160: fatal("execl failed");
161: default: /* parent */
1.7 nicm 162: close(out[1]);
1.1 nicm 163:
1.7 nicm 164: job->fd = out[0];
1.1 nicm 165: if ((mode = fcntl(job->fd, F_GETFL)) == -1)
166: fatal("fcntl failed");
167: if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
168: fatal("fcntl failed");
169: if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
170: fatal("fcntl failed");
171:
172: if (BUFFER_USED(job->out) != 0)
173: buffer_remove(job->out, BUFFER_USED(job->out));
174:
175: return (0);
176: }
177: }
178:
179: /* Kill a job. */
180: void
181: job_kill(struct job *job)
182: {
183: if (job->pid == -1)
184: return;
185: kill(job->pid, SIGTERM);
186: job->pid = -1;
187: }