mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-01 11:32:48 -05:00
New library-style 'utils' subdirectories.
Now that the new CMake build system is encouraging us to lay out the code like a set of libraries, it seems like a good idea to make them look more _like_ libraries, by putting things into separate modules as far as possible. This fixes several previous annoyances in which you had to link against some object in order to get a function you needed, but that object also contained other functions you didn't need which included link-time symbol references you didn't want to have to deal with. The usual offender was subsidiary supporting programs including misc.c for some innocuous function and then finding they had to deal with the requirements of buildinfo(). This big reorganisation introduces three new subdirectories called 'utils', one at the top level and one in each platform subdir. In each case, the directory contains basically the same files that were previously placed in the 'utils' build-time library, except that the ones that were extremely miscellaneous (misc.c, utils.c, uxmisc.c, winmisc.c, winmiscs.c, winutils.c) have been split up into much smaller pieces.
This commit is contained in:
80
unix/utils/arm_arch_queries.c
Normal file
80
unix/utils/arm_arch_queries.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Unix implementation of the OS query functions that detect Arm
|
||||
* architecture extensions.
|
||||
*/
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
#include "utils/arm_arch_queries.h"
|
||||
|
||||
#if defined __arm__ || defined __aarch64__
|
||||
|
||||
bool platform_aes_hw_available(void)
|
||||
{
|
||||
#if defined HWCAP_AES
|
||||
return getauxval(AT_HWCAP) & HWCAP_AES;
|
||||
#elif defined HWCAP2_AES
|
||||
return getauxval(AT_HWCAP2) & HWCAP2_AES;
|
||||
#elif defined __APPLE__
|
||||
/* M1 macOS defines no optional sysctl flag indicating presence of
|
||||
* the AES extension, which I assume to be because it's always
|
||||
* present */
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool platform_sha256_hw_available(void)
|
||||
{
|
||||
#if defined HWCAP_SHA2
|
||||
return getauxval(AT_HWCAP) & HWCAP_SHA2;
|
||||
#elif defined HWCAP2_SHA2
|
||||
return getauxval(AT_HWCAP2) & HWCAP2_SHA2;
|
||||
#elif defined __APPLE__
|
||||
/* Assume always present on M1 macOS, similarly to AES */
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool platform_sha1_hw_available(void)
|
||||
{
|
||||
#if defined HWCAP_SHA1
|
||||
return getauxval(AT_HWCAP) & HWCAP_SHA1;
|
||||
#elif defined HWCAP2_SHA1
|
||||
return getauxval(AT_HWCAP2) & HWCAP2_SHA1;
|
||||
#elif defined __APPLE__
|
||||
/* Assume always present on M1 macOS, similarly to AES */
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool platform_sha512_hw_available(void)
|
||||
{
|
||||
#if defined HWCAP_SHA512
|
||||
return getauxval(AT_HWCAP) & HWCAP_SHA512;
|
||||
#elif defined HWCAP2_SHA512
|
||||
return getauxval(AT_HWCAP2) & HWCAP2_SHA512;
|
||||
#elif defined __APPLE__
|
||||
return test_sysctl_flag("hw.optional.armv8_2_sha512");
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* defined __arm__ || defined __aarch64__ */
|
||||
|
||||
/*
|
||||
* Include _something_ in this file to prevent an annoying compiler
|
||||
* warning, and to avoid having to condition out this file in
|
||||
* CMakeLists. It's in a library, so this variable shouldn't end up in
|
||||
* any actual program, because nothing will refer to it.
|
||||
*/
|
||||
const int arm_arch_queries_dummy_variable = 0;
|
||||
|
||||
#endif /* defined __arm__ || defined __aarch64__ */
|
65
unix/utils/arm_arch_queries.h
Normal file
65
unix/utils/arm_arch_queries.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Header included only by arm_arch_queries.c.
|
||||
*
|
||||
* The only reason this is a header file instead of a source file is
|
||||
* so that I can define 'static inline' functions which may or may not
|
||||
* be used, without provoking a compiler warning when I turn out not
|
||||
* to use them in the subsequent source file.
|
||||
*/
|
||||
|
||||
#ifndef PUTTY_ARM_ARCH_QUERIES_H
|
||||
#define PUTTY_ARM_ARCH_QUERIES_H
|
||||
|
||||
#if defined __APPLE__
|
||||
#if HAVE_SYS_SYSCTL_H
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#endif /* defined __APPLE__ */
|
||||
|
||||
#if defined __arm__ || defined __aarch64__
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_AUXV_H
|
||||
#include <sys/auxv.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_ASM_HWCAP_H
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_GETAUXVAL
|
||||
/* No code needed: getauxval has just the API we want already */
|
||||
#elif HAVE_ELF_AUX_INFO
|
||||
/* Implement the simple getauxval API in terms of FreeBSD elf_aux_info */
|
||||
static inline u_long getauxval(int which)
|
||||
{
|
||||
u_long toret;
|
||||
if (elf_aux_info(which, &toret, sizeof(toret)) != 0)
|
||||
return 0; /* elf_aux_info didn't work */
|
||||
return toret;
|
||||
}
|
||||
#else
|
||||
/* Implement a stub getauxval which returns no capabilities */
|
||||
static inline u_long getauxval(int which) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* defined __arm__ || defined __aarch64__ */
|
||||
|
||||
#if defined __APPLE__
|
||||
static inline bool test_sysctl_flag(const char *flagname)
|
||||
{
|
||||
#if HAVE_SYSCTLBYNAME
|
||||
int value;
|
||||
size_t size = sizeof(value);
|
||||
return (sysctlbyname(flagname, &value, &size, NULL, 0) == 0 &&
|
||||
size == sizeof(value) && value != 0);
|
||||
#else /* HAVE_SYSCTLBYNAME */
|
||||
return false;
|
||||
#endif /* HAVE_SYSCTLBYNAME */
|
||||
}
|
||||
#endif /* defined __APPLE__ */
|
||||
|
||||
#endif /* PUTTY_ARM_ARCH_QUERIES_H */
|
21
unix/utils/block_signal.c
Normal file
21
unix/utils/block_signal.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Handy function to block or unblock a signal, which does all the
|
||||
* messing about with sigset_t for you.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
void block_signal(int sig, bool block_it)
|
||||
{
|
||||
sigset_t ss;
|
||||
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, sig);
|
||||
if(sigprocmask(block_it ? SIG_BLOCK : SIG_UNBLOCK, &ss, 0) < 0) {
|
||||
perror("sigprocmask");
|
||||
exit(1);
|
||||
}
|
||||
}
|
49
unix/utils/cloexec.c
Normal file
49
unix/utils/cloexec.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Set and clear the FD_CLOEXEC fcntl option on a file descriptor.
|
||||
*
|
||||
* We don't realistically expect these operations to fail (the most
|
||||
* plausible error condition is EBADF, but we always believe ourselves
|
||||
* to be passing a valid fd so even that's an assertion-fail sort of
|
||||
* response), so we don't make any effort to return sensible error
|
||||
* codes to the caller - we just log to standard error and die
|
||||
* unceremoniously.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
void cloexec(int fd)
|
||||
{
|
||||
int fdflags;
|
||||
|
||||
fdflags = fcntl(fd, F_GETFD);
|
||||
if (fdflags < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_GETFD): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC) < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_SETFD): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void noncloexec(int fd)
|
||||
{
|
||||
int fdflags;
|
||||
|
||||
fdflags = fcntl(fd, F_GETFD);
|
||||
if (fdflags < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_GETFD): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (fcntl(fd, F_SETFD, fdflags & ~FD_CLOEXEC) < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_SETFD): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
24
unix/utils/dputs.c
Normal file
24
unix/utils/dputs.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Implementation of dputs() for Unix.
|
||||
*
|
||||
* The debug messages are written to standard output, and also into a
|
||||
* file called debug.log.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
static FILE *debug_fp = NULL;
|
||||
|
||||
void dputs(const char *buf)
|
||||
{
|
||||
if (!debug_fp) {
|
||||
debug_fp = fopen("debug.log", "w");
|
||||
}
|
||||
|
||||
if (write(1, buf, strlen(buf)) < 0) {} /* 'error check' to placate gcc */
|
||||
|
||||
fputs(buf, debug_fp);
|
||||
fflush(debug_fp);
|
||||
}
|
72
unix/utils/filename.c
Normal file
72
unix/utils/filename.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Implementation of Filename for Unix, including f_open().
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
Filename *filename_from_str(const char *str)
|
||||
{
|
||||
Filename *ret = snew(Filename);
|
||||
ret->path = dupstr(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Filename *filename_copy(const Filename *fn)
|
||||
{
|
||||
return filename_from_str(fn->path);
|
||||
}
|
||||
|
||||
const char *filename_to_str(const Filename *fn)
|
||||
{
|
||||
return fn->path;
|
||||
}
|
||||
|
||||
bool filename_equal(const Filename *f1, const Filename *f2)
|
||||
{
|
||||
return !strcmp(f1->path, f2->path);
|
||||
}
|
||||
|
||||
bool filename_is_null(const Filename *fn)
|
||||
{
|
||||
return !fn->path[0];
|
||||
}
|
||||
|
||||
void filename_free(Filename *fn)
|
||||
{
|
||||
sfree(fn->path);
|
||||
sfree(fn);
|
||||
}
|
||||
|
||||
void filename_serialise(BinarySink *bs, const Filename *f)
|
||||
{
|
||||
put_asciz(bs, f->path);
|
||||
}
|
||||
Filename *filename_deserialise(BinarySource *src)
|
||||
{
|
||||
return filename_from_str(get_asciz(src));
|
||||
}
|
||||
|
||||
char filename_char_sanitise(char c)
|
||||
{
|
||||
if (c == '/')
|
||||
return '.';
|
||||
return c;
|
||||
}
|
||||
|
||||
FILE *f_open(const Filename *filename, char const *mode, bool is_private)
|
||||
{
|
||||
if (!is_private) {
|
||||
return fopen(filename->path, mode);
|
||||
} else {
|
||||
int fd;
|
||||
assert(mode[0] == 'w'); /* is_private is meaningless for read,
|
||||
and tricky for append */
|
||||
fd = open(filename->path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
return fdopen(fd, mode);
|
||||
}
|
||||
}
|
35
unix/utils/fontspec.c
Normal file
35
unix/utils/fontspec.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Implementation of FontSpec for Unix. This is more or less
|
||||
* degenerate - on this platform a font specification is just a
|
||||
* string.
|
||||
*/
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
FontSpec *fontspec_new(const char *name)
|
||||
{
|
||||
FontSpec *f = snew(FontSpec);
|
||||
f->name = dupstr(name);
|
||||
return f;
|
||||
}
|
||||
|
||||
FontSpec *fontspec_copy(const FontSpec *f)
|
||||
{
|
||||
return fontspec_new(f->name);
|
||||
}
|
||||
|
||||
void fontspec_free(FontSpec *f)
|
||||
{
|
||||
sfree(f->name);
|
||||
sfree(f);
|
||||
}
|
||||
|
||||
void fontspec_serialise(BinarySink *bs, FontSpec *f)
|
||||
{
|
||||
put_asciz(bs, f->name);
|
||||
}
|
||||
|
||||
FontSpec *fontspec_deserialise(BinarySource *src)
|
||||
{
|
||||
return fontspec_new(get_asciz(src));
|
||||
}
|
52
unix/utils/get_username.c
Normal file
52
unix/utils/get_username.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Implementation of get_username() for Unix.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
char *get_username(void)
|
||||
{
|
||||
struct passwd *p;
|
||||
uid_t uid = getuid();
|
||||
char *user, *ret = NULL;
|
||||
|
||||
/*
|
||||
* First, find who we think we are using getlogin. If this
|
||||
* agrees with our uid, we'll go along with it. This should
|
||||
* allow sharing of uids between several login names whilst
|
||||
* coping correctly with people who have su'ed.
|
||||
*/
|
||||
user = getlogin();
|
||||
#if HAVE_SETPWENT
|
||||
setpwent();
|
||||
#endif
|
||||
if (user)
|
||||
p = getpwnam(user);
|
||||
else
|
||||
p = NULL;
|
||||
if (p && p->pw_uid == uid) {
|
||||
/*
|
||||
* The result of getlogin() really does correspond to
|
||||
* our uid. Fine.
|
||||
*/
|
||||
ret = user;
|
||||
} else {
|
||||
/*
|
||||
* If that didn't work, for whatever reason, we'll do
|
||||
* the simpler version: look up our uid in the password
|
||||
* file and map it straight to a name.
|
||||
*/
|
||||
p = getpwuid(uid);
|
||||
if (!p)
|
||||
return NULL;
|
||||
ret = p->pw_name;
|
||||
}
|
||||
#if HAVE_ENDPWENT
|
||||
endpwent();
|
||||
#endif
|
||||
|
||||
return dupstr(ret);
|
||||
}
|
33
unix/utils/getticks.c
Normal file
33
unix/utils/getticks.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Implement getticks() for Unix.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
unsigned long getticks(void)
|
||||
{
|
||||
/*
|
||||
* We want to use milliseconds rather than the microseconds or
|
||||
* nanoseconds given by the underlying clock functions, because we
|
||||
* need a decent number of them to fit into a 32-bit word so it
|
||||
* can be used for keepalives.
|
||||
*/
|
||||
#if HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC
|
||||
{
|
||||
/* Use CLOCK_MONOTONIC if available, so as to be unconfused if
|
||||
* the system clock changes. */
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
||||
return ts.tv_sec * TICKSPERSEC +
|
||||
ts.tv_nsec / (1000000000 / TICKSPERSEC);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec * TICKSPERSEC + tv.tv_usec / (1000000 / TICKSPERSEC);
|
||||
}
|
||||
}
|
1011
unix/utils/keysym_to_unicode.c
Normal file
1011
unix/utils/keysym_to_unicode.c
Normal file
File diff suppressed because it is too large
Load Diff
60
unix/utils/make_dir_and_check_ours.c
Normal file
60
unix/utils/make_dir_and_check_ours.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Create a directory accessible only to us, and then check afterwards
|
||||
* that we really did end up with a directory with the right ownership
|
||||
* and permissions.
|
||||
*
|
||||
* The idea is that this is a directory in which we're about to create
|
||||
* something sensitive, like a listening Unix-domain socket for SSH
|
||||
* connection sharing or an SSH agent. We want to be protected against
|
||||
* somebody else previously having created the directory in a way
|
||||
* that's writable to us, and thus manipulating us into creating the
|
||||
* actual socket in a directory they can see so that they can connect
|
||||
* to it and (say) use our authenticated SSH sessions.
|
||||
*
|
||||
* NOTE: The strategy used in this function is not safe if the enemy
|
||||
* has unrestricted write access to the containing directory. In that
|
||||
* case, they could move our directory out of the way and make a new
|
||||
* one, after this function returns and before we create our socket
|
||||
* (or whatever) inside it.
|
||||
*
|
||||
* But this should be OK for temp directories (which modify the
|
||||
* default world-write behaviour by also setting the 't' bit,
|
||||
* preventing people from renaming or deleting things in there that
|
||||
* they don't own). And of course it's also safe if the directory is
|
||||
* writable only by our _own_ uid.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
char *make_dir_and_check_ours(const char *dirname)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
/*
|
||||
* Create the directory. We might have created it before, so
|
||||
* EEXIST is an OK error; but anything else is doom.
|
||||
*/
|
||||
if (mkdir(dirname, 0700) < 0 && errno != EEXIST)
|
||||
return dupprintf("%s: mkdir: %s", dirname, strerror(errno));
|
||||
|
||||
/*
|
||||
* Stat the directory and check its ownership and permissions.
|
||||
*/
|
||||
if (stat(dirname, &st) < 0)
|
||||
return dupprintf("%s: stat: %s", dirname, strerror(errno));
|
||||
if (st.st_uid != getuid())
|
||||
return dupprintf("%s: directory owned by uid %d, not by us",
|
||||
dirname, st.st_uid);
|
||||
if ((st.st_mode & 077) != 0)
|
||||
return dupprintf("%s: directory has overgenerous permissions %03o"
|
||||
" (expected 700)", dirname, st.st_mode & 0777);
|
||||
|
||||
return NULL;
|
||||
}
|
39
unix/utils/make_dir_path.c
Normal file
39
unix/utils/make_dir_path.c
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Make a path of subdirectories, tolerating EEXIST at every step.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
char *make_dir_path(const char *path, mode_t mode)
|
||||
{
|
||||
int pos = 0;
|
||||
char *prefix;
|
||||
|
||||
while (1) {
|
||||
pos += strcspn(path + pos, "/");
|
||||
|
||||
if (pos > 0) {
|
||||
prefix = dupprintf("%.*s", pos, path);
|
||||
|
||||
if (mkdir(prefix, mode) < 0 && errno != EEXIST) {
|
||||
char *ret = dupprintf("%s: mkdir: %s",
|
||||
prefix, strerror(errno));
|
||||
sfree(prefix);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sfree(prefix);
|
||||
}
|
||||
|
||||
if (!path[pos])
|
||||
return NULL;
|
||||
pos += strspn(path + pos, "/");
|
||||
}
|
||||
}
|
55
unix/utils/nonblock.c
Normal file
55
unix/utils/nonblock.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Set and clear the O_NONBLOCK fcntl option on an open file.
|
||||
*
|
||||
* We don't realistically expect these operations to fail (the most
|
||||
* plausible error condition is EBADF, but we always believe ourselves
|
||||
* to be passing a valid fd so even that's an assertion-fail sort of
|
||||
* response), so we don't make any effort to return sensible error
|
||||
* codes to the caller - we just log to standard error and die
|
||||
* unceremoniously.
|
||||
*
|
||||
* Returns the previous state of O_NONBLOCK.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
bool nonblock(int fd)
|
||||
{
|
||||
int fdflags;
|
||||
|
||||
fdflags = fcntl(fd, F_GETFL);
|
||||
if (fdflags < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_GETFL): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, fdflags | O_NONBLOCK) < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_SETFL): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return fdflags & O_NONBLOCK;
|
||||
}
|
||||
|
||||
bool no_nonblock(int fd)
|
||||
{
|
||||
int fdflags;
|
||||
|
||||
fdflags = fcntl(fd, F_GETFL);
|
||||
if (fdflags < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_GETFL): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) {
|
||||
fprintf(stderr, "%d: fcntl(F_SETFL): %s\n", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return fdflags & O_NONBLOCK;
|
||||
}
|
44
unix/utils/open_for_write_would_lose_data.c
Normal file
44
unix/utils/open_for_write_would_lose_data.c
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Unix implementation of open_for_write_would_lose_data().
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
bool open_for_write_would_lose_data(const Filename *fn)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(fn->path, &st) < 0) {
|
||||
/*
|
||||
* If the file doesn't even exist, we obviously want to return
|
||||
* false. If we failed to stat it for any other reason,
|
||||
* ignoring the precise error code and returning false still
|
||||
* doesn't seem too unreasonable, because then we'll try to
|
||||
* open the file for writing and report _that_ error, which is
|
||||
* likely to be more to the point.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, something exists at this pathname and we've found out
|
||||
* something about it. But an open-for-write will only
|
||||
* destructively truncate it if it's a regular file with nonzero
|
||||
* size. If it's empty, or some other kind of special thing like a
|
||||
* character device (e.g. /dev/tty) or a named pipe, then opening
|
||||
* it for write is already non-destructive and it's pointless and
|
||||
* annoying to warn about it just because the same file can be
|
||||
* opened for reading. (Indeed, if it's a named pipe, opening it
|
||||
* for reading actually _causes inconvenience_ in its own right,
|
||||
* even before the question of whether it gives misleading
|
||||
* information.)
|
||||
*/
|
||||
if (S_ISREG(st.st_mode) && st.st_size > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
23
unix/utils/pgp_fingerprints.c
Normal file
23
unix/utils/pgp_fingerprints.c
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Display the fingerprints of the PGP Master Keys to the user.
|
||||
*
|
||||
* (This is in its own file rather than in uxcons.c, because it's
|
||||
* appropriate even for Unix GUI apps.)
|
||||
*/
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
void pgp_fingerprints(void)
|
||||
{
|
||||
fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
|
||||
"be used to establish a trust path from this executable to another\n"
|
||||
"one. See the manual for more information.\n"
|
||||
"(Note: these fingerprints have nothing to do with SSH!)\n"
|
||||
"\n"
|
||||
"PuTTY Master Key as of " PGP_MASTER_KEY_YEAR
|
||||
" (" PGP_MASTER_KEY_DETAILS "):\n"
|
||||
" " PGP_MASTER_KEY_FP "\n\n"
|
||||
"Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR
|
||||
", " PGP_PREV_MASTER_KEY_DETAILS "):\n"
|
||||
" " PGP_PREV_MASTER_KEY_FP "\n", stdout);
|
||||
}
|
190
unix/utils/pollwrap.c
Normal file
190
unix/utils/pollwrap.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Wrapper system around poll() that lets me treat it more or less
|
||||
* like select(), but avoiding the inherent limitation of select()
|
||||
* that it can't handle the full range of fds that are capable of
|
||||
* existing.
|
||||
*
|
||||
* The pollwrapper structure contains the 'struct pollfd' array passed
|
||||
* to poll() itself, and also a tree234 that maps each fd to its
|
||||
* location in the list, which makes it convenient to add or remove
|
||||
* individual fds from the system or change what events you're
|
||||
* watching for on them. So the API is _shaped_ basically like select,
|
||||
* even if none of the details are identical: from outside this
|
||||
* module, a pollwrapper can be used wherever you'd otherwise have had
|
||||
* an fd_set.
|
||||
*
|
||||
* Also, this module translate between the simple select r/w/x
|
||||
* classification and the richer poll flags. We have to stick to r/w/x
|
||||
* in this code base, because it ports to other systems where that's
|
||||
* all you get.
|
||||
*/
|
||||
|
||||
/* On some systems this is needed to get poll.h to define eg.. POLLRDNORM */
|
||||
#define _XOPEN_SOURCE
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "tree234.h"
|
||||
|
||||
struct pollwrapper {
|
||||
struct pollfd *fds;
|
||||
size_t nfd, fdsize;
|
||||
tree234 *fdtopos;
|
||||
};
|
||||
|
||||
typedef struct pollwrap_fdtopos pollwrap_fdtopos;
|
||||
struct pollwrap_fdtopos {
|
||||
int fd;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
static int pollwrap_fd_cmp(void *av, void *bv)
|
||||
{
|
||||
pollwrap_fdtopos *a = (pollwrap_fdtopos *)av;
|
||||
pollwrap_fdtopos *b = (pollwrap_fdtopos *)bv;
|
||||
return a->fd < b->fd ? -1 : a->fd > b->fd ? +1 : 0;
|
||||
}
|
||||
|
||||
pollwrapper *pollwrap_new(void)
|
||||
{
|
||||
pollwrapper *pw = snew(pollwrapper);
|
||||
pw->fdsize = 16;
|
||||
pw->nfd = 0;
|
||||
pw->fds = snewn(pw->fdsize, struct pollfd);
|
||||
pw->fdtopos = newtree234(pollwrap_fd_cmp);
|
||||
return pw;
|
||||
}
|
||||
|
||||
void pollwrap_free(pollwrapper *pw)
|
||||
{
|
||||
pollwrap_clear(pw);
|
||||
freetree234(pw->fdtopos);
|
||||
sfree(pw->fds);
|
||||
sfree(pw);
|
||||
}
|
||||
|
||||
void pollwrap_clear(pollwrapper *pw)
|
||||
{
|
||||
pw->nfd = 0;
|
||||
for (pollwrap_fdtopos *f2p;
|
||||
(f2p = delpos234(pw->fdtopos, 0)) != NULL ;)
|
||||
sfree(f2p);
|
||||
}
|
||||
|
||||
void pollwrap_add_fd_events(pollwrapper *pw, int fd, int events)
|
||||
{
|
||||
pollwrap_fdtopos *f2p, f2p_find;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
f2p_find.fd = fd;
|
||||
f2p = find234(pw->fdtopos, &f2p_find, NULL);
|
||||
if (!f2p) {
|
||||
sgrowarray(pw->fds, pw->fdsize, pw->nfd);
|
||||
size_t index = pw->nfd++;
|
||||
pw->fds[index].fd = fd;
|
||||
pw->fds[index].events = pw->fds[index].revents = 0;
|
||||
|
||||
f2p = snew(pollwrap_fdtopos);
|
||||
f2p->fd = fd;
|
||||
f2p->pos = index;
|
||||
pollwrap_fdtopos *added = add234(pw->fdtopos, f2p);
|
||||
assert(added == f2p);
|
||||
}
|
||||
|
||||
pw->fds[f2p->pos].events |= events;
|
||||
}
|
||||
|
||||
/* Omit any of the POLL{RD,WR}{NORM,BAND} flag values that are still
|
||||
* not defined by poll.h, just in case */
|
||||
#ifndef POLLRDNORM
|
||||
#define POLLRDNORM 0
|
||||
#endif
|
||||
#ifndef POLLRDBAND
|
||||
#define POLLRDBAND 0
|
||||
#endif
|
||||
#ifndef POLLWRNORM
|
||||
#define POLLWRNORM 0
|
||||
#endif
|
||||
#ifndef POLLWRBAND
|
||||
#define POLLWRBAND 0
|
||||
#endif
|
||||
|
||||
#define SELECT_R_IN (POLLIN | POLLRDNORM | POLLRDBAND)
|
||||
#define SELECT_W_IN (POLLOUT | POLLWRNORM | POLLWRBAND)
|
||||
#define SELECT_X_IN (POLLPRI)
|
||||
|
||||
#define SELECT_R_OUT (SELECT_R_IN | POLLERR | POLLHUP)
|
||||
#define SELECT_W_OUT (SELECT_W_IN | POLLERR)
|
||||
#define SELECT_X_OUT (SELECT_X_IN)
|
||||
|
||||
void pollwrap_add_fd_rwx(pollwrapper *pw, int fd, int rwx)
|
||||
{
|
||||
int events = 0;
|
||||
if (rwx & SELECT_R)
|
||||
events |= SELECT_R_IN;
|
||||
if (rwx & SELECT_W)
|
||||
events |= SELECT_W_IN;
|
||||
if (rwx & SELECT_X)
|
||||
events |= SELECT_X_IN;
|
||||
pollwrap_add_fd_events(pw, fd, events);
|
||||
}
|
||||
|
||||
int pollwrap_poll_instant(pollwrapper *pw)
|
||||
{
|
||||
return poll(pw->fds, pw->nfd, 0);
|
||||
}
|
||||
|
||||
int pollwrap_poll_endless(pollwrapper *pw)
|
||||
{
|
||||
return poll(pw->fds, pw->nfd, -1);
|
||||
}
|
||||
|
||||
int pollwrap_poll_timeout(pollwrapper *pw, int milliseconds)
|
||||
{
|
||||
assert(milliseconds >= 0);
|
||||
return poll(pw->fds, pw->nfd, milliseconds);
|
||||
}
|
||||
|
||||
static void pollwrap_get_fd_events_revents(pollwrapper *pw, int fd,
|
||||
int *events_p, int *revents_p)
|
||||
{
|
||||
pollwrap_fdtopos *f2p, f2p_find;
|
||||
int events = 0, revents = 0;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
f2p_find.fd = fd;
|
||||
f2p = find234(pw->fdtopos, &f2p_find, NULL);
|
||||
if (f2p) {
|
||||
events = pw->fds[f2p->pos].events;
|
||||
revents = pw->fds[f2p->pos].revents;
|
||||
}
|
||||
|
||||
if (events_p)
|
||||
*events_p = events;
|
||||
if (revents_p)
|
||||
*revents_p = revents;
|
||||
}
|
||||
|
||||
int pollwrap_get_fd_events(pollwrapper *pw, int fd)
|
||||
{
|
||||
int revents;
|
||||
pollwrap_get_fd_events_revents(pw, fd, NULL, &revents);
|
||||
return revents;
|
||||
}
|
||||
|
||||
int pollwrap_get_fd_rwx(pollwrapper *pw, int fd)
|
||||
{
|
||||
int events, revents;
|
||||
pollwrap_get_fd_events_revents(pw, fd, &events, &revents);
|
||||
int rwx = 0;
|
||||
if ((events & POLLIN) && (revents & SELECT_R_OUT))
|
||||
rwx |= SELECT_R;
|
||||
if ((events & POLLOUT) && (revents & SELECT_W_OUT))
|
||||
rwx |= SELECT_W;
|
||||
if ((events & POLLPRI) && (revents & SELECT_X_OUT))
|
||||
rwx |= SELECT_X;
|
||||
return rwx;
|
||||
}
|
30
unix/utils/signal.c
Normal file
30
unix/utils/signal.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* PuTTY's wrapper on signal(2).
|
||||
*
|
||||
* Calling signal() is non-portable, as it varies in meaning between
|
||||
* platforms and depending on feature macros, and has stupid semantics
|
||||
* at least some of the time.
|
||||
*
|
||||
* This function provides the same interface as the libc function, but
|
||||
* provides consistent semantics. It assumes POSIX semantics for
|
||||
* sigaction() (so you might need to do some more work if you port to
|
||||
* something ancient like SunOS 4).
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
void (*putty_signal(int sig, void (*func)(int)))(int)
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct sigaction old;
|
||||
|
||||
sa.sa_handler = func;
|
||||
if(sigemptyset(&sa.sa_mask) < 0)
|
||||
return SIG_ERR;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
if(sigaction(sig, &sa, &old) < 0)
|
||||
return SIG_ERR;
|
||||
return old.sa_handler;
|
||||
}
|
88
unix/utils/x11_ignore_error.c
Normal file
88
unix/utils/x11_ignore_error.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Error handling mechanism which permits us to ignore specific X11
|
||||
* errors from particular requests. We maintain a list of upcoming
|
||||
* potential error events that we want to not treat as fatal errors.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
#ifndef NOT_X_WINDOWS
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "x11misc.h"
|
||||
|
||||
static int (*orig_x11_error_handler)(Display *thisdisp, XErrorEvent *err);
|
||||
|
||||
struct x11_err_to_ignore {
|
||||
Display *display;
|
||||
unsigned char error_code;
|
||||
unsigned long serial;
|
||||
};
|
||||
|
||||
static struct x11_err_to_ignore *errs;
|
||||
static size_t nerrs, errsize;
|
||||
|
||||
static int x11_error_handler(Display *thisdisp, XErrorEvent *err)
|
||||
{
|
||||
for (size_t i = 0; i < nerrs; i++) {
|
||||
if (thisdisp == errs[i].display &&
|
||||
err->serial == errs[i].serial &&
|
||||
err->error_code == errs[i].error_code) {
|
||||
/* Ok, this is an error we're happy to ignore */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (*orig_x11_error_handler)(thisdisp, err);
|
||||
}
|
||||
|
||||
void x11_ignore_error(Display *disp, unsigned char errcode)
|
||||
{
|
||||
/*
|
||||
* Install our error handler, if we haven't already.
|
||||
*/
|
||||
if (!orig_x11_error_handler)
|
||||
orig_x11_error_handler = XSetErrorHandler(x11_error_handler);
|
||||
|
||||
/*
|
||||
* This is as good a moment as any to winnow the ignore list based
|
||||
* on requests we know to have been processed.
|
||||
*/
|
||||
{
|
||||
unsigned long last = LastKnownRequestProcessed(disp);
|
||||
size_t i, j;
|
||||
for (i = j = 0; i < nerrs; i++) {
|
||||
if (errs[i].display == disp && errs[i].serial <= last)
|
||||
continue;
|
||||
errs[j++] = errs[i];
|
||||
}
|
||||
nerrs = j;
|
||||
}
|
||||
|
||||
sgrowarray(errs, errsize, nerrs);
|
||||
errs[nerrs].display = disp;
|
||||
errs[nerrs].error_code = errcode;
|
||||
errs[nerrs].serial = NextRequest(disp);
|
||||
nerrs++;
|
||||
}
|
||||
|
||||
#else /* NOT_X_WINDOWS */
|
||||
|
||||
/*
|
||||
* Include _something_ in this file to prevent an annoying compiler
|
||||
* warning, and to avoid having to condition out this file in
|
||||
* CMakeLists. It's in a library, so this variable shouldn't end up in
|
||||
* any actual program, because nothing will refer to it.
|
||||
*/
|
||||
const int x11_ignore_error_dummy_variable = 0;
|
||||
|
||||
#endif /* NOT_X_WINDOWS */
|
Reference in New Issue
Block a user