Patch from Tito to unify deluser and delgroup, and generally shrink code.
[oweals/busybox.git] / loginutils / deluser.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * deluser (remove lusers from the system ;) for TinyLogin
4  *
5  * Copyright (C) 1999 by Lineo, inc. and John Beppu
6  * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7  * Unified with delgroup by Tito Ragusa <farmatito@tiscali.it>
8  *
9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10  *
11  */
12
13 #include <sys/stat.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "busybox.h"
19
20 /* where to start and stop deletion */
21 typedef struct {
22         size_t start;
23         size_t stop;
24 } Bounds;
25
26 /* An interesting side-effect of boundary()'s
27  * implementation is that the first user (typically root)
28  * cannot be removed.  Let's call it a feature. */
29 static inline Bounds boundary(const char *buffer, const char *login)
30 {
31         char needle[256];
32         char *start;
33         char *stop;
34         Bounds b;
35
36         snprintf(needle, 256, "\n%s:", login);
37         needle[255] = 0;
38         start = strstr(buffer, needle);
39         if (!start) {
40                 b.start = 0;
41                 b.stop = 0;
42                 return b;
43         }
44         start++;
45
46         stop = index(start, '\n');      /* index is a BSD-ism */
47         b.start = start - buffer;
48         b.stop = stop - buffer;
49         return b;
50 }
51
52 /* grep -v ^login (except it only deletes the first match) */
53 /* ...in fact, I think I'm going to simplify this later */
54 static void del_line_matching(const char *login, const char *filename)
55 {
56         char *buffer;
57         FILE *passwd;
58         Bounds b;
59         struct stat statbuf;
60
61
62         if ((passwd = bb_wfopen(filename, "r"))) {
63                 xstat(filename, &statbuf);
64                 buffer = (char *) xmalloc(statbuf.st_size * sizeof(char));
65                 fread(buffer, statbuf.st_size, sizeof(char), passwd);
66                 fclose(passwd);
67                 /* find the user to remove */
68                 b = boundary(buffer, login);
69                 if (b.stop != 0) {
70                         /* write the file w/o the user */
71                         if ((passwd = bb_wfopen(filename, "w"))) {
72                                 fwrite(buffer, (b.start - 1), sizeof(char), passwd);
73                                 fwrite(&buffer[b.stop], (statbuf.st_size - b.stop), sizeof(char), passwd);
74                                 fclose(passwd);
75                         }
76                 } else {
77                         bb_error_msg("Can't find '%s' in '%s'", login, filename);
78                 }
79                 free(buffer);
80         }
81 }
82
83 int deluser_main(int argc, char **argv)
84 {
85         if (argc != 2) {
86                 bb_show_usage();
87         } else {
88                 if (ENABLE_DELUSER && bb_applet_name[3] == 'u') {
89                         del_line_matching(argv[1], bb_path_passwd_file);
90                         if (ENABLE_FEATURE_SHADOWPASSWDS)
91                                 del_line_matching(argv[1], bb_path_shadow_file);
92                 }
93                 del_line_matching(argv[1], bb_path_group_file);
94                 if (ENABLE_FEATURE_SHADOWPASSWDS)
95                         del_line_matching(argv[1], bb_path_gshadow_file);
96         }
97         return (EXIT_SUCCESS);
98 }
99
100 /* $Id: deluser.c,v 1.4 2003/07/14 20:20:45 andersen Exp $ */