bin/96248: vipw fail on RO /etc

Alex Kozlov spam at rm-rf.kiev.ua
Mon Apr 24 22:50:26 UTC 2006


The following reply was made to PR bin/96248; it has been noted by GNATS.

From: Alex Kozlov <spam at rm-rf.kiev.ua>
To: Maxim Konovalov <maxim at macomnet.ru>
Cc: bug-followup at freebsd.org
Subject: Re: bin/96248: vipw fail on RO /etc
Date: Tue, 25 Apr 2006 01:44:02 +0300

 On Mon, Apr 24, 2006 at 11:16:01PM +0400, Maxim Konovalov wrote:
 > On Mon, 24 Apr 2006, 21:46+0300, Alex Kozlov wrote:
 > 
 > > Hi, Maxim
 > >
 > > No need to touch pw_util.
 > >
 > > Have pw_tmp in one certain place will be nice, but different fs problem...
 > > Hmm.
 > >
 > > Much easier to teach vipw call PAGER if pw_edit fall on RO fs.
 > >
 > > This patch can be accepted? If no, you may close PR.
 > 
 > I haven't seen any patches yet but personally don't see much sense in
 > such subtle mechanism.
 It trivial. Something like this:
  
 --- vipw.c	Tue Apr 19 19:18:07 2006
 +++ vipw.c.new	Tue Apr 25 00:16:16 2006
 @@ -50,9 +50,13 @@
  
  #include <sys/types.h>
  #include <sys/stat.h>
 +#include <sys/errno.h>
 +#include <sys/wait.h>
  
  #include <err.h>
 +#include <libgen.h>
  #include <pwd.h>
 +#include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
 @@ -66,9 +70,14 @@
  main(int argc, char *argv[])
  {
  	const char *passwd_dir = NULL;
 +	const char *pager;
  	int ch, pfd, tfd;
 +	int pstat;
  	char *line;
  	size_t len;
 +	struct sigaction sa, sa_int, sa_quit;
 +	sigset_t oldsigset, sigset;
 +	static pid_t pagerpid = -1;
  
  	while ((ch = getopt(argc, argv, "d:")) != -1)
  		switch (ch) {
 @@ -93,8 +102,67 @@
  		err(1, "pw_lock()");
  	}
  	if ((tfd = pw_tmp(pfd)) == -1) {
 -		pw_fini();
 -		err(1, "pw_tmp()");
 +		if (errno == EROFS) {
 +			/* pw_view */
 +
 +			(void)close(tfd);
 +			
 +			if ((pager = getenv("PAGER")) == NULL)
 +				//pager = _PATH_MORE
 +				pager = "/usr/bin/more";
 +
 +			sa.sa_handler = SIG_IGN;
 +			sigemptyset(&sa.sa_mask);
 +			sa.sa_flags = 0;
 +			sigaction(SIGINT, &sa, &sa_int);
 +			sigaction(SIGQUIT, &sa, &sa_quit);
 +			sigemptyset(&sigset);
 +			sigaddset(&sigset, SIGCHLD);
 +			sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
 +			switch ((pagerpid = fork())) {
 +			case -1:
 +				err(1, "pw_view()");
 +			case 0:
 +				sigaction(SIGINT, &sa_int, NULL);
 +				sigaction(SIGQUIT, &sa_quit, NULL);
 +				sigprocmask(SIG_SETMASK, &oldsigset, NULL);
 +
 +				errno = 0;
 +				dup2(pfd, STDIN_FILENO);
 +				execlp(pager, basename(pager), NULL, (char *)NULL);
 +				_exit(errno);
 +			default:
 +				(void)close(pfd);
 +				pw_fini();
 +			/* parent */
 +			break;
 +			}
 +
 +			for (;;) {
 +				if (waitpid(pagerpid, &pstat, WUNTRACED) == -1) {
 +					if (errno == EINTR)
 +						continue;
 +					pagerpid = -1;
 +					break;
 +				} else if (WIFSTOPPED(pstat)) {
 +					raise(WSTOPSIG(pstat));
 +				} else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
 +					pagerpid = -1;
 +					break;
 +				} else {
 +					pagerpid = -1;
 +					break;
 +				}
 +			}
 +			sigaction(SIGINT, &sa_int, NULL);
 +			sigaction(SIGQUIT, &sa_quit, NULL);
 +			sigprocmask(SIG_SETMASK, &oldsigset, NULL);
 +
 +			exit(0);
 +		} else {
 +			pw_fini();
 +			err(1, "pw_tmp()");
 +		}
  	}
  	(void)close(tfd);
  	/* Force umask for partial writes made in the edit phase */
 
 
 >  I believe a simple script could solve the problem in your environment.
 Almost any missing features can be done with wrapper script.
 But programs continue to improve.
 Also I don't want script in sudo case. 
 
 P.S. Btw, lib/libutil don't respect NO_INET6 knob. Fix is simple.
 Shall I fill another PR?
 
 --
 Adios


More information about the freebsd-bugs mailing list