2 vipw, vigr edit the password or group file
3 with -s will edit shadow or gshadow file
5 Copyright (C) 1997 Guy Maor <maor@ece.utexas.edu>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 #include <sys/types.h>
37 #include "exitcodes.h"
40 #include "prototypes.h"
45 #define MSG_WARN_EDIT_OTHER_FILE _( \
46 "You have modified %s.\n"\
47 "You may need to modify %s for consistency.\n"\
48 "Please use the command `%s' to do so.\n")
53 static const char *progname, *filename, *fileeditname;
54 static int filelocked = 0, createedit = 0;
55 static int (*unlock) (void);
58 /* local function prototypes */
59 static void usage (void);
60 static int create_backup_file (FILE *, const char *, struct stat *);
61 static void vipwexit (const char *, int, int);
62 static void vipwedit (const char *, int (*)(void), int (*)(void));
65 * usage - display usage message and exit
67 static void usage (void)
69 fputs (_("Usage: vipw [options]\n"
72 " -g, --group edit group database\n"
73 " -h, --help display this help message and exit\n"
74 " -p, --passwd edit passwd database\n"
75 " -q, --quiet quiet mode\n"
76 " -s, --shadow edit shadow or gshadow database\n"
84 static int create_backup_file (FILE * fp, const char *backup, struct stat *sb)
92 bkfp = fopen (backup, "w");
98 if (fseeko (fp, 0, SEEK_SET) == 0)
99 while ((c = getc (fp)) != EOF) {
100 if (putc (c, bkfp) == EOF)
103 if (c != EOF || ferror (fp) || fflush (bkfp)) {
113 ub.actime = sb->st_atime;
114 ub.modtime = sb->st_mtime;
115 if (utime (backup, &ub) ||
116 chmod (backup, sb->st_mode) ||
117 chown (backup, sb->st_uid, sb->st_gid)) {
127 static void vipwexit (const char *msg, int syserr, int ret)
132 unlink (fileeditname);
136 fprintf (stderr, "%s: %s", progname, msg);
138 fprintf (stderr, ": %s", strerror (err));
140 fprintf (stdout, _("\n%s: %s is unchanged\n"), progname,
145 #ifndef DEFAULT_EDITOR
146 #define DEFAULT_EDITOR "vi"
153 vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
157 struct stat st1, st2;
160 char filebackup[1024], fileedit[1024];
162 snprintf (filebackup, sizeof filebackup, "%s-", file);
163 snprintf (fileedit, sizeof fileedit, "%s.edit", file);
164 unlock = file_unlock;
166 fileeditname = fileedit;
168 if (access (file, F_OK))
169 vipwexit (file, 1, 1);
171 vipwexit (_("Couldn't lock file"), errno, 5);
174 /* edited copy has same owners, perm */
175 if (stat (file, &st1))
176 vipwexit (file, 1, 1);
177 if (!(f = fopen (file, "r")))
178 vipwexit (file, 1, 1);
179 if (create_backup_file (f, fileedit, &st1))
180 vipwexit (_("Couldn't make backup"), errno, 1);
183 editor = getenv ("VISUAL");
185 editor = getenv ("EDITOR");
187 editor = DEFAULT_EDITOR;
189 if ((pid = fork ()) == -1)
190 vipwexit ("fork", 1, 1);
192 /* use the system() call to invoke the editor so that it accepts
193 command line args in the EDITOR and VISUAL environment vars */
196 buf = (char *) malloc (strlen (editor) + strlen (fileedit) + 2);
197 snprintf (buf, strlen (editor) + strlen (fileedit) + 2,
198 "%s %s", editor, fileedit);
199 if (system (buf) != 0) {
200 fprintf (stderr, "%s: %s: %s\n", progname, editor,
208 pid = waitpid (pid, &status, WUNTRACED);
209 if (WIFSTOPPED (status)) {
210 kill (getpid (), SIGSTOP);
211 kill (getpid (), SIGCONT);
216 if (pid == -1 || !WIFEXITED (status) || WEXITSTATUS (status))
217 vipwexit (editor, 1, 1);
219 if (stat (fileedit, &st2))
220 vipwexit (fileedit, 1, 1);
221 if (st1.st_mtime == st2.st_mtime)
225 * XXX - here we should check fileedit for errors; if there are any,
226 * ask the user what to do (edit again, save changes anyway, or quit
227 * without saving). Use pwck or grpck to do the check. --marekm
231 link (file, filebackup);
232 if (rename (fileedit, file) == -1) {
235 ("%s: can't restore %s: %s (your changes are in %s)\n"),
236 progname, file, strerror (errno), fileedit);
243 int main (int argc, char **argv)
249 setlocale (LC_ALL, "");
250 bindtextdomain (PACKAGE, LOCALEDIR);
251 textdomain (PACKAGE);
253 progname = ((a = strrchr (*argv, '/')) ? a + 1 : *argv);
254 do_vipw = (strcmp (progname, "vigr") != 0);
258 * Parse the command line options.
261 static struct option long_options[] = {
262 {"group", no_argument, NULL, 'g'},
263 {"help", no_argument, NULL, 'h'},
264 {"passwd", no_argument, NULL, 'p'},
265 {"quiet", no_argument, NULL, 'q'},
266 {"shadow", no_argument, NULL, 's'},
269 getopt_long (argc, argv, "ghpqs",
270 long_options, NULL)) != -1) {
295 vipwedit (SHADOW_FILE, spw_lock, spw_unlock);
296 printf (MSG_WARN_EDIT_OTHER_FILE,
301 vipwedit (PASSWD_FILE, pw_lock, pw_unlock);
302 if (spw_file_present ()) {
303 printf (MSG_WARN_EDIT_OTHER_FILE,
312 vipwedit (SGROUP_FILE, sgr_lock, sgr_unlock);
313 printf (MSG_WARN_EDIT_OTHER_FILE,
319 vipwedit (GROUP_FILE, gr_lock, gr_unlock);
321 if (sgr_file_present ()) {
322 printf (MSG_WARN_EDIT_OTHER_FILE,
331 nscd_flush_cache ("passwd");
332 nscd_flush_cache ("group");