]> git.pld-linux.org Git - projects/setup.git/blame - joinpasswd.c
add etc/sub[ug]id
[projects/setup.git] / joinpasswd.c
CommitLineData
31aff165 1/*
31aff165 2 *
e040c79e 3 * Copyright (c) 2001 Michal Moskal <malekith@pld-linux.org>.
31aff165
MM
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Michal Moskal.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY MICHAL MOSKAL AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *
34 *
35 * USAGE: joinpasswd
36 *
37 * Add entries from freshly created {passwd,shadow,group}.rpmnew to existing
38 * {passwd,shadow,group}. It is usable as part of setup package, during upgrade
39 * where new system user/group is to be added. If entry is already found in
3da0d83f
MM
40 * system database, it is left, otherwise it is added. UIDs/GIDs are *not*
41 * checked anyhow.
31aff165
MM
42 *
43 * For typical sizes of files in setup package, it takes about 1 second per
44 * 20000 users in system database on Pentium class machine. After static link
45 * against uClibc it is under 2k on x86. Stdio hasn't been used intentionally.
46 *
e040c79e 47 * Written for PLD Linux (http://www.pld-linux.org/) setup package.
31aff165
MM
48 *
49 * Compilation against uClibc:
50 * UCROOT=/usr/lib/bootdisk/usr
51 * gcc -I$UCROOT/include -nostdlib -O2 joinpasswd.c $UCROOT/lib/crt0.o \
52 * $UCROOT/lib/libc.a -lgcc -o joinpasswd
53 * strip -R .comment -R .note joinpasswd
54 *
e040c79e 55 * The idea of this program comes from Lukasz Dobrek <dobrek@pld-linux.org>.
31aff165
MM
56 *
57 */
58
59#include <sys/types.h>
60#include <sys/mman.h>
61#include <sys/stat.h>
cbc25e75 62#include <stdio.h>
8356227d 63#include <errno.h>
31aff165 64#include <unistd.h>
cbc25e75 65#include <stdarg.h>
31aff165
MM
66#include <fcntl.h>
67#include <stdlib.h>
68#include <string.h>
507b603d 69#include <signal.h>
31aff165
MM
70
71#define FILE1 "/etc/passwd"
72#define FILE2 "/etc/shadow"
73#define FILE3 "/etc/group"
1a43487e 74#define FILE4 "/etc/gshadow"
31aff165 75
507b603d
MM
76/* #define OLD_LOCK */
77
78#define LOCK_FILE "/etc/.pwd.lock"
79
31aff165 80#define SUFFIX ".rpmnew"
f88ff4b9
MM
81/* maybe "-" or sth? */
82#define BACKUP ".old"
31aff165
MM
83
84/* #define SILENT */
85
cbc25e75 86void eputs(const char *fmt, ...)
31aff165 87{
cbc25e75
AM
88 va_list args;
89
90 va_start(args, fmt);
91 vfprintf(stderr, fmt, args);
92 va_end(args);
31aff165
MM
93}
94
cbc25e75 95void fatal(const char *fmt, ...)
31aff165 96{
cbc25e75
AM
97 va_list args;
98
99 va_start(args, fmt);
100 eputs(fmt, args);
101 va_end(args);
102
31aff165
MM
103 eputs("\n");
104 exit(1);
105}
106
db127c35 107char *map_file(const char *name, ssize_t *sz)
31aff165
MM
108{
109 int fd;
110 void *ptr;
111 struct stat st;
112
113 fd = open(name, O_RDONLY);
114 if (fd == -1)
115 return NULL;
bd3b57f6
AM
116 if (fstat(fd, &st) < 0)
117 return NULL;
31aff165
MM
118 *sz = st.st_size;
119 ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
120 if (ptr == MAP_FAILED)
121 return NULL;
122
123 return ptr;
124}
125
db127c35 126int exist(char *id, int id_len, char *ptr, ssize_t sz)
31aff165 127{
db127c35 128 ssize_t i;
31aff165
MM
129
130 for (i = 0; i < sz; ) {
131 if (sz - i > id_len && memcmp(id, ptr + i, id_len + 1) == 0)
132 return 1;
133 while (i < sz && ptr[i] != '\n')
134 i++;
135 i++;
136 }
137
138 return 0;
139}
140
3da0d83f
MM
141void itoa(char *buf, long i)
142{
143 char tmp[32];
144 char *p;
145
146 if (i < 0) {
147 strcpy(buf, "-");
148 buf++;
149 i = -i;
150 }
151 if (i == 0) {
152 strcpy(buf, "0");
153 return;
154 }
155 for (p = tmp; i; i /= 10)
156 *p++ = (i % 10) + '0';
157 while (p > tmp)
158 *buf++ = *--p;
159 *buf = 0;
160}
161
507b603d
MM
162#ifndef OLD_LOCK
163int lock_fd = -1;
164void noop(int x)
165{
166 (void)x;
167}
168#endif
169
3da0d83f
MM
170int try_lock(const char *name)
171{
507b603d 172#ifdef OLD_LOCK
3da0d83f
MM
173 char file[strlen(name) + 32], lock[strlen(name) + 32];
174 char buf[32];
175 int fd;
176 long pid;
177
178 strcpy(lock, name);
179 strcpy(file, name);
180 strcat(lock, ".lock");
181 itoa(buf, (long)getpid());
182 strcat(file, ".");
183 strcat(file, buf);
184
185 fd = open(file, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
186 if (fd < 0)
187 return -1;
ed0f82b9
AM
188 if (write(fd, buf, strlen(buf)) < 0) {
189 close(fd);
190 return -1;
191 }
192 if (close(fd) < 0)
193 return -1;
3da0d83f
MM
194
195 if (link(file, lock) == 0) {
196 unlink(file);
197 return 0;
198 }
199
200 fd = open(lock, O_RDONLY);
201 if (fd < 0)
202 goto oops;
203 memset(buf, 0, sizeof(buf));
204 read(fd, buf, sizeof(buf));
205 pid = atol(buf);
206 if (pid == 0 || kill(pid, 0) != 0) {
207 /* stale lock */
208 unlink(file);
209 unlink(lock);
210 /* try again */
211 return try_lock(name);
212 }
213
214oops:
215 unlink(file);
216 return -1;
507b603d
MM
217#else
218 struct flock fl;
219
220 if (lock_fd != -1)
221 return -1;
222 lock_fd = open(LOCK_FILE, O_RDWR|O_CREAT, 0600);
223 if (lock_fd == -1)
224 return -1;
225 signal(SIGALRM, noop);
226 alarm(15);
227 memset(&fl, 0, sizeof(fl));
228 fl.l_type = F_WRLCK;
229 fl.l_whence = SEEK_SET;
230 if (fcntl(lock_fd, F_SETLKW, &fl) != 0) {
231 alarm(0);
232 close(lock_fd);
233 lock_fd = -1;
234 return -1;
235 }
236 alarm(0);
237
238 return 0;
239#endif
3da0d83f
MM
240}
241
242void unlock(const char *name)
243{
507b603d 244#ifdef OLD_LOCK
3da0d83f
MM
245 char lock[strlen(name) + 32];
246
247 strcpy(lock, name);
248 strcat(lock, ".lock");
249 unlink(lock);
507b603d
MM
250#else
251 if (lock_fd != -1)
252 close(lock_fd);
253 lock_fd = -1;
254#endif
3da0d83f
MM
255}
256
257void lock(const char *name)
258{
259 int n;
260
261 n = 5;
262 while (n--) {
263 if (try_lock(name) == 0)
264 return;
265 eputs("waiting for lock...\n");
266 sleep(1);
267 }
268 fatal("cannot get lock");
269}
270
f88ff4b9 271int join(const char *old_name, const char *new_name, const char *backup_name)
31aff165
MM
272{
273 char *old, *new, *id;
274 int i, fd;
db127c35 275 ssize_t old_sz, new_sz;
31aff165
MM
276
277 new = map_file(new_name, &new_sz);
278 if (new == NULL)
279 return -1;
3da0d83f
MM
280
281 lock(old_name);
31aff165
MM
282 old = map_file(old_name, &old_sz);
283 if (old == NULL)
cbc25e75 284 fatal("cannot mmap file `%s': %m", old_name);
f88ff4b9
MM
285
286 fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
287 if (fd < 0)
cbc25e75 288 fatal("cannot create backup file `%s': %m", backup_name);
8356227d 289 if (write(fd, old, old_sz) < 0)
cbc25e75 290 fatal("writting to backup file `%s' failed: %m", backup_name);
8356227d 291 if (fsync(fd) < 0)
cbc25e75 292 fatal("syncing backup file `%s' failed: %m", backup_name);
8356227d 293 if (close(fd) < 0)
cbc25e75 294 fatal("closing backup file `%s' failed: %m", backup_name);
f88ff4b9 295
31aff165 296#ifndef SILENT
128250fd 297 eputs("merging content of `");
31aff165
MM
298 eputs(old_name);
299 eputs("' with `");
300 eputs(new_name);
301 eputs("'\n");
302#endif /* SILENT */
303
304 fd = open(old_name, O_WRONLY|O_APPEND);
bd3b57f6 305 if (fd < 0)
cbc25e75 306 fatal("cannot open old file `%s': %m", old_name);
31aff165
MM
307
308 for (i = 0; i < new_sz; ) {
309 id = new + i;
310 while (i < new_sz && new[i] != ':' && new[i] != '\n')
311 i++;
312 if (i < new_sz && new[i] == ':') {
313 int id_len, line_len;
314
315 id_len = i - (id - new);
316 while (i < new_sz && new[i] != '\n')
317 i++;
318 if (i < new_sz)
319 i++;
320 line_len = i - (id - new);
321
322 if (!exist(id, id_len, old, old_sz)) {
323#ifndef SILENT
324 eputs(old_name);
325 eputs(": adding `");
326 write(2, id, id_len);
327 eputs("'\n");
328#endif /* SILENT */
8356227d 329 if (write(fd, id, line_len) < 0)
cbc25e75 330 fatal("writting line to `%s' failed, check backup file: %m", old_name);
31aff165
MM
331 }
332 } else if (i < new_sz)
333 i++;
334 }
bd9aee69
AM
335 fsync(fd);
336 close(fd);
31aff165
MM
337
338#if 0
339 /* user may want to exime this file... */
340 unlink(new_name);
341#endif
3da0d83f 342 unlock(old_name);
31aff165
MM
343
344 return 0;
345}
346
347int main()
348{
1a43487e 349#if 1
3da0d83f
MM
350 join(FILE1, FILE1 SUFFIX, FILE1 BACKUP);
351 join(FILE2, FILE2 SUFFIX, FILE2 BACKUP);
352 join(FILE3, FILE3 SUFFIX, FILE3 BACKUP);
1a43487e 353 join(FILE4, FILE4 SUFFIX, FILE4 BACKUP);
31aff165 354#else
3da0d83f 355 join("test", "test.new", "test.old");
31aff165
MM
356#endif
357 return 0;
358}
This page took 0.240336 seconds and 4 git commands to generate.