allbery@ncoast.UUCP (Brandon Allbery) (12/10/85)
Expires: Quoted from <392@brl-tgr.ARPA> ["Re: Magic Numbers"], by gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>)... +--------------- | > Csh on non-4.2 systems checks for a # as | > the first character of the file, and forks itself if it sees it; if not, it | > forks a /bin/sh. | | Yes, some of them do, but if they do that's a bug. | Virtually all of my Bourne shell scripts (including | SVR2 system utility scripts) start with "#". +--------------- All of them do. When csh was written bsh still only spoke :. There *is* a simple (albeit slow) solution. Write a program to intuit the program to invoke on the file, with the file's full pathname passed as argv[1] and its arguments as argv[2] .. argv[argc - 1]. Then say: alias shell $HOME/bin/bexec or whatever you decide to call it. IT MUST BE A BINARY FILE AND IT MUST BE A FULL PATHNAME. If csh can't exec() a program it will prepend the value of the ``shell'' alias to it, if any, and try again; if there isn't a shell alias it uses its own heuristics. The program below uses this (mis-?)feature of bastard (orphaned?) csh'es to handle #! magic numbers, sans set[ug]id and other fun stuff. Other than that it uses the same test as csh itself. But you can do whatever you like, say to use * to cause your local Kermit-running MS-DOS machine to receive and execute the file as an MS-DOS batch file. [ :-) ] Let me know if you come up with any interesting new twists. --Brandon ----------------------------- cut here --------------------------------------- #include <stdio.h> #include <fcntl.h> /* * bexec: execute a non-binary file for csh, with #! recognition * (usage: alias shell /usr/local/bin/bexec) */ extern int errno; extern char *sys_errlist[]; #define SH "/bin/sh" #define CSH "/usr/plx/csh" #define NARG 512 /* this is the number csh uses */ char *sysargv[NARG + 1]; char **newargv(); char *basename(); extern char *strrchr(); main(argc, argv, envp) char **argv, **envp; { FILE *cmd; char kcmd[512]; char *cp, *ap; if ((cmd = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "bexec: can't open %s: %s\n", argv[1], sys_errlist[errno]); exit(1); } fgets(kcmd, sizeof kcmd, cmd); kcmd[strlen(kcmd) - 1] = '\0'; /* kill trailing \n */ if (strncmp(kcmd, "#!", 2) != 0) { if (kcmd[0] == '#') { argv[0] = "csh"; cp = CSH; } else { argv[0] = "sh"; cp = SH; } execve(cp, argv, envp); fprintf(stderr, "bexec: can't exec %s: %s\n", cp, sys_errlist[errno]); exit(100); } for (cp = kcmd + 2; *cp == ' '; cp++) ; for (ap = cp; *ap != ' ' && *ap != '\0'; ap++) ; if (*ap == ' ') *ap++ = '\0'; argv = newargv(basename(argv[1]), ap, argv); fclose(stdin); fcntl(fileno(cmd), F_DUPFD, 0); lseek(0, ftell(cmd), 0); fclose(cmd); execve(cp, argv, envp); fprintf(stderr, "bexec: can't exec %s: %s\n", cp, sys_errlist[errno]); exit(100); } char **newargv(newar0, newar1, oldargv) char *newar0, *newar1, **oldargv; { int ap, op; sysargv[0] = newar0; ap = 1; if (newar1[0] != '\0') { sysargv[1] = newar1; ap++; } for (op = 2; ap < NARG && oldargv[op] != NULL; ap++, op++) sysargv[ap] = oldargv[op]; sysargv[ap] = NULL; return sysargv; } char *basename(path) char *path; { char *cp; if ((cp = strrchr(path, '/')) == NULL) return path; return cp + 1; } -- Lord Charteris (thurb) ncoast!allbery@Case.CSNet (ncoast!allbery%Case.CSNet@CSNet-Relay.ARPA) ..decvax!cwruecmp!ncoast!allbery (..ncoast!tdi2!root for business) 6615 Center St., Mentor, OH 44060 (I moved) --Phone: +01 216 974 9210 CIS 74106,1032 -- MCI MAIL BALLBERY (WARNING: I am only a part-time denizen...)