10e42dee6Sartem /* 20e42dee6Sartem * CDDL HEADER START 30e42dee6Sartem * 40e42dee6Sartem * The contents of this file are subject to the terms of the 50e42dee6Sartem * Common Development and Distribution License (the "License"). 60e42dee6Sartem * You may not use this file except in compliance with the License. 70e42dee6Sartem * 80e42dee6Sartem * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90e42dee6Sartem * or http://www.opensolaris.org/os/licensing. 100e42dee6Sartem * See the License for the specific language governing permissions 110e42dee6Sartem * and limitations under the License. 120e42dee6Sartem * 130e42dee6Sartem * When distributing Covered Code, include this CDDL HEADER in each 140e42dee6Sartem * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150e42dee6Sartem * If applicable, add the following below this CDDL HEADER, with the 160e42dee6Sartem * fields enclosed by brackets "[]" replaced with your own identifying 170e42dee6Sartem * information: Portions Copyright [yyyy] [name of copyright owner] 180e42dee6Sartem * 190e42dee6Sartem * CDDL HEADER END 200e42dee6Sartem */ 210e42dee6Sartem /* 22*88ecc943SGeorge Wilson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230e42dee6Sartem * Use is subject to license terms. 240e42dee6Sartem */ 250e42dee6Sartem 260e42dee6Sartem #include <fcntl.h> 270e42dee6Sartem #include <stdio.h> 280e42dee6Sartem #include <stdlib.h> 290e42dee6Sartem #include <sys/types.h> 300e42dee6Sartem #include <sys/stat.h> 310e42dee6Sartem #include <unistd.h> 320e42dee6Sartem #include <libintl.h> 330e42dee6Sartem #include <locale.h> 340e42dee6Sartem #include <string.h> 350e42dee6Sartem #include <strings.h> 360e42dee6Sartem #include <errno.h> 370e42dee6Sartem #include <dirent.h> 380e42dee6Sartem #include <dlfcn.h> 390e42dee6Sartem #include <sys/wait.h> 400e42dee6Sartem #include <sys/fstyp.h> 41ca29f3daSprabahar #include <sys/dkio.h> 42ca29f3daSprabahar #include <sys/param.h> 430e42dee6Sartem #include <libfstyp.h> 440e42dee6Sartem #include <sys/dktp/fdisk.h> 450e42dee6Sartem #include <sys/fs/pc_label.h> 460e42dee6Sartem 47f5ac0e94Smc208700@nadesico #include "libadm.h" 48f5ac0e94Smc208700@nadesico 490e42dee6Sartem #define FSTYP_LIBFS_DIR "/usr/lib/fs" 500e42dee6Sartem 510e42dee6Sartem static const char *getmodfsname(); 520e42dee6Sartem static char *getexecpathname(); 530e42dee6Sartem static boolean_t dos_to_dev(char *path, char **devpath, int *num); 54ca29f3daSprabahar static boolean_t find_dos_drive(int fd, int num, off_t *offset); 550e42dee6Sartem static void run_legacy_cmds(int fd, char *device, int vflag); 560e42dee6Sartem static int run_cmd(char *path, char *arg0, char *arg1, char *arg2); 570e42dee6Sartem 580e42dee6Sartem 590e42dee6Sartem static void 600e42dee6Sartem usage(void) 610e42dee6Sartem { 620e42dee6Sartem (void) fprintf(stderr, gettext("Usage: fstyp [-av] <device>\n")); 630e42dee6Sartem exit(1); 640e42dee6Sartem } 650e42dee6Sartem 660e42dee6Sartem int 670e42dee6Sartem main(int argc, char **argv) 680e42dee6Sartem { 690e42dee6Sartem int fd = -1; 700e42dee6Sartem int c; 710e42dee6Sartem int aflag = 0; 720e42dee6Sartem int vflag = 0; 730e42dee6Sartem int indent = 0; 740e42dee6Sartem char *devpath; 750e42dee6Sartem boolean_t is_dos; 76ca29f3daSprabahar int dos_num; 770e42dee6Sartem off_t offset = 0; 780e42dee6Sartem nvlist_t *attr = NULL; 790e42dee6Sartem fstyp_handle_t h = NULL; 800e42dee6Sartem const char *modfsname; 810e42dee6Sartem const char *fsname; 820e42dee6Sartem int error = FSTYP_ERR_NO_MATCH; 830e42dee6Sartem 840e42dee6Sartem (void) setlocale(LC_ALL, ""); 850e42dee6Sartem 860e42dee6Sartem #if !defined(TEXT_DOMAIN) 870e42dee6Sartem #define TEXT_DOMAIN "SYS_TEST" 880e42dee6Sartem #endif 890e42dee6Sartem (void) textdomain(TEXT_DOMAIN); 900e42dee6Sartem 910e42dee6Sartem while ((c = getopt(argc, argv, "av")) != -1) { 920e42dee6Sartem switch (c) { 930e42dee6Sartem case 'a': 940e42dee6Sartem aflag = 1; 950e42dee6Sartem break; 960e42dee6Sartem case 'v': 970e42dee6Sartem vflag = 1; 980e42dee6Sartem break; 990e42dee6Sartem default: 1000e42dee6Sartem usage(); 1010e42dee6Sartem break; 1020e42dee6Sartem } 1030e42dee6Sartem } 1040e42dee6Sartem 1050e42dee6Sartem argv += optind; 1060e42dee6Sartem argc -= optind; 1070e42dee6Sartem 1080e42dee6Sartem if (argc != 1) { 1090e42dee6Sartem usage(); 1100e42dee6Sartem } 1110e42dee6Sartem 1120e42dee6Sartem modfsname = getmodfsname(); 1130e42dee6Sartem 1140e42dee6Sartem /* 1150e42dee6Sartem * Open device, find partition offset if requested 1160e42dee6Sartem */ 1170e42dee6Sartem if (!(is_dos = dos_to_dev(argv[0], &devpath, &dos_num))) { 1180e42dee6Sartem devpath = argv[0]; 1190e42dee6Sartem } 1200e42dee6Sartem if ((fd = open(devpath, O_RDONLY)) < 0) { 1210e42dee6Sartem error = FSTYP_ERR_DEV_OPEN; 1220e42dee6Sartem goto out; 1230e42dee6Sartem } 1240e42dee6Sartem if (is_dos) { 125ca29f3daSprabahar if (!find_dos_drive(fd, dos_num, &offset)) { 1260e42dee6Sartem error = FSTYP_ERR_NO_PARTITION; 1270e42dee6Sartem goto out; 1280e42dee6Sartem } 1290e42dee6Sartem } 1300e42dee6Sartem 1310e42dee6Sartem /* 1320e42dee6Sartem * Use libfstyp to identify filesystem 1330e42dee6Sartem */ 1340e42dee6Sartem if ((error = fstyp_init(fd, offset, NULL, &h)) != 0) { 1350e42dee6Sartem goto out; 1360e42dee6Sartem } 1370e42dee6Sartem if ((error = fstyp_ident(h, modfsname, &fsname)) != 0) { 1380e42dee6Sartem fstyp_fini(h); 1390e42dee6Sartem h = NULL; 1400e42dee6Sartem 1410e42dee6Sartem run_legacy_cmds(fd, argv[0], vflag); 1420e42dee6Sartem 1430e42dee6Sartem goto out; 1440e42dee6Sartem } 1450e42dee6Sartem 1460e42dee6Sartem (void) printf("%s\n", fsname); 1470e42dee6Sartem 1480e42dee6Sartem /* 1490e42dee6Sartem * Output additional info if requested 1500e42dee6Sartem */ 1510e42dee6Sartem if (vflag) { 1520e42dee6Sartem error = fstyp_dump(h, stdout, stderr); 1530e42dee6Sartem } 1540e42dee6Sartem if (aflag || (vflag && (error == FSTYP_ERR_NOP))) { 1550e42dee6Sartem if ((error = fstyp_get_attr(h, &attr)) != 0) { 1560e42dee6Sartem goto out; 1570e42dee6Sartem } 1580e42dee6Sartem dump_nvlist(attr, indent); 1590e42dee6Sartem } 1600e42dee6Sartem 1610e42dee6Sartem out: 1620e42dee6Sartem if (error != 0) { 1630e42dee6Sartem (void) fprintf(stderr, gettext("unknown_fstyp (%s)\n"), 1640e42dee6Sartem fstyp_strerror(h, error)); 1650e42dee6Sartem } 1660e42dee6Sartem if (h != NULL) { 1670e42dee6Sartem fstyp_fini(h); 1680e42dee6Sartem } 1690e42dee6Sartem if (fd >= 0) { 1700e42dee6Sartem (void) close(fd); 1710e42dee6Sartem } 1720e42dee6Sartem if (devpath != argv[0]) { 1730e42dee6Sartem free(devpath); 1740e42dee6Sartem } 1750e42dee6Sartem return (error); 1760e42dee6Sartem 1770e42dee6Sartem } 1780e42dee6Sartem 1790e42dee6Sartem /* 1800e42dee6Sartem * If the executable is a fs-specific hardlink, /usr/lib/fs/<fsname>/fstyp, 1810e42dee6Sartem * return that fsname; otherwise return NULL. 1820e42dee6Sartem */ 1830e42dee6Sartem static const char * 1840e42dee6Sartem getmodfsname() 1850e42dee6Sartem { 1860e42dee6Sartem static char fsname_buf[FSTYPSZ + 1]; 1870e42dee6Sartem char *fsname = NULL; 1880e42dee6Sartem char *path; 1890e42dee6Sartem char *p; 1900e42dee6Sartem int len; 1910e42dee6Sartem 1920e42dee6Sartem if ((path = getexecpathname()) == NULL) { 1930e42dee6Sartem return (NULL); 1940e42dee6Sartem } 1950e42dee6Sartem if ((p = strrchr(path, '/')) != NULL) { 1960e42dee6Sartem *p = '\0'; 1970e42dee6Sartem if ((p = strrchr(path, '/')) != NULL) { 1980e42dee6Sartem *p++ = '\0'; 1990e42dee6Sartem len = strlen(p); 2000e42dee6Sartem if ((strcmp(path, FSTYP_LIBFS_DIR) == 0) && 2010e42dee6Sartem (len > 0) && (len < sizeof (fsname_buf))) { 2020e42dee6Sartem (void) strlcpy(fsname_buf, p, 2030e42dee6Sartem sizeof (fsname_buf)); 2040e42dee6Sartem fsname = fsname_buf; 2050e42dee6Sartem } 2060e42dee6Sartem } 2070e42dee6Sartem } 2080e42dee6Sartem free(path); 2090e42dee6Sartem return (fsname); 2100e42dee6Sartem } 2110e42dee6Sartem 2120e42dee6Sartem /* 2130e42dee6Sartem * Return executable's absolute pathname 2140e42dee6Sartem */ 2150e42dee6Sartem static char * 2160e42dee6Sartem getexecpathname() 2170e42dee6Sartem { 2180e42dee6Sartem size_t size; 2190e42dee6Sartem const char *execname; 2200e42dee6Sartem char *cwd; 2210e42dee6Sartem char *path; 2220e42dee6Sartem char *rpath; 2230e42dee6Sartem 2240e42dee6Sartem size = pathconf(".", _PC_PATH_MAX) + 1; 2250e42dee6Sartem path = malloc(size); 2260e42dee6Sartem rpath = malloc(size); 2270e42dee6Sartem cwd = getcwd(NULL, size); 2280e42dee6Sartem if ((path == NULL) || (rpath == NULL) || (cwd == NULL)) { 2290e42dee6Sartem goto out; 2300e42dee6Sartem } 2310e42dee6Sartem execname = getexecname(); 2320e42dee6Sartem 2330e42dee6Sartem if (execname[0] == '/') { 2340e42dee6Sartem (void) snprintf(path, size, "%s", execname); 2350e42dee6Sartem } else { 2360e42dee6Sartem (void) snprintf(path, size, "%s/%s", cwd, execname); 2370e42dee6Sartem } 2380e42dee6Sartem if (realpath(path, rpath) == NULL) { 2390e42dee6Sartem free(rpath); 2400e42dee6Sartem rpath = NULL; 2410e42dee6Sartem } 2420e42dee6Sartem 2430e42dee6Sartem out: 2440e42dee6Sartem if (path != NULL) { 2450e42dee6Sartem free(path); 2460e42dee6Sartem } 2470e42dee6Sartem if (cwd != NULL) { 2480e42dee6Sartem free(cwd); 2490e42dee6Sartem } 2500e42dee6Sartem return (rpath); 2510e42dee6Sartem } 2520e42dee6Sartem 2530e42dee6Sartem /* 2540e42dee6Sartem * Separates dos notation device spec into device and drive number 2550e42dee6Sartem */ 2560e42dee6Sartem static boolean_t 2570e42dee6Sartem dos_to_dev(char *path, char **devpath, int *num) 2580e42dee6Sartem { 2590e42dee6Sartem char *p; 2600e42dee6Sartem 2610e42dee6Sartem if ((p = strrchr(path, ':')) == NULL) { 2620e42dee6Sartem return (B_FALSE); 2630e42dee6Sartem } 2640e42dee6Sartem if ((*num = atoi(p + 1)) == 0) { 2650e42dee6Sartem return (B_FALSE); 2660e42dee6Sartem } 2670e42dee6Sartem p[0] = '\0'; 268f5ac0e94Smc208700@nadesico *devpath = getfullrawname(path); 2690e42dee6Sartem p[0] = ':'; 270f5ac0e94Smc208700@nadesico if (*devpath != NULL && **devpath == '\0') { 271f5ac0e94Smc208700@nadesico free(*devpath); 272f5ac0e94Smc208700@nadesico *devpath = NULL; 273f5ac0e94Smc208700@nadesico } 2740e42dee6Sartem return (*devpath != NULL); 2750e42dee6Sartem } 2760e42dee6Sartem 2770e42dee6Sartem static boolean_t 2780e42dee6Sartem is_dos_drive(uchar_t type) 2790e42dee6Sartem { 2802d700530Sartem return ((type == DOSOS12) || (type == DOSOS16) || 2812d700530Sartem (type == DOSHUGE) || (type == FDISK_WINDOWS) || 2822d700530Sartem (type == FDISK_EXT_WIN) || (type == FDISK_FAT95) || 2832d700530Sartem (type == DIAGPART)); 2840e42dee6Sartem } 2850e42dee6Sartem 2860e42dee6Sartem static boolean_t 2870e42dee6Sartem is_dos_extended(uchar_t id) 2880e42dee6Sartem { 2890e42dee6Sartem return ((id == EXTDOS) || (id == FDISK_EXTLBA)); 2900e42dee6Sartem } 2910e42dee6Sartem 2920e42dee6Sartem struct part_find_s { 2930e42dee6Sartem int num; 2940e42dee6Sartem int count; 2950e42dee6Sartem int systid; 2960e42dee6Sartem int r_systid; 297342440ecSPrasad Singamsetty uint32_t r_relsect; 298342440ecSPrasad Singamsetty uint32_t r_numsect; 2990e42dee6Sartem }; 3000e42dee6Sartem 3010e42dee6Sartem enum { WALK_CONTINUE, WALK_TERMINATE }; 3020e42dee6Sartem 3030e42dee6Sartem /* 3040e42dee6Sartem * Walk partition tables and invoke a callback for each. 3050e42dee6Sartem */ 3060e42dee6Sartem static void 307342440ecSPrasad Singamsetty walk_partitions(int fd, uint32_t startsec, off_t secsz, 308342440ecSPrasad Singamsetty int (*f)(void *, int, uint32_t, uint32_t), void *arg) 3090e42dee6Sartem { 3100e42dee6Sartem uint32_t buf[1024/4]; 3110e42dee6Sartem int bufsize = 1024; 3120e42dee6Sartem struct mboot *mboot = (struct mboot *)&buf[0]; 3130e42dee6Sartem struct ipart ipart[FD_NUMPART]; 314342440ecSPrasad Singamsetty uint32_t sec = startsec; 315342440ecSPrasad Singamsetty uint32_t lastsec = sec + 1; 316342440ecSPrasad Singamsetty uint32_t relsect; 3170e42dee6Sartem int ext = 0; 3180e42dee6Sartem int systid; 3190e42dee6Sartem boolean_t valid; 3200e42dee6Sartem int i; 3210e42dee6Sartem 3220e42dee6Sartem while (sec != lastsec) { 323ca29f3daSprabahar if (pread(fd, buf, bufsize, (off_t)sec * secsz) != bufsize) { 3240e42dee6Sartem break; 3250e42dee6Sartem } 3260e42dee6Sartem lastsec = sec; 3270e42dee6Sartem if (ltohs(mboot->signature) != MBB_MAGIC) { 3280e42dee6Sartem break; 3290e42dee6Sartem } 3300e42dee6Sartem bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart)); 3310e42dee6Sartem 3320e42dee6Sartem for (i = 0; i < FD_NUMPART; i++) { 3330e42dee6Sartem systid = ipart[i].systid; 3340e42dee6Sartem relsect = sec + ltohi(ipart[i].relsect); 3350e42dee6Sartem if (systid == 0) { 3360e42dee6Sartem continue; 3370e42dee6Sartem } 3380e42dee6Sartem valid = B_TRUE; 3390e42dee6Sartem if (is_dos_extended(systid) && (sec == lastsec)) { 3400e42dee6Sartem sec = startsec + ltohi(ipart[i].relsect); 3410e42dee6Sartem if (ext++ == 0) { 3420e42dee6Sartem relsect = startsec = sec; 3430e42dee6Sartem } else { 3440e42dee6Sartem valid = B_FALSE; 3450e42dee6Sartem } 3460e42dee6Sartem } 3470e42dee6Sartem if (valid && f(arg, ipart[i].systid, relsect, 3480e42dee6Sartem ltohi(ipart[i].numsect)) == WALK_TERMINATE) { 3490e42dee6Sartem return; 3500e42dee6Sartem } 3510e42dee6Sartem } 3520e42dee6Sartem } 3530e42dee6Sartem } 3540e42dee6Sartem 3550e42dee6Sartem static int 356342440ecSPrasad Singamsetty find_dos_drive_cb(void *arg, int systid, uint32_t relsect, uint32_t numsect) 3570e42dee6Sartem { 3580e42dee6Sartem struct part_find_s *p = arg; 3590e42dee6Sartem 3600e42dee6Sartem if (is_dos_drive(systid)) { 3610e42dee6Sartem if (++p->count == p->num) { 3620e42dee6Sartem p->r_relsect = relsect; 3630e42dee6Sartem p->r_numsect = numsect; 3640e42dee6Sartem p->r_systid = systid; 3650e42dee6Sartem return (WALK_TERMINATE); 3660e42dee6Sartem } 3670e42dee6Sartem } 3680e42dee6Sartem 3690e42dee6Sartem return (WALK_CONTINUE); 3700e42dee6Sartem } 3710e42dee6Sartem 3720e42dee6Sartem /* 373ca29f3daSprabahar * Given a dos drive number, return its relative offset in the drive. 3740e42dee6Sartem */ 3750e42dee6Sartem static boolean_t 376ca29f3daSprabahar find_dos_drive(int fd, int num, off_t *offset) 3770e42dee6Sartem { 378ca29f3daSprabahar struct dk_minfo mi; 379ca29f3daSprabahar off_t secsz; 3800e42dee6Sartem struct part_find_s p = { 0, 0, 0, 0, 0, 0 }; 3810e42dee6Sartem 3820e42dee6Sartem p.num = num; 3830e42dee6Sartem 384ca29f3daSprabahar /* 385ca29f3daSprabahar * It is possible that the media we are dealing with can have different 386ca29f3daSprabahar * sector size than the default 512 bytes. Query the driver and check 387ca29f3daSprabahar * whether the media has different sector size. 388ca29f3daSprabahar */ 389ca29f3daSprabahar if (ioctl(fd, DKIOCGMEDIAINFO, &mi) < 0) 390ca29f3daSprabahar secsz = DEV_BSIZE; 391ca29f3daSprabahar else 392ca29f3daSprabahar secsz = mi.dki_lbsize; 393ca29f3daSprabahar 3940e42dee6Sartem if (num > 0) { 395ca29f3daSprabahar walk_partitions(fd, 0, secsz, find_dos_drive_cb, &p); 3960e42dee6Sartem if (p.count == num) { 397ca29f3daSprabahar *offset = secsz * (off_t)p.r_relsect; 3980e42dee6Sartem return (B_TRUE); 3990e42dee6Sartem } 4000e42dee6Sartem } 4010e42dee6Sartem 4020e42dee6Sartem return (B_FALSE); 4030e42dee6Sartem } 4040e42dee6Sartem 4050e42dee6Sartem /* 4060e42dee6Sartem * libfstyp identification failed: as a last resort, try to 4070e42dee6Sartem * find and run legacy /usr/lib/fs/<fsname>/fstyp commands. 4080e42dee6Sartem */ 4090e42dee6Sartem static void 4100e42dee6Sartem run_legacy_cmds(int fd, char *device, int vflag) 4110e42dee6Sartem { 4120e42dee6Sartem char *lib_dir = FSTYP_LIBFS_DIR; 4130e42dee6Sartem char *path; 4140e42dee6Sartem long name_max; 4150e42dee6Sartem DIR *dirp; 4160e42dee6Sartem struct dirent *dp_mem, *dp; 4170e42dee6Sartem struct stat st; 4180e42dee6Sartem fstyp_handle_t h; 4190e42dee6Sartem int error; 4200e42dee6Sartem char *arg1, *arg2; 4210e42dee6Sartem 4220e42dee6Sartem if (vflag) { 4230e42dee6Sartem arg1 = "-v"; 4240e42dee6Sartem arg2 = device; 4250e42dee6Sartem } else { 4260e42dee6Sartem arg1 = device; 4270e42dee6Sartem arg2 = NULL; 4280e42dee6Sartem } 4290e42dee6Sartem 4300e42dee6Sartem if ((dirp = opendir(lib_dir)) == NULL) { 4310e42dee6Sartem return; 4320e42dee6Sartem } 4330e42dee6Sartem 4340e42dee6Sartem name_max = pathconf(lib_dir, _PC_NAME_MAX); 4350e42dee6Sartem path = calloc(1, name_max + 1); 4360e42dee6Sartem dp = dp_mem = calloc(1, sizeof (struct dirent) + name_max + 1); 4370e42dee6Sartem if ((path == NULL) || (dp_mem == NULL)) { 4380e42dee6Sartem goto out; 4390e42dee6Sartem } 4400e42dee6Sartem 4410e42dee6Sartem while ((readdir_r(dirp, dp, &dp) == 0) && (dp != NULL)) { 4420e42dee6Sartem if (dp->d_name[0] == '.') { 4430e42dee6Sartem continue; 4440e42dee6Sartem } 4450e42dee6Sartem (void) snprintf(path, name_max, "%s/%s", lib_dir, dp->d_name); 4460e42dee6Sartem 4470e42dee6Sartem /* it's legacy if there's no libfstyp module for it */ 4480e42dee6Sartem error = fstyp_init(fd, 0, path, &h); 4490e42dee6Sartem if (error != FSTYP_ERR_MOD_NOT_FOUND) { 4500e42dee6Sartem if (error == 0) { 4510e42dee6Sartem fstyp_fini(h); 4520e42dee6Sartem } 4530e42dee6Sartem continue; 4540e42dee6Sartem } 4550e42dee6Sartem 4560e42dee6Sartem /* file must exist and be executable */ 4570e42dee6Sartem (void) snprintf(path, name_max, 4580e42dee6Sartem "%s/%s/fstyp", lib_dir, dp->d_name); 4590e42dee6Sartem if ((stat(path, &st) < 0) || 4600e42dee6Sartem ((st.st_mode & S_IXUSR) == 0)) { 4610e42dee6Sartem continue; 4620e42dee6Sartem } 4630e42dee6Sartem 4640e42dee6Sartem if ((error = run_cmd(path, "fstyp", arg1, arg2)) == 0) { 4650e42dee6Sartem exit(0); 4660e42dee6Sartem } 4670e42dee6Sartem } 4680e42dee6Sartem 4690e42dee6Sartem out: 4700e42dee6Sartem if (dp_mem != NULL) { 4710e42dee6Sartem free(dp_mem); 4720e42dee6Sartem } 4730e42dee6Sartem if (path != NULL) { 4740e42dee6Sartem free(path); 4750e42dee6Sartem } 4760e42dee6Sartem (void) closedir(dirp); 4770e42dee6Sartem } 4780e42dee6Sartem 4790e42dee6Sartem static int 4800e42dee6Sartem run_cmd(char *path, char *arg0, char *arg1, char *arg2) 4810e42dee6Sartem { 4820e42dee6Sartem pid_t pid; 4830e42dee6Sartem int status = 1; 4840e42dee6Sartem 4850e42dee6Sartem pid = fork(); 4860e42dee6Sartem if (pid < 0) { 4870e42dee6Sartem return (1); 4880e42dee6Sartem } else if (pid == 0) { 4890e42dee6Sartem /* child */ 4900e42dee6Sartem (void) execl(path, arg0, arg1, arg2, 0); 4910e42dee6Sartem exit(1); 4920e42dee6Sartem } 4930e42dee6Sartem /* parent */ 4940e42dee6Sartem (void) wait(&status); 4950e42dee6Sartem return (status); 4960e42dee6Sartem } 497