1 #include <tcl.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <string.h> 6 7 int main(int argc, char **argv) { 8 Tcl_Interp *interp; 9 char newpath_str[8192], parse_str[8192], execdir_str[8192], putenv_buf[8192]; 10 char linkinfo[8192], *tmp = NULL; 11 char *scpfile = NULL, *pt_env = NULL, *pathinfo = NULL; 12 char *path = NULL; 13 size_t chklen; 14 int chkval; 15 long bytes_to_copy; 16 CONST char *chkstr; 17 CONST char *orig_errmsg, *err_errmsg; 18 19 /* 20 * Verify we were called correctly. 21 */ 22 if (argc == 0) { 23 fprintf(stderr, "Wrong number of arguments, aborting.\n"); 24 return(EXIT_FAILURE); 25 } 26 27 pt_env = getenv("PATH_TRANSLATED"); 28 if (pt_env) { 29 scpfile = strdup(pt_env); 30 } 31 32 /* 33 * Create an interpreter or bail out. 34 */ 35 interp = Tcl_CreateInterp(); 36 if (!interp) { 37 fprintf(stderr, "Could not create interpreter, aborting.\n"); 38 return(EXIT_FAILURE); 39 } 40 41 /* 42 * Perform standard Tcl initialization. 43 */ 44 chkval = Tcl_Init(interp); 45 46 /* 47 * Update the "auto_path" variable 48 * -- Determine the path to the package 49 * -- Determine the path to ourselves 50 */ 51 execdir_str[0] = '\0'; 52 53 /* 54 * If no argv[0] is specified, give up trying to find ourselves. 55 */ 56 if (argv[0] == NULL) { 57 fprintf(stderr, "Could not locate myself, aborting. (argv[0] = null)\n"); 58 return(EXIT_FAILURE); 59 } 60 61 /* 62 * Ensure we have enough buffer room to hold the value 63 */ 64 if (strlen(argv[0]) >= sizeof(execdir_str)) { 65 fprintf(stderr, "Could not locate myself, aborting. (argv[0] too big)\n"); 66 return(EXIT_FAILURE); 67 } 68 69 /* 70 * Copy the value into our buffer 71 */ 72 strcpy(execdir_str, argv[0]); 73 74 #ifdef __WIN32__ 75 { 76 char *p; 77 p = execdir_str; 78 79 while (*p) { 80 if (*p == '\\') { 81 *p = '/'; 82 } 83 84 p++; 85 } 86 } 87 #endif 88 89 #ifdef LINUX 90 /* 91 * Under Linux we can find ourselves via "/proc/PID/exe" 92 */ 93 snprintf(execdir_str, sizeof(execdir_str), "/proc/%i/exe", getpid()); 94 execdir_str[sizeof(execdir_str) - 1] = '\0'; 95 #else 96 /* 97 * If there was no path delimiters in the passed argv[0] assume 98 * the executable can be found in the path. 99 */ 100 tmp = strrchr(execdir_str, '/'); 101 if (!tmp) { 102 path = getenv("PATH"); 103 if (path) { 104 path = strdup(path); 105 } 106 107 if (path) { 108 for (tmp = strtok(path, ":"); tmp; tmp = strtok(NULL, ":")) { 109 chklen = snprintf(execdir_str, sizeof(execdir_str), "%s/%s", tmp, argv[0]); 110 if (chklen >= sizeof(execdir_str)) { 111 execdir_str[0] = '\0'; 112 continue; 113 } 114 115 if (access(execdir_str, X_OK) == 0) { 116 break; 117 } 118 119 execdir_str[0] = '\0'; 120 } 121 } 122 } 123 #endif 124 125 if (execdir_str[0] == '\0') { 126 fprintf(stderr, "Could not locate myself, aborting. (failed to perform)\n"); 127 return(EXIT_FAILURE); 128 } 129 130 if (access(execdir_str, X_OK) != 0) { 131 fprintf(stderr, "Could not locate myself, aborting. (not executable)\n"); 132 return(EXIT_FAILURE); 133 } 134 135 /* 136 * Resolve all symlinks whose target is the executable itself. 137 */ 138 while (1) { 139 #ifndef __WIN32__ 140 chkval = readlink(execdir_str, linkinfo, sizeof(linkinfo)); 141 #else 142 chkval = -1; 143 #endif 144 145 if (chkval == -1) { 146 break; 147 } 148 149 if ((size_t) chkval >= sizeof(linkinfo)) { 150 fprintf(stderr, "Could not locate myself, aborting. (linkname too big)\n"); 151 return(EXIT_FAILURE); 152 } 153 154 linkinfo[chkval] = '\0'; 155 156 tmp = strrchr(execdir_str, '/'); 157 if (tmp && linkinfo[0] != '/') { 158 tmp++; 159 *tmp = '\0'; 160 bytes_to_copy = sizeof(execdir_str) - strlen(execdir_str) - 1; 161 162 if (bytes_to_copy <= 0) { 163 fprintf(stderr, "Could not locate myself, aborting. (no bytes to copy)\n"); 164 return(EXIT_FAILURE); 165 } 166 167 strncat(execdir_str, linkinfo, bytes_to_copy); 168 } else { 169 strcpy(execdir_str, linkinfo); 170 } 171 } 172 173 /* 174 * Ensure that this target is real, and executable. 175 */ 176 if (access(execdir_str, X_OK) != 0) { 177 fprintf(stderr, "Could not locate myself, aborting. (no access to execdir=\"%s\")\n", execdir_str); 178 return(EXIT_FAILURE); 179 } 180 181 /* 182 * Now that we have resolved the symbolic links, remove the filename. 183 */ 184 tmp = strrchr(execdir_str, '/'); 185 if (tmp) { 186 *tmp = '\0'; 187 } 188 189 /* 190 * -- Construct the path to the package 191 */ 192 chklen = snprintf(newpath_str, sizeof(newpath_str), "%s/../packages/tclrivet/", execdir_str); 193 if (chklen >= sizeof(newpath_str)) { 194 fprintf(stderr, "Could not construct pathname, aborting.\n"); 195 return(EXIT_FAILURE); 196 } 197 198 /* 199 * -- Update the "auto_path" variable 200 */ 201 chkstr = Tcl_SetVar(interp, "auto_path", newpath_str, TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 202 if (chkstr == NULL) { 203 fprintf(stderr, "Could update auto_path, aborting.\n"); 204 return(EXIT_FAILURE); 205 } 206 207 /* 208 * Free allocated memory. 209 */ 210 if (path) { 211 free(path); 212 } 213 214 /* 215 * Load the "tclrivet" package 216 */ 217 chkval = Tcl_Eval(interp, "package require tclrivet"); 218 if (chkval != TCL_OK) { 219 fprintf(stderr, "Could not evaluate package command, aborting.\n"); 220 return(EXIT_FAILURE); 221 } 222 223 /* 224 * Ensure that the script file is properly defined and accessible. 225 */ 226 /* 227 * -- Verify that the scpfile has even been defined 228 */ 229 if (scpfile == NULL) { 230 fprintf(stderr, "Could not determine executable script, aborting.\n"); 231 return(EXIT_FAILURE); 232 } 233 234 /* 235 * -- If the "scpfile" doesn't exist, see if it's being MultiView'd/PATH_INFO processed 236 */ 237 pathinfo = strdup(scpfile); 238 tmp = NULL; 239 while (access(scpfile, F_OK) != 0) { 240 tmp = strrchr(scpfile, '/'); 241 if (!tmp) { 242 break; 243 } 244 *tmp = '\0'; 245 } 246 if (tmp) { 247 if (tmp > scpfile) { 248 pathinfo += tmp - scpfile; 249 snprintf(putenv_buf, sizeof(putenv_buf), "PATH_INFO=%s", pathinfo); 250 putenv_buf[sizeof(putenv_buf) - 1] = '\0'; 251 putenv(putenv_buf); 252 } 253 } 254 255 if (access(scpfile, F_OK) != 0 || strlen(scpfile) < 2) { 256 fprintf(stderr, "Could not access executable script, aborting. (scp=\"%s\")\n", scpfile); 257 return(EXIT_FAILURE); 258 } 259 260 /* 261 * Change directories to the script root 262 */ 263 path = strdup(scpfile); 264 if (path) { 265 tmp = strrchr(path, '/'); 266 if (tmp) { 267 *tmp = '\0'; 268 269 chdir(path); 270 } 271 272 free(path); 273 } 274 275 /* 276 * Hand off execution to the script passed in scpfile 277 * -- Construct the command string 278 */ 279 chklen = snprintf(parse_str, sizeof(parse_str), "parse \"%s\"", scpfile); 280 if (chklen >= sizeof(parse_str)) { 281 fprintf(stderr, "Could not construct parse command, aborting.\n"); 282 return(EXIT_FAILURE); 283 } 284 285 /* 286 * -- Evaluate the command string 287 */ 288 chkval = Tcl_Eval(interp, parse_str); 289 if (chkval != TCL_OK) { 290 orig_errmsg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 291 if (orig_errmsg) { 292 orig_errmsg = strdup(orig_errmsg); 293 } 294 295 /* 296 * Attempt to generate an error page. 297 */ 298 chkval = Tcl_Eval(interp, "rivet_error"); 299 if (chkval != TCL_OK) { 300 fprintf(stderr, "Error evaluating parse command: %s\n", orig_errmsg); 301 err_errmsg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 302 fprintf(stderr, "Additionally, an error occured while generating the error page: %s\n", err_errmsg); 303 } 304 305 return(EXIT_FAILURE); 306 } 307 308 /* 309 * Call "rivet_flush" and ignore any errors. 310 */ 311 Tcl_Eval(interp, "rivet_flush"); 312 313 /* 314 * Done 315 */ 316 return(EXIT_SUCCESS); 317 } |