]> git.draconx.ca Git - scripts.git/blob - cmdwrap.c
Add script to convert "JWK"-format RSA keys to normal.
[scripts.git] / cmdwrap.c
1 /* Copyright (C) 2010 Nick Bowler
2  *
3  * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
4  * This is free software: you are free to do what the fuck you want to.
5  * There is NO WARRANTY, to the extent permitted by law.
6  *
7  * Putting . in PATH is generally not a good idea, for a variety of reasons.
8  * However, some programs expect it to be there, and do not function correctly
9  * without it.  This program allows one to invoke specific programs in the
10  * current working directory as though . was in the PATH without it actually
11  * being there.
12  *
13  * To work, place a copy of (or symlink to) this program somewhere that is
14  * actually in the PATH.  The name of the command determines what program
15  * gets invoked.  Basic checks are done to avoid accidental infinite
16  * recursion.
17  *
18  * This is probably not portable to non-GNU/Linux systems.
19  */
20
21 #define _GNU_SOURCE
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <limits.h>
26 #include <errno.h>
27
28 #include <unistd.h>
29 #include <fcntl.h>
30
31 /* Common shell return codes */
32 #define SHELL_CMD_NOT_FOUND 127
33 #define SHELL_CMD_NOT_EXEC  126
34
35 /*
36  * A wrapper around readlink which dynamically allocates a buffer large
37  * enough to contain the entire filename.  Also add a null terminator
38  * so that the filename can be used as a C string.
39  */
40 char *readlink_alloc(const char *path)
41 {
42         ssize_t bufsize = 64, rc;
43         char *buf = NULL, *tmp;
44
45         while (1) {
46                 if (bufsize >= SSIZE_MAX/2) {
47                         fprintf(stderr, "cmdwrap: %s: %s\n",
48                                         path, strerror(ENAMETOOLONG));
49                         break;
50                 }
51
52                 tmp = realloc(buf, bufsize * 2);
53                 if (!tmp) {
54                         fprintf(stderr, "cmdwrap: %s\n", strerror(errno));
55                         break;
56                 }
57
58                 bufsize *= 2;
59                 buf = tmp;
60
61                 rc = readlink(path, buf, bufsize);
62                 if (rc == -1) {
63                         fprintf(stderr, "cmdwrap: %s: %s\n",
64                                         path, strerror(errno));
65                         break;
66                 } else if (rc < bufsize) {
67                         buf[rc] = 0;
68                         return buf;
69                 }
70         }
71
72         free(buf);
73         return NULL;
74 }
75
76 int main(int argc, char **argv)
77 {
78         char *curexe, *newexe, fdname[64];
79         int fd;
80
81         if (argc < 1) {
82                 fprintf(stderr, "cmdwrap: command name must be present in the argument list.\n");
83                 return SHELL_CMD_NOT_FOUND;
84         }
85
86         fd = open(argv[0], O_RDONLY);
87         if (fd == -1) {
88                 fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno));
89                 return SHELL_CMD_NOT_FOUND;
90         }
91
92         /* Try to avoid accidental infinite recursion. */
93         sprintf(fdname, "/proc/self/fd/%d", fd);
94         newexe = readlink_alloc(fdname);
95         if (!newexe)
96                 return SHELL_CMD_NOT_FOUND;
97
98         curexe = readlink_alloc("/proc/self/exe");
99         if (!curexe)
100                 return SHELL_CMD_NOT_FOUND;
101
102         if (strcmp(newexe, curexe) == 0) {
103                 fprintf(stderr, "cmdwrap: infinite recursion detected\n");
104                 return SHELL_CMD_NOT_EXEC;
105         }
106
107         /*
108          * Some programs expect argv[0] to point to their actual executable
109          * (potentially after a path lookup).  But if we leave argv[0] as it
110          * is, they'll tend to find this program instead of the right one.
111          *
112          * Fix that up, too.
113          */
114         argv[0] = newexe;
115         free(curexe);
116
117         fexecve(fd, argv, environ);
118         fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno));
119         return SHELL_CMD_NOT_EXEC;
120 }