Index: usr.sbin/crunch/crunchgen/crunched_main.c =================================================================== --- usr.sbin/crunch/crunchgen/crunched_main.c +++ usr.sbin/crunch/crunchgen/crunched_main.c @@ -35,58 +35,113 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include #include +#include +#include +#include struct stub { char *name; int (*f)(); }; -extern char *__progname; +extern const char *__progname; extern struct stub entry_points[]; static void crunched_usage(void); +static struct stub * +find_entry_point(const char *basename) +{ + struct stub *ep = NULL; + + for (ep = entry_points; ep->name != NULL; ep++) + if (!strcmp(basename, ep->name)) + break; + + return (ep); +} + +static const char * +get_basename(const char *exe_path) +{ + const char *slash = strrchr(exe_path, '/'); + return (slash ? slash + 1 : exe_path); +} + int main(int argc, char **argv, char **envp) { - char *slash, *basename; - struct stub *ep; + struct stub *ep = NULL; + const char *basename = NULL; + + /* + * Look at __progname first (this will be set if the crunched binary is + * invoked directly). + */ + if (__progname) { + basename = get_basename(__progname); + ep = find_entry_point(basename); + } - if(argv[0] == NULL || *argv[0] == '\0') - crunched_usage(); + /* + * Otherwise try to find entry point based on argv[0] (this works for + * both symlinks as well as hardlinks). However, it does not work when + * su invokes a crunched shell because it sets argv[0] to _su when + * invoking the shell. In that case we look at AT_EXECPATH as a + * fallback. + */ + if (ep == NULL) { + basename = get_basename(argv[0]); + ep = find_entry_point(basename); + } - slash = strrchr(argv[0], '/'); - basename = slash? slash+1 : argv[0]; + /* + * If we didn't find the entry point based on __progname or argv[0], + * try AT_EXECPATH to get the actual binary that was executed. + */ + if (ep == NULL) { + char buf[MAXPATHLEN]; + int error = elf_aux_info(AT_EXECPATH, &buf, sizeof(buf)); + if (error == 0) { + const char *exe_name = get_basename(buf); + /* + * Keep using argv[0] if AT_EXECPATH is the crunched + * binary so that symlinks to the crunched binary report + * "not compiled in" instead of invoking + * crunched_main(). + */ + if (strcmp(exe_name, EXECNAME) != 0) { + basename = exe_name; + ep = find_entry_point(basename); + } + } else { + warnc(error, "elf_aux_info(AT_EXECPATH) failed :\n"); + } + } - for(ep=entry_points; ep->name != NULL; ep++) - if(!strcmp(basename, ep->name)) break; + if (basename == NULL || *basename == '\0') + crunched_usage(); - if(ep->name) - return ep->f(argc, argv, envp); - else { - fprintf(stderr, "%s: %s not compiled in\n", EXECNAME, basename); - crunched_usage(); - } + if (ep != NULL) { + return ep->f(argc, argv, envp); + } else { + fprintf(stderr, "%s: %s not compiled in\n", EXECNAME, basename); + crunched_usage(); + } } - int crunched_main(int argc, char **argv, char **envp) { - char *slash; - struct stub *ep; - int columns, len; - - if(argc <= 1) - crunched_usage(); - - slash = strrchr(argv[1], '/'); - __progname = slash? slash+1 : argv[1]; + if (argc <= 1) + crunched_usage(); - return main(--argc, ++argv, envp); + __progname = get_basename(argv[1]); + return main(--argc, ++argv, envp); }