aboutsummaryrefslogblamecommitdiffstats
path: root/key2root-lskeys.c
blob: a25b32de0f5758a334d5e53b95ac016afc6068de (plain) (tree)
1
2
3
4
5
6
7
8
                                                         


                   

                   

                   














                                                         















                                                                                                       
                                                                                                             


                                                
                                                                                                               




























                                                        
                                                                                                           


















                                                                                                     
                            
                                                                                                       








                                                                                         
                             
                           


                                                                                                                       
         





                      


                            



                           




                        
                   
                                              


                                            
                                                                                                      











                                                                                                           
                                          


                                            
                                                                                                  










                                                                          
                                                                                                  








                                                                           
 
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "arg.h"


char *argv0;


static void
usage(void)
{
	fprintf(stderr, "usage: %s [user] ...\n", argv0);
	exit(1);
}


static int
outputkey(char *data, size_t whead, size_t *rheadp, size_t *rhead2p, size_t *linenop, const char *user)
{
	int failed = 0;
	size_t len;

	while (*rhead2p < whead || data[*rhead2p] != '\n')
		++*rhead2p;

	if (data[*rhead2p] != '\n')
		return 0;

	len = *rhead2p - *rheadp;
	*linenop += 1;

	if (memchr(&data[*rheadp], '\0', len)) {
		fprintf(stderr, "%s: NUL byte found in %s/%s on line %zu\n", argv0, KEYPATH, user, *linenop);
		failed = 1;
	}
	if (!memchr(&data[*rheadp], ' ', len)) {
		fprintf(stderr, "%s: no SP byte found in %s/%s on line %zu\n", argv0, KEYPATH, user, *linenop);
		failed = 1;
	}

	if (!failed) {
		data[*rhead2p] = '\0';
		printf("%s %s\n", user, &data[*rheadp]);
	}

	*rheadp = ++*rhead2p;
	return failed;
}


static int
listkeys(int dir, const char *user)
{
	int fd, failed = 0;
	char *data = NULL, *new;
	size_t size = 0;
	size_t whead = 0;
	size_t rhead = 0;
	size_t rhead2 = 0;
	size_t lineno = 0;
	ssize_t r = 1;

	fd = openat(dir, user, O_RDONLY);
	if (fd < 0) {
		if (errno == ENOENT)
			return 0;
		fprintf(stderr, "%s: openat %s/ %s O_RDONLY: %s\n", argv0, KEYPATH, user, strerror(errno));
		return 1;
	}

	while (r) {
		if (whead == size) {
			memmove(data, &data[rhead], whead -= rhead);
			rhead2 -= rhead;
			rhead = 0;
			if (whead == size) {
				new = realloc(data, size += 1024);
				if (!new) {
					fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
					close(fd);
					return 1;
				}
				data = new;
			}
		}
		r = read(fd, &data[whead], size - whead);
		if (r < 0) {
			fprintf(stderr, "%s: read %s/%s: %s\n", argv0, KEYPATH, user, strerror(errno));
			close(fd);
			return 1;
		}
		whead += (size_t)r;

		while (rhead2 < whead)
			failed |= outputkey(data, whead, &rhead, &rhead2, &lineno, user);
	}

	if (rhead != whead) {
		failed = 1;
		fprintf(stderr, "%s: file truncated: %s/%s\n", argv0, KEYPATH, user);
		if (memchr(&data[rhead], '\0', whead - rhead))
			fprintf(stderr, "%s: NUL byte found in %s/%s on line %zu\n", argv0, KEYPATH, user, lineno + 1);
	}

	close(fd);
	return failed;
}


int
main(int argc, char *argv[])
{
	int failed = 0, fd;
	DIR *dir;
	struct dirent *f;

	ARGBEGIN {
	default:
		usage();
	} ARGEND;

	if (argc) {
		fd = open(KEYPATH"/", O_PATH);
		if (fd < 0) {
			if (errno == ENOENT)
				return 0;
			fprintf(stderr, "%s: open %s/ O_PATH: %s\n", argv0, KEYPATH, strerror(errno));
			exit(1);
		}
		for (; *argv; argv++) {
			if (!(*argv)[0] || (*argv)[0] == '.' || strchr(*argv, '/') || strchr(*argv, '~')) {
				fprintf(stderr, "%s: bad user name specified: %s\n", argv0, *argv);
				failed = 1;
			} else {
				failed |= listkeys(fd, *argv);
			}
		}
		close(fd);
	} else {
		dir = opendir(KEYPATH"/");
		if (!dir) {
			if (errno == ENOENT)
				return 0;
			fprintf(stderr, "%s: opendir %s/: %s\n", argv0, KEYPATH, strerror(errno));
			exit(1);
		}
		fd = dirfd(dir);
		if (fd < 0)
			abort();
		while ((errno = 0, f = readdir(dir))) {
			if (f->d_name[0] == '.' || strchr(f->d_name, '~'))
				continue;
			listkeys(fd, f->d_name);
		}
		if (errno || closedir(dir)) {
			fprintf(stderr, "%s: readdir %s/: %s\n", argv0, KEYPATH, strerror(errno));
			exit(1);
		}
	}

	if (fflush(stdout) || ferror(stdout) || fclose(stdout)) {
		fprintf(stderr, "%s: print: %s\n", argv0, strerror(errno));
		exit(1);
	}
	return failed;
}