1/* 2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <sys/errno.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <sys/wait.h> 27 28#include <err.h> 29#include <fcntl.h> 30#include <fstab.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#include <paths.h> 35#include <unistd.h> 36#include <signal.h> 37 38char *warning = "\ 39#\n\ 40# Warning - this file should only be modified with vifs(8)\n\ 41#\n\ 42# Failure to do so is unsupported and may be destructive.\n\ 43#\n"; 44 45int 46main(int argc, char *argv[]) 47{ 48 struct stat sb; 49 int fd, x; 50 uid_t euid; 51 pid_t editpid; 52 char *p, *editor; 53 54 if (argc != 1) { 55 printf("usage: vifs\n"); 56 exit(1); 57 } 58 59 euid = geteuid(); 60 if (euid != 0) 61 errx(1, "need to run as root"); 62 63 /* examine the existing fstab, try to create it if needed */ 64 if (stat(_PATH_FSTAB, &sb) < 0) { 65 if (errno == ENOENT) { 66 fd = open(_PATH_FSTAB, O_CREAT | O_WRONLY, 67 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 68 if (fd < 0) 69 errx(1, "error creating %s", _PATH_FSTAB); 70 write(fd, warning, strlen(warning)); 71 close(fd); 72 } else { 73 errx(1, "could not stat %s", _PATH_FSTAB); 74 } 75 } 76 77 /* prepare the file for the editor */ 78 fd = open(_PATH_FSTAB, O_RDONLY, 0); 79 if (fd < 0) 80 errx(1, "error opening %s", _PATH_FSTAB); 81 82 x = fcntl(fd, F_SETFD, 1); 83 if (x < 0) 84 errx(1, "error setting close on exit"); 85 86 x = flock(fd, LOCK_EX | LOCK_NB); 87 if (x != 0) 88 errx(1, "file is busy"); 89 90 /* obtain and invoke the editor */ 91 editor = getenv("EDITOR"); 92 if (editor == NULL) 93 editor = _PATH_VI; 94 p = strrchr(editor, '/'); 95 if (p != NULL) 96 ++p; 97 else 98 p = editor; 99 100 editpid = vfork(); 101 if (editpid == 0) { 102 execlp(editor, p, _PATH_FSTAB, NULL); 103 _exit(1); 104 } 105 106 for ( ; ; ) { 107 editpid = waitpid(editpid, (int *)&x, WUNTRACED); 108 if (editpid == -1) 109 errx(1, "editing error"); 110 else if (WIFSTOPPED(x)) 111 raise(WSTOPSIG(x)); 112 else if (WIFEXITED(x) && WEXITSTATUS(x) == 0) 113 break; 114 else 115 errx(1, "editing error"); 116 } 117 118 /* let process death clean up locks and file descriptors */ 119 return 0; 120} 121