This is selfdir.c in view mode; [Download] [Up]
/* detects the path of the started executable from argv[0] and the enviroment- variable $PATH Copyright (c) MUFTI (Dipl. Phys. J. Scheurich (scheurich@rus.uni-stuttgart.de)) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You could have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Fixed bug with relative paths in $PATH and on the commandline; also * fixed some other bugs concerning '//' as directory seperator, spaces * in $PATH and a misplaced dump_on_memoryleak. * This file is a mess and I'm sure I've left some bugs in. Somebody should * consider rewriting it. But it's late and I'd like to go to bed now :-) * 6.2.95, Martin Buck <martin.buck@student.uni-ulm.de> * * Some fixes for brain-damaged Ultrix-systems * 21.2.95, Martin Buck <martin.buck@student.uni-ulm.de> */ #include "c-auto.h" #include <sys/types.h> #include <sys/stat.h> #include <sys/errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #ifndef NeXT #include <dirent.h> #else #include <sys/dir.h> #include <libc.h> #define S_IXUSR _S_IXUSR #define S_IXGRP 0000010 #define S_IXOTH 0000001 #endif #include <unistd.h> #include <kpathsea/config.h> #include <kpathsea/c-pathmx.h> #ifndef TRUE #define TRUE -1 #endif #ifndef FALSE #define FALSE 0 #endif #define CONSTLINK 1 #define CONSTFILE 2 #define CONSTDIRECTORY 3 #define CONSTSPECIAL 4 /* * Avoid name conflicts with other routines of a user * only the "main"-routine(selfdir) has a common name */ /* * I always thought declaring functions as static would be the solution * to this problem... Am I missing something? */ #define dump_on_memoryleak _dump_on_memoryleak_ #define existinode _existinode_ #define identifyinode _identifyinode_ #define testexecutable _testexecutable_ #define inodeoflink _inodeoflink_ #define getdir _getdir_ #define getlink _getlink_ #define absolutepath _absolutepath_ #define searchfile _searchfile_ void dump_on_memoryleak(char* buff); /* * search if the inode pointed by directory and file exist * give back inode on success, else return NULL */ char* existinode(char* directory,char* file) { int result; struct stat buf; char* inode; char* nothing; inode=(char*)malloc((strlen(directory)+strlen(file)+2)*sizeof(char)); dump_on_memoryleak(inode); nothing=strcpy(inode,directory); if (directory[0]!=(char)0) strcat(inode,"/"); strcat(inode,file); result=stat(inode,&buf); if (result==0) return(inode); free(inode); return(NULL); } /* * identify inode, if it is link, directory, file or special */ int identifyinode(char* inode) { int result; struct stat buf; /* note, that it's important to use here lstat instead of stat under POSIX, cause stat can't get back the st_mode of the link itself (it gets the st_mode of the pointed inode) */ result=lstat(inode,&buf); if (result==-1) return(0); if (((buf.st_mode) & S_IFLNK)==S_IFLNK) result=CONSTLINK; else if (((buf.st_mode) & S_IFDIR)==S_IFDIR) result=CONSTDIRECTORY; else if (((buf.st_mode) & S_IFREG)==S_IFREG) result=CONSTFILE; else result=CONSTSPECIAL; return(result); } /* * test if the file is executable, if yes, return inode, if no return NULL */ char* testexecutable(char* inode) { int result; struct stat buf; result=stat(inode,&buf); if (result<0) return(NULL); result=-1; if (((buf.st_mode) & S_IXUSR) != 0) result=0; else if (((buf.st_mode) & S_IXGRP) != 0) result=0; else if (((buf.st_mode) & S_IXOTH) != 0) result=0; if (result<0) return(NULL); return(inode); } /* * search the inode of a filelink */ char* inodeoflink(char* inode) { int result; int i; size_t buflen=MAXNAMLEN; char* buf; buf=(char*)malloc((MAXNAMLEN+1)*sizeof(char)); dump_on_memoryleak(buf); for (i=0;i<=MAXNAMLEN;i=i+1) buf[i]=(char)0; result=readlink(inode,buf,buflen); buf[buflen]=(char)0; if (result<0) return(NULL); return(buf); } /* * make a coredump, if there is no more memory */ void dump_on_memoryleak(char* buff) { int i; if (buff==NULL) { perror(" in self.c "); printf("can't malloc, make coredump\n"); i=0; i=1/i; /* avoid to optimise the former line away ... */ printf("%d\n",i); exit(ENOMEM); } } /* * give back the directory of a file */ char* getdir(char* file) { int i; if (file==NULL) return(file); for (i=strlen(file)-1;i>=0;i=i-1) if (file[i]=='/') { while (i >= 0 && file[i] == '/') { file[i+1]=(char)0; i--; } i = 0; break; } if (i<0) return(NULL); return(file); } /* * get a proper path of the inode of a FILElink */ char* getlink(char* inode) { char* inodepath; char* temp; char* returninode; returninode=inodeoflink(inode); if (returninode==NULL) { return(NULL); free(inode); } /* relative links need extra code ! */ if (returninode[0]!='/') { inodepath=getdir(inode); temp=malloc(strlen(inodepath)+strlen(returninode)+1); dump_on_memoryleak(temp); strcpy(temp,inodepath); while ((returninode[0] == '.') && (returninode[1] == '.') && (returninode[2] == '/') && strlen(temp)) { returninode += 3; while (*returninode == '/') /* Multiple slashes are valid */ returninode++; /* directory-seperators ! */ temp[strlen(temp)-1]='\0'; getdir(temp); } strcat(temp,returninode); returninode=temp; } free(inode); return(returninode); } /* * Make an absolute path from a relative one. We assume that nobody * chdir'ed up to now. */ #ifndef HAVE_GETCWD #define getcwd(a,b) getwd(a) #endif char * absolutepath(char* path) { char* apath; if (path[0] == '/') { apath = xstrdup(path); return(apath); } else { while (path[0] == '.' && path[1] == '/') { path += 2; while (*path == '/') path++; } apath = (char*)malloc((PATH_MAX + strlen(path) + 2) * sizeof(char)); dump_on_memoryleak(apath); apath = getcwd(apath, PATH_MAX); while (path[0] == '.' && path[1] == '.' && path[2] == '/' && strlen(apath)) { path += 3; while (*path == '/') path++; apath[strlen(apath) - 1] = '\0'; getdir(apath); } if (strlen(apath) && apath[strlen(apath) - 1] != '/') strcat(apath, "/"); strcat(apath, path); return(apath); } } /* * look if the inode pointed by directory and file is a true file * if the inode is a filelink, search the true file * if the inode is a directory or a special file, return error (NULL) * on success (file found) and it's executable return the path */ char* searchfile(char* inode) { while (identifyinode(inode)==CONSTLINK) inode=getlink(inode); if (inode!=NULL) if (identifyinode(inode)!=CONSTFILE) { free(inode); return(NULL); } inode=testexecutable(inode); return(inode); } /* * detects the path of the called binary from argv[0] and the enviroment- * variable $PATH (the path includes the last slash of the file) */ char *selfdir(char* argv0) { char* inode; char* temp; char* dollarpath; int pathlen; int i; char* target; char* apath; /* if argv0 contains a path don't search any more */ for (i=0;i<=strlen(argv0);i++) if (argv0[i]=='/') { target=(char*)malloc((strlen(argv0)+1)*sizeof(char)); dump_on_memoryleak(target); /* Checking first seems to be a good idea */ strcpy(target,argv0); apath = absolutepath(target); free(target); return(getdir(searchfile(apath))); } temp=getenv("PATH"); pathlen=strlen(temp); dollarpath=(char*)malloc((pathlen+1)*sizeof(char)); dump_on_memoryleak(dollarpath); strcpy(dollarpath,temp); /* strip whitespaces and ':' from path-variable */ for (i=0;i<pathlen;i++) if ((*(dollarpath+i)==':')) /* || (*(dollarpath+i)<=' ')) Why not have spaces in $PATH ? */ *(dollarpath+i)=(char)0; /* walk through all paths */ i=0; while (i<pathlen) if (*(dollarpath+i)!=(char)0) { inode=existinode(dollarpath+i,argv0); if (inode!=NULL) { apath = absolutepath(inode); free(inode); target=getdir(searchfile(apath)); if (target!=NULL) { free(dollarpath); return(target); } } i=i+strlen(dollarpath+i); } else i=i+1; free(dollarpath); return(NULL); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.