--- bin/ln/symlink.7.orig Mon Mar 3 19:04:46 2003 +++ bin/ln/symlink.7 Tue Aug 5 01:01:59 2003 @@ -410,6 +410,53 @@ or .Fl P options. +.Sh MAGIC SYMLINKS +Symlinks in file systems with the +.Li MNT_MAGICLINKS +flag set have +.Dq magic +patterns in symlinks expanded. Those patterns begin with +.Dq @ +(an at-sign), and end at the end of the pathname component +(i.e. at the next +.Dq / , +or at the end of the symbolic link if there are no more slashes). +The following patterns are supported: +.Bl -tag -width @machine_arch +.It @domainname +Expands to the machine's domain name, as set by +.Xr setdomainname 3 . +.It @hostname +Expands to the machine's host name, as set by +.Xr sethostname 3 . +.It @kernel_ident +Expands to the name of the +.Xr config 8 +file used to generate the running kernel. +.It @machine +Expands to the value of +.Li MACHINE +for the system (also, the same as +.Xr make 1 's +.Li ${MACHINE} +variable). +.It @machine_arch +Expands to the value of +.Li MACHINE_ARCH +for the system (also, the same as +.Xr make 1 's +.Li ${MACHINE_ARCH} +variable). +.It @osrelease +Expands to the operating system release of the running kernel. +.It @ostype +Expands to the operating system type of the running kernel. +(This will always be +.Dq NetBSD +for +NetBSD +systems.) +.El .Pp To maintain compatibility with historic systems, the @@ -437,6 +484,7 @@ .Xr find 1 , .Xr ln 1 , .Xr ls 1 , +.Xr mount 2 , .Xr mv 1 , .Xr pax 1 , .Xr rm 1 , --- lib/libc/sys/mount.2.orig Fri Jan 17 22:02:42 2003 +++ lib/libc/sys/mount.2 Tue Aug 5 01:01:59 2003 @@ -86,6 +86,12 @@ may be specified to suppress default semantics which affect filesystem access. .Bl -tag -width MNT_SYNCHRONOUS +.It Dv MNT_MAGICLINKS +Expand special strings (beginning with +.Dq @ ) +when traversing symbolic links. See +.Xr symlink 7 +for a list of supported strings. .It Dv MNT_RDONLY The filesystem should be treated as read-only; Even the super-user may not write on it. --- sbin/mount/mntopts.h.orig Sat Oct 9 11:54:07 1999 +++ sbin/mount/mntopts.h Tue Aug 5 01:01:59 2003 @@ -43,6 +43,7 @@ /* User-visible MNT_ flags. */ #define MOPT_ASYNC { "async", 0, MNT_ASYNC, 0 } +#define MOPT_MAGICLINKS { "magiclinks", 0, MNT_MAGICLINKS, 0 } #define MOPT_NOATIME { "atime", 1, MNT_NOATIME, 0 } #define MOPT_NODEV { "dev", 1, MNT_NODEV, 0 } #define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC, 0 } @@ -76,6 +77,7 @@ MOPT_USERQUOTA, \ MOPT_GROUPQUOTA, \ MOPT_FSTAB_COMPAT, \ + MOPT_MAGICLINKS, \ MOPT_NOATIME, \ MOPT_NODEV, \ MOPT_NOEXEC, \ --- sbin/mount/mount.8.orig Sun Feb 23 21:17:42 2003 +++ sbin/mount/mount.8 Tue Aug 5 01:01:59 2003 @@ -134,6 +134,12 @@ flag, this is the same as specifying all the options listed in the .Xr fstab 5 file for the filesystem. +.It Cm magiclinks +Expand special strings (beginning with +.Dq @ ) +when traversing symbolic links. See +.Xr symlink 7 +for a list of supported strings. .It Cm noasync Metadata I/O should be done synchronously, while data I/O should be done asynchronously. --- sbin/mount/mount.c.orig Wed Aug 1 08:26:23 2001 +++ sbin/mount/mount.c Tue Aug 5 01:01:59 2003 @@ -94,6 +94,7 @@ { MNT_ASYNC, "asynchronous" }, { MNT_EXPORTED, "NFS exported" }, { MNT_LOCAL, "local" }, + { MNT_MAGICLINKS, "magiclinks" }, { MNT_NOATIME, "noatime" }, { MNT_NODEV, "nodev" }, { MNT_NOEXEC, "noexec" }, --- sys/conf/newvers.sh.orig Tue Jul 22 16:07:39 2003 +++ sys/conf/newvers.sh Tue Aug 5 01:01:59 2003 @@ -86,6 +86,7 @@ touch version v=`cat version` u=${USER-root} d=`pwd` h=`hostname` t=`date` +id=`basename ${d}` cat << EOF > vers.c $COPYRIGHT char sccspad[32 - 4 /* sizeof(sccs) */] = { '\\0' }; @@ -95,5 +96,6 @@ char osrelease[] = "${RELEASE}"; int osreldate = ${RELDATE}; EOF +echo "char kernel_ident[] = \"${id}\";" >> vers.c echo `expr ${v} + 1` > version --- sys/kern/vfs_lookup.c.orig Fri Aug 31 19:36:49 2001 +++ sys/kern/vfs_lookup.c Wed Aug 6 11:58:24 2003 @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -55,6 +56,11 @@ #include +extern char osrelease[]; +extern char ostype[]; +extern char kernel_ident[]; +int symlink_magic __P((char *cp, int *len, struct proc *p)); + /* * Convert a pathname into a pointer to a locked inode. * @@ -206,7 +212,13 @@ error = ENOENT; break; } - if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { + /* + * Do symlink substitution, if appropriate, and + * check length for potential overflow. + */ + if ((ndp->ni_vp->v_mount->mnt_flag & MNT_MAGICLINKS + && symlink_magic(cp, &linklen, p)) || + (linklen + ndp->ni_pathlen >= MAXPATHLEN)) { if (ndp->ni_pathlen > 1) zfree(namei_zone, cp); error = ENAMETOOLONG; @@ -227,6 +239,89 @@ vput(ndp->ni_vp); ndp->ni_vp = NULL; return (error); +} + +/* + * Substitute replacement text for 'magic' strings in symlinks. + * Returns 0 if successful, and returns non-zero if an error + * occurs. (Currently, the only possible error is running + * out of temporary pathname space.) + * + * Looks for "@" and "@/", where is a + * recognized 'magic' string. Replaces the "@" with + * the appropriate replacement text. (Note that in some + * cases the replacement text may have zero length.) + * + * This would have been table driven, but the variance in + * replacement strings (& replacement string lengths) made + * that impractical. + */ + +#define MATCH(str,chr) \ + ((i + (sizeof(str) - 1) == *len) || \ + ((i + (sizeof(str) - 1) < *len) && \ + (cp[i + sizeof(str) - 1] == chr))) && \ + !strncmp((str), &cp[i], sizeof(str) - 1) + +#define SUBSTITUTE(m, s, sl) \ + if ((newlen + (sl)) > MAXPATHLEN) \ + return (1); \ + i += sizeof(m) - 1; \ + bcopy((s), &tmp[newlen], (sl)); \ + newlen += (sl); \ + change = 1; + +int +symlink_magic(cp, len, p) + char *cp; + int *len; + struct proc *p; +{ + char tmp[MAXPATHLEN]; + int change, i, newlen; + + for (change = i = newlen = 0; i < *len; ) { + if (cp[i] != '@') + tmp[newlen++] = cp[i++]; + else { + i++; + /* + * The following checks should be ordered + * according to frequency of use. + */ + if (MATCH("machine_arch", '/')) { + SUBSTITUTE("machine_arch", MACHINE_ARCH, + sizeof(MACHINE_ARCH) - 1); + } else if (MATCH("machine", '/')) { + SUBSTITUTE("machine", MACHINE, + sizeof(MACHINE) - 1); + } else if (MATCH("hostname", '/')) { + SUBSTITUTE("hostname", hostname, + strlen(hostname)); + } else if (MATCH("osrelease", '/')) { + SUBSTITUTE("osrelease", osrelease, + strlen(osrelease)); + } else if (MATCH("kernel_ident", '/')) { + SUBSTITUTE("kernel_ident", kernel_ident, + strlen(kernel_ident)); + } else if (MATCH("domainname", '/')) { + SUBSTITUTE("domainname", domainname, + strlen(domainname)); + } else if (MATCH("ostype", '/')) { + SUBSTITUTE("ostype", ostype, + strlen(ostype)); + } else + tmp[newlen++] = '@'; + } + } + + if (!change) + return (0); + + bcopy(tmp, cp, newlen); + *len = newlen; + + return (0); } /* --- sys/kern/vfs_syscalls.c.orig Fri Apr 4 20:35:58 2003 +++ sys/kern/vfs_syscalls.c Tue Aug 5 01:01:59 2003 @@ -302,11 +302,12 @@ mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME | MNT_NOSYMFOLLOW | MNT_IGNORE | - MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); + MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR | MNT_MAGICLINKS); mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | MNT_NOSYMFOLLOW | MNT_IGNORE | - MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); + MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR | + MNT_MAGICLINKS); /* * Mount the filesystem. * XXX The final recipients of VFS_MOUNT just overwrite the ndp they --- sys/kern/vfs_conf.c.orig Tue Jan 7 11:56:53 2003 +++ sys/kern/vfs_conf.c Tue Aug 5 01:01:59 2003 @@ -205,6 +205,9 @@ goto done; } mp->mnt_flag |= MNT_ROOTFS; +#ifdef ROOTFS_MAGICLINKS + mp->mnt_flag |= MNT_MAGICLINKS; +#endif /* do our best to set rootdev */ if ((path[0] != 0) && setrootbyname(path)) --- sys/sys/mount.h.orig Fri Apr 4 20:35:57 2003 +++ sys/sys/mount.h Tue Aug 5 01:01:59 2003 @@ -146,6 +146,7 @@ #define MNT_NODEV 0x00000010 /* don't interpret special files */ #define MNT_UNION 0x00000020 /* union with underlying filesystem */ #define MNT_ASYNC 0x00000040 /* file system written asynchronously */ +#define MNT_MAGICLINKS 0x00000080 /* interpret symlinks for magic names */ #define MNT_SUIDDIR 0x00100000 /* special handling of SUID on dirs */ #define MNT_SOFTDEP 0x00200000 /* soft updates being done */ #define MNT_NOSYMFOLLOW 0x00400000 /* do not follow symlinks */ @@ -174,6 +175,7 @@ #define MNT_USER 0x00008000 /* mounted by a user */ #define MNT_IGNORE 0x00800000 /* do not show entry in df */ + /* * Mask of flags that are visible to statfs() * XXX I think that this could now become (~(MNT_CMDFLAGS)) @@ -181,7 +183,8 @@ */ #define MNT_VISFLAGMASK (MNT_RDONLY | MNT_SYNCHRONOUS | MNT_NOEXEC | \ MNT_NOSUID | MNT_NODEV | MNT_UNION | \ - MNT_ASYNC | MNT_EXRDONLY | MNT_EXPORTED | \ + MNT_ASYNC | \ + MNT_MAGICLINKS | MNT_EXRDONLY | MNT_EXPORTED | \ MNT_DEFEXPORTED | MNT_EXPORTANON| MNT_EXKERB | \ MNT_LOCAL | MNT_USER | MNT_QUOTA | \ MNT_ROOTFS | MNT_NOATIME | MNT_NOCLUSTERR| \