]> git.pld-linux.org Git - projects/setup.git/blob - joinpasswd.c
- tool for adding new users that appeard in .rpmnew files.
[projects/setup.git] / joinpasswd.c
1 /*
2  * $Id$
3  * 
4  * Copyright (c) 2001 Michal Moskal <malekith@pld.org.pl>.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Michal Moskal.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY MICHAL MOSKAL AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * 
36  * USAGE: joinpasswd
37  *
38  * Add entries from freshly created {passwd,shadow,group}.rpmnew to existing
39  * {passwd,shadow,group}. It is usable as part of setup package, during upgrade
40  * where new system user/group is to be added. If entry is already found in 
41  * system database, it is left, otherwise it is added. UIDs/GIDs are *not* checked
42  * anyhow. 
43  *
44  * For typical sizes of files in setup package, it takes about 1 second per
45  * 20000 users in system database on Pentium class machine. After static link
46  * against uClibc it is under 2k on x86. Stdio hasn't been used intentionally.
47  * 
48  * Written for PLD GNU/Linux (http://www.pld.org.pl) setup package.
49  *
50  * Compilation against uClibc:
51  * UCROOT=/usr/lib/bootdisk/usr
52  * gcc -I$UCROOT/include -nostdlib -O2 joinpasswd.c $UCROOT/lib/crt0.o \
53  *              $UCROOT/lib/libc.a -lgcc -o joinpasswd
54  * strip -R .comment -R .note joinpasswd
55  *
56  * The idea of this program comes from Lukasz Dobrek <dobrek@pld.org.pl>.
57  * 
58  */
59
60 #include <sys/types.h>
61 #include <sys/mman.h>
62 #include <sys/stat.h>
63 #include <unistd.h>
64 #include <fcntl.h>
65 #include <stdlib.h>
66 #include <string.h>
67
68 #define FILE1 "/etc/passwd"
69 #define FILE2 "/etc/shadow"
70 #define FILE3 "/etc/group"
71
72 #define SUFFIX ".rpmnew"
73
74 /* #define SILENT */
75
76 void eputs(const char *msg)
77 {
78         write(2, msg, strlen(msg));
79 }
80
81 void fatal(const char *msg)
82 {
83         eputs(msg);
84         eputs("\n");
85         exit(1);
86 }
87
88 char *map_file(const char *name, int *sz)
89 {
90         int fd;
91         void *ptr;
92         struct stat st;
93
94         fd = open(name, O_RDONLY);
95         if (fd == -1)
96                 return NULL;
97         fstat(fd, &st);
98         *sz = st.st_size;
99         ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
100         if (ptr == MAP_FAILED)
101                 return NULL;
102
103         return ptr;
104 }
105
106 int exist(char *id, int id_len, char *ptr, int sz)
107 {
108         int i;
109
110         for (i = 0; i < sz; ) {
111                 if (sz - i > id_len && memcmp(id, ptr + i, id_len + 1) == 0)
112                         return 1;
113                 while (i < sz && ptr[i] != '\n')
114                         i++;
115                 i++;
116         }
117
118         return 0;
119 }
120
121 int join(const char *old_name, const char *new_name)
122 {
123         char *old, *new, *id;
124         int i, fd;
125         int old_sz, new_sz;
126
127         new = map_file(new_name, &new_sz);
128         if (new == NULL)
129                 return -1;
130                 
131         old = map_file(old_name, &old_sz);
132         if (old == NULL)
133                 fatal("cannot mmap old");
134
135 #ifndef SILENT
136         eputs("marging contest of `");
137         eputs(old_name);
138         eputs("' with `");
139         eputs(new_name);
140         eputs("'\n");
141 #endif /* SILENT */
142
143         fd = open(old_name, O_WRONLY|O_APPEND);
144         
145         for (i = 0; i < new_sz; ) {
146                 id = new + i;
147                 while (i < new_sz && new[i] != ':' && new[i] != '\n')
148                         i++;
149                 if (i < new_sz && new[i] == ':') {
150                         int id_len, line_len;
151
152                         id_len = i - (id - new);
153                         while (i < new_sz && new[i] != '\n')
154                                 i++;
155                         if (i < new_sz)
156                                 i++;
157                         line_len = i - (id - new);
158                         
159                         if (!exist(id, id_len, old, old_sz)) {
160 #ifndef SILENT
161                                 eputs(old_name);
162                                 eputs(": adding `");
163                                 write(2, id, id_len);
164                                 eputs("'\n");
165 #endif /* SILENT */
166                                 write(fd, id, line_len);
167                         }
168                 } else if (i < new_sz)
169                         i++;
170         }
171
172 #if 0
173         /* user may want to exime this file... */
174         unlink(new_name);
175 #endif
176
177         return 0;
178 }
179
180 int main()
181 {
182 #if 1
183         join(FILE1, FILE1 SUFFIX);
184         join(FILE2, FILE2 SUFFIX);
185         join(FILE3, FILE3 SUFFIX);
186 #else
187         join("test", "test.new");
188 #endif
189         return 0;
190 }
This page took 0.058561 seconds and 4 git commands to generate.