Skip to content

HTTPS clone URL

Subversion checkout URL

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