18fae3551SRodney W. Grimes /* 28fae3551SRodney W. Grimes * Copyright (c) 1983, 1993 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 68fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 78fae3551SRodney W. Grimes * are met: 88fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 98fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 108fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 128fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 138fae3551SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 148fae3551SRodney W. Grimes * must display the following acknowledgement: 158fae3551SRodney W. Grimes * This product includes software developed by the University of 168fae3551SRodney W. Grimes * California, Berkeley and its contributors. 178fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 188fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 198fae3551SRodney W. Grimes * without specific prior written permission. 208fae3551SRodney W. Grimes * 218fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 228fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 258fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 268fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 278fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 288fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 298fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 308fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318fae3551SRodney W. Grimes * SUCH DAMAGE. 328fae3551SRodney W. Grimes */ 338fae3551SRodney W. Grimes 348fae3551SRodney W. Grimes #ifndef lint 358679b1b4SPhilippe Charnier static const char copyright[] = 368fae3551SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\ 378fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 388fae3551SRodney W. Grimes #endif /* not lint */ 398fae3551SRodney W. Grimes 408fae3551SRodney W. Grimes #ifndef lint 418679b1b4SPhilippe Charnier #if 0 428fae3551SRodney W. Grimes static char sccsid[] = "@(#)tunefs.c 8.2 (Berkeley) 4/19/94"; 438679b1b4SPhilippe Charnier #endif 448679b1b4SPhilippe Charnier static const char rcsid[] = 457382c45aSLuoqi Chen "$Id: tunefs.c,v 1.6 1998/08/03 06:41:20 charnier Exp $"; 468fae3551SRodney W. Grimes #endif /* not lint */ 478fae3551SRodney W. Grimes 488fae3551SRodney W. Grimes /* 498fae3551SRodney W. Grimes * tunefs: change layout parameters to an existing file system. 508fae3551SRodney W. Grimes */ 518fae3551SRodney W. Grimes #include <sys/param.h> 527382c45aSLuoqi Chen #include <sys/mount.h> 538fae3551SRodney W. Grimes #include <sys/stat.h> 548fae3551SRodney W. Grimes 558fae3551SRodney W. Grimes #include <ufs/ffs/fs.h> 567382c45aSLuoqi Chen #include <ufs/ufs/ufsmount.h> 578fae3551SRodney W. Grimes 588fae3551SRodney W. Grimes #include <err.h> 598fae3551SRodney W. Grimes #include <fcntl.h> 608fae3551SRodney W. Grimes #include <fstab.h> 618fae3551SRodney W. Grimes #include <paths.h> 628679b1b4SPhilippe Charnier #include <stdio.h> 638fae3551SRodney W. Grimes #include <stdlib.h> 647382c45aSLuoqi Chen #include <string.h> 658fae3551SRodney W. Grimes #include <unistd.h> 668fae3551SRodney W. Grimes 678fae3551SRodney W. Grimes /* the optimization warning string template */ 688fae3551SRodney W. Grimes #define OPTWARN "should optimize for %s with minfree %s %d%%" 698fae3551SRodney W. Grimes 708fae3551SRodney W. Grimes union { 718fae3551SRodney W. Grimes struct fs sb; 728fae3551SRodney W. Grimes char pad[MAXBSIZE]; 738fae3551SRodney W. Grimes } sbun; 748fae3551SRodney W. Grimes #define sblock sbun.sb 758fae3551SRodney W. Grimes 768fae3551SRodney W. Grimes int fi; 778fae3551SRodney W. Grimes long dev_bsize = 1; 788fae3551SRodney W. Grimes 798fae3551SRodney W. Grimes void bwrite(daddr_t, char *, int); 808fae3551SRodney W. Grimes int bread(daddr_t, char *, int); 818fae3551SRodney W. Grimes void getsb(struct fs *, char *); 828fae3551SRodney W. Grimes void usage __P((void)); 8316a7269eSJoerg Wunsch void printfs __P((void)); 847382c45aSLuoqi Chen char *rawname __P((char *, char *)); 858fae3551SRodney W. Grimes 868fae3551SRodney W. Grimes int 878fae3551SRodney W. Grimes main(argc, argv) 888fae3551SRodney W. Grimes int argc; 898fae3551SRodney W. Grimes char *argv[]; 908fae3551SRodney W. Grimes { 91b1897c19SJulian Elischer char *cp, *special, *name, *action; 928fae3551SRodney W. Grimes struct stat st; 938fae3551SRodney W. Grimes int i; 947382c45aSLuoqi Chen int Aflag = 0, active = 0; 958fae3551SRodney W. Grimes struct fstab *fs; 968fae3551SRodney W. Grimes char *chg[2], device[MAXPATHLEN]; 977382c45aSLuoqi Chen struct ufs_args args; 987382c45aSLuoqi Chen struct statfs stfs; 998fae3551SRodney W. Grimes 1008fae3551SRodney W. Grimes argc--, argv++; 1018fae3551SRodney W. Grimes if (argc < 2) 1028fae3551SRodney W. Grimes usage(); 1038fae3551SRodney W. Grimes special = argv[argc - 1]; 1048fae3551SRodney W. Grimes fs = getfsfile(special); 1057382c45aSLuoqi Chen if (fs) { 1067382c45aSLuoqi Chen if (statfs(special, &stfs) == 0) { 1077382c45aSLuoqi Chen if ((stfs.f_flags & MNT_RDONLY) == 0) { 1087382c45aSLuoqi Chen errx(1, "cannot work on read-write mounted file system"); 1097382c45aSLuoqi Chen } 1107382c45aSLuoqi Chen active = 1; 1117382c45aSLuoqi Chen special = rawname(fs->fs_spec, device); 1127382c45aSLuoqi Chen } else 1138fae3551SRodney W. Grimes special = fs->fs_spec; 1147382c45aSLuoqi Chen } 1158fae3551SRodney W. Grimes again: 1168fae3551SRodney W. Grimes if (stat(special, &st) < 0) { 1178fae3551SRodney W. Grimes if (*special != '/') { 1188fae3551SRodney W. Grimes if (*special == 'r') 1198fae3551SRodney W. Grimes special++; 1208fae3551SRodney W. Grimes (void)sprintf(device, "%s/%s", _PATH_DEV, special); 1218fae3551SRodney W. Grimes special = device; 1228fae3551SRodney W. Grimes goto again; 1238fae3551SRodney W. Grimes } 1248fae3551SRodney W. Grimes err(1, "%s", special); 1258fae3551SRodney W. Grimes } 1268fae3551SRodney W. Grimes if ((st.st_mode & S_IFMT) != S_IFBLK && 1278fae3551SRodney W. Grimes (st.st_mode & S_IFMT) != S_IFCHR) 1288fae3551SRodney W. Grimes errx(10, "%s: not a block or character device", special); 1298fae3551SRodney W. Grimes getsb(&sblock, special); 1308fae3551SRodney W. Grimes for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { 1318fae3551SRodney W. Grimes for (cp = &argv[0][1]; *cp; cp++) 1328fae3551SRodney W. Grimes switch (*cp) { 1338fae3551SRodney W. Grimes 1348fae3551SRodney W. Grimes case 'A': 1358fae3551SRodney W. Grimes Aflag++; 1368fae3551SRodney W. Grimes continue; 1378fae3551SRodney W. Grimes 13816a7269eSJoerg Wunsch case 'p': 13916a7269eSJoerg Wunsch printfs(); 14016a7269eSJoerg Wunsch exit(0); 14116a7269eSJoerg Wunsch 1428fae3551SRodney W. Grimes case 'a': 1438fae3551SRodney W. Grimes name = "maximum contiguous block count"; 1448fae3551SRodney W. Grimes if (argc < 1) 1458fae3551SRodney W. Grimes errx(10, "-a: missing %s", name); 1468fae3551SRodney W. Grimes argc--, argv++; 1478fae3551SRodney W. Grimes i = atoi(*argv); 1488fae3551SRodney W. Grimes if (i < 1) 1498fae3551SRodney W. Grimes errx(10, "%s must be >= 1 (was %s)", 1508fae3551SRodney W. Grimes name, *argv); 1518fae3551SRodney W. Grimes warnx("%s changes from %d to %d", 1528fae3551SRodney W. Grimes name, sblock.fs_maxcontig, i); 1538fae3551SRodney W. Grimes sblock.fs_maxcontig = i; 1548fae3551SRodney W. Grimes continue; 1558fae3551SRodney W. Grimes 1568fae3551SRodney W. Grimes case 'd': 1578fae3551SRodney W. Grimes name = 1588fae3551SRodney W. Grimes "rotational delay between contiguous blocks"; 1598fae3551SRodney W. Grimes if (argc < 1) 1608fae3551SRodney W. Grimes errx(10, "-d: missing %s", name); 1618fae3551SRodney W. Grimes argc--, argv++; 1628fae3551SRodney W. Grimes i = atoi(*argv); 1638fae3551SRodney W. Grimes warnx("%s changes from %dms to %dms", 1648fae3551SRodney W. Grimes name, sblock.fs_rotdelay, i); 1658fae3551SRodney W. Grimes sblock.fs_rotdelay = i; 1668fae3551SRodney W. Grimes continue; 1678fae3551SRodney W. Grimes 1688fae3551SRodney W. Grimes case 'e': 1698fae3551SRodney W. Grimes name = 1708fae3551SRodney W. Grimes "maximum blocks per file in a cylinder group"; 1718fae3551SRodney W. Grimes if (argc < 1) 1728fae3551SRodney W. Grimes errx(10, "-e: missing %s", name); 1738fae3551SRodney W. Grimes argc--, argv++; 1748fae3551SRodney W. Grimes i = atoi(*argv); 1758fae3551SRodney W. Grimes if (i < 1) 1768fae3551SRodney W. Grimes errx(10, "%s must be >= 1 (was %s)", 1778fae3551SRodney W. Grimes name, *argv); 1788fae3551SRodney W. Grimes warnx("%s changes from %d to %d", 1798fae3551SRodney W. Grimes name, sblock.fs_maxbpg, i); 1808fae3551SRodney W. Grimes sblock.fs_maxbpg = i; 1818fae3551SRodney W. Grimes continue; 1828fae3551SRodney W. Grimes 1838fae3551SRodney W. Grimes case 'm': 1848fae3551SRodney W. Grimes name = "minimum percentage of free space"; 1858fae3551SRodney W. Grimes if (argc < 1) 1868fae3551SRodney W. Grimes errx(10, "-m: missing %s", name); 1878fae3551SRodney W. Grimes argc--, argv++; 1888fae3551SRodney W. Grimes i = atoi(*argv); 1898fae3551SRodney W. Grimes if (i < 0 || i > 99) 1908fae3551SRodney W. Grimes errx(10, "bad %s (%s)", name, *argv); 1918fae3551SRodney W. Grimes warnx("%s changes from %d%% to %d%%", 1928fae3551SRodney W. Grimes name, sblock.fs_minfree, i); 1938fae3551SRodney W. Grimes sblock.fs_minfree = i; 1948fae3551SRodney W. Grimes if (i >= MINFREE && 1958fae3551SRodney W. Grimes sblock.fs_optim == FS_OPTSPACE) 1968fae3551SRodney W. Grimes warnx(OPTWARN, "time", ">=", MINFREE); 1978fae3551SRodney W. Grimes if (i < MINFREE && 1988fae3551SRodney W. Grimes sblock.fs_optim == FS_OPTTIME) 1998fae3551SRodney W. Grimes warnx(OPTWARN, "space", "<", MINFREE); 2008fae3551SRodney W. Grimes continue; 2018fae3551SRodney W. Grimes 202b1897c19SJulian Elischer case 'n': 203b1897c19SJulian Elischer name = "soft updates"; 204b1897c19SJulian Elischer if (argc < 1) 205b1897c19SJulian Elischer errx(10, "-s: missing %s", name); 206b1897c19SJulian Elischer argc--, argv++; 207b1897c19SJulian Elischer if (strcmp(*argv, "enable") == 0) { 208b1897c19SJulian Elischer sblock.fs_flags |= FS_DOSOFTDEP; 209b1897c19SJulian Elischer action = "set"; 210b1897c19SJulian Elischer } else if (strcmp(*argv, "disable") == 0) { 211b1897c19SJulian Elischer sblock.fs_flags &= ~FS_DOSOFTDEP; 212b1897c19SJulian Elischer action = "cleared"; 213b1897c19SJulian Elischer } else { 214b1897c19SJulian Elischer errx(10, "bad %s (options are %s)", 215b1897c19SJulian Elischer name, "`enable' or `disable'"); 216b1897c19SJulian Elischer } 217b1897c19SJulian Elischer warnx("%s %s", name, action); 218b1897c19SJulian Elischer continue; 219b1897c19SJulian Elischer 2208fae3551SRodney W. Grimes case 'o': 2218fae3551SRodney W. Grimes name = "optimization preference"; 2228fae3551SRodney W. Grimes if (argc < 1) 2238fae3551SRodney W. Grimes errx(10, "-o: missing %s", name); 2248fae3551SRodney W. Grimes argc--, argv++; 2258fae3551SRodney W. Grimes chg[FS_OPTSPACE] = "space"; 2268fae3551SRodney W. Grimes chg[FS_OPTTIME] = "time"; 2278fae3551SRodney W. Grimes if (strcmp(*argv, chg[FS_OPTSPACE]) == 0) 2288fae3551SRodney W. Grimes i = FS_OPTSPACE; 2298fae3551SRodney W. Grimes else if (strcmp(*argv, chg[FS_OPTTIME]) == 0) 2308fae3551SRodney W. Grimes i = FS_OPTTIME; 2318fae3551SRodney W. Grimes else 2328fae3551SRodney W. Grimes errx(10, "bad %s (options are `space' or `time')", 2338fae3551SRodney W. Grimes name); 2348fae3551SRodney W. Grimes if (sblock.fs_optim == i) { 2358fae3551SRodney W. Grimes warnx("%s remains unchanged as %s", 2368fae3551SRodney W. Grimes name, chg[i]); 2378fae3551SRodney W. Grimes continue; 2388fae3551SRodney W. Grimes } 2398fae3551SRodney W. Grimes warnx("%s changes from %s to %s", 2408fae3551SRodney W. Grimes name, chg[sblock.fs_optim], chg[i]); 2418fae3551SRodney W. Grimes sblock.fs_optim = i; 2428fae3551SRodney W. Grimes if (sblock.fs_minfree >= MINFREE && 2438fae3551SRodney W. Grimes i == FS_OPTSPACE) 2448fae3551SRodney W. Grimes warnx(OPTWARN, "time", ">=", MINFREE); 2458fae3551SRodney W. Grimes if (sblock.fs_minfree < MINFREE && 2468fae3551SRodney W. Grimes i == FS_OPTTIME) 2478fae3551SRodney W. Grimes warnx(OPTWARN, "space", "<", MINFREE); 2488fae3551SRodney W. Grimes continue; 2498fae3551SRodney W. Grimes 2508fae3551SRodney W. Grimes default: 2518fae3551SRodney W. Grimes usage(); 2528fae3551SRodney W. Grimes } 2538fae3551SRodney W. Grimes } 2548fae3551SRodney W. Grimes if (argc != 1) 2558fae3551SRodney W. Grimes usage(); 2568fae3551SRodney W. Grimes bwrite((daddr_t)SBOFF / dev_bsize, (char *)&sblock, SBSIZE); 2578fae3551SRodney W. Grimes if (Aflag) 2588fae3551SRodney W. Grimes for (i = 0; i < sblock.fs_ncg; i++) 2598fae3551SRodney W. Grimes bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)), 2608fae3551SRodney W. Grimes (char *)&sblock, SBSIZE); 2618fae3551SRodney W. Grimes close(fi); 2627382c45aSLuoqi Chen if (active) { 2637382c45aSLuoqi Chen bzero(&args, sizeof(args)); 2647382c45aSLuoqi Chen if (mount("ufs", fs->fs_file, 2657382c45aSLuoqi Chen stfs.f_flags | MNT_UPDATE | MNT_RELOAD, &args) < 0) 2667382c45aSLuoqi Chen err(9, "%s: reload", special); 2677382c45aSLuoqi Chen warnx("file system reloaded"); 2687382c45aSLuoqi Chen } 2698fae3551SRodney W. Grimes exit(0); 2708fae3551SRodney W. Grimes } 2718fae3551SRodney W. Grimes 2728fae3551SRodney W. Grimes void 2738fae3551SRodney W. Grimes usage() 2748fae3551SRodney W. Grimes { 2758679b1b4SPhilippe Charnier fprintf(stderr, "%s\n%s\n%s\n", 2768679b1b4SPhilippe Charnier "usage: tunefs [-A] [-a maxcontig] [-d rotdelay] [-e maxbpg] [-m minfree]", 2778679b1b4SPhilippe Charnier " [-p] [-n enable | disable] [-o optimize_preference]", 2788679b1b4SPhilippe Charnier " [special | filesystem]"); 2798fae3551SRodney W. Grimes exit(2); 2808fae3551SRodney W. Grimes } 2818fae3551SRodney W. Grimes 2828fae3551SRodney W. Grimes void 2838fae3551SRodney W. Grimes getsb(fs, file) 2848fae3551SRodney W. Grimes register struct fs *fs; 2858fae3551SRodney W. Grimes char *file; 2868fae3551SRodney W. Grimes { 2878fae3551SRodney W. Grimes 2888fae3551SRodney W. Grimes fi = open(file, 2); 2898fae3551SRodney W. Grimes if (fi < 0) 2908fae3551SRodney W. Grimes err(3, "cannot open %s", file); 2918fae3551SRodney W. Grimes if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE)) 2928fae3551SRodney W. Grimes err(4, "%s: bad super block", file); 2938fae3551SRodney W. Grimes if (fs->fs_magic != FS_MAGIC) 2948fae3551SRodney W. Grimes err(5, "%s: bad magic number", file); 2958fae3551SRodney W. Grimes dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); 2968fae3551SRodney W. Grimes } 2978fae3551SRodney W. Grimes 2988fae3551SRodney W. Grimes void 29916a7269eSJoerg Wunsch printfs() 30016a7269eSJoerg Wunsch { 301b1897c19SJulian Elischer warnx("soft updates: (-n) %s", 302b1897c19SJulian Elischer (sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled"); 30316a7269eSJoerg Wunsch warnx("maximum contiguous block count: (-a) %d", 30416a7269eSJoerg Wunsch sblock.fs_maxcontig); 30516a7269eSJoerg Wunsch warnx("rotational delay between contiguous blocks: (-d) %d ms", 30616a7269eSJoerg Wunsch sblock.fs_rotdelay); 30716a7269eSJoerg Wunsch warnx("maximum blocks per file in a cylinder group: (-e) %d", 30816a7269eSJoerg Wunsch sblock.fs_maxbpg); 30916a7269eSJoerg Wunsch warnx("minimum percentage of free space: (-m) %d%%", 31016a7269eSJoerg Wunsch sblock.fs_minfree); 31116a7269eSJoerg Wunsch warnx("optimization preference: (-o) %s", 31216a7269eSJoerg Wunsch sblock.fs_optim == FS_OPTSPACE ? "space" : "time"); 31316a7269eSJoerg Wunsch if (sblock.fs_minfree >= MINFREE && 31416a7269eSJoerg Wunsch sblock.fs_optim == FS_OPTSPACE) 31516a7269eSJoerg Wunsch warnx(OPTWARN, "time", ">=", MINFREE); 31616a7269eSJoerg Wunsch if (sblock.fs_minfree < MINFREE && 31716a7269eSJoerg Wunsch sblock.fs_optim == FS_OPTTIME) 31816a7269eSJoerg Wunsch warnx(OPTWARN, "space", "<", MINFREE); 31916a7269eSJoerg Wunsch } 32016a7269eSJoerg Wunsch 32116a7269eSJoerg Wunsch void 3228fae3551SRodney W. Grimes bwrite(blk, buf, size) 3238fae3551SRodney W. Grimes daddr_t blk; 3248fae3551SRodney W. Grimes char *buf; 3258fae3551SRodney W. Grimes int size; 3268fae3551SRodney W. Grimes { 3278fae3551SRodney W. Grimes 3288fae3551SRodney W. Grimes if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0) 3298fae3551SRodney W. Grimes err(6, "FS SEEK"); 3308fae3551SRodney W. Grimes if (write(fi, buf, size) != size) 3318fae3551SRodney W. Grimes err(7, "FS WRITE"); 3328fae3551SRodney W. Grimes } 3338fae3551SRodney W. Grimes 3348fae3551SRodney W. Grimes int 3358fae3551SRodney W. Grimes bread(bno, buf, cnt) 3368fae3551SRodney W. Grimes daddr_t bno; 3378fae3551SRodney W. Grimes char *buf; 3388fae3551SRodney W. Grimes int cnt; 3398fae3551SRodney W. Grimes { 3408fae3551SRodney W. Grimes int i; 3418fae3551SRodney W. Grimes 3428fae3551SRodney W. Grimes if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0) 3438fae3551SRodney W. Grimes return(1); 3448fae3551SRodney W. Grimes if ((i = read(fi, buf, cnt)) != cnt) { 3458fae3551SRodney W. Grimes for(i=0; i<sblock.fs_bsize; i++) 3468fae3551SRodney W. Grimes buf[i] = 0; 3478fae3551SRodney W. Grimes return (1); 3488fae3551SRodney W. Grimes } 3498fae3551SRodney W. Grimes return (0); 3508fae3551SRodney W. Grimes } 3517382c45aSLuoqi Chen 3527382c45aSLuoqi Chen char * 3537382c45aSLuoqi Chen rawname(special, pathbuf) 3547382c45aSLuoqi Chen char *special; 3557382c45aSLuoqi Chen char *pathbuf; 3567382c45aSLuoqi Chen { 3577382c45aSLuoqi Chen char *p; 3587382c45aSLuoqi Chen int n; 3597382c45aSLuoqi Chen 3607382c45aSLuoqi Chen p = strrchr(special, '/'); 3617382c45aSLuoqi Chen if (p) { 3627382c45aSLuoqi Chen n = ++p - special; 3637382c45aSLuoqi Chen bcopy(special, pathbuf, n); 3647382c45aSLuoqi Chen } else { 3657382c45aSLuoqi Chen strcpy(pathbuf, _PATH_DEV); 3667382c45aSLuoqi Chen n = strlen(pathbuf); 3677382c45aSLuoqi Chen p = special; 3687382c45aSLuoqi Chen } 3697382c45aSLuoqi Chen pathbuf[n++] = 'r'; 3707382c45aSLuoqi Chen strcpy(pathbuf + n, p); 3717382c45aSLuoqi Chen return pathbuf; 3727382c45aSLuoqi Chen } 373