]> git.pld-linux.org Git - projects/setup.git/blob - joinpasswd.c
- added making backup of updated 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 /* maybe "-" or sth? */
74 #define BACKUP ".old"
75
76 /* #define SILENT */
77
78 void eputs(const char *msg)
79 {
80         write(2, msg, strlen(msg));
81 }
82
83 void fatal(const char *msg)
84 {
85         eputs(msg);
86         eputs("\n");
87         exit(1);
88 }
89
90 char *map_file(const char *name, int *sz)
91 {
92         int fd;
93         void *ptr;
94         struct stat st;
95
96         fd = open(name, O_RDONLY);
97         if (fd == -1)
98                 return NULL;
99         fstat(fd, &st);
100         *sz = st.st_size;
101         ptr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
102         if (ptr == MAP_FAILED)
103                 return NULL;
104
105         return ptr;
106 }
107
108 int exist(char *id, int id_len, char *ptr, int sz)
109 {
110         int i;
111
112         for (i = 0; i < sz; ) {
113                 if (sz - i > id_len && memcmp(id, ptr + i, id_len + 1) == 0)
114                         return 1;
115                 while (i < sz && ptr[i] != '\n')
116                         i++;
117                 i++;
118         }
119
120         return 0;
121 }
122
123 int join(const char *old_name, const char *new_name, const char *backup_name)
124 {
125         char *old, *new, *id;
126         int i, fd;
127         int old_sz, new_sz;
128
129         new = map_file(new_name, &new_sz);
130         if (new == NULL)
131                 return -1;
132                 
133         old = map_file(old_name, &old_sz);
134         if (old == NULL)
135                 fatal("cannot mmap old");
136         
137         fd = open(backup_name, O_WRONLY|O_CREAT|O_TRUNC, 0600);
138         if (fd < 0)
139                 fatal("cannot make backup");
140         write(fd, old, old_sz);
141         close(fd);
142         
143 #ifndef SILENT
144         eputs("marging contest of `");
145         eputs(old_name);
146         eputs("' with `");
147         eputs(new_name);
148         eputs("'\n");
149 #endif /* SILENT */
150
151         fd = open(old_name, O_WRONLY|O_APPEND);
152         
153         for (i = 0; i < new_sz; ) {
154                 id = new + i;
155                 while (i < new_sz && new[i] != ':' && new[i] != '\n')
156                         i++;
157                 if (i < new_sz && new[i] == ':') {
158                         int id_len, line_len;
159
160                         id_len = i - (id - new);
161                         while (i < new_sz && new[i] != '\n')
162                                 i++;
163                         if (i < new_sz)
164                                 i++;
165                         line_len = i - (id - new);
166                         
167                         if (!exist(id, id_len, old, old_sz)) {
168 #ifndef SILENT
169                                 eputs(old_name);
170                                 eputs(": adding `");
171                                 write(2, id, id_len);
172                                 eputs("'\n");
173 #endif /* SILENT */
174                                 write(fd, id, line_len);
175                         }
176                 } else if (i < new_sz)
177                         i++;
178         }
179
180 #if 0
181         /* user may want to exime this file... */
182         unlink(new_name);
183 #endif
184
185         return 0;
186 }
187
188 int main()
189 {
190 #if 1
191         join(FILE1, FILE1 SUFFIX);
192         join(FILE2, FILE2 SUFFIX);
193         join(FILE3, FILE3 SUFFIX);
194 #else
195         join("test", "test.new");
196 #endif
197         return 0;
198 }
This page took 0.062829 seconds and 4 git commands to generate.