]> git.pld-linux.org Git - projects/setup.git/blame - joinpasswd.c
- added gshadow
[projects/setup.git] / joinpasswd.c
CommitLineData
31aff165
MM
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
3da0d83f
MM
41 * system database, it is left, otherwise it is added. UIDs/GIDs are *not*
42 * checked anyhow.
31aff165
MM
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"
1a43487e 71#define FILE4 "/etc/gshadow"
31aff165
MM
72
73#define SUFFIX ".rpmnew"
f88ff4b9
MM
74/* maybe "-" or sth? */
75#define BACKUP ".old"
31aff165
MM
76
77/* #define SILENT */
78
79void eputs(const char *msg)
80{
81 write(2, msg, strlen(msg));
82}
83
84void fatal(const char *msg)
85{
86 eputs(msg);
87 eputs("\n");
88 exit(1);
89}
90
91char *map_file(const char *name, int *sz)
92{
93 int fd;
94 void *ptr;
95 struct stat st;
96
97 fd = open(name, O_RDONLY);
98 if (fd == -1)
99 return NULL;
100 fstat(fd, &st);
101 *sz = st.st_size;
102 ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
103 if (ptr == MAP_FAILED)
104 return NULL;
105
106 return ptr;
107}
108
109int exist(char *id, int id_len, char *ptr, int sz)
110{
111 int i;
112
113 for (i = 0; i < sz; ) {
114 if (sz - i > id_len && memcmp(id, ptr + i, id_len + 1) == 0)
115 return 1;
116 while (i < sz && ptr[i] != '\n')
117 i++;
118 i++;
119 }
120
121 return 0;
122}
123
3da0d83f
MM
124void itoa(char *buf, long i)
125{
126 char tmp[32];
127 char *p;
128
129 if (i < 0) {
130 strcpy(buf, "-");
131 buf++;
132 i = -i;
133 }
134 if (i == 0) {
135 strcpy(buf, "0");
136 return;
137 }
138 for (p = tmp; i; i /= 10)
139 *p++ = (i % 10) + '0';
140 while (p > tmp)
141 *buf++ = *--p;
142 *buf = 0;
143}
144
145int try_lock(const char *name)
146{
147 char file[strlen(name) + 32], lock[strlen(name) + 32];
148 char buf[32];
149 int fd;
150 long pid;
151
152 strcpy(lock, name);
153 strcpy(file, name);
154 strcat(lock, ".lock");
155 itoa(buf, (long)getpid());
156 strcat(file, ".");
157 strcat(file, buf);
158
159 fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
160 if (fd < 0)
161 return -1;
162 write(fd, buf, strlen(buf));
163 close(fd);
164
165 if (link(file, lock) == 0) {
166 unlink(file);
167 return 0;
168 }
169
170 fd = open(lock, O_RDONLY);
171 if (fd < 0)
172 goto oops;
173 memset(buf, 0, sizeof(buf));
174 read(fd, buf, sizeof(buf));
175 pid = atol(buf);
176 if (pid == 0 || kill(pid, 0) != 0) {
177 /* stale lock */
178 unlink(file);
179 unlink(lock);
180 /* try again */
181 return try_lock(name);
182 }
183
184oops:
185 unlink(file);
186 return -1;
187}
188
189void unlock(const char *name)
190{
191 char lock[strlen(name) + 32];
192
193 strcpy(lock, name);
194 strcat(lock, ".lock");
195 unlink(lock);
196}
197
198void lock(const char *name)
199{
200 int n;
201
202 n = 5;
203 while (n--) {
204 if (try_lock(name) == 0)
205 return;
206 eputs("waiting for lock...\n");
207 sleep(1);
208 }
209 fatal("cannot get lock");
210}
211
f88ff4b9 212int join(const char *old_name, const char *new_name, const char *backup_name)
31aff165
MM
213{
214 char *old, *new, *id;
215 int i, fd;
216 int old_sz, new_sz;
217
218 new = map_file(new_name, &new_sz);
219 if (new == NULL)
220 return -1;
3da0d83f
MM
221
222 lock(old_name);
31aff165
MM
223 old = map_file(old_name, &old_sz);
224 if (old == NULL)
225 fatal("cannot mmap old");
f88ff4b9
MM
226
227 fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
228 if (fd < 0)
229 fatal("cannot make backup");
230 write(fd, old, old_sz);
231 close(fd);
232
31aff165
MM
233#ifndef SILENT
234 eputs("marging contest of `");
235 eputs(old_name);
236 eputs("' with `");
237 eputs(new_name);
238 eputs("'\n");
239#endif /* SILENT */
240
241 fd = open(old_name, O_WRONLY|O_APPEND);
242
243 for (i = 0; i < new_sz; ) {
244 id = new + i;
245 while (i < new_sz && new[i] != ':' && new[i] != '\n')
246 i++;
247 if (i < new_sz && new[i] == ':') {
248 int id_len, line_len;
249
250 id_len = i - (id - new);
251 while (i < new_sz && new[i] != '\n')
252 i++;
253 if (i < new_sz)
254 i++;
255 line_len = i - (id - new);
256
257 if (!exist(id, id_len, old, old_sz)) {
258#ifndef SILENT
259 eputs(old_name);
260 eputs(": adding `");
261 write(2, id, id_len);
262 eputs("'\n");
263#endif /* SILENT */
264 write(fd, id, line_len);
265 }
266 } else if (i < new_sz)
267 i++;
268 }
269
270#if 0
271 /* user may want to exime this file... */
272 unlink(new_name);
273#endif
3da0d83f 274 unlock(old_name);
31aff165
MM
275
276 return 0;
277}
278
279int main()
280{
1a43487e 281#if 1
3da0d83f
MM
282 join(FILE1, FILE1 SUFFIX, FILE1 BACKUP);
283 join(FILE2, FILE2 SUFFIX, FILE2 BACKUP);
284 join(FILE3, FILE3 SUFFIX, FILE3 BACKUP);
1a43487e 285 join(FILE4, FILE4 SUFFIX, FILE4 BACKUP);
31aff165 286#else
3da0d83f 287 join("test", "test.new", "test.old");
31aff165
MM
288#endif
289 return 0;
290}
This page took 0.135872 seconds and 4 git commands to generate.