Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 270 lines (240 sloc) 9.255 kb
2467806 @ChrisJohnsen LICENSE: Simplified BSD
authored
1 /*
2 * Copyright (c) 2011, Chris Johnsen <chris_johnsen@pobox.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
32 #include <unistd.h>
33 #include <stdlib.h>
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
34 #include <sys/errno.h>
35 #include <string.h>
36 #include <fcntl.h>
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
37 #include <dlfcn.h>
97ba160 @ChrisJohnsen SessionCreate from Security framework
authored
38
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
39 #include "msg.h"
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
40
d847e84 @ChrisJohnsen Crank up and fix warnings
authored
41 #define UNUSED __attribute__ ((unused))
42
564759b @ChrisJohnsen test: internal functions should be static
authored
43 static int our_daemon(int nochdir, int noclose) {
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
44 /*
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
45 * Implementation based on description in daemon(3).
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
46 * Hmm, got pretty close.
47 * http://www.opensource.apple.com/source/Libc/Libc-594.9.4/gen/daemon-fbsd.c
48 * Theirs touches on signal handling, too. And, it does the
49 * unwanted bit about moving to the root bootstrap namespace.
50 */
51 pid_t p;
52 int fd, i;
53 if ((p = fork()) < 0) return -1;
54 if (p>0) exit(0);
55 if ((p = setsid()) < 0) return -1;
56 if (!nochdir) chdir("/");
57 if (!noclose &&
58 !((fd = open("/dev/null", O_RDWR)) < 0)) {
59 for (i = 0; i < 3; i++) { dup2(fd,i); }
60 if (fd > 2) close(fd);
61 }
62 return 0;
63 }
64
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
65 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
66 static int sys_daemon(int nocd, int nocl) { return daemon(nocd, nocl); }
67 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
68
69 static void do_daemon(const char *opt) {
70 if (!(opt && *opt))
71 die(2, "daemon requires an option (i.e. daemon=sys)");
72
73 int (*daemon_)(int,int);
74 if (!strcmp(opt,"sys"))
75 daemon_ = sys_daemon;
76 else if (!strcmp(opt, "ours"))
77 daemon_ = our_daemon;
78 else
79 die(2, "daemon: unknown option: %s", opt);
80
81 int r = daemon_(1,0);
82 if (r) die_errno(2, "%s daemon() failed = %d", opt, r);
83 }
84
85 static void show_pid(const char *opt) {
86 msg("pid: %d (%s)", getpid(), opt ? opt : "");
87 }
88
89 #include <stdint.h> /* uint64_t */
90 typedef void *(*move_to_user_10_5_f)
91 (uid_t target_user, const char *session_type);
92 typedef void *(*move_to_user_10_6_f)
93 (uid_t target_user, const char *session_type, uint64_t flags);
94 static void move_to_user(const char *opt) {
95 if (!(opt && *opt))
96 die(3, "move-to-user: requires an option (i.e. move-to-user=10.6)");
97
dc3687f @ChrisJohnsen standardize static strings
authored
98 static const char move_to_user_fn[] = "_vprocmgr_move_subset_to_user";
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
99 void *f = dlsym(RTLD_NEXT, move_to_user_fn);
100 if (!f) die(3, "unable to find %s: %s", move_to_user_fn, dlerror());
101
dc3687f @ChrisJohnsen standardize static strings
authored
102 static const char session_type[] = "Background";
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
103 void *r;
104 if (!strcmp(opt, "10.5"))
105 r = ((move_to_user_10_5_f)f)(getuid(), session_type);
106 else if (!strcmp(opt, "10.6"))
107 r = ((move_to_user_10_6_f)f)(getuid(), session_type, 0);
108 else
109 die(3, "move-to-user: unkown option: %s", opt);
110 if (r) die(3, "%s failed", move_to_user_fn);
111 }
112
113 typedef void *(*detach_from_console_f)(unsigned int flags);
564759b @ChrisJohnsen test: internal functions should be static
authored
114 static void detach_from_console(const char *opt UNUSED) {
dc3687f @ChrisJohnsen standardize static strings
authored
115 static const char detach_fn[] = "_vprocmgr_detach_from_console";
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
116 void *f = dlsym(RTLD_NEXT, detach_fn);
117 if (!f) die(4, "unable to find %s: %s", detach_fn, dlerror());
118 if (((detach_from_console_f)f)(0) != NULL)
119 die(4, "%s failed", detach_fn);
120 }
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
121
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
122 static int out_fd;
564759b @ChrisJohnsen test: internal functions should be static
authored
123 static void do_system(const char *opt) {
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
124 if (dup2(out_fd,1) < 0)
125 die_errno(5, "dup2(out_fd,1) failed");
126 if (dup2(out_fd,2) < 0)
127 die_errno(5, "dup2(out_fd,2) failed");
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
128
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
129 int r = system(opt);
130 if (r < 0)
131 die(5, "system() failed");
132
133 if (WIFEXITED(r))
134 msg("system(%s) process exited %d", opt, WEXITSTATUS(r));
135 else if (WIFSIGNALED(r))
136 msg("system(%s) process terminated by signal %d", opt, WTERMSIG(r));
137 else if (WIFSTOPPED(r))
138 msg("system(%s) process stopped with signal %d", opt, WSTOPSIG(r));
139 }
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
140
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
141 static int parse_int(const char *str, char **rest_,
142 char expected_stop) {
143 char *rest;
144 errno = 0;
145 int v = strtoul(str, &rest, 0);
146 if (errno)
147 die_errno(1, "error parsing \"%s\" as int", str);
148 if (rest && *rest != expected_stop)
149 die(1, "unexpected char '%c' (%d) while parsing int from \"%s\"",
150 *rest, *rest, str);
151 if (rest_) *rest_ = rest;
152 return v;
153 }
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
154
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
155 typedef int (*session_create_f)(int, int);
156 static void session_create(const char *opt) {
dc3687f @ChrisJohnsen standardize static strings
authored
157 static const char fw[] =
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
158 "/System/Library/Frameworks/Security.framework/Versions/Current/Security";
dc3687f @ChrisJohnsen standardize static strings
authored
159 static const char fn[] = "SessionCreate";
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
160 if (!(opt && *opt && strchr(opt, ',')))
161 die(6, "session-createn needs two args (e.g. 0,0)");
162 char *rest;
163 int a = parse_int(opt, &rest, ',');
164 int b = parse_int(rest+1, NULL, '\0');
165 void *lib = dlopen(fw, RTLD_LAZY|RTLD_LOCAL);
166 if (!lib)
167 die(6, "unable to load Security framework (%s): %s", fw, dlerror());
168 void *f = dlsym(lib, fn);
169 msg("calling %s(0x%x,0x%x)", fn, a, b);
170 int r = ((session_create_f)f)(a, b);
171 if (r) die(6, "%s failed: %d", fn, r);
172 if (dlclose(lib))
173 die(6, "unable to close Security framework: %s", dlerror());
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
174 /*
97ba160 @ChrisJohnsen SessionCreate from Security framework
authored
175 OSStatus result = SessionCreate(0, 0x30);
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
176 * 0x1,0x11,0x21,0x1001,0x1011,0x1021,0x1031 -> -60501
97ba160 @ChrisJohnsen SessionCreate from Security framework
authored
177 * (invalid attribute bits)
178 */
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
179 }
180
564759b @ChrisJohnsen test: internal functions should be static
authored
181 static void do_sleep(const char *opt) {
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
182 int s = parse_int(opt, NULL, '\0');
183 sleep(s);
184 }
97ba160 @ChrisJohnsen SessionCreate from Security framework
authored
185
564759b @ChrisJohnsen test: internal functions should be static
authored
186 static void show_msg(const char *opt) {
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
187 msg("%s", opt);
188 }
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
189
07b849f @ChrisJohnsen test: const-ize (struct cmd).func
authored
190 typedef void cmd_func(const char *opt);
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
191 struct cmd {
07b849f @ChrisJohnsen test: const-ize (struct cmd).func
authored
192 cmd_func * const func;
80c176c @ChrisJohnsen test: clean up struct cmd strings
authored
193 const char * const str;
194 const char * const desc;
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
195 };
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
196
07b849f @ChrisJohnsen test: const-ize (struct cmd).func
authored
197 static cmd_func
198 show_msg, show_pid, do_sleep, do_daemon, detach_from_console,
199 do_system, move_to_user, session_create, help;
200
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
201 static struct cmd all_cmds[] = {
8f7b0af @ChrisJohnsen add usage/help
authored
202 { show_msg, "msg", "=<text> print text to stderr" },
203 { show_pid, "pid", "=<text> print pid and text to stderr" },
204 { do_sleep, "sleep", "=<secs> sleep(secs)" },
205 { do_daemon, "daemon", "=sys system daemon(3)\n"
206 "=ours non-Apple version" },
207 { detach_from_console,
208 "detach", " _vprocmgr_detach_from_console(0)", },
209 { do_system, "system", "=<cmd> system(cmd)"},
210 { move_to_user, "move-to-user",
211 "=10.5 _vprocmgr_move_subset_to_user(uid,\"Background\")\n"
212 "=10.6 call with extra arg == 0" },
213 { session_create, "session-create",
214 "=<a>,<b> SessionCreate(a,b) (numeric a and b)" },
215 { help, "help", " show this help text" },
216 { NULL, "", "" }
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
217 };
218
d847e84 @ChrisJohnsen Crank up and fix warnings
authored
219 static void help(const char *opt UNUSED) {
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
220 struct cmd *c = all_cmds;
8f7b0af @ChrisJohnsen add usage/help
authored
221 int w, cmd_width = 0;
222 for (c = all_cmds; c->func; c++) {
223 w = strlen(c->str);
224 cmd_width = w > cmd_width ? w : cmd_width;
225 }
226 for (c = all_cmds; c->func; c++) {
80c176c @ChrisJohnsen test: clean up struct cmd strings
authored
227 const char *nl, *s = c->desc;
8f7b0af @ChrisJohnsen add usage/help
authored
228 while ((nl = strchr(s, '\n'))) {
229 msg(" %*s%.*s", cmd_width, c->str, nl-s, s);
230 s = nl+1;
231 }
232 msg(" %*s%s", cmd_width, c->str, s);
233 }
234 }
235
236 static void run_cmd(const char *cmd) {
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
237 const char *opt = strchr(cmd, '=');
d847e84 @ChrisJohnsen Crank up and fix warnings
authored
238 size_t cmd_len = opt ? (size_t)(opt-cmd) : strlen(cmd);
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
239 if (!cmd_len)
240 die(1, "no command in argument: %s", cmd);
241 if (opt)
242 opt++;
8f7b0af @ChrisJohnsen add usage/help
authored
243 struct cmd *c;
244 for (c = all_cmds; c->func; c++)
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
245 if (!strncmp(cmd, c->str, cmd_len) &&
246 c->str[cmd_len] == '\0')
247 return c->func(opt);
8f7b0af @ChrisJohnsen add usage/help
authored
248 die(1, "unknown command: %s (try help)", cmd);
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
249 }
250
251 int main(int argc, const char * const argv[]) {
252 if ((out_fd = dup(2)) < 0)
253 die_errno(1, "dup msgout");
254 FILE *out = fdopen(out_fd, "w");
255 if (!out) die_errno(1, "fdopen for msgout");
256 msgout = out;
257
8f7b0af @ChrisJohnsen add usage/help
authored
258 if (argc < 2)
259 die(1, "usage: %s <command>...\n\n"
260 " Execute the given commands.\n"
261 " Run \"%s help\" for command list.\n",
262 argv[0], argv[0]);
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
263
8f7b0af @ChrisJohnsen add usage/help
authored
264 const char * const * cmds = argv+1;
6d017a0 @ChrisJohnsen test: runtime configurable actions
authored
265 while(*cmds)
266 run_cmd(*cmds++);
31864a1 @ChrisJohnsen Notes and code to test daemon(3) and pbpaste
authored
267
268 return 0;
269 }
Something went wrong with that request. Please try again.