Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 274 lines (202 sloc) 10.645 kB
2697c6a @ChrisJohnsen README.md: add Quick Summary
authored
1 # Quick Summary
2
3 * Using the Mac OS X programs *pbpaste* and *pbcopy* under *tmux*
4 does not work.
5 Other services and unpatched builds of *screen* are also affected.
6
7 * Certain undocumented, private API functions can fix the problem.
8
9 * Because the functions are private, undocumented, and unstable (one
10 acquired an extra argument in 10.6), I think using a small wrapper
11 program might be better than patching *tmux*.
12
13 Thus, my wrapper-based workaround:
14
15 1. Compile *reattach-to-user-namespace* from this repository.
16 Make it available in your PATH (or use the absolute pathname in
17 the next step).
18
149acd9 @trevor minor doc styling
trevor authored
19 make reattach-to-user-namespace &&
20 cp reattach-to-user-namespace ~/bin
2697c6a @ChrisJohnsen README.md: add Quick Summary
authored
21
22 1. Configure *tmux* to use this wrapper program to start the shell
23 for each new window.
24
ce5ed9b @trevor minor doc styling
trevor authored
25 In `.tmux.conf`:
2697c6a @ChrisJohnsen README.md: add Quick Summary
authored
26
ce5ed9b @trevor minor doc styling
trevor authored
27 set-option -g default-command "reattach-to-user-namespace -l zsh"
2697c6a @ChrisJohnsen README.md: add Quick Summary
authored
28
29 1. Restart your *tmux* server (or start a new one, or just
30 reconfigure your existing one).
c3aea83 @ChrisJohnsen README.md: be explicit about kill-server
authored
31
32 To kill your existing *tmux* server (and everything running
33 “inside” it!):
34
ce5ed9b @trevor minor doc styling
trevor authored
35 tmux kill-server
2697c6a @ChrisJohnsen README.md: add Quick Summary
authored
36
37 1. Enjoy being able to use *pbpaste*, *pbcopy*, etc. in new shell
38 windows.
39
351e829 @ChrisJohnsen README.md
authored
40 # Purpose of These Programs
41
42 The programs in this repository were created to diagnose and enable
43 reliable access to the Mac OS X pasteboard for programs run under
44 [*tmux*][1] and unmodified versions of [*screen*][2].
45
46 [1]: http://tmux.sourceforge.net/
47 [2]: http://www.gnu.org/software/screen/
48
49 # Mac OS X Pasteboard Access Under *tmux* And *screen*
50
51 ## The Problem
52
53 The most commonly reported broken behavior is that the [*pbcopy* and
54 *pbpaste*][3] command-line programs that come with Mac OS X fail to
55 function properly when run under *tmux* and (sometimes) under
56 “unpatched” *screen*.
57
58 Apple has patched their builds of *screen* (included with Mac OS X)
59 to fix the problem; the [*screen* “port”][4] in the [MacPorts][5]
60 system has [adopted][6] Apple’s *screen* patches.
61
62 Their *screen* patch allows (for example) the user to create
63 a *screen* session under a normal GUI login session and access the
64 pasteboard (inside the *screen* session) anytime that user is logged
65 into the GUI. Programs that are run in a session of “unpatched” *screen* will
66 only encounter the problem when the *screen* session outlives its
67 parent Mac OS X login session (e.g. a normal GUI login or an SSH
68 login).
69
70 Third-party programs (run under *tmux* or unpatched *screen*) are
71 also affected (e.g. non-GUI builds of [Vim][7] [7.3][8] can access
72 the pasteboard when compiled with the `+clipboard` feature).
73
74 [3]: http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/pbcopy.1.html
75 [4]: https://trac.macports.org/browser/trunk/dports/sysutils/screen/Portfile
76 [5]: http://www.macports.org/
77 [6]: https://trac.macports.org/browser/trunk/dports/sysutils/screen/files/patch-screen.c
78 [7]: http://www.vim.org/
79 [8]: http://vimhelp.appspot.com/version7.txt.html#added-7.3
80
81 ## Why Pasteboard Breaks
82
83 ### Access to the Mac OS X Pasteboard Service
84
85 The pasteboard service in Mac OS X is registered in a "bootstrap
86 namespace" (see Apple’s [TN2083][9]). The namespaces exist in
87 a hierarchy: “higher” namespaces include access to “lower”
88 namespaces. A process in a lower namespace can not access higher
89 namespaces. So, all process can access the lowest, “root” bootstrap
90 namespace, but only processes in a higher namespace can access that
91 namespace. Processes created as a part of a Mac OS X login session
92 are automatically included in the user’s “per-user” bootstrap
93 namespace. The pasteboard service is only available to processes in
94 the per-user bootstrap namespace.
95
96 [9]: http://developer.apple.com/library/mac/#technotes/tn2083/_index.html
97
98 ### Interaction with *tmux*
99
100 *tmux* uses the *daemon(3)* library function when starting its
101 server process. In Mac OS X 10.5, Apple changed *daemon(3)* to move
102 the resulting process from its original bootstrap namespace to the
103 root bootstrap namespace. This means that the *tmux* server, and its
104 children, will automatically and uncontrollably lose access to what
105 would have been their original bootstrap namespace (i.e. the one
106 that has access to the pasteboard service).
107
108 ### Interaction with Unpatched *screen*
109
110 The situation with *screen* is a bit different since it does not use
111 *daemon(3)*. Unpatched *screen*, and its children, only lose access
112 to the per-user bootstrap namespace when its parent login session
113 exits.
114
115 ## Solution Space
116
117 Apple (and MacPorts) have already handled *screen*. Apple prevents
118 *screen* from losing access to the per-user bootstrap namespace by
119 “migrating to [the] background session” ([in 10.5][10] using
120 *_vprocmgr_move_subset_to_user*) or “detach[ing] from console”
121 ([in 10.6][11] using *_vprocmgr_detach_from_console*). For the
122 purposes of *screen*, both of these let the *screen* process access
123 the per-user bootstrap namespace even after the processes initial
124 Mac OS X login session has ended.
125
126 [10]: http://www.opensource.apple.com/source/screen/screen-12/patches/screen.c.diff
127 [11]: http://www.opensource.apple.com/source/screen/screen-19/screen/screen.c
128
129 ### Patch *tmux*?
130
131 Ideally, we could port Apple’s patch to *tmux*. Practically, there
132 are problems with a direct port.
133
134 The undocumented, private function used in Apple’s 10.6 patch,
135 *_vprocmgr_detach_from_console*, is not effective if called before
136 *daemon(3)* (since it forcibly moves the process to the root
137 bootstrap namespace); if called after *daemon(3)*, it just returns
138 an error.
139
140 The undocumented, private function used in Apple’s 10.5 patch,
141 *_vprocmgr_move_subset_to_user*, is also available in 10.6 (though
142 an extra parameter has been added to it in 10.6). Again, there is no
143 point in calling it before *daemon(3)*, but it is effective if
144 called after *daemon(3)*.
145
146 The functionality of *_vprocmgr_move_subset_to_user* seems to be
147 a sort of superset of that of *_vprocmgr_detach_from_console* in
148 that both move to the `"Background"` session, but the former does
149 some extra work that can attach to a user namespace even if the
150 process has been previously moved out of it.
151
152 So, another approach that works is to call either the private
153 function after invoking a custom *daemon* that does not forcibly
154 move its resulting process to the root bootstrap namespace (*tmux*
155 even already has one).
156
157 The fact that the signature of *_vprocmgr_move_subset_to_user*
158 changed between 10.5 and 10.6 is a strong indication that Apple sees
159 these functions as part of a private API that is liable to change or
160 become available in any (major?) release. It seems inappropriate to
161 ask upstream *tmux* to incorporate calls to functions such as these.
162 It might be appropriate for MacPorts to apply a patch to its port
163 though.
164
165 ### Use a “Reattaching” Wrapper Program
166
167 While it would be nice to have the *tmux* server itself reattached
168 to the per-user bootstrap namespace, it is probably enough to
169 selectively reattach just some of its children. A small wrapper
170 could do the work of reattaching to the appropriate namespace and
171 then execing some other program that will (eventually) need
172 access to the per-user namespace.
173
174 Such a wrapper could be used to run *pbcopy*, *pbpaste*, *vim*, et
175 cetera. This would require the user to remember to use the wrapper
176 (or write scripts/shell-functions/aliases to always do it; or notice
177 it fail then re-run it under the wrapper).
178
179 A more automated solution that probably covers most of the problem
180 scenarios for most users would be to set *tmux*’s `default-command`
181 option so that new windows start shells via the wrapper by default.
182 The major area this would not cover would be commands given directly
183 to `new-session` and `new-window` (there are some other commands
184 that start new children, but those are the major ones).
185
186 # Some New Programs For Your Consideration
187
188 ## The Wrapper Program
189
190 The *reattach-to-user-namespace* program implements the “wrapper”
191 solution described above.
192
193 reattach-to-user-namespace program args...
194
195 Its `-l` option causes it to rewrite the execed program’s `argv[0]` to
196 start with a dash (`-`). Most shells take this as a signal that they should
197 start as “login” shells.
198
199 exec reattach-to-user-namespace -l "$SHELL"
200
201 In `.tmux.conf`:
202
203 set-option -g default-command "reattach-to-user-namespace -l zsh"
204
205 ## The Diagnostic Program
206
207 The *test* program was created to easily examine the effects and
208 interactions of some of the “functions of interest” (primarily
209 *daemon(3)*, and the private “vproc” functions).
210
211 Its arguments are interpreted as instructions to call various
212 functions and/or display some result.
213
214 Examples:
215
216 Emulate calling *pbpaste* under plain *tmux*:
217
218 ./test daemon=sys system=pbpaste
219
220 Emulate a *tmux* patch that would automatically reattach to the user
221 namespace (also equivalent to using the wrapper program under an
222 unpatched *tmux*):
223
224 ./test daemon=sys move-to-user=10.6 system=pbpaste
225
226 Emulate a *tmux* patch that uses compat/daemon.c and “detaches from
227 the console”:
228
229 ./test daemon=ours deatch system=pbpaste
230
231 Demonstrate revocation of access to the per-user bootstrap namespace
232 when the Mac OS X login session ends:
233
234 # while logged into the GUI
235
236 # login session ends before pbpaste happens: failure
237 cp /dev/null /tmp/f &&
238 ssh localhost `pwd`/test \
239 daemon=ours \
240 msg=sleeping... sleep=1 msg='done\ sleeping' \
241 system=pbpaste 2\> /tmp/f &&
242 { cat /tmp/f; tail -f /tmp/f; }
243
244 # pbpaste happens before login session ends: success
245 cp /dev/null /tmp/f &&
246 ssh localhost `pwd`/test \
247 daemon=ours \
248 msg=sleeping... msg='done\ sleeping' \
249 system=pbpaste 2\> /tmp/f \; sleep 1 &&
250 { cat /tmp/f; tail -f /tmp/f; }
251
252 Test workarounds to prevent the above end-of-login revocation:
253
254 # while logged into the GUI
255
256 # emulate tmux patched to move to the user namespace
257 # or, equivalently, unpatched *tmux* and wrapper
258 cp /dev/null /tmp/f &&
259 ssh localhost `pwd`/test \
260 daemon=sys \
261 move-to-user=10.6 \
262 msg=sleeping... sleep=1 msg='done\ sleeping' \
263 system=pbpaste 2\> /tmp/f &&
264 { cat /tmp/f; tail -f /tmp/f; }
265
266 # emuate tmux patched to use compat/daemon + detach
267 cp /dev/null /tmp/f &&
268 ssh localhost `pwd`/test \
269 daemon=ours \
270 detach \
271 msg=sleeping... sleep=1 msg='done\ sleeping' \
272 system=pbpaste 2\> /tmp/f &&
273 { cat /tmp/f; tail -f /tmp/f; }
Something went wrong with that request. Please try again.