1 /* Copyright (C) 2010 Nick Bowler
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.
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
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
18 * This is probably not portable to non-GNU/Linux systems.
31 /* Common shell return codes */
32 #define SHELL_CMD_NOT_FOUND 127
33 #define SHELL_CMD_NOT_EXEC 126
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.
40 char *readlink_alloc(const char *path)
42 ssize_t bufsize = 64, rc;
43 char *buf = NULL, *tmp;
46 if (bufsize >= SSIZE_MAX/2) {
47 fprintf(stderr, "cmdwrap: %s: %s\n",
48 path, strerror(ENAMETOOLONG));
52 tmp = realloc(buf, bufsize * 2);
54 fprintf(stderr, "cmdwrap: %s\n", strerror(errno));
61 rc = readlink(path, buf, bufsize);
63 fprintf(stderr, "cmdwrap: %s: %s\n",
64 path, strerror(errno));
66 } else if (rc < bufsize) {
76 int main(int argc, char **argv)
78 char *curexe, *newexe, fdname[64];
82 fprintf(stderr, "cmdwrap: command name must be present in the argument list.\n");
83 return SHELL_CMD_NOT_FOUND;
86 fd = open(argv[0], O_RDONLY);
88 fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno));
89 return SHELL_CMD_NOT_FOUND;
92 /* Try to avoid accidental infinite recursion. */
93 sprintf(fdname, "/proc/self/fd/%d", fd);
94 newexe = readlink_alloc(fdname);
96 return SHELL_CMD_NOT_FOUND;
98 curexe = readlink_alloc("/proc/self/exe");
100 return SHELL_CMD_NOT_FOUND;
102 if (strcmp(newexe, curexe) == 0) {
103 fprintf(stderr, "cmdwrap: infinite recursion detected\n");
104 return SHELL_CMD_NOT_EXEC;
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.
117 fexecve(fd, argv, environ);
118 fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno));
119 return SHELL_CMD_NOT_EXEC;