Annotation of src/usr.bin/tmux/job.c, Revision 1.2
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:
108: RB_INSERT(jobs, jobs, job);
1.2 ! nicm 109: SLIST_INSERT_HEAD(&all_jobs, job, lentry);
1.1 nicm 110:
111: return (job);
112: }
113:
114: /* Kill and free an individual job. */
115: void
116: job_free(struct job *job)
117: {
118: job_kill(job);
119:
120: xfree(job->cmd);
121:
122: if (job->fd != -1)
123: close(job->fd);
124: if (job->out != NULL)
125: buffer_destroy(job->out);
126:
127: xfree(job);
128: }
129:
130: /* Start a job running, if it isn't already. */
131: int
132: job_run(struct job *job)
133: {
134: int nullfd, out[2], mode;
135:
136: if (job->fd != -1)
137: return (0);
138:
139: if (pipe(out) != 0)
140: return (-1);
141:
142: switch (job->pid = fork()) {
143: case -1:
144: return (-1);
145: case 0: /* child */
146: sigreset();
147: /* XXX environ? */
148:
149: nullfd = open(_PATH_DEVNULL, O_RDONLY, 0);
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: close(out[1]);
160: if (dup2(out[0], STDOUT_FILENO) == -1)
161: fatal("dup2 failed");
162: if (out[0] != STDOUT_FILENO)
163: close(out[0]);
164:
165: execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
166: fatal("execl failed");
167: default: /* parent */
168: close(out[0]);
169:
170: job->fd = out[1];
171: if ((mode = fcntl(job->fd, F_GETFL)) == -1)
172: fatal("fcntl failed");
173: if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
174: fatal("fcntl failed");
175: if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
176: fatal("fcntl failed");
177:
178: if (BUFFER_USED(job->out) != 0)
179: buffer_remove(job->out, BUFFER_USED(job->out));
180:
181: return (0);
182: }
183: }
184:
185: /* Kill a job. */
186: void
187: job_kill(struct job *job)
188: {
189: if (job->pid == -1)
190: return;
191: kill(job->pid, SIGTERM);
192: job->pid = -1;
193: }