405 lines
8.0 KiB
C
Executable File
405 lines
8.0 KiB
C
Executable File
#ident "@(#)tilde.c 1.7 93/06/08 SMI" /* From AT&T Toolchest */
|
|
|
|
/*
|
|
* sh_tilde - process tilde expansion
|
|
*
|
|
* David Korn
|
|
* AT&T Bell Laboratories
|
|
* Room 3C-526B
|
|
* Murray Hill, N. J. 07974
|
|
* Tel. x7975
|
|
*
|
|
* February, 1983
|
|
* revised March, 1988
|
|
*/
|
|
|
|
#include "sh_config.h"
|
|
#ifdef NOGETPW
|
|
/*
|
|
* If we're not using the standard getpwent()
|
|
* routines, we'll need all the standard ksh
|
|
* definitions.
|
|
*/
|
|
# ifdef KSHELL
|
|
# include "defs.h"
|
|
# else
|
|
extern char *strrchr();
|
|
extern char *strcpy();
|
|
# endif /* KSHELL */
|
|
#else /* NOGETPW */
|
|
/*
|
|
* Otherwise, we just need access to <pwd.h>,
|
|
* which also includes <stdio.h>, which is
|
|
* incompatible with the standard ksh defs.h.
|
|
*/
|
|
# include <pwd.h>
|
|
# include <string.h>
|
|
#endif /* NOGETPW */
|
|
|
|
#ifdef RDS
|
|
# ifdef _mnttab_
|
|
# include <mnttab.h>
|
|
# else
|
|
# undef RDS
|
|
# endif /* _mnttab_ */
|
|
# ifdef _sys_utsname_
|
|
# include <sys/utsname.h>
|
|
# else
|
|
# undef RDS
|
|
# endif /* _sys_utsname_ */
|
|
#endif /* RDS */
|
|
|
|
#define UNAME 20
|
|
#define LOGDIR 64
|
|
#define LINSZ 256
|
|
static char u_name[UNAME];
|
|
static char u_logdir[LOGDIR];
|
|
|
|
|
|
char *logdir();
|
|
static int passwdent();
|
|
#ifndef apollo
|
|
static int finddir();
|
|
#endif /* !apollo */
|
|
|
|
#ifdef RDS
|
|
/* ~host!user added by Gary J. Murakami for PDU use July 1984 */
|
|
/* generalized for random RFS mount points for R&D (12/87 emk) */
|
|
/* merged with official KornShell source, 1988 */
|
|
# define HOSTLEN 10
|
|
# define NENTS (IOBSIZE/sizeof(struct mnttab))
|
|
static char *getpbase();
|
|
static char *bang;
|
|
static char name_set = 0;
|
|
static struct utsname name;
|
|
extern int uname();
|
|
#endif /* RDS */
|
|
/*
|
|
* This routine is used to resolve ~ filenames.
|
|
* If string starts with ~ then ~name is replaced with login directory of name.
|
|
* A ~ by itself is replaced with the users login directory.
|
|
* A ~- is replaced by the last working directory in Shell.
|
|
* If string doesn't start with ~ then NULL returned.
|
|
* If not found then the NULL string is returned.
|
|
*/
|
|
|
|
char *sh_tilde(string)
|
|
char *string;
|
|
{
|
|
register char *sp = string;
|
|
register char *cp;
|
|
register int c;
|
|
if(*sp++!='~')
|
|
return(NULL);
|
|
if((c = *sp)==0 || c=='/')
|
|
{
|
|
return("$HOME");
|
|
}
|
|
#ifdef KSHELL
|
|
if((c=='-' || c=='+') && ((c= *(sp+1))==0 || c=='/'))
|
|
{
|
|
if(*sp=='+')
|
|
return("$PWD");
|
|
else
|
|
return("$OLDPWD");
|
|
}
|
|
#endif /* KSHELL */
|
|
if((cp=strrchr(sp,'/')) != NULL)
|
|
*cp = 0;
|
|
sp = logdir(sp);
|
|
if(cp)
|
|
*cp = '/';
|
|
return(sp);
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine returns a pointer to a null-terminated string that
|
|
* contains the login directory of the given <user>.
|
|
* NULL is returned if there is no entry for the given user in the
|
|
* /etc/passwd file or if no room for directory entry.
|
|
* The most recent login directory is saved for future access
|
|
*/
|
|
|
|
char *logdir(user)
|
|
char *user;
|
|
{
|
|
if(strcmp(user,u_name))
|
|
{
|
|
#ifdef NOGETPW
|
|
if(passwdent(user)<0)
|
|
return(NULL);
|
|
#else /* NOGETPW */
|
|
struct passwd *pw;
|
|
|
|
if ((pw = getpwnam(user)) == NULL ||
|
|
(int)strlen(pw->pw_dir) >= LOGDIR)
|
|
return(NULL);
|
|
strcpy(u_name,user);
|
|
strcpy(u_logdir,pw->pw_dir);
|
|
endpwent();
|
|
#endif /* NOGETPW */
|
|
}
|
|
return(u_logdir);
|
|
}
|
|
|
|
|
|
#ifdef NOGETPW
|
|
/*
|
|
* read the passwd entry for a given <user> and save the uid, gid and home
|
|
*/
|
|
|
|
#ifdef apollo
|
|
# include <pwd.h>
|
|
|
|
static int passwdent(user)
|
|
char *user;
|
|
{
|
|
struct passwd *pwd;
|
|
pwd = getpwnam(user);
|
|
if (!pwd)
|
|
return -1;
|
|
else
|
|
{
|
|
strcpy(u_logdir, pwd->pw_dir);
|
|
strcpy(u_name, pwd->pw_name);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#else /* !apollo */
|
|
|
|
static int passwdent(user)
|
|
char *user;
|
|
{
|
|
register char *cp;
|
|
register char *bp;
|
|
register int c;
|
|
int fd;
|
|
register int n = strlen(user);
|
|
char buff[LINSZ+IOBSIZE+1];
|
|
char *buff2;
|
|
#ifdef RDS
|
|
char hostdir[LINSZ];
|
|
char *host;
|
|
int hostlen;
|
|
extern char *getenv(), *getlogin(), *strchr();
|
|
#endif /*RDS*/
|
|
|
|
if(n>=UNAME)
|
|
return(-1);
|
|
#ifdef RDS
|
|
/* check for ~machine!user */
|
|
if((bang=strchr(user,'!')))
|
|
{
|
|
hostlen = bang-user; /* when hostlen=0, on this machine */
|
|
if (hostlen >= HOSTLEN)
|
|
hostlen = HOSTLEN - 1;
|
|
#ifdef PDU
|
|
strcpy(buff,"/../");
|
|
strcpy(buff+4,user);
|
|
buff[hostlen+4] = 0;
|
|
if ( (fd = open(buff,O_RDONLY)) < 0 )
|
|
return( -1 );
|
|
#else
|
|
(void) strncpy(hostdir, user, hostlen);
|
|
hostdir[hostlen] = '\0';
|
|
if ((hostlen==0) || !(bp=getpbase(hostdir,buff)))
|
|
{
|
|
if (!name_set)
|
|
{
|
|
if (uname(&name) <0)/* save for future access */
|
|
return(-1);
|
|
else
|
|
name_set++;
|
|
}
|
|
if(hostlen && (strcmp(hostdir,name.nodename)!=0))
|
|
return(-1);
|
|
hostlen = 0; /* on this machine */
|
|
}
|
|
else
|
|
{
|
|
hostlen = strlen(bp);
|
|
strcpy(hostdir, bp);
|
|
}
|
|
strcpy(hostdir+hostlen, "/etc/passwd");
|
|
|
|
if((fd=open(hostdir,O_RDONLY))<0)
|
|
return(-1);
|
|
hostdir[hostlen] = 0;
|
|
#endif
|
|
host = user;
|
|
user = bp = bang + 1;
|
|
if(*bp == '\0')
|
|
{
|
|
if((bp = getenv("LOGNAME")) != NULL)
|
|
user = bp;
|
|
else if((bp = getlogin()) != NULL)
|
|
user = bp;
|
|
else
|
|
bp = user; /* set back to null char */
|
|
}
|
|
n = strlen(user); /* have to do again */
|
|
}
|
|
else
|
|
#endif /*RDS*/
|
|
if((fd=open("/etc/passwd",O_RDONLY))<0)
|
|
return(-1);
|
|
bp = buff2 = &buff[LINSZ];
|
|
*bp = 0;
|
|
while (1)
|
|
{
|
|
/* get a line at a time */
|
|
while((c= *bp++) != '\n')
|
|
{
|
|
/* test for end of buffer */
|
|
if(c==0)
|
|
{
|
|
/* c is length of buff2 entry so far */
|
|
c = bp-buff2;
|
|
if(--c >= LINSZ)
|
|
{
|
|
bp--;
|
|
/* we already have a complete entry */
|
|
break;
|
|
}
|
|
bp = &buff[LINSZ];
|
|
buff2 = strcpy(bp-c,buff2);
|
|
c = read(fd,bp,IOBSIZE);
|
|
bp[c] = 0;
|
|
if(c<=0)
|
|
goto breakout;
|
|
}
|
|
}
|
|
cp = buff2;
|
|
buff2 = bp;
|
|
*(bp-1) = 0;
|
|
#ifdef YELLOWP
|
|
if (*cp == '+') cp++;
|
|
#endif /* YELLOWP */
|
|
if (cp[n] == ':' && strncmp(cp,user,n) == 0)
|
|
{
|
|
#ifdef RDS
|
|
if (bang)
|
|
#ifdef PDU
|
|
(void) sprintf( u_logdir,
|
|
"/../%.*s",
|
|
hostlen, host );
|
|
#else
|
|
strcpy(u_logdir, hostdir);
|
|
#endif
|
|
|
|
#endif /*RDS*/
|
|
if (finddir(cp)) /*found dir name*/
|
|
{
|
|
close(fd);
|
|
#ifdef RDS
|
|
if (bang)
|
|
strcpy(u_name, host);
|
|
else
|
|
#endif /*RDS*/
|
|
strcpy(u_name,user);
|
|
return(0);
|
|
}
|
|
break; /*No directory field; check YP*/
|
|
}
|
|
}
|
|
breakout:
|
|
close(fd);
|
|
#ifdef YELLOWP
|
|
/**we don't report err if network is down; */
|
|
{ /*we just return search failure*/
|
|
char *sp;
|
|
char *domain;
|
|
int len;
|
|
|
|
if (yp_get_default_domain(&domain) == 0
|
|
&& yp_match(domain,"passwd.byname",user,n,&sp,&len) == 0)
|
|
if (finddir(sp)) /*found in YP*/
|
|
{
|
|
strcpy(u_name,user);
|
|
return(0);
|
|
}
|
|
}
|
|
#endif /* YELLOWP */
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* Returns true home directory is found in <passwdline>
|
|
*/
|
|
|
|
static int finddir(passwdline)
|
|
char *passwdline;
|
|
{
|
|
|
|
register char *cp;
|
|
register char *sp;
|
|
register int fields=0;
|
|
|
|
for (cp = passwdline; *cp != '\0'; cp++)
|
|
{
|
|
if (*cp == ':' && ++fields == 5)
|
|
{
|
|
cp++;
|
|
#ifdef RDS
|
|
if (bang)
|
|
sp = u_logdir+strlen(u_logdir);
|
|
else
|
|
#endif /* RDS */
|
|
sp = u_logdir;
|
|
|
|
while (*cp != ':' && *cp != '\n' && *cp != '\0')
|
|
{
|
|
*sp++ = *cp++;
|
|
if (sp >= (u_logdir+LOGDIR))
|
|
return(0);
|
|
}
|
|
*sp = '\0';
|
|
return (sp != u_logdir);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
#endif /* apollo */
|
|
|
|
#ifdef RDS
|
|
/*
|
|
* Looks for <host> in the mount table, using buffer <buff>
|
|
* returns 0 if can't find buff.
|
|
* Otherwise, returns pointer to directory within <buff>
|
|
*/
|
|
|
|
static char *
|
|
getpbase(host,buff)
|
|
register char *host;
|
|
char *buff;
|
|
{
|
|
register struct mnttab *tab;
|
|
register int n;
|
|
register int fd;
|
|
#ifdef KSHELL
|
|
extern char *path_basename();
|
|
#else
|
|
# define path_basename(s) (strrchr(s,'/')+1)
|
|
#endif /* KSHELL */
|
|
if ((fd = open(MNTTAB, O_RDONLY)) < 0)
|
|
return (0); /* oh, well... shouldn't EVER happen */
|
|
/* we want to loop through mnttab, searching for the host */
|
|
while((n=read(fd,buff,NENTS*sizeof(struct mnttab)))>0)
|
|
{
|
|
for(tab=(struct mnttab*)buff;n>0;n-=sizeof(struct mnttab),tab++)
|
|
{
|
|
if(strcmp(path_basename(tab->mt_filsys),host)==0)
|
|
{
|
|
close(fd);
|
|
return(tab->mt_filsys);
|
|
}
|
|
}
|
|
}
|
|
close(fd);
|
|
return(0);
|
|
}
|
|
#endif /* RDS */
|
|
#endif /* NOGETPW */
|