mirror of https://github.com/ksherlock/ample.git
add pty_shell command.
note that c modules had to be disabled in the build settings due to #define TTYDEFCHARS.
This commit is contained in:
parent
6ca897739a
commit
88c12a4832
|
@ -62,6 +62,8 @@
|
||||||
B6152B5725F4549F00605E6E /* Slot.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5525F4549F00605E6E /* Slot.m */; };
|
B6152B5725F4549F00605E6E /* Slot.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5525F4549F00605E6E /* Slot.m */; };
|
||||||
B6152B5A25F5B57E00605E6E /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5925F5B57E00605E6E /* Media.m */; };
|
B6152B5A25F5B57E00605E6E /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5925F5B57E00605E6E /* Media.m */; };
|
||||||
B6152B5B25F5B57E00605E6E /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5925F5B57E00605E6E /* Media.m */; };
|
B6152B5B25F5B57E00605E6E /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5925F5B57E00605E6E /* Media.m */; };
|
||||||
|
B6374AC4260EBBCF0045CA16 /* pty_shell.c in Sources */ = {isa = PBXBuildFile; fileRef = B6374AB6260EBB970045CA16 /* pty_shell.c */; };
|
||||||
|
B6374AC5260EBC5A0045CA16 /* pty_shell in CopyFiles */ = {isa = PBXBuildFile; fileRef = B6374ABD260EBBC90045CA16 /* pty_shell */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||||
B63C1B8B24FF4BF700511A71 /* Ample.m in Sources */ = {isa = PBXBuildFile; fileRef = B63C1B8A24FF4BF700511A71 /* Ample.m */; };
|
B63C1B8B24FF4BF700511A71 /* Ample.m in Sources */ = {isa = PBXBuildFile; fileRef = B63C1B8A24FF4BF700511A71 /* Ample.m */; };
|
||||||
B63C1B8C24FF4BF700511A71 /* Ample.m in Sources */ = {isa = PBXBuildFile; fileRef = B63C1B8A24FF4BF700511A71 /* Ample.m */; };
|
B63C1B8C24FF4BF700511A71 /* Ample.m in Sources */ = {isa = PBXBuildFile; fileRef = B63C1B8A24FF4BF700511A71 /* Ample.m */; };
|
||||||
B63C1B8E25004C6D00511A71 /* mame-data.tgz in Resources */ = {isa = PBXBuildFile; fileRef = B63C1B8D25004C6D00511A71 /* mame-data.tgz */; };
|
B63C1B8E25004C6D00511A71 /* mame-data.tgz in Resources */ = {isa = PBXBuildFile; fileRef = B63C1B8D25004C6D00511A71 /* mame-data.tgz */; };
|
||||||
|
@ -232,6 +234,15 @@
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
B6374ABB260EBBC90045CA16 /* CopyFiles */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = /usr/share/man/man1/;
|
||||||
|
dstSubfolderSpec = 0;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 1;
|
||||||
|
};
|
||||||
B66236B124FDA443006CABD7 /* Embed Frameworks */ = {
|
B66236B124FDA443006CABD7 /* Embed Frameworks */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -251,6 +262,7 @@
|
||||||
files = (
|
files = (
|
||||||
B6841BDA251ECB1C006A5C39 /* mame64 in CopyFiles */,
|
B6841BDA251ECB1C006A5C39 /* mame64 in CopyFiles */,
|
||||||
B6E08076252574690075F4E1 /* vmnet_helper in CopyFiles */,
|
B6E08076252574690075F4E1 /* vmnet_helper in CopyFiles */,
|
||||||
|
B6374AC5260EBC5A0045CA16 /* pty_shell in CopyFiles */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -335,6 +347,8 @@
|
||||||
B6152B5525F4549F00605E6E /* Slot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Slot.m; sourceTree = "<group>"; };
|
B6152B5525F4549F00605E6E /* Slot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Slot.m; sourceTree = "<group>"; };
|
||||||
B6152B5825F5B4F100605E6E /* Media.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = "<group>"; };
|
B6152B5825F5B4F100605E6E /* Media.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = "<group>"; };
|
||||||
B6152B5925F5B57E00605E6E /* Media.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Media.m; sourceTree = "<group>"; };
|
B6152B5925F5B57E00605E6E /* Media.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Media.m; sourceTree = "<group>"; };
|
||||||
|
B6374AB6260EBB970045CA16 /* pty_shell.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pty_shell.c; sourceTree = "<group>"; };
|
||||||
|
B6374ABD260EBBC90045CA16 /* pty_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pty_shell; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B63C1B8924FF4B7100511A71 /* Ample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ample.h; sourceTree = "<group>"; };
|
B63C1B8924FF4B7100511A71 /* Ample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ample.h; sourceTree = "<group>"; };
|
||||||
B63C1B8A24FF4BF700511A71 /* Ample.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Ample.m; sourceTree = "<group>"; };
|
B63C1B8A24FF4BF700511A71 /* Ample.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Ample.m; sourceTree = "<group>"; };
|
||||||
B63C1B8D25004C6D00511A71 /* mame-data.tgz */ = {isa = PBXFileReference; lastKnownFileType = file; name = "mame-data.tgz"; path = "embedded/mame-data.tgz"; sourceTree = "<group>"; };
|
B63C1B8D25004C6D00511A71 /* mame-data.tgz */ = {isa = PBXFileReference; lastKnownFileType = file; name = "mame-data.tgz"; path = "embedded/mame-data.tgz"; sourceTree = "<group>"; };
|
||||||
|
@ -423,6 +437,13 @@
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
B6374ABA260EBBC90045CA16 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
B6841BCD251EC913006A5C39 /* Frameworks */ = {
|
B6841BCD251EC913006A5C39 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -450,6 +471,14 @@
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
B6374AB2260EBB970045CA16 /* pty_shell */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B6374AB6260EBB970045CA16 /* pty_shell.c */,
|
||||||
|
);
|
||||||
|
path = pty_shell;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
B649798C24EEC165008ABD20 /* Recovered References */ = {
|
B649798C24EEC165008ABD20 /* Recovered References */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -564,6 +593,7 @@
|
||||||
B6BA257D24E99BE9005FB8FF /* Ample */,
|
B6BA257D24E99BE9005FB8FF /* Ample */,
|
||||||
B66236BD24FDA7EA006CABD7 /* Embedded Content */,
|
B66236BD24FDA7EA006CABD7 /* Embedded Content */,
|
||||||
B6841BD1251EC913006A5C39 /* vmnet_helper */,
|
B6841BD1251EC913006A5C39 /* vmnet_helper */,
|
||||||
|
B6374AB2260EBB970045CA16 /* pty_shell */,
|
||||||
B6BA257C24E99BE9005FB8FF /* Products */,
|
B6BA257C24E99BE9005FB8FF /* Products */,
|
||||||
B649798C24EEC165008ABD20 /* Recovered References */,
|
B649798C24EEC165008ABD20 /* Recovered References */,
|
||||||
B66236B624FDA686006CABD7 /* Frameworks */,
|
B66236B624FDA686006CABD7 /* Frameworks */,
|
||||||
|
@ -576,6 +606,7 @@
|
||||||
B6BA257B24E99BE9005FB8FF /* Ample.app */,
|
B6BA257B24E99BE9005FB8FF /* Ample.app */,
|
||||||
B6E4B5FA24FDE2670094A35C /* Ample Lite.app */,
|
B6E4B5FA24FDE2670094A35C /* Ample Lite.app */,
|
||||||
B6841BD0251EC913006A5C39 /* vmnet_helper */,
|
B6841BD0251EC913006A5C39 /* vmnet_helper */,
|
||||||
|
B6374ABD260EBBC90045CA16 /* pty_shell */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -683,6 +714,23 @@
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
B6374ABC260EBBC90045CA16 /* pty_shell */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = B6374AC1260EBBC90045CA16 /* Build configuration list for PBXNativeTarget "pty_shell" */;
|
||||||
|
buildPhases = (
|
||||||
|
B6374AB9260EBBC90045CA16 /* Sources */,
|
||||||
|
B6374ABA260EBBC90045CA16 /* Frameworks */,
|
||||||
|
B6374ABB260EBBC90045CA16 /* CopyFiles */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = pty_shell;
|
||||||
|
productName = pty_shell;
|
||||||
|
productReference = B6374ABD260EBBC90045CA16 /* pty_shell */;
|
||||||
|
productType = "com.apple.product-type.tool";
|
||||||
|
};
|
||||||
B6841BCF251EC913006A5C39 /* vmnet_helper */ = {
|
B6841BCF251EC913006A5C39 /* vmnet_helper */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = B6841BD4251EC913006A5C39 /* Build configuration list for PBXNativeTarget "vmnet_helper" */;
|
buildConfigurationList = B6841BD4251EC913006A5C39 /* Build configuration list for PBXNativeTarget "vmnet_helper" */;
|
||||||
|
@ -747,6 +795,9 @@
|
||||||
LastUpgradeCheck = 1130;
|
LastUpgradeCheck = 1130;
|
||||||
ORGANIZATIONNAME = "Kelvin Sherlock";
|
ORGANIZATIONNAME = "Kelvin Sherlock";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
B6374ABC260EBBC90045CA16 = {
|
||||||
|
CreatedOnToolsVersion = 11.3.1;
|
||||||
|
};
|
||||||
B6841BCF251EC913006A5C39 = {
|
B6841BCF251EC913006A5C39 = {
|
||||||
CreatedOnToolsVersion = 11.3.1;
|
CreatedOnToolsVersion = 11.3.1;
|
||||||
};
|
};
|
||||||
|
@ -771,6 +822,7 @@
|
||||||
B6BA257A24E99BE9005FB8FF /* Ample */,
|
B6BA257A24E99BE9005FB8FF /* Ample */,
|
||||||
B6E4B5AE24FDE2670094A35C /* Ample Lite */,
|
B6E4B5AE24FDE2670094A35C /* Ample Lite */,
|
||||||
B6841BCF251EC913006A5C39 /* vmnet_helper */,
|
B6841BCF251EC913006A5C39 /* vmnet_helper */,
|
||||||
|
B6374ABC260EBBC90045CA16 /* pty_shell */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
@ -990,6 +1042,14 @@
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
B6374AB9260EBBC90045CA16 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
B6374AC4260EBBCF0045CA16 /* pty_shell.c in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
B6841BCC251EC913006A5C39 /* Sources */ = {
|
B6841BCC251EC913006A5C39 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -1129,6 +1189,24 @@
|
||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
|
B6374AC2260EBBC90045CA16 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = NO;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
B6374AC3260EBBC90045CA16 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = NO;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
B6841BD5251EC913006A5C39 /* Debug */ = {
|
B6841BD5251EC913006A5C39 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
@ -1335,6 +1413,15 @@
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
B6374AC1260EBBC90045CA16 /* Build configuration list for PBXNativeTarget "pty_shell" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
B6374AC2260EBBC90045CA16 /* Debug */,
|
||||||
|
B6374AC3260EBBC90045CA16 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
B6841BD4251EC913006A5C39 /* Build configuration list for PBXNativeTarget "vmnet_helper" */ = {
|
B6841BD4251EC913006A5C39 /* Build configuration list for PBXNativeTarget "vmnet_helper" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>pty_shell.xcscheme_^#shared#^_</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>3</integer>
|
||||||
|
</dict>
|
||||||
<key>vmnet_helper.xcscheme_^#shared#^_</key>
|
<key>vmnet_helper.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>isShown</key>
|
<key>isShown</key>
|
||||||
|
|
|
@ -0,0 +1,390 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sysexits.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
#define TTYDEFCHARS
|
||||||
|
#include <sys/ttydefaults.h>
|
||||||
|
|
||||||
|
|
||||||
|
void usage(int rv) {
|
||||||
|
|
||||||
|
fputs(
|
||||||
|
"Usage: pty_shell [-T term] [-w] [-r] pty [command ...]\n"
|
||||||
|
" -T term TERM (default vt100)\n"
|
||||||
|
" -w Don't wait for child to finish\n"
|
||||||
|
" -r Raw I/O\n"
|
||||||
|
, stderr);
|
||||||
|
exit(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *xsprintf(char *fmt, ...) {
|
||||||
|
|
||||||
|
int ok;
|
||||||
|
char *buffer = NULL;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ok = vasprintf(&buffer, fmt, ap);
|
||||||
|
if (ok < 0) {
|
||||||
|
errx(EX_SOFTWARE, "vasprintf failed");
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-create execve path search so we have better control */
|
||||||
|
/* return string may or may not be allocated */
|
||||||
|
char *findexe(char *name) {
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
char *cp;
|
||||||
|
int ok;
|
||||||
|
|
||||||
|
char *path = getenv("PATH");
|
||||||
|
if (!path) path = _PATH_DEFPATH;
|
||||||
|
|
||||||
|
if (!name || !*name) {
|
||||||
|
errno = ENOENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (*name == '/') return name;
|
||||||
|
if (strchr(name, '/')) {
|
||||||
|
cp = realpath(name, NULL);
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *start = path;
|
||||||
|
char *end = NULL;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
end = strchr(start, ':');
|
||||||
|
if (!end) {
|
||||||
|
/* last one */
|
||||||
|
l = strlen(start);
|
||||||
|
} else {
|
||||||
|
l = end - start;
|
||||||
|
}
|
||||||
|
if (l == 0) {
|
||||||
|
/* current directory */
|
||||||
|
cp = realpath(name, NULL);
|
||||||
|
} else {
|
||||||
|
cp = xsprintf("%.*s/%s", l, start, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fprintf(stderr, "%s\n", cp);
|
||||||
|
ok = stat(cp, &st);
|
||||||
|
|
||||||
|
if (ok >= 0 && (st.st_mode & S_IXUSR))
|
||||||
|
return cp;
|
||||||
|
|
||||||
|
free(cp);
|
||||||
|
|
||||||
|
if (!end) break;
|
||||||
|
start = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
errno = ENOENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dup012(int fd) {
|
||||||
|
dup2(fd, 0);
|
||||||
|
dup2(fd, 1);
|
||||||
|
dup2(fd, 2);
|
||||||
|
if (fd > 2) close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(int fd, char *path, char **argv, char **env) {
|
||||||
|
|
||||||
|
int ok;
|
||||||
|
int err_fd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 0);
|
||||||
|
|
||||||
|
// ok = 0; dup012(fd);
|
||||||
|
ok = login_tty(fd);
|
||||||
|
if (ok < 0) {
|
||||||
|
dprintf(err_fd, "%s: login_tty: %s\n",
|
||||||
|
getprogname(), strerror(errno)
|
||||||
|
);
|
||||||
|
_exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
execve(path, argv, env);
|
||||||
|
|
||||||
|
dprintf(err_fd, "%s: execve %s: %s\n",
|
||||||
|
getprogname(), path, strerror(errno)
|
||||||
|
);
|
||||||
|
|
||||||
|
_exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pid_t child_pid;
|
||||||
|
int pty_fd;
|
||||||
|
void sig_handler(int sig, siginfo_t *info, void *context) {
|
||||||
|
|
||||||
|
if (sig == SIGINFO || sig == SIGUSR1) {
|
||||||
|
int rlen, wlen;
|
||||||
|
rlen = wlen = 0;
|
||||||
|
|
||||||
|
if (pty_fd > 0) {
|
||||||
|
char buffer[128];
|
||||||
|
int n,x;
|
||||||
|
|
||||||
|
ioctl(pty_fd, TIOCOUTQ, &wlen);
|
||||||
|
ioctl(pty_fd, FIONREAD, &rlen);
|
||||||
|
|
||||||
|
if (rlen > 9999) rlen = 9999;
|
||||||
|
if (wlen > 9999) wlen = 9999;
|
||||||
|
|
||||||
|
memcpy(buffer, "child pid: read queue: write queue: \n", 58);
|
||||||
|
|
||||||
|
|
||||||
|
n = 16;
|
||||||
|
x = child_pid;
|
||||||
|
do {
|
||||||
|
buffer[n--] = '0' + (x %10);
|
||||||
|
x /= 10;
|
||||||
|
} while(x);
|
||||||
|
|
||||||
|
n = 35;
|
||||||
|
x = rlen;
|
||||||
|
do {
|
||||||
|
buffer[n--] = '0' + (x %10);
|
||||||
|
x /= 10;
|
||||||
|
} while(x);
|
||||||
|
|
||||||
|
n = 55;
|
||||||
|
x = wlen;
|
||||||
|
do {
|
||||||
|
buffer[n--] = '0' + (x %10);
|
||||||
|
x /= 10;
|
||||||
|
} while(x);
|
||||||
|
|
||||||
|
write(STDERR_FILENO, buffer, 58);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sig == SIGHUP || sig == SIGINT || sig == SIGTERM) {
|
||||||
|
/* pass to child */
|
||||||
|
if (child_pid >= 0) {
|
||||||
|
kill(child_pid, sig);
|
||||||
|
}
|
||||||
|
struct sigaction sa;
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_handler = SIG_DFL;
|
||||||
|
sigaction(sig, &sa, NULL);
|
||||||
|
kill(getpid(), sig);
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
int c;
|
||||||
|
int fd;
|
||||||
|
pid_t pid;
|
||||||
|
int ok, i;
|
||||||
|
char *pty;
|
||||||
|
char *term = "vt100";
|
||||||
|
char *path = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
struct winsize ws = { 24, 80, 0, 0 };
|
||||||
|
struct termios tios;
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
|
|
||||||
|
char *env[10];
|
||||||
|
int flag_w = 0;
|
||||||
|
// int flag_i = 0;
|
||||||
|
int flag_f = 0;
|
||||||
|
int flag_r = 0;
|
||||||
|
int flag_v = 0;
|
||||||
|
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "T:rwhv")) != -1) {
|
||||||
|
switch(c) {
|
||||||
|
// case 'f': flag_f = 1; break;
|
||||||
|
case 'r': flag_r = 1; break;
|
||||||
|
case 'w': flag_w = 1; break;
|
||||||
|
case 'v': flag_v = 1; break;
|
||||||
|
case 'h': usage(0);
|
||||||
|
case 'T':
|
||||||
|
term = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
exit(EX_USAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
// pty [optional command]
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
usage(EX_USAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* n.b. - with nonblock, fd can close before all data sent */
|
||||||
|
pty = argv[0];
|
||||||
|
fd = open(pty, O_RDWR | /* O_NONBLOCK | */ O_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
err(EX_NOINPUT, "open %s", pty);
|
||||||
|
}
|
||||||
|
pty_fd = fd;
|
||||||
|
|
||||||
|
--argc;
|
||||||
|
++argv;
|
||||||
|
|
||||||
|
|
||||||
|
memset(&tios, 0, sizeof(tios));
|
||||||
|
memcpy(tios.c_cc, ttydefchars, sizeof(ttydefchars));
|
||||||
|
if (flag_r) {
|
||||||
|
cfmakeraw(&tios);
|
||||||
|
} else {
|
||||||
|
tios.c_oflag = TTYDEF_OFLAG;
|
||||||
|
tios.c_lflag = TTYDEF_LFLAG;
|
||||||
|
tios.c_iflag = TTYDEF_IFLAG;
|
||||||
|
tios.c_cflag = TTYDEF_CFLAG;
|
||||||
|
}
|
||||||
|
tios.c_ispeed = tios.c_ospeed = B9600;
|
||||||
|
|
||||||
|
|
||||||
|
/* verify it's pty? */
|
||||||
|
|
||||||
|
ok = tcsetattr(fd, TCSAFLUSH, &tios);
|
||||||
|
ok = ioctl(fd, TIOCSWINSZ, (void *)&ws);
|
||||||
|
|
||||||
|
|
||||||
|
/* todo - option to retain environment? */
|
||||||
|
i = 0;
|
||||||
|
env[i++] = "LANG=C";
|
||||||
|
env[i++] = xsprintf("TERM=%s", term);
|
||||||
|
env[i++] = "COLUMNS=80";
|
||||||
|
env[i++] = "LINES=24";
|
||||||
|
if (argc) {
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
cp = getenv("HOME");
|
||||||
|
if (cp) {
|
||||||
|
env[i++] = xsprintf("HOME=%s", cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env[i] = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (argc) {
|
||||||
|
path = findexe(argv[0]);
|
||||||
|
if (!path) {
|
||||||
|
errx(EX_OSERR, "Unable to find %s", argv[0]);
|
||||||
|
}
|
||||||
|
argv[0] = basename(argv[0]);
|
||||||
|
} else {
|
||||||
|
/* -p: don't discard environment */
|
||||||
|
static char *args[] = {
|
||||||
|
"login",
|
||||||
|
"-pf",
|
||||||
|
"",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
char *login;
|
||||||
|
|
||||||
|
login = getlogin();
|
||||||
|
if (!login) {
|
||||||
|
errx(EX_OSERR, "getlogin() failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
path = "/usr/bin/login";
|
||||||
|
args[2] = login;
|
||||||
|
argv = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* n.b. - login_tty will fail unless root :/ */
|
||||||
|
if (flag_f) {
|
||||||
|
/* foreground */
|
||||||
|
execute(fd, path, argv, env);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
close(fd);
|
||||||
|
err(EX_OSERR, "fork");
|
||||||
|
}
|
||||||
|
if (!pid) {
|
||||||
|
/* child */
|
||||||
|
|
||||||
|
execute(fd, path, argv, env);
|
||||||
|
}
|
||||||
|
child_pid = pid;
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_flags = SA_SIGINFO | SA_RESTART;
|
||||||
|
sa.sa_sigaction = sig_handler;
|
||||||
|
sigfillset(&sa.sa_mask);
|
||||||
|
|
||||||
|
sigaction(SIGINFO, &sa, NULL);
|
||||||
|
sigaction(SIGUSR1, &sa, NULL);
|
||||||
|
sigaction(SIGHUP, &sa, NULL);
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
|
||||||
|
/* wait for the child so data isn't lost. */
|
||||||
|
if (!flag_w) {
|
||||||
|
pid_t ok;
|
||||||
|
int st;
|
||||||
|
|
||||||
|
printf("Waiting on child %d\n", (int)pid);
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
ok = waitpid(pid, &st, 0);
|
||||||
|
if (ok < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
warn("waitpid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
child_pid = -1;
|
||||||
|
if (WIFEXITED(st) && WEXITSTATUS(st)) {
|
||||||
|
printf("Exit status: %d\n", WEXITSTATUS(st));
|
||||||
|
}
|
||||||
|
if (WIFSIGNALED(st)) {
|
||||||
|
printf("Exit signal: %s\n", strsignal(WTERMSIG(st)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// flush discards data.
|
||||||
|
//ok = tcflush(fd, TCIOFLUSH);
|
||||||
|
ok = tcdrain(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue