finger

finger fortune@hhvn.uk
Log | Files | Refs | LICENSE

commit 2a49d14fd2c0c0dee69084fde6f8ab8716cd235d
Author: hhvn <dev@hhvn.uk>
Date:   Sun,  6 Jun 2021 16:17:16 +0100

finger.c makefile arg.h strlcpy.c: init

Diffstat:
Aarg.h | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afinger.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amakefile | 24++++++++++++++++++++++++
Astrlcpy.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 296 insertions(+), 0 deletions(-)

diff --git a/arg.h b/arg.h @@ -0,0 +1,70 @@ +/* + * Copy me if you can. + * by 20h + * + * 2012-2016 Christoph Lohmann <20h at r-36 dot net> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + int i_;\ + for (i_ = 1, brk_ = 0, argv_ = argv;\ + argv[0][i_] && !brk_;\ + i_++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][i_];\ + switch (argc_) + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][i_+1] != '\0')?\ + (&argv[0][i_+1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][i_+1] != '\0')?\ + (&argv[0][i_+1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/finger.c b/finger.c @@ -0,0 +1,150 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <libgen.h> +#include <unistd.h> +#include <netdb.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include "arg.h" + +#define EXIT_USAGE 2 +#define USER_DFLT "" +#define HOST_DFLT "localhost" +#define PORT_DFLT "79" + +enum { ISUSER, ISHOST, ISPORT }; + +char *argv0; +int verbose = 0; + +void +usage(void) { + fprintf(stderr, "usage: %s [-lv] [user]@[host[:port]] ...\n", basename(argv0)); + exit(EXIT_USAGE); +} + +int +die(const int exitc, const char *format, ...) { + va_list ap; + + va_start(ap, format); + fprintf(stderr, "Fatal: "); + vfprintf(stderr, format, ap); + va_end(ap); + + exit(exitc); +} + +int +read_line(int fd, char *dest, size_t len) { + size_t i = 0; + char c = 0; + + do { + if (read(fd, &c, sizeof(char)) != sizeof(char)) + return 0; + if (c != '\r') + dest[i++] = c; + } while (c != '\n' && i < len); + + dest[i-1] = '\0'; + return 1; +} + +void +finger(char *user, char *host, char *port, int w) { + struct addrinfo hints; + struct addrinfo *ai; + char buf[1024]; + int sret, sock; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if ((sret = getaddrinfo(host, port, &hints, &ai)) != 0 || ai == NULL) + die(1, "%s%s\n", verbose ? "getaddrinfo(): " : "", gai_strerror(sret)); + if ((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == 1) + die(1, "%s%s\n", verbose ? "socket(): " : "", strerror(errno)); + if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) + die(1, "%s%s\n", verbose ? "connect(): " : "", strerror(errno)); + + if (strcmp(port, "79") == 0) + printf("[%s@%s]\n", user, host); + else + printf("[%s@%s:%s]\n", user, host, port); + + dprintf(sock, "%s\r\n", user); + while (read_line(sock, buf, sizeof(buf)) != 0) + printf("%s\n", buf); + return; +} + +int +main(int argc, char *argv[]) { + char user[128], + host[128], + port[128]; + int sendw = 0; + int segment; + int i, j, k; + + ARGBEGIN { + case 'l': + sendw = 1; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + } ARGEND; + + if (argc < 1) + die(1, "no targets specified\n"); + + for (i=0; i < argc; i++) { + segment = ISUSER; + for (j=k=0; argv[i] && argv[i][k]; j++, k++) { + switch (segment) { + case ISUSER: + if (argv[i][k] == '@') { + if (argv[i][k+1] == '\0' || argv[i][k+1] == ':') + die(1, "missing hostname in: %s\n", argv[i]); + user[j] = '\0'; + segment++; + j = -1; + } else { + user[j] = argv[i][k]; + } + break; + case ISHOST: + if (argv[i][k] == ':') { + if (argv[i][k+1] == '\0') + die(1, "missing port in: %s\n", argv[i]); + host[j] = '\0'; + segment++; + j = -1; + } else { + host[j] = argv[i][k]; + } + break; + case ISPORT: + port[j] = argv[i][k]; + } + } + + /* set defaults */ + switch (segment) { + case ISUSER: strlcpy(host, HOST_DFLT, sizeof(host)); + case ISHOST: strlcpy(port, PORT_DFLT, sizeof(port)); + } + + finger(user, host, port, sendw); + } + + return EXIT_SUCCESS; +} diff --git a/makefile b/makefile @@ -0,0 +1,24 @@ +PREFIX = /usr/local +CC ?= cc +OBJ = finger.o strlcpy.o +BIN = finger +COMMIT = `git log HEAD...HEAD~1 --pretty=format:%h` + +$(BIN): $(OBJ) + $(CC) -g $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) + +.c.o: + $(CC) -g $(CFLAGS) $(LDFLAGS) -o $@ -c $< + +clean: + rm $(BIN) $(OBJ) + +install: $(BIN) + install -m0755 $(BIN) $(PREFIX)/bin/$(BIN) + sed "s/COMMIT/$(COMMIT)/" \ + < $(BIN).8 \ + > $(PREFIX)/share/man/man8/$(BIN).8 + +uninstall: + -rm $(PREFIX)/bin/$(BIN) + -rm $(PREFIX)/share/man/man8/$(BIN).8 diff --git a/strlcpy.c b/strlcpy.c @@ -0,0 +1,52 @@ +#ifndef __OpenBSD__ +/* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <string.h> + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} +#endif