mirror of
https://github.com/kaboomserver/buildpack.git
synced 2025-04-10 03:04:24 -04:00
Add comments, restructure
This commit is contained in:
parent
25d16d97fd
commit
e7389ee35b
22 changed files with 7730 additions and 26 deletions
8
app.json
8
app.json
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "Kaboom",
|
||||
"env": {
|
||||
"REMOTE_KEY": {
|
||||
"description": "Private key for reverse SSH",
|
||||
"PROXY_KEY": {
|
||||
"description": "Private key for proxy server",
|
||||
"required": true
|
||||
},
|
||||
"SYNC_KEY": {
|
||||
"description": "Private key for data sync",
|
||||
"SCHEMATIC_KEY": {
|
||||
"description": "Private key for schematic repository",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
|
|
10
bin/compile
10
bin/compile
|
@ -2,5 +2,15 @@
|
|||
BIN_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
BUILD_DIR=$1
|
||||
|
||||
# Build dtach for running server in background
|
||||
|
||||
cd src/detach*
|
||||
./configure
|
||||
make
|
||||
mkdir $BUILD_DIR/detach/bin/
|
||||
mv detach $BUILD_DIR/detach/bin/
|
||||
|
||||
# Set up scripts
|
||||
|
||||
mv script $BUILD_DIR/script
|
||||
mv $BIN_DIR/start $BUILD_DIR/script/
|
||||
|
|
25
bin/start
25
bin/start
|
@ -1,22 +1,25 @@
|
|||
#!/bin/sh
|
||||
PATH="$HOME/autossh/bin/:$HOME/java/bin/:$HOME/tmux/bin/:$HOME/ttyd/bin/:$PATH"
|
||||
PATH="$HOME/detach/bin/:$HOME/java/bin/:$PATH"
|
||||
|
||||
echo "$REMOTE_KEY" > .ssh/remote
|
||||
echo "$SYNC_KEY" > .ssh/id_rsa
|
||||
chmod 600 .ssh/remote
|
||||
# Set up SSH for proxy server and schematics repository
|
||||
# Load keys from environmental variables
|
||||
|
||||
echo "$PROXY_KEY" > .ssh/proxy
|
||||
chmod 600 .ssh/proxy
|
||||
|
||||
echo "$SCHEMATIC_KEY" > .ssh/id_rsa
|
||||
ssh-keyscan github.com >> .ssh/known_hosts
|
||||
|
||||
chmod -R 500 plugins/bStats/ plugins/PluginMetrics/
|
||||
|
||||
git clone git@github.com:kaboomserver/schematics.git plugins/FastAsyncWorldEdit/schematics/
|
||||
# Run scripts for starting the Minecraft server, reverse proxy and schematic
|
||||
# checker in the background
|
||||
|
||||
while true; do
|
||||
tmux new -d -s server 'sh -c script/server' >/dev/null
|
||||
tmux new -d -s remote 'sh -x script/remote' >/dev/null
|
||||
#tmux new -d -s webconsole 'sh -x script/webconsole' >/dev/null
|
||||
tmux new -d -s schematics 'sh -x script/schematics' >/dev/null
|
||||
dtach -n server 'sh -c script/server'
|
||||
dtach -n proxy 'sh -x script/proxy'
|
||||
dtach -n schematics 'sh -x script/schematics'
|
||||
sleep 5
|
||||
done &
|
||||
|
||||
# Keep this startup script alive to prevent Heroku from stopping the server
|
||||
|
||||
sleep infinity
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
#!/bin/sh
|
||||
|
||||
# The following script is a failsafe for killing the Minecraft server if it happens
|
||||
# to be stuck
|
||||
|
||||
while true; do
|
||||
sleep 420
|
||||
logfile=$HOME/logs/latest.log
|
||||
|
||||
if [ -f "$logfile" ]; then
|
||||
|
||||
# If localhost:25565 doesn't respond to ping, or if the log file is older than
|
||||
# 3 minutes, kill the server
|
||||
|
||||
if [ "$(env printf '\xFE' | nc -w 5 localhost 25565 | wc -m)" -eq 0 ] ||
|
||||
[ "$(( $(date +%s) - $(date -r $logfile +%s) ))" -gt 180 ]; then
|
||||
if [ "$(tail -20 $logfile | grep -c 'ERROR]: Requested chunk')" -eq 1 ]; then
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Since we can't open TCP ports on Heroku, we need to forward traffic to a proxy server that
|
||||
# permits incoming connections
|
||||
# Resources for setting up the proxy server: https://github.com/kaboomserver/proxy
|
||||
|
||||
ssh -i ~/.ssh/remote \
|
||||
-o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes -o StreamLocalBindUnlink=yes \
|
||||
-c aes128-ctr \
|
|
@ -1,4 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Schematics are saved in a separate git repository, which is cloned whenever Heroku starts
|
||||
# from a fresh state. Only non-existing files are added to the repository.
|
||||
|
||||
git clone git@github.com:kaboomserver/schematics.git $HOME/plugins/FastAsyncWorldEdit/schematics/
|
||||
|
||||
while true; do
|
||||
cd $HOME/plugins/FastAsyncWorldEdit/schematics/
|
||||
if [ "$(git add $(git ls-files -o) -v)" ]; then
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#!/bin/sh
|
||||
|
||||
# The alive checker and Minecraft server is started at the same time. For performance reasons, the
|
||||
# OpenJ9 JVM is used instead of Java's default Hotspot JVM.
|
||||
|
||||
chmod -R 500 $HOME/plugins/bStats/ $HOME/plugins/PluginMetrics/
|
||||
dtach -n alivecheck 'sh -x $HOME/script/alivecheck'
|
||||
|
||||
while true; do
|
||||
stty intr undef
|
||||
unset TMUX
|
||||
tmux new -d -s alivecheck 'sh -x script/alivecheck'
|
||||
java -Xmx384M -Xtune:virtualized -Xaggressive -Xcompressedrefs -Xdump:none -Xgc:concurrentScavenge -Xgc:dnssExpectedTimeRatioMaximum=3 -Xgc:scvNoAdaptiveTenure -Xdisableexplicitgc -Xshareclasses -Xshareclasses:noPersistentDiskSpaceCheck -XX:-HeapDumpOnOutOfMemoryError -XX:OnOutofMemoryError="pkill -9 java" -XX:MaxDirectMemorySize=64M -XX:+UseContainerSupport -XX:+ClassRelationshipVerifier -Dpaper.playerconnection.keepalive=360 -DIReallyKnowWhatIAmDoingISwear -jar server.jar --world-dir=worlds
|
||||
tmux kill-session -t alivecheck
|
||||
sleep 1
|
||||
done
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Shutdown script for Paper/Spigot
|
||||
|
||||
pkill -9 java
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/sh
|
||||
cd $HOME/plugins/FastAsyncWorldEdit/schematics/
|
||||
|
||||
while true; do
|
||||
python3 -m http.server $PORT --bind 0.0.0.0
|
||||
sleep 1
|
||||
done
|
11
src/dtach-0.9/.gitignore
vendored
Executable file
11
src/dtach-0.9/.gitignore
vendored
Executable file
|
@ -0,0 +1,11 @@
|
|||
# Files generated by configure
|
||||
|
||||
/Makefile
|
||||
/config.h
|
||||
/config.log
|
||||
/config.status
|
||||
/configure.lineno
|
||||
|
||||
# Files generated by make
|
||||
*.o
|
||||
/dtach
|
340
src/dtach-0.9/COPYING
Executable file
340
src/dtach-0.9/COPYING
Executable file
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
36
src/dtach-0.9/Makefile.in
Executable file
36
src/dtach-0.9/Makefile.in
Executable file
|
@ -0,0 +1,36 @@
|
|||
srcdir = @srcdir@
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ -I.
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
VERSION = @PACKAGE_VERSION@
|
||||
VPATH = $(srcdir)
|
||||
|
||||
OBJ = attach.o master.o main.o
|
||||
SRC = $(srcdir)/attach.c $(srcdir)/master.c $(srcdir)/main.c
|
||||
|
||||
TARFILES = $(srcdir)/README $(srcdir)/COPYING $(srcdir)/Makefile.in \
|
||||
$(srcdir)/config.h.in $(SRC) \
|
||||
$(srcdir)/dtach.h $(srcdir)/dtach.spec $(srcdir)/configure \
|
||||
$(srcdir)/configure.ac $(srcdir)/dtach.1
|
||||
|
||||
dtach: $(OBJ)
|
||||
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f dtach $(OBJ) dtach-$(VERSION).tar.gz
|
||||
|
||||
distclean: clean
|
||||
rm -f config.h Makefile config.log config.status config.cache
|
||||
|
||||
tar:
|
||||
mkdir dtach-$(VERSION)
|
||||
cp $(TARFILES) dtach-$(VERSION)
|
||||
tar -cf dtach-$(VERSION).tar dtach-$(VERSION)/
|
||||
gzip -9f dtach-$(VERSION).tar
|
||||
rm -rf dtach-$(VERSION)
|
||||
|
||||
attach.o: @srcdir@/attach.c @srcdir@/dtach.h config.h
|
||||
master.o: @srcdir@/master.c @srcdir@/dtach.h config.h
|
||||
main.o: @srcdir@/main.c @srcdir@/dtach.h config.h
|
||||
|
210
src/dtach-0.9/README
Executable file
210
src/dtach-0.9/README
Executable file
|
@ -0,0 +1,210 @@
|
|||
1. INTRODUCTION
|
||||
|
||||
dtach is a program written in C that emulates the detach feature of
|
||||
screen, which allows a program to be executed in an environment that is
|
||||
protected from the controlling terminal. For instance, the program under
|
||||
the control of dtach would not be affected by the terminal being
|
||||
disconnected for some reason.
|
||||
|
||||
dtach was written because screen did not adequately meet my needs; I did
|
||||
not need screen's extra features, such as support for multiple
|
||||
terminals or terminal emulation support. screen was also too big,
|
||||
bulky, and had source code that was difficult to understand.
|
||||
|
||||
screen also interfered with my use of full-screen applications such as
|
||||
emacs and ircII, due to its excessive interpretation of the stream between
|
||||
the program and the attached terminals. dtach does not have a terminal
|
||||
emulation layer, and passes the raw output stream of the program to the
|
||||
attached terminals. The only input processing that dtach does perform is
|
||||
scanning for the detach character (which signals dtach to detach from
|
||||
the program) and processing the suspend key (which tells dtach to
|
||||
temporarily suspend itself without affecting the running program), and both
|
||||
of these can both be disabled if desired.
|
||||
|
||||
Contrary to screen, dtach has minimal features, and is extremely tiny.
|
||||
This allows dtach to be more easily audited for bugs and security
|
||||
holes, and makes it accessible in environments where space is limited,
|
||||
such as on rescue disks.
|
||||
|
||||
dtach has only been tested on the Linux/x86 platform, however it should
|
||||
be easily portable to other variants of Unix. It currently assumes that
|
||||
the host system uses POSIX termios, and has a working forkpty function
|
||||
available.
|
||||
|
||||
dtach may need access to various devices in the filesystem depending on what
|
||||
forkpty does. For example, dtach on Linux usually needs access to /dev/ptmx
|
||||
and /dev/pts.
|
||||
|
||||
2. QUICK START
|
||||
|
||||
Compiling dtach should be simple, as it uses autoconf:
|
||||
|
||||
$ ./configure
|
||||
$ make
|
||||
|
||||
If all goes well, a dtach binary should be built for your system. You can
|
||||
then copy it to the appropriate place on your system.
|
||||
|
||||
dtach uses Unix-domain sockets to represent sessions; these are network
|
||||
sockets that are stored in the filesystem. You specify the name of the
|
||||
socket that dtach should use when creating or attaching to dtach sessions.
|
||||
|
||||
For example, let's create a new session that is running ircII. We will use
|
||||
/tmp/foozle as the session's socket:
|
||||
|
||||
$ dtach -A /tmp/foozle irc RuneB irc.freenode.net
|
||||
|
||||
Here, -A tells dtach to either create a new session or attach to the
|
||||
existing session. If the session at /tmp/foozle does not exist yet, the
|
||||
program will be executed. If it does exist, then dtach will attach to
|
||||
the existing session.
|
||||
|
||||
dtach has another attach mode, which is specified by using -a. The -a
|
||||
mode attaches to an already existing session, but will not create a new
|
||||
session. Each attaching process can have a separate detach character,
|
||||
suspend behavior, and redraw method, which are explained in the
|
||||
following sections.
|
||||
|
||||
dtach is able to attach to the same session multiple times, though you
|
||||
will likely encounter problems if your terminals have different window
|
||||
sizes. Pressing ^L (Ctrl-L) will reset the window size of the program to
|
||||
match the current terminal.
|
||||
|
||||
dtach also has a mode that copies the contents of standard input to a session.
|
||||
For example:
|
||||
|
||||
$ echo -ne 'cd /var/log\nls -l\n' | dtach -p /tmp/foozle
|
||||
|
||||
The contents are sent verbatim including any embedded control characters (e.g.
|
||||
the newline characters in the above example), and dtach will not scan the
|
||||
input for a detach character.
|
||||
|
||||
3. DETACHING FROM THE SESSION
|
||||
|
||||
By default, dtach scans the keyboard input looking for the detach character.
|
||||
When the detach character is pressed, dtach will detach from the current
|
||||
session and exit, leaving the program running in the background. You can then
|
||||
re-attach to the program by running dtach again with -A or -a.
|
||||
|
||||
The default detach character is ^\ (Ctrl-\). This can be changed by supplying
|
||||
the -e option to dtach when attaching. For example:
|
||||
|
||||
$ dtach -a /tmp/foozle -e '^A'
|
||||
|
||||
That command would attach to the existing session at /tmp/foozle and use
|
||||
^A (Ctrl-A) as the detach character, instead of the default ^\.
|
||||
|
||||
You can disable processing of the detach character by supplying the -E
|
||||
option to dtach when attaching.
|
||||
|
||||
4. SUSPENDING DTACH
|
||||
|
||||
By default, dtach also processes the suspend key (^Z or Ctrl-Z) itself,
|
||||
instead of passing it to the program. Thus, pressing suspend only suspends
|
||||
the attaching process, instead of the running program. This can be very
|
||||
useful for applications such as ircII, where you may not necessarily want
|
||||
the program to be suspended.
|
||||
|
||||
Processing of the suspend key can be disabled by supplying the -z option
|
||||
to dtach when attaching.
|
||||
|
||||
5. REDRAW METHOD
|
||||
|
||||
When attaching, dtach can use one of three methods to redraw the screen
|
||||
(none, ctrl_l, or winch). By default, dtach uses the ctrl_l method,
|
||||
which simply sends a ^L (Ctrl-L) character to the program if the
|
||||
terminal is in character-at-a-time and no-echo mode. The winch method
|
||||
forces a WINCH signal to be sent to the program, and the none method
|
||||
disables redrawing completely.
|
||||
|
||||
For example, this command tells dtach to attach to a session at
|
||||
/tmp/foozle and use the winch redraw method:
|
||||
|
||||
$ dtach -a /tmp/foozle -r winch
|
||||
|
||||
When creating a new session (with the -c or -A modes), the specified
|
||||
method is used as the default redraw method for the session.
|
||||
|
||||
6. CHANGES
|
||||
|
||||
The changes in version 0.9 are:
|
||||
- Added AIX support.
|
||||
- Added dtach -N, a mode similar to dtach -n, except dtach will stay in the
|
||||
foreground instead of daemonizing.
|
||||
- Added dtach -p, which copies the contents of standard input to a session.
|
||||
- dtach will no longer send 255 bytes of garbage to the program when read()
|
||||
returns an error.
|
||||
- The executable bit is now set on the socket if clients are attached, and
|
||||
cleared when all clients have detached.
|
||||
- The initial state of signals such as SIGPIPE are now preserved when
|
||||
executing the program, instead of having the program start with some signals
|
||||
ignored.
|
||||
- A buffer overflow no longer occurs when a long socket path name is used, and
|
||||
dtach will now try to use chdir to get around the length limitation if
|
||||
necessary.
|
||||
|
||||
The changes in version 0.8 are:
|
||||
- When using dtach -A or dtach -c, the master will now wait until the client
|
||||
attaches before trying to read from the program being executed. This avoids
|
||||
a race condition when the program prints something and exits before the
|
||||
client can attach itself.
|
||||
- Instead of exiting quietly, dtach will now report any errors that occur
|
||||
while trying to execute the program.
|
||||
- dtach -n can now be used without a terminal.
|
||||
- dtach -A will now try to detect and remove stale sockets.
|
||||
- Removed a Linux-specific escape sequence from the code that restores the
|
||||
original terminal settings.
|
||||
- Changed dtach.1 to use \- for the dashes in command line options, and
|
||||
fix an ambiguous backslash.
|
||||
- Use non-blocking mode in the master process, and avoid data loss by ensuring
|
||||
that at least one attaching client succesfully completes a write.
|
||||
- Fix -e ^<char> to work with lowercase characters.
|
||||
|
||||
The changes in version 0.7 are:
|
||||
- The redraw method can now be explicitly specified on the command line
|
||||
(either no redraw at all, the old ^L character method, and the new WINCH
|
||||
signal method), since many programs only handle one or the other properly.
|
||||
- Changed the default redraw method back to the old ^L character method.
|
||||
- Changed the attach code to check the return value of select more carefully.
|
||||
- Changed the SIGWINCH handler to reinstall itself, to handle systems that
|
||||
always reset the handler.
|
||||
- Added more proper process group handling.
|
||||
|
||||
The changes in version 0.6 are:
|
||||
- Redraws are now handled by sending the child process a WINCH signal instead
|
||||
of by sending a ^L character. This should help prevent line-oriented
|
||||
programs (such as bash) from clearing the screen excessively.
|
||||
- Flow control is now disabled when setting raw mode on the terminal.
|
||||
- Switched to using select instead of poll.
|
||||
- Changed some exits to exit succesfully instead of non-sucessfully.
|
||||
- Updated my email address.
|
||||
- Updated to Autoconf 2.59, renaming some files in the process.
|
||||
|
||||
The changes in version 0.5 are:
|
||||
- Fix fd leakage.
|
||||
- Prevent atexit from being called twice on dtach -A.
|
||||
|
||||
The changes in version 0.4 are:
|
||||
- Slightly improved README and dtach.1
|
||||
- Portability updates thanks to sourceforge's compile farm. dtach should now
|
||||
work on: FreeBSD, Debian/alpha, Debian/sparc, Debian/PPC, and Solaris.
|
||||
|
||||
The changes in version 0.3 are:
|
||||
- Fixed a typo in dtach.1
|
||||
- Changed the attach code so that it tells the master when a suspend
|
||||
occurs.
|
||||
- Decreased the client <-> master packet size.
|
||||
- Changed the master to send a stream of text to attaching clients
|
||||
instead of sending a huge packet all the time.
|
||||
- Use getrlimit and dynamically allocate the data structures, if
|
||||
possible.
|
||||
- Added some more autoconf checks.
|
||||
- Initial sourceforge release.
|
||||
|
||||
7. AUTHOR
|
||||
|
||||
dtach is (C)Copyright 2004-2016 Ned T. Crigler, and is under the GNU General
|
||||
Public License.
|
||||
|
||||
Comments and suggestions about dtach are welcome, and can be sent to
|
||||
the author at: <crigler@users.sourceforge.net>.
|
361
src/dtach-0.9/attach.c
Executable file
361
src/dtach-0.9/attach.c
Executable file
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
dtach - A simple program that emulates the detach feature of screen.
|
||||
Copyright (C) 2004-2016 Ned T. Crigler
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "dtach.h"
|
||||
|
||||
#ifndef VDISABLE
|
||||
#ifdef _POSIX_VDISABLE
|
||||
#define VDISABLE _POSIX_VDISABLE
|
||||
#else
|
||||
#define VDISABLE 0377
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The current terminal settings. After coming back from a suspend, we
|
||||
** restore this.
|
||||
*/
|
||||
static struct termios cur_term;
|
||||
/* 1 if the window size changed */
|
||||
static int win_changed;
|
||||
|
||||
/* Restores the original terminal settings. */
|
||||
static void
|
||||
restore_term(void)
|
||||
{
|
||||
tcsetattr(0, TCSADRAIN, &orig_term);
|
||||
|
||||
/* Make cursor visible. Assumes VT100. */
|
||||
printf("\033[?25h");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* Connects to a unix domain socket */
|
||||
static int
|
||||
connect_socket(char *name)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_un sockun;
|
||||
|
||||
if (strlen(name) > sizeof(sockun.sun_path) - 1)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (s < 0)
|
||||
return -1;
|
||||
sockun.sun_family = AF_UNIX;
|
||||
strcpy(sockun.sun_path, name);
|
||||
if (connect(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0)
|
||||
{
|
||||
close(s);
|
||||
|
||||
/* ECONNREFUSED is also returned for regular files, so make
|
||||
** sure we are trying to connect to a socket. */
|
||||
if (errno == ECONNREFUSED)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(name, &st) < 0)
|
||||
return -1;
|
||||
else if (!S_ISSOCK(st.st_mode) || S_ISREG(st.st_mode))
|
||||
errno = ENOTSOCK;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Signal */
|
||||
static RETSIGTYPE
|
||||
die(int sig)
|
||||
{
|
||||
/* Print a nice pretty message for some things. */
|
||||
if (sig == SIGHUP || sig == SIGINT)
|
||||
printf(EOS "\r\n[detached]\r\n");
|
||||
else
|
||||
printf(EOS "\r\n[got signal %d - dying]\r\n", sig);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Window size change. */
|
||||
static RETSIGTYPE
|
||||
win_change()
|
||||
{
|
||||
signal(SIGWINCH, win_change);
|
||||
win_changed = 1;
|
||||
}
|
||||
|
||||
/* Handles input from the keyboard. */
|
||||
static void
|
||||
process_kbd(int s, struct packet *pkt)
|
||||
{
|
||||
/* Suspend? */
|
||||
if (!no_suspend && (pkt->u.buf[0] == cur_term.c_cc[VSUSP]))
|
||||
{
|
||||
/* Tell the master that we are suspending. */
|
||||
pkt->type = MSG_DETACH;
|
||||
write(s, pkt, sizeof(struct packet));
|
||||
|
||||
/* And suspend... */
|
||||
tcsetattr(0, TCSADRAIN, &orig_term);
|
||||
printf(EOS "\r\n");
|
||||
kill(getpid(), SIGTSTP);
|
||||
tcsetattr(0, TCSADRAIN, &cur_term);
|
||||
|
||||
/* Tell the master that we are returning. */
|
||||
pkt->type = MSG_ATTACH;
|
||||
write(s, pkt, sizeof(struct packet));
|
||||
|
||||
/* We would like a redraw, too. */
|
||||
pkt->type = MSG_REDRAW;
|
||||
pkt->len = redraw_method;
|
||||
ioctl(0, TIOCGWINSZ, &pkt->u.ws);
|
||||
write(s, pkt, sizeof(struct packet));
|
||||
return;
|
||||
}
|
||||
/* Detach char? */
|
||||
else if (pkt->u.buf[0] == detach_char)
|
||||
{
|
||||
printf(EOS "\r\n[detached]\r\n");
|
||||
exit(0);
|
||||
}
|
||||
/* Just in case something pukes out. */
|
||||
else if (pkt->u.buf[0] == '\f')
|
||||
win_changed = 1;
|
||||
|
||||
/* Push it out */
|
||||
write(s, pkt, sizeof(struct packet));
|
||||
}
|
||||
|
||||
int
|
||||
attach_main(int noerror)
|
||||
{
|
||||
struct packet pkt;
|
||||
unsigned char buf[BUFSIZE];
|
||||
fd_set readfds;
|
||||
int s;
|
||||
|
||||
/* Attempt to open the socket. Don't display an error if noerror is
|
||||
** set. */
|
||||
s = connect_socket(sockname);
|
||||
if (s < 0 && errno == ENAMETOOLONG)
|
||||
{
|
||||
char *slash = strrchr(sockname, '/');
|
||||
|
||||
/* Try to shorten the socket's path name by using chdir. */
|
||||
if (slash)
|
||||
{
|
||||
int dirfd = open(".", O_RDONLY);
|
||||
|
||||
if (dirfd >= 0)
|
||||
{
|
||||
*slash = '\0';
|
||||
if (chdir(sockname) >= 0)
|
||||
{
|
||||
s = connect_socket(slash + 1);
|
||||
fchdir(dirfd);
|
||||
}
|
||||
*slash = '/';
|
||||
close(dirfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s < 0)
|
||||
{
|
||||
if (!noerror)
|
||||
printf("%s: %s: %s\n", progname, sockname,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The current terminal settings are equal to the original terminal
|
||||
** settings at this point. */
|
||||
cur_term = orig_term;
|
||||
|
||||
/* Set a trap to restore the terminal when we die. */
|
||||
atexit(restore_term);
|
||||
|
||||
/* Set some signals. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGXFSZ, SIG_IGN);
|
||||
signal(SIGHUP, die);
|
||||
signal(SIGTERM, die);
|
||||
signal(SIGINT, die);
|
||||
signal(SIGQUIT, die);
|
||||
signal(SIGWINCH, win_change);
|
||||
|
||||
/* Set raw mode. */
|
||||
cur_term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
|
||||
cur_term.c_iflag &= ~(IXON|IXOFF);
|
||||
cur_term.c_oflag &= ~(OPOST);
|
||||
cur_term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||
cur_term.c_cflag &= ~(CSIZE|PARENB);
|
||||
cur_term.c_cflag |= CS8;
|
||||
cur_term.c_cc[VLNEXT] = VDISABLE;
|
||||
cur_term.c_cc[VMIN] = 1;
|
||||
cur_term.c_cc[VTIME] = 0;
|
||||
tcsetattr(0, TCSADRAIN, &cur_term);
|
||||
|
||||
/* Clear the screen. This assumes VT100. */
|
||||
write(1, "\33[H\33[J", 6);
|
||||
|
||||
/* Tell the master that we want to attach. */
|
||||
memset(&pkt, 0, sizeof(struct packet));
|
||||
pkt.type = MSG_ATTACH;
|
||||
write(s, &pkt, sizeof(struct packet));
|
||||
|
||||
/* We would like a redraw, too. */
|
||||
pkt.type = MSG_REDRAW;
|
||||
pkt.len = redraw_method;
|
||||
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
|
||||
write(s, &pkt, sizeof(struct packet));
|
||||
|
||||
/* Wait for things to happen */
|
||||
while (1)
|
||||
{
|
||||
int n;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(0, &readfds);
|
||||
FD_SET(s, &readfds);
|
||||
n = select(s + 1, &readfds, NULL, NULL, NULL);
|
||||
if (n < 0 && errno != EINTR && errno != EAGAIN)
|
||||
{
|
||||
printf(EOS "\r\n[select failed]\r\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Pty activity */
|
||||
if (n > 0 && FD_ISSET(s, &readfds))
|
||||
{
|
||||
ssize_t len = read(s, buf, sizeof(buf));
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
printf(EOS "\r\n[EOF - dtach terminating]"
|
||||
"\r\n");
|
||||
exit(0);
|
||||
}
|
||||
else if (len < 0)
|
||||
{
|
||||
printf(EOS "\r\n[read returned an error]\r\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Send the data to the terminal. */
|
||||
write(1, buf, len);
|
||||
n--;
|
||||
}
|
||||
/* stdin activity */
|
||||
if (n > 0 && FD_ISSET(0, &readfds))
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
pkt.type = MSG_PUSH;
|
||||
memset(pkt.u.buf, 0, sizeof(pkt.u.buf));
|
||||
len = read(0, pkt.u.buf, sizeof(pkt.u.buf));
|
||||
|
||||
if (len <= 0)
|
||||
exit(1);
|
||||
|
||||
pkt.len = len;
|
||||
process_kbd(s, &pkt);
|
||||
n--;
|
||||
}
|
||||
|
||||
/* Window size changed? */
|
||||
if (win_changed)
|
||||
{
|
||||
win_changed = 0;
|
||||
|
||||
pkt.type = MSG_WINCH;
|
||||
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
|
||||
write(s, &pkt, sizeof(pkt));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
push_main()
|
||||
{
|
||||
struct packet pkt;
|
||||
int s;
|
||||
|
||||
/* Attempt to open the socket. */
|
||||
s = connect_socket(sockname);
|
||||
if (s < 0 && errno == ENAMETOOLONG)
|
||||
{
|
||||
char *slash = strrchr(sockname, '/');
|
||||
|
||||
/* Try to shorten the socket's path name by using chdir. */
|
||||
if (slash)
|
||||
{
|
||||
int dirfd = open(".", O_RDONLY);
|
||||
|
||||
if (dirfd >= 0)
|
||||
{
|
||||
*slash = '\0';
|
||||
if (chdir(sockname) >= 0)
|
||||
{
|
||||
s = connect_socket(slash + 1);
|
||||
fchdir(dirfd);
|
||||
}
|
||||
*slash = '/';
|
||||
close(dirfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s < 0)
|
||||
{
|
||||
printf("%s: %s: %s\n", progname, sockname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set some signals. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Push the contents of standard input to the socket. */
|
||||
pkt.type = MSG_PUSH;
|
||||
for (;;)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
memset(pkt.u.buf, 0, sizeof(pkt.u.buf));
|
||||
len = read(0, pkt.u.buf, sizeof(pkt.u.buf));
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
else if (len < 0)
|
||||
{
|
||||
printf("%s: %s: %s\n", progname, sockname,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
pkt.len = len;
|
||||
if (write(s, &pkt, sizeof(struct packet)) < 0)
|
||||
{
|
||||
printf("%s: %s: %s\n", progname, sockname,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
136
src/dtach-0.9/config.h.in
Executable file
136
src/dtach-0.9/config.h.in
Executable file
|
@ -0,0 +1,136 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the `atexit' function. */
|
||||
#undef HAVE_ATEXIT
|
||||
|
||||
/* Define to 1 if you have the `dup2' function. */
|
||||
#undef HAVE_DUP2
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `forkpty' function. */
|
||||
#undef HAVE_FORKPTY
|
||||
|
||||
/* Define to 1 if you have the `grantpt' function. */
|
||||
#undef HAVE_GRANTPT
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the `util' library (-lutil). */
|
||||
#undef HAVE_LIBUTIL
|
||||
|
||||
/* Define to 1 if you have the <libutil.h> header file. */
|
||||
#undef HAVE_LIBUTIL_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the `openpty' function. */
|
||||
#undef HAVE_OPENPTY
|
||||
|
||||
/* Define to 1 if you have the `ptsname' function. */
|
||||
#undef HAVE_PTSNAME
|
||||
|
||||
/* Define to 1 if you have the <pty.h> header file. */
|
||||
#undef HAVE_PTY_H
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <stropts.h> header file. */
|
||||
#undef HAVE_STROPTS_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#undef HAVE_SYS_RESOURCE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#undef HAVE_TERMIOS_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `unlockpt' function. */
|
||||
#undef HAVE_UNLOCKPT
|
||||
|
||||
/* Define to 1 if you have the <util.h> header file. */
|
||||
#undef HAVE_UTIL_H
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
4997
src/dtach-0.9/configure
vendored
Executable file
4997
src/dtach-0.9/configure
vendored
Executable file
File diff suppressed because it is too large
Load diff
37
src/dtach-0.9/configure.ac
Executable file
37
src/dtach-0.9/configure.ac
Executable file
|
@ -0,0 +1,37 @@
|
|||
# Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(dtach, 0.9, crigler@users.sourceforge.net)
|
||||
AC_PREREQ(2.60)
|
||||
AC_CONFIG_SRCDIR(main.c)
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
CFLAGS="$CFLAGS -W -Wall";
|
||||
fi
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(util, openpty)
|
||||
AC_CHECK_LIB(socket, socket)
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS(fcntl.h sys/select.h sys/socket.h sys/time.h)
|
||||
AC_CHECK_HEADERS(sys/ioctl.h sys/resource.h pty.h termios.h util.h)
|
||||
AC_CHECK_HEADERS(libutil.h stropts.h)
|
||||
AC_HEADER_TIME
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SSIZE_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS(atexit dup2 memset)
|
||||
AC_CHECK_FUNCS(select socket strerror)
|
||||
AC_CHECK_FUNCS(openpty forkpty ptsname grantpt unlockpt)
|
||||
|
||||
AC_CONFIG_FILES(Makefile)
|
||||
AC_OUTPUT
|
216
src/dtach-0.9/dtach.1
Executable file
216
src/dtach-0.9/dtach.1
Executable file
|
@ -0,0 +1,216 @@
|
|||
.TH dtach 1 "May 2016" "dtach 0.9"
|
||||
.SH NAME
|
||||
dtach \- simple program that emulates the detach feature of screen.
|
||||
.SH SYNOPSIS
|
||||
.B dtach \-a
|
||||
.I <socket> <options>
|
||||
.br
|
||||
.B dtach \-A
|
||||
.I <socket> <options> <command...>
|
||||
.br
|
||||
.B dtach \-c
|
||||
.I <socket> <options> <command...>
|
||||
.br
|
||||
.B dtach \-n
|
||||
.I <socket> <options> <command...>
|
||||
.br
|
||||
.B dtach \-N
|
||||
.I <socket> <options> <command...>
|
||||
.br
|
||||
.B dtach \-p
|
||||
.I <socket>
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dtach
|
||||
is a program that emulates the detach feature of screen. It is designed
|
||||
to be transparent and un-intrusive; it avoids interpreting the input and output
|
||||
between attached terminals and the program under its control. Consequently, it
|
||||
works best with full-screen applications such as emacs.
|
||||
|
||||
.B dtach
|
||||
is intended for users who want the detach feature of screen without the other
|
||||
overhead of screen. It is tiny, does not use many libraries, and stays
|
||||
out of the way as much as possible.
|
||||
|
||||
.SS SESSIONS
|
||||
A session in
|
||||
.B dtach
|
||||
is a single instance in which a program is running under the control of
|
||||
.BR dtach .
|
||||
The program is disassociated from the original terminal, and is thus protected
|
||||
from your original terminal being disconnected for some reason.
|
||||
.PP
|
||||
|
||||
Other instances of
|
||||
.B dtach
|
||||
can attach themselves to a particular session. Input and output is copied
|
||||
between the program running in the
|
||||
.B dtach
|
||||
session, and the attached terminals.
|
||||
.PP
|
||||
|
||||
.B dtach
|
||||
avoids interpreting the communication stream between the program and the
|
||||
attached terminals; it instead relies on the ability of the attached terminals
|
||||
to manage the screen.
|
||||
.PP
|
||||
|
||||
Sessions are represented by Unix-domain sockets in the filesystem. No other
|
||||
permission checking other than the filesystem access checks is performed.
|
||||
.B dtach
|
||||
creates a master process that monitors the session socket, the program, and any
|
||||
attached terminals.
|
||||
|
||||
.PP
|
||||
.SS MODES
|
||||
.B dtach
|
||||
has several modes of operation. It can create a new session in which a
|
||||
program is executed, or it can attach to an existing session. The first
|
||||
argument specifies which mode
|
||||
.B dtach
|
||||
should operate in.
|
||||
.TP
|
||||
.B \-a
|
||||
Attach to an existing session.
|
||||
.B dtach
|
||||
attaches itself to the session specified by
|
||||
.IR <socket> .
|
||||
After the attach is completed, the window size of the current terminal is sent
|
||||
to the master process, and a redraw is also requested.
|
||||
.TP
|
||||
.B \-A
|
||||
Attach to an existing session, or create a new one.
|
||||
.B dtach
|
||||
first tries to attach to the session specified by
|
||||
.I <socket>
|
||||
if possible. If the attempt to open the socket fails,
|
||||
.B dtach
|
||||
tries to create a new session before attaching to it.
|
||||
.TP
|
||||
.B \-c
|
||||
Creates a new session. A new session is created in which the specified program
|
||||
is executed.
|
||||
.B dtach
|
||||
then tries to attach itself to the newly created session.
|
||||
.TP
|
||||
.B \-n
|
||||
Creates a new session, without attaching to it. A new session is created in
|
||||
which the specified program is executed.
|
||||
.B dtach
|
||||
does not try to attach to the newly created session, however, and exits
|
||||
instead.
|
||||
.TP
|
||||
.B \-N
|
||||
Creates a new session, without attaching to it or daemonizing. A new session is
|
||||
created in which the specified program is executed.
|
||||
.B dtach
|
||||
does not try to attach to the newly created session, however, and will stay
|
||||
in the foreground until the program exits.
|
||||
.TP
|
||||
.B \-p
|
||||
Copies the contents of standard input to a session.
|
||||
.B dtach
|
||||
connects to the session specified by
|
||||
.IR <socket> ,
|
||||
copies the contents of standard input to the session, and then exits. dtach
|
||||
will not scan the input for a detach character.
|
||||
|
||||
.PP
|
||||
.SS OPTIONS
|
||||
.B dtach
|
||||
has a few options that allow you to modify its behavior. Each attaching
|
||||
process can have separate settings for these options, which allows for
|
||||
some flexibility.
|
||||
|
||||
.TP
|
||||
.BI "\-e " "<char>"
|
||||
Sets the detach character to
|
||||
.IR <char> .
|
||||
When the detach character is pressed,
|
||||
.B dtach
|
||||
detaches itself from the current session and exits. The process running in
|
||||
the session is unaffected by the detach. By default, the detach character is
|
||||
set to ^\e (Ctrl-\e).
|
||||
|
||||
.TP
|
||||
.B \-E
|
||||
Disables the detach character.
|
||||
.B dtach
|
||||
does not try to scan input from the terminal for a detach character. The only
|
||||
way to detach from the session is then by sending the attaching process an
|
||||
appropriate signal.
|
||||
|
||||
.TP
|
||||
.BI "\-r " "<method>"
|
||||
Sets the redraw method to
|
||||
.IR <method> .
|
||||
The valid methods are
|
||||
.IR none ,
|
||||
.IR ctrl_l ,
|
||||
or
|
||||
.IR winch .
|
||||
|
||||
.I none
|
||||
disables redrawing completely,
|
||||
.I ctrl_l
|
||||
sends a Ctrl L character to the program if the terminal is in
|
||||
character-at-a-time and no-echo mode, and
|
||||
.I winch
|
||||
forces a WINCH signal to be sent to the program.
|
||||
|
||||
When creating a new session, the specified method is used as the default
|
||||
redraw method for the session. If not specified, the
|
||||
.I ctrl_l
|
||||
method is used.
|
||||
|
||||
.TP
|
||||
.B \-z
|
||||
Disables processing of the suspend key.
|
||||
Normally,
|
||||
.B dtach
|
||||
will suspend itself when the suspend key is pressed. With this option, the
|
||||
suspend character is sent to the session instead of being handled by
|
||||
.BR dtach .
|
||||
|
||||
.PP
|
||||
.SH EXAMPLES
|
||||
|
||||
The following example creates a new session that has the detach character
|
||||
and suspend processing disabled. A socket is created in the /tmp directory
|
||||
for the session.
|
||||
|
||||
.nf
|
||||
$ dtach \-c /tmp/foozle \-Ez bash
|
||||
.fi
|
||||
|
||||
The following example attaches to the /tmp/foozle session if it exists, and if
|
||||
not, creates a new session using /tmp/foozle as the socket for the session.
|
||||
Processing of the suspend character is also disabled for the attach instance.
|
||||
|
||||
.nf
|
||||
$ dtach \-A /tmp/foozle \-z bash
|
||||
.fi
|
||||
|
||||
The following example attaches to the /tmp/foozle session, using the
|
||||
.I winch
|
||||
redraw method to redraw the screen.
|
||||
|
||||
.nf
|
||||
$ dtach \-a /tmp/foozle \-r winch
|
||||
.fi
|
||||
|
||||
The following example creates a new session and sets the default redraw method
|
||||
for the session to the
|
||||
.I winch
|
||||
redraw method.
|
||||
|
||||
.nf
|
||||
$ dtach \-c /tmp/foozle \-r winch bash
|
||||
.fi
|
||||
|
||||
.PP
|
||||
.SH AUTHOR
|
||||
Ned T. Crigler <crigler@users.sourceforge.net>.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR screen "(1)"
|
137
src/dtach-0.9/dtach.h
Executable file
137
src/dtach-0.9/dtach.h
Executable file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
dtach - A simple program that emulates the detach feature of screen.
|
||||
Copyright (C) 2001, 2004-2016 Ned T. Crigler
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef dtach_h
|
||||
#define dtach_h
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#else
|
||||
#if HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIL_H
|
||||
#include <util.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUTIL_H
|
||||
#include <libutil.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STROPTS_H
|
||||
#include <stropts.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include <termios.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
#ifndef S_ISSOCK
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
#endif
|
||||
|
||||
extern char *progname, *sockname;
|
||||
extern int detach_char, no_suspend, redraw_method;
|
||||
extern struct termios orig_term;
|
||||
extern int dont_have_tty;
|
||||
|
||||
enum
|
||||
{
|
||||
MSG_PUSH = 0,
|
||||
MSG_ATTACH = 1,
|
||||
MSG_DETACH = 2,
|
||||
MSG_WINCH = 3,
|
||||
MSG_REDRAW = 4,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
REDRAW_UNSPEC = 0,
|
||||
REDRAW_NONE = 1,
|
||||
REDRAW_CTRL_L = 2,
|
||||
REDRAW_WINCH = 3,
|
||||
};
|
||||
|
||||
/* The client to master protocol. */
|
||||
struct packet
|
||||
{
|
||||
unsigned char type;
|
||||
unsigned char len;
|
||||
union
|
||||
{
|
||||
unsigned char buf[sizeof(struct winsize)];
|
||||
struct winsize ws;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
** The master sends a simple stream of text to the attaching clients, without
|
||||
** any protocol. This might change back to the packet based protocol in the
|
||||
** future. In the meantime, however, we minimize the amount of data sent back
|
||||
** and forth between the client and the master. BUFSIZE is the size of the
|
||||
** buffer used for the text stream.
|
||||
*/
|
||||
#define BUFSIZE 4096
|
||||
|
||||
/* This hopefully moves to the bottom of the screen */
|
||||
#define EOS "\033[999H"
|
||||
|
||||
int attach_main(int noerror);
|
||||
int master_main(char **argv, int waitattach, int dontfork);
|
||||
int push_main(void);
|
||||
|
||||
#ifdef sun
|
||||
#define BROKEN_MASTER
|
||||
#endif
|
||||
#endif
|
108
src/dtach-0.9/dtach.spec
Executable file
108
src/dtach-0.9/dtach.spec
Executable file
|
@ -0,0 +1,108 @@
|
|||
Summary: A simple program that emulates the detach feature of screen.
|
||||
Name: dtach
|
||||
Version: 0.9
|
||||
Release: 1
|
||||
License: GPL
|
||||
URL: http://dtach.sourceforge.net
|
||||
Group: Applications/System
|
||||
Source: http://prdownloads.sourceforge.net/dtach/dtach-%{version}.tar.gz
|
||||
Buildroot: %{_tmppath}/%{name}-%{version}-root
|
||||
|
||||
%description
|
||||
|
||||
dtach is a program that emulates the detach feature of screen, with
|
||||
less overhead. It is designed to be transparent and un-intrusive; it
|
||||
avoids interpreting the input and output between attached terminals
|
||||
and the program under its control. Consequently, it works best with
|
||||
full-screen applications such as emacs.
|
||||
|
||||
%prep
|
||||
%setup
|
||||
|
||||
%build
|
||||
%configure
|
||||
make
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT/*
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_bindir}
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/share/doc/dtach-%{version}
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1
|
||||
install -m 755 dtach $RPM_BUILD_ROOT/%{_bindir}/dtach
|
||||
install -m 644 dtach.1 $RPM_BUILD_ROOT/%{_mandir}/man1/dtach.1
|
||||
|
||||
%clean
|
||||
make clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
rm -rf $RPM_BUILD_DIR/%{name}-%{version}
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%doc COPYING README
|
||||
%{_bindir}/dtach
|
||||
%{_mandir}/*/*
|
||||
|
||||
%changelog
|
||||
* Sun May 8 2016 Ned T. Crigler <crigler@users.sourceforge.net> 0.9
|
||||
- New release
|
||||
|
||||
* Wed Jan 30 2008 Ned T. Crigler <crigler@users.sourceforge.net> 0.8
|
||||
- New release
|
||||
|
||||
* Sat Jul 3 2004 Ned T. Crigler <crigler@users.sourceforge.net> 0.7
|
||||
- New release
|
||||
|
||||
* Fri Nov 30 2001 Ned T. Crigler <crigler@hell-city.org> 0.5
|
||||
- Fix fd leakage.
|
||||
- Prevent atexit from being called twice on dtach -A.
|
||||
|
||||
* Fri Nov 30 2001 Trond Eivind Glomsrød <teg@redhat.com> 0.4-1
|
||||
- s/Copyright/License/
|
||||
- Minor description change
|
||||
- fix use of %%doc
|
||||
- Add full location of source tarball
|
||||
|
||||
* Sat Nov 03 2001 Ned T. Crigler <crigler@hell-city.org> 0.4
|
||||
- Portability updates thanks to sourceforge's compile farm. dtach should now
|
||||
work on: FreeBSD, Debian/alpha, Debian/PPC, Debian/sparc, Debian/PPC, and
|
||||
Solaris.
|
||||
|
||||
* Thu Sep 27 2001 Ned T. Crigler <crigler@hell-city.org>
|
||||
- Modified spec file URL: to point to http://dtach.sourceforge.net
|
||||
|
||||
* Wed Sep 26 2001 Ned T. Crigler <crigler@hell-city.org> 0.3
|
||||
- Use getrlimit and dynamically allocate the data structures, if possible.
|
||||
- Added some more autoconf checks.
|
||||
- Initial sourceforge release.
|
||||
|
||||
* Thu Sep 20 2001 Ned T. Crigler <crigler@hell-city.org>
|
||||
- Changed the master to send a stream of text to attaching clients instead
|
||||
of sending a huge packet all the time.
|
||||
- Decreased the client <-> master packet size.
|
||||
- Changed the attach code so that it tells the master when a suspend occurs.
|
||||
|
||||
* Tue Sep 18 2001 Ned T. Crigler <crigler@hell-city.org>
|
||||
- Fixed a typo in dtach.1
|
||||
|
||||
* Tue Sep 18 2001 Ned T. Crigler <crigler@hell-city.org> 0.2
|
||||
- Removed silly thinko regarding terminal settings in attach, we
|
||||
always set the terminal to raw mode now.
|
||||
- Moved redraw code into the master, which tries to be smarter when
|
||||
using ^L.
|
||||
- Moved the code that obtains the current terminal settings into main,
|
||||
preventing a race condition between the master and attach processes.
|
||||
- Rewrote argument parsing code.
|
||||
- Changed name to dtach.
|
||||
- Added a man page.
|
||||
|
||||
* Mon Sep 17 2001 Ned T. Crigler <crigler@hell-city.org>
|
||||
- Changed fchmod to chmod in create_socket.
|
||||
|
||||
* Mon Sep 17 2001 Isaiah Weiner <iweiner@redhat.com>
|
||||
- Modified spec file to correct detach binary permissions
|
||||
- Modified spec file to correct detach documentation path
|
||||
- Modified spec file URL: to point to http://people.redhat.com/iweiner/detach
|
||||
- Modified spec file %clean to remove buildroot and builddir.
|
||||
|
||||
* Mon Sep 17 2001 Ned T. Crigler <crigler@hell-city.org> 0.1
|
||||
- Initial rpm release.
|
284
src/dtach-0.9/main.c
Executable file
284
src/dtach-0.9/main.c
Executable file
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
dtach - A simple program that emulates the detach feature of screen.
|
||||
Copyright (C) 2004-2016 Ned T. Crigler
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "dtach.h"
|
||||
|
||||
/*
|
||||
** dtach is a quick hack, since I wanted the detach feature of screen without
|
||||
** all the other crud. It'll work best with full-screen applications, as it
|
||||
** does not keep track of the screen or anything like that.
|
||||
*/
|
||||
|
||||
/* Make sure the binary has a copyright. */
|
||||
const char copyright[] = "dtach - version " PACKAGE_VERSION "(C)Copyright 2004-2016 Ned T. Crigler";
|
||||
|
||||
/* argv[0] from the program */
|
||||
char *progname;
|
||||
/* The name of the passed in socket. */
|
||||
char *sockname;
|
||||
/* The character used for detaching. Defaults to '^\' */
|
||||
int detach_char = '\\' - 64;
|
||||
/* 1 if we should not interpret the suspend character. */
|
||||
int no_suspend;
|
||||
/* The default redraw method. Initially set to unspecified. */
|
||||
int redraw_method = REDRAW_UNSPEC;
|
||||
|
||||
/*
|
||||
** The original terminal settings. Shared between the master and attach
|
||||
** processes. The master uses it to initialize the pty, and the attacher uses
|
||||
** it to restore the original settings.
|
||||
*/
|
||||
struct termios orig_term;
|
||||
int dont_have_tty;
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
printf(
|
||||
"dtach - version %s, compiled on %s at %s.\n"
|
||||
"Usage: dtach -a <socket> <options>\n"
|
||||
" dtach -A <socket> <options> <command...>\n"
|
||||
" dtach -c <socket> <options> <command...>\n"
|
||||
" dtach -n <socket> <options> <command...>\n"
|
||||
" dtach -N <socket> <options> <command...>\n"
|
||||
" dtach -p <socket>\n"
|
||||
"Modes:\n"
|
||||
" -a\t\tAttach to the specified socket.\n"
|
||||
" -A\t\tAttach to the specified socket, or create it if it\n"
|
||||
"\t\t does not exist, running the specified command.\n"
|
||||
" -c\t\tCreate a new socket and run the specified command.\n"
|
||||
" -n\t\tCreate a new socket and run the specified command "
|
||||
"detached.\n"
|
||||
" -N\t\tCreate a new socket and run the specified command "
|
||||
"detached,\n"
|
||||
"\t\t and have dtach run in the foreground.\n"
|
||||
" -p\t\tCopy the contents of standard input to the specified\n"
|
||||
"\t\t socket.\n"
|
||||
"Options:\n"
|
||||
" -e <char>\tSet the detach character to <char>, defaults "
|
||||
"to ^\\.\n"
|
||||
" -E\t\tDisable the detach character.\n"
|
||||
" -r <method>\tSet the redraw method to <method>. The "
|
||||
"valid methods are:\n"
|
||||
"\t\t none: Don't redraw at all.\n"
|
||||
"\t\t ctrl_l: Send a Ctrl L character to the program.\n"
|
||||
"\t\t winch: Send a WINCH signal to the program.\n"
|
||||
" -z\t\tDisable processing of the suspend key.\n"
|
||||
"\nReport any bugs to <" PACKAGE_BUGREPORT ">.\n",
|
||||
PACKAGE_VERSION, __DATE__, __TIME__);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
/* Save the program name */
|
||||
progname = argv[0];
|
||||
++argv; --argc;
|
||||
|
||||
/* Parse the arguments */
|
||||
if (argc >= 1 && **argv == '-')
|
||||
{
|
||||
if (strncmp(*argv, "--help", strlen(*argv)) == 0)
|
||||
usage();
|
||||
else if (strncmp(*argv, "--version", strlen(*argv)) == 0)
|
||||
{
|
||||
printf("dtach - version %s, compiled on %s at %s.\n",
|
||||
PACKAGE_VERSION, __DATE__, __TIME__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mode = argv[0][1];
|
||||
if (mode == '?')
|
||||
usage();
|
||||
else if (mode != 'a' && mode != 'c' && mode != 'n' &&
|
||||
mode != 'A' && mode != 'N' && mode != 'p')
|
||||
{
|
||||
printf("%s: Invalid mode '-%c'\n", progname, mode);
|
||||
printf("Try '%s --help' for more information.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!mode)
|
||||
{
|
||||
printf("%s: No mode was specified.\n", progname);
|
||||
printf("Try '%s --help' for more information.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
++argv; --argc;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
printf("%s: No socket was specified.\n", progname);
|
||||
printf("Try '%s --help' for more information.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
sockname = *argv;
|
||||
++argv; --argc;
|
||||
|
||||
if (mode == 'p')
|
||||
{
|
||||
if (argc > 0)
|
||||
{
|
||||
printf("%s: Invalid number of arguments.\n",
|
||||
progname);
|
||||
printf("Try '%s --help' for more information.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
return push_main();
|
||||
}
|
||||
|
||||
while (argc >= 1 && **argv == '-')
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = argv[0] + 1; *p; ++p)
|
||||
{
|
||||
if (*p == 'E')
|
||||
detach_char = -1;
|
||||
else if (*p == 'z')
|
||||
no_suspend = 1;
|
||||
else if (*p == 'e')
|
||||
{
|
||||
++argv; --argc;
|
||||
if (argc < 1)
|
||||
{
|
||||
printf("%s: No escape character "
|
||||
"specified.\n", progname);
|
||||
printf("Try '%s --help' for more "
|
||||
"information.\n", progname);
|
||||
return 1;
|
||||
}
|
||||
if (argv[0][0] == '^' && argv[0][1])
|
||||
{
|
||||
if (argv[0][1] == '?')
|
||||
detach_char = '\177';
|
||||
else
|
||||
detach_char = argv[0][1] & 037;
|
||||
}
|
||||
else
|
||||
detach_char = argv[0][0];
|
||||
break;
|
||||
}
|
||||
else if (*p == 'r')
|
||||
{
|
||||
++argv; --argc;
|
||||
if (argc < 1)
|
||||
{
|
||||
printf("%s: No redraw method "
|
||||
"specified.\n", progname);
|
||||
printf("Try '%s --help' for more "
|
||||
"information.\n", progname);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[0], "none") == 0)
|
||||
redraw_method = REDRAW_NONE;
|
||||
else if (strcmp(argv[0], "ctrl_l") == 0)
|
||||
redraw_method = REDRAW_CTRL_L;
|
||||
else if (strcmp(argv[0], "winch") == 0)
|
||||
redraw_method = REDRAW_WINCH;
|
||||
else
|
||||
{
|
||||
printf("%s: Invalid redraw method "
|
||||
"specified.\n", progname);
|
||||
printf("Try '%s --help' for more "
|
||||
"information.\n", progname);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: Invalid option '-%c'\n",
|
||||
progname, *p);
|
||||
printf("Try '%s --help' for more information.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
++argv; --argc;
|
||||
}
|
||||
|
||||
if (mode != 'a' && argc < 1)
|
||||
{
|
||||
printf("%s: No command was specified.\n", progname);
|
||||
printf("Try '%s --help' for more information.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Save the original terminal settings. */
|
||||
if (tcgetattr(0, &orig_term) < 0)
|
||||
{
|
||||
memset(&orig_term, 0, sizeof(struct termios));
|
||||
dont_have_tty = 1;
|
||||
}
|
||||
|
||||
if (dont_have_tty && mode != 'n' && mode != 'N')
|
||||
{
|
||||
printf("%s: Attaching to a session requires a terminal.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mode == 'a')
|
||||
{
|
||||
if (argc > 0)
|
||||
{
|
||||
printf("%s: Invalid number of arguments.\n",
|
||||
progname);
|
||||
printf("Try '%s --help' for more information.\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
return attach_main(0);
|
||||
}
|
||||
else if (mode == 'n')
|
||||
return master_main(argv, 0, 0);
|
||||
else if (mode == 'N')
|
||||
return master_main(argv, 0, 1);
|
||||
else if (mode == 'c')
|
||||
{
|
||||
if (master_main(argv, 1, 0) != 0)
|
||||
return 1;
|
||||
return attach_main(0);
|
||||
}
|
||||
else if (mode == 'A')
|
||||
{
|
||||
/* Try to attach first. If that doesn't work, create a new
|
||||
** socket. */
|
||||
if (attach_main(1) != 0)
|
||||
{
|
||||
if (errno == ECONNREFUSED || errno == ENOENT)
|
||||
{
|
||||
if (errno == ECONNREFUSED)
|
||||
unlink(sockname);
|
||||
if (master_main(argv, 1, 0) != 0)
|
||||
return 1;
|
||||
}
|
||||
return attach_main(0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
800
src/dtach-0.9/master.c
Executable file
800
src/dtach-0.9/master.c
Executable file
|
@ -0,0 +1,800 @@
|
|||
/*
|
||||
dtach - A simple program that emulates the detach feature of screen.
|
||||
Copyright (C) 2004-2016 Ned T. Crigler
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "dtach.h"
|
||||
|
||||
/* The pty struct - The pty information is stored here. */
|
||||
struct pty
|
||||
{
|
||||
/* File descriptor of the pty */
|
||||
int fd;
|
||||
#ifdef BROKEN_MASTER
|
||||
/* File descriptor of the slave side of the pty. For broken systems. */
|
||||
int slave;
|
||||
#endif
|
||||
/* Process id of the child. */
|
||||
pid_t pid;
|
||||
/* The terminal parameters of the pty. Old and new for comparision
|
||||
** purposes. */
|
||||
struct termios term;
|
||||
/* The current window size of the pty. */
|
||||
struct winsize ws;
|
||||
};
|
||||
|
||||
/* A connected client */
|
||||
struct client
|
||||
{
|
||||
/* The next client in the linked list. */
|
||||
struct client *next;
|
||||
/* The previous client in the linked list. */
|
||||
struct client **pprev;
|
||||
/* File descriptor of the client. */
|
||||
int fd;
|
||||
/* Whether or not the client is attached. */
|
||||
int attached;
|
||||
};
|
||||
|
||||
/* The list of connected clients. */
|
||||
static struct client *clients;
|
||||
/* The pseudo-terminal created for the child process. */
|
||||
static struct pty the_pty;
|
||||
|
||||
#ifndef HAVE_FORKPTY
|
||||
pid_t forkpty(int *amaster, char *name, struct termios *termp,
|
||||
struct winsize *winp);
|
||||
#endif
|
||||
|
||||
/* Unlink the socket */
|
||||
static void
|
||||
unlink_socket(void)
|
||||
{
|
||||
unlink(sockname);
|
||||
}
|
||||
|
||||
/* Signal */
|
||||
static RETSIGTYPE
|
||||
die(int sig)
|
||||
{
|
||||
/* Well, the child died. */
|
||||
if (sig == SIGCHLD)
|
||||
{
|
||||
#ifdef BROKEN_MASTER
|
||||
/* Damn you Solaris! */
|
||||
close(the_pty.fd);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Sets a file descriptor to non-blocking mode. */
|
||||
static int
|
||||
setnonblocking(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
#if defined(O_NONBLOCK)
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
#elif defined(FIONBIO)
|
||||
flags = 1;
|
||||
if (ioctl(fd, FIONBIO, &flags) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
#else
|
||||
#warning Do not know how to set non-blocking mode.
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Initialize the pty structure. */
|
||||
static int
|
||||
init_pty(char **argv, int statusfd)
|
||||
{
|
||||
/* Use the original terminal's settings. We don't have to set the
|
||||
** window size here, because the attacher will send it in a packet. */
|
||||
the_pty.term = orig_term;
|
||||
memset(&the_pty.ws, 0, sizeof(struct winsize));
|
||||
|
||||
/* Create the pty process */
|
||||
if (!dont_have_tty)
|
||||
the_pty.pid = forkpty(&the_pty.fd, NULL, &the_pty.term, NULL);
|
||||
else
|
||||
the_pty.pid = forkpty(&the_pty.fd, NULL, NULL, NULL);
|
||||
if (the_pty.pid < 0)
|
||||
return -1;
|
||||
else if (the_pty.pid == 0)
|
||||
{
|
||||
/* Child.. Execute the program. */
|
||||
execvp(*argv, argv);
|
||||
|
||||
/* Report the error to statusfd if we can, or stdout if we
|
||||
** can't. */
|
||||
if (statusfd != -1)
|
||||
dup2(statusfd, 1);
|
||||
else
|
||||
printf(EOS "\r\n");
|
||||
|
||||
printf("%s: could not execute %s: %s\r\n", progname,
|
||||
*argv, strerror(errno));
|
||||
fflush(stdout);
|
||||
_exit(127);
|
||||
}
|
||||
/* Parent.. Finish up and return */
|
||||
#ifdef BROKEN_MASTER
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = ptsname(the_pty.fd);
|
||||
the_pty.slave = open(buf, O_RDWR|O_NOCTTY);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send a signal to the slave side of a pseudo-terminal. */
|
||||
static void
|
||||
killpty(struct pty *pty, int sig)
|
||||
{
|
||||
pid_t pgrp = -1;
|
||||
|
||||
#ifdef TIOCSIGNAL
|
||||
if (ioctl(pty->fd, TIOCSIGNAL, sig) >= 0)
|
||||
return;
|
||||
#endif
|
||||
#ifdef TIOCSIG
|
||||
if (ioctl(pty->fd, TIOCSIG, sig) >= 0)
|
||||
return;
|
||||
#endif
|
||||
#ifdef TIOCGPGRP
|
||||
#ifdef BROKEN_MASTER
|
||||
if (ioctl(pty->slave, TIOCGPGRP, &pgrp) >= 0 && pgrp != -1 &&
|
||||
kill(-pgrp, sig) >= 0)
|
||||
return;
|
||||
#endif
|
||||
if (ioctl(pty->fd, TIOCGPGRP, &pgrp) >= 0 && pgrp != -1 &&
|
||||
kill(-pgrp, sig) >= 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Fallback using the child's pid. */
|
||||
kill(-pty->pid, sig);
|
||||
}
|
||||
|
||||
/* Creates a new unix domain socket. */
|
||||
static int
|
||||
create_socket(char *name)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_un sockun;
|
||||
|
||||
if (strlen(name) > sizeof(sockun.sun_path) - 1)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (s < 0)
|
||||
return -1;
|
||||
sockun.sun_family = AF_UNIX;
|
||||
strcpy(sockun.sun_path, name);
|
||||
if (bind(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0)
|
||||
{
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
if (listen(s, 128) < 0)
|
||||
{
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
if (setnonblocking(s) < 0)
|
||||
{
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
/* chmod it to prevent any suprises */
|
||||
if (chmod(name, 0600) < 0)
|
||||
{
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Update the modes on the socket. */
|
||||
static void
|
||||
update_socket_modes(int exec)
|
||||
{
|
||||
struct stat st;
|
||||
mode_t newmode;
|
||||
|
||||
if (stat(sockname, &st) < 0)
|
||||
return;
|
||||
|
||||
if (exec)
|
||||
newmode = st.st_mode | S_IXUSR;
|
||||
else
|
||||
newmode = st.st_mode & ~S_IXUSR;
|
||||
|
||||
if (st.st_mode != newmode)
|
||||
chmod(sockname, newmode);
|
||||
}
|
||||
|
||||
/* Process activity on the pty - Input and terminal changes are sent out to
|
||||
** the attached clients. If the pty goes away, we die. */
|
||||
static void
|
||||
pty_activity(int s)
|
||||
{
|
||||
unsigned char buf[BUFSIZE];
|
||||
ssize_t len;
|
||||
struct client *p;
|
||||
fd_set readfds, writefds;
|
||||
int highest_fd, nclients;
|
||||
|
||||
/* Read the pty activity */
|
||||
len = read(the_pty.fd, buf, sizeof(buf));
|
||||
|
||||
/* Error -> die */
|
||||
if (len <= 0)
|
||||
exit(1);
|
||||
|
||||
#ifdef BROKEN_MASTER
|
||||
/* Get the current terminal settings. */
|
||||
if (tcgetattr(the_pty.slave, &the_pty.term) < 0)
|
||||
exit(1);
|
||||
#else
|
||||
/* Get the current terminal settings. */
|
||||
if (tcgetattr(the_pty.fd, &the_pty.term) < 0)
|
||||
exit(1);
|
||||
#endif
|
||||
|
||||
top:
|
||||
/*
|
||||
** Wait until at least one client is writable. Also wait on the control
|
||||
** socket in case a new client tries to connect.
|
||||
*/
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(s, &readfds);
|
||||
highest_fd = s;
|
||||
for (p = clients, nclients = 0; p; p = p->next)
|
||||
{
|
||||
if (!p->attached)
|
||||
continue;
|
||||
FD_SET(p->fd, &writefds);
|
||||
if (p->fd > highest_fd)
|
||||
highest_fd = p->fd;
|
||||
nclients++;
|
||||
}
|
||||
if (nclients == 0)
|
||||
return;
|
||||
if (select(highest_fd + 1, &readfds, &writefds, NULL, NULL) < 0)
|
||||
return;
|
||||
|
||||
/* Send the data out to the clients. */
|
||||
for (p = clients, nclients = 0; p; p = p->next)
|
||||
{
|
||||
ssize_t written;
|
||||
|
||||
if (!FD_ISSET(p->fd, &writefds))
|
||||
continue;
|
||||
|
||||
written = 0;
|
||||
while (written < len)
|
||||
{
|
||||
ssize_t n = write(p->fd, buf + written, len - written);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
written += n;
|
||||
continue;
|
||||
}
|
||||
else if (n < 0 && errno == EINTR)
|
||||
continue;
|
||||
else if (n < 0 && errno != EAGAIN)
|
||||
nclients = -1;
|
||||
break;
|
||||
}
|
||||
if (nclients != -1 && written == len)
|
||||
nclients++;
|
||||
}
|
||||
|
||||
/* Try again if nothing happened. */
|
||||
if (!FD_ISSET(s, &readfds) && nclients == 0)
|
||||
goto top;
|
||||
}
|
||||
|
||||
/* Process activity on the control socket */
|
||||
static void
|
||||
control_activity(int s)
|
||||
{
|
||||
int fd;
|
||||
struct client *p;
|
||||
|
||||
/* Accept the new client and link it in. */
|
||||
fd = accept(s, NULL, NULL);
|
||||
if (fd < 0)
|
||||
return;
|
||||
else if (setnonblocking(fd) < 0)
|
||||
{
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Link it in. */
|
||||
p = malloc(sizeof(struct client));
|
||||
p->fd = fd;
|
||||
p->attached = 0;
|
||||
p->pprev = &clients;
|
||||
p->next = *(p->pprev);
|
||||
if (p->next)
|
||||
p->next->pprev = &p->next;
|
||||
*(p->pprev) = p;
|
||||
}
|
||||
|
||||
/* Process activity from a client. */
|
||||
static void
|
||||
client_activity(struct client *p)
|
||||
{
|
||||
ssize_t len;
|
||||
struct packet pkt;
|
||||
|
||||
/* Read the activity. */
|
||||
len = read(p->fd, &pkt, sizeof(struct packet));
|
||||
if (len < 0 && (errno == EAGAIN || errno == EINTR))
|
||||
return;
|
||||
|
||||
/* Close the client on an error. */
|
||||
if (len <= 0)
|
||||
{
|
||||
close(p->fd);
|
||||
if (p->next)
|
||||
p->next->pprev = p->pprev;
|
||||
*(p->pprev) = p->next;
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Push out data to the program. */
|
||||
if (pkt.type == MSG_PUSH)
|
||||
{
|
||||
if (pkt.len <= sizeof(pkt.u.buf))
|
||||
write(the_pty.fd, pkt.u.buf, pkt.len);
|
||||
}
|
||||
|
||||
/* Attach or detach from the program. */
|
||||
else if (pkt.type == MSG_ATTACH)
|
||||
p->attached = 1;
|
||||
else if (pkt.type == MSG_DETACH)
|
||||
p->attached = 0;
|
||||
|
||||
/* Window size change request, without a forced redraw. */
|
||||
else if (pkt.type == MSG_WINCH)
|
||||
{
|
||||
the_pty.ws = pkt.u.ws;
|
||||
ioctl(the_pty.fd, TIOCSWINSZ, &the_pty.ws);
|
||||
}
|
||||
|
||||
/* Force a redraw using a particular method. */
|
||||
else if (pkt.type == MSG_REDRAW)
|
||||
{
|
||||
int method = pkt.len;
|
||||
|
||||
/* If the client didn't specify a particular method, use
|
||||
** whatever we had on startup. */
|
||||
if (method == REDRAW_UNSPEC)
|
||||
method = redraw_method;
|
||||
if (method == REDRAW_NONE)
|
||||
return;
|
||||
|
||||
/* Set the window size. */
|
||||
the_pty.ws = pkt.u.ws;
|
||||
ioctl(the_pty.fd, TIOCSWINSZ, &the_pty.ws);
|
||||
|
||||
/* Send a ^L character if the terminal is in no-echo and
|
||||
** character-at-a-time mode. */
|
||||
if (method == REDRAW_CTRL_L)
|
||||
{
|
||||
char c = '\f';
|
||||
|
||||
if (((the_pty.term.c_lflag & (ECHO|ICANON)) == 0) &&
|
||||
(the_pty.term.c_cc[VMIN] == 1))
|
||||
{
|
||||
write(the_pty.fd, &c, 1);
|
||||
}
|
||||
}
|
||||
/* Send a WINCH signal to the program. */
|
||||
else if (method == REDRAW_WINCH)
|
||||
{
|
||||
killpty(&the_pty, SIGWINCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The master process - It watches over the pty process and the attached */
|
||||
/* clients. */
|
||||
static void
|
||||
master_process(int s, char **argv, int waitattach, int statusfd)
|
||||
{
|
||||
struct client *p, *next;
|
||||
fd_set readfds;
|
||||
int highest_fd;
|
||||
int nullfd;
|
||||
|
||||
int has_attached_client = 0;
|
||||
|
||||
/* Okay, disassociate ourselves from the original terminal, as we
|
||||
** don't care what happens to it. */
|
||||
setsid();
|
||||
|
||||
/* Set a trap to unlink the socket when we die. */
|
||||
atexit(unlink_socket);
|
||||
|
||||
/* Create a pty in which the process is running. */
|
||||
signal(SIGCHLD, die);
|
||||
if (init_pty(argv, statusfd) < 0)
|
||||
{
|
||||
if (statusfd != -1)
|
||||
dup2(statusfd, 1);
|
||||
if (errno == ENOENT)
|
||||
printf("%s: Could not find a pty.\n", progname);
|
||||
else
|
||||
printf("%s: init_pty: %s\n", progname, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Set up some signals. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGXFSZ, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGINT, die);
|
||||
signal(SIGTERM, die);
|
||||
|
||||
/* Close statusfd, since we don't need it anymore. */
|
||||
if (statusfd != -1)
|
||||
close(statusfd);
|
||||
|
||||
/* Make sure stdin/stdout/stderr point to /dev/null. We are now a
|
||||
** daemon. */
|
||||
nullfd = open("/dev/null", O_RDWR);
|
||||
dup2(nullfd, 0);
|
||||
dup2(nullfd, 1);
|
||||
dup2(nullfd, 2);
|
||||
if (nullfd > 2)
|
||||
close(nullfd);
|
||||
|
||||
/* Loop forever. */
|
||||
while (1)
|
||||
{
|
||||
int new_has_attached_client = 0;
|
||||
|
||||
/* Re-initialize the file descriptor set for select. */
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(s, &readfds);
|
||||
highest_fd = s;
|
||||
|
||||
/*
|
||||
** When waitattach is set, wait until the client attaches
|
||||
** before trying to read from the pty.
|
||||
*/
|
||||
if (waitattach)
|
||||
{
|
||||
if (clients && clients->attached)
|
||||
waitattach = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FD_SET(the_pty.fd, &readfds);
|
||||
if (the_pty.fd > highest_fd)
|
||||
highest_fd = the_pty.fd;
|
||||
}
|
||||
|
||||
for (p = clients; p; p = p->next)
|
||||
{
|
||||
FD_SET(p->fd, &readfds);
|
||||
if (p->fd > highest_fd)
|
||||
highest_fd = p->fd;
|
||||
|
||||
if (p->attached)
|
||||
new_has_attached_client = 1;
|
||||
}
|
||||
|
||||
/* chmod the socket if necessary. */
|
||||
if (has_attached_client != new_has_attached_client)
|
||||
{
|
||||
update_socket_modes(new_has_attached_client);
|
||||
has_attached_client = new_has_attached_client;
|
||||
}
|
||||
|
||||
/* Wait for something to happen. */
|
||||
if (select(highest_fd + 1, &readfds, NULL, NULL, NULL) < 0)
|
||||
{
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* New client? */
|
||||
if (FD_ISSET(s, &readfds))
|
||||
control_activity(s);
|
||||
/* Activity on a client? */
|
||||
for (p = clients; p; p = next)
|
||||
{
|
||||
next = p->next;
|
||||
if (FD_ISSET(p->fd, &readfds))
|
||||
client_activity(p);
|
||||
}
|
||||
/* pty activity? */
|
||||
if (FD_ISSET(the_pty.fd, &readfds))
|
||||
pty_activity(s);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
master_main(char **argv, int waitattach, int dontfork)
|
||||
{
|
||||
int fd[2] = {-1, -1};
|
||||
int s;
|
||||
pid_t pid;
|
||||
|
||||
/* Use a default redraw method if one hasn't been specified yet. */
|
||||
if (redraw_method == REDRAW_UNSPEC)
|
||||
redraw_method = REDRAW_CTRL_L;
|
||||
|
||||
/* Create the unix domain socket. */
|
||||
s = create_socket(sockname);
|
||||
if (s < 0 && errno == ENAMETOOLONG)
|
||||
{
|
||||
char *slash = strrchr(sockname, '/');
|
||||
|
||||
/* Try to shorten the socket's path name by using chdir. */
|
||||
if (slash)
|
||||
{
|
||||
int dirfd = open(".", O_RDONLY);
|
||||
|
||||
if (dirfd >= 0)
|
||||
{
|
||||
*slash = '\0';
|
||||
if (chdir(sockname) >= 0)
|
||||
{
|
||||
s = create_socket(slash + 1);
|
||||
fchdir(dirfd);
|
||||
}
|
||||
*slash = '/';
|
||||
close(dirfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s < 0)
|
||||
{
|
||||
printf("%s: %s: %s\n", progname, sockname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(F_SETFD) && defined(FD_CLOEXEC)
|
||||
fcntl(s, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
/* If FD_CLOEXEC works, create a pipe and use it to report any errors
|
||||
** that occur while trying to execute the program. */
|
||||
if (dontfork)
|
||||
{
|
||||
fd[1] = dup(2);
|
||||
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0)
|
||||
{
|
||||
close(fd[1]);
|
||||
fd[1] = -1;
|
||||
}
|
||||
}
|
||||
else if (pipe(fd) >= 0)
|
||||
{
|
||||
if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0 ||
|
||||
fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0)
|
||||
{
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
fd[0] = fd[1] = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dontfork)
|
||||
{
|
||||
master_process(s, argv, waitattach, fd[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fork off so we can daemonize and such */
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
printf("%s: fork: %s\n", progname, strerror(errno));
|
||||
unlink_socket();
|
||||
return 1;
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
/* Child - this becomes the master */
|
||||
if (fd[0] != -1)
|
||||
close(fd[0]);
|
||||
master_process(s, argv, waitattach, fd[1]);
|
||||
return 0;
|
||||
}
|
||||
/* Parent - just return. */
|
||||
|
||||
#if defined(F_SETFD) && defined(FD_CLOEXEC)
|
||||
/* Check if an error occurred while trying to execute the program. */
|
||||
if (fd[0] != -1)
|
||||
{
|
||||
char buf[1024];
|
||||
ssize_t len;
|
||||
|
||||
close(fd[1]);
|
||||
len = read(fd[0], buf, sizeof(buf));
|
||||
if (len > 0)
|
||||
{
|
||||
write(2, buf, len);
|
||||
kill(pid, SIGTERM);
|
||||
return 1;
|
||||
}
|
||||
close(fd[0]);
|
||||
}
|
||||
#endif
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* BSDish functions for systems that don't have them. */
|
||||
#ifndef HAVE_OPENPTY
|
||||
#define HAVE_OPENPTY
|
||||
/* openpty: Use /dev/ptmx and Unix98 if we have it. */
|
||||
#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT)
|
||||
int
|
||||
openpty(int *amaster, int *aslave, char *name, struct termios *termp,
|
||||
struct winsize *winp)
|
||||
{
|
||||
int master, slave;
|
||||
char *buf;
|
||||
|
||||
#ifdef _AIX
|
||||
master = open("/dev/ptc", O_RDWR|O_NOCTTY);
|
||||
if (master < 0)
|
||||
return -1;
|
||||
buf = ttyname(master);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
slave = open(buf, O_RDWR|O_NOCTTY);
|
||||
if (slave < 0)
|
||||
return -1;
|
||||
#else
|
||||
master = open("/dev/ptmx", O_RDWR);
|
||||
if (master < 0)
|
||||
return -1;
|
||||
if (grantpt(master) < 0)
|
||||
return -1;
|
||||
if (unlockpt(master) < 0)
|
||||
return -1;
|
||||
buf = ptsname(master);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
slave = open(buf, O_RDWR|O_NOCTTY);
|
||||
if (slave < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef I_PUSH
|
||||
if (ioctl(slave, I_PUSH, "ptem") < 0)
|
||||
return -1;
|
||||
if (ioctl(slave, I_PUSH, "ldterm") < 0)
|
||||
return -1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
*amaster = master;
|
||||
*aslave = slave;
|
||||
if (name)
|
||||
strcpy(name, buf);
|
||||
if (termp)
|
||||
tcsetattr(slave, TCSAFLUSH, termp);
|
||||
if (winp)
|
||||
ioctl(slave, TIOCSWINSZ, winp);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#error Do not know how to define openpty.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FORKPTY
|
||||
#if defined(HAVE_OPENPTY)
|
||||
pid_t
|
||||
forkpty(int *amaster, char *name, struct termios *termp,
|
||||
struct winsize *winp)
|
||||
{
|
||||
pid_t pid;
|
||||
int master, slave;
|
||||
|
||||
if (openpty(&master, &slave, name, termp, winp) < 0)
|
||||
return -1;
|
||||
*amaster = master;
|
||||
|
||||
/* Fork off... */
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
else if (pid == 0)
|
||||
{
|
||||
char *buf;
|
||||
int fd;
|
||||
|
||||
setsid();
|
||||
#ifdef TIOCSCTTY
|
||||
buf = NULL;
|
||||
if (ioctl(slave, TIOCSCTTY, NULL) < 0)
|
||||
_exit(1);
|
||||
#elif defined(_AIX)
|
||||
fd = open("/dev/tty", O_RDWR|O_NOCTTY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
ioctl(fd, TIOCNOTTY, NULL);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
buf = ttyname(master);
|
||||
fd = open(buf, O_RDWR);
|
||||
close(fd);
|
||||
|
||||
fd = open("/dev/tty", O_WRONLY);
|
||||
if (fd < 0)
|
||||
_exit(1);
|
||||
close(fd);
|
||||
|
||||
if (termp && tcsetattr(slave, TCSAFLUSH, termp) == -1)
|
||||
_exit(1);
|
||||
if (ioctl(slave, TIOCSWINSZ, winp) == -1)
|
||||
_exit(1);
|
||||
#else
|
||||
buf = ptsname(master);
|
||||
fd = open(buf, O_RDWR);
|
||||
close(fd);
|
||||
#endif
|
||||
dup2(slave, 0);
|
||||
dup2(slave, 1);
|
||||
dup2(slave, 2);
|
||||
|
||||
if (slave > 2)
|
||||
close(slave);
|
||||
close(master);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
close(slave);
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error Do not know how to define forkpty.
|
||||
#endif
|
||||
#endif
|
Loading…
Add table
Reference in a new issue