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