Initialize Tizen 2.3
[external/prelink.git] / src / doit.c
1 /* Copyright (C) 2001, 2003, 2004, 2005, 2007 Red Hat, Inc.
2    Written by Jakub Jelinek <jakub@redhat.com>, 2001.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include <config.h>
19 #include <alloca.h>
20 #include <errno.h>
21 #include <error.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include "prelinktab.h"
28
29 struct collect_ents
30   {
31     struct prelink_entry **ents;
32     int nents;
33   };
34
35 static int
36 find_ents (void **p, void *info)
37 {
38   struct collect_ents *l = (struct collect_ents *) info;
39   struct prelink_entry *e = * (struct prelink_entry **) p;
40
41   e->u.tmp = 0;
42   if ((e->type == ET_DYN && e->done == 1)
43       || (e->type == ET_EXEC && e->done == 0 && ! libs_only))
44     l->ents[l->nents++] = e;
45
46   return 1;
47 }
48
49 static void
50 prelink_ent (struct prelink_entry *ent)
51 {
52   int i, j;
53   DSO *dso;
54   struct stat64 st;
55   struct prelink_link *hardlink;
56   char *move = NULL;
57   size_t movelen = 0;
58
59   for (i = 0; i < ent->ndepends; ++i)
60     if (ent->depends[i]->done == 1)
61       prelink_ent (ent->depends[i]);
62
63   for (i = 0; i < ent->ndepends; ++i)
64     if (ent->depends[i]->done != 2)
65       {
66         ent->done = 0;
67         if (! undo)
68           ent->type = ET_UNPRELINKABLE;
69         if (verbose)
70           error (0, 0, "Could not prelink %s because its dependency %s could not be prelinked",
71                  ent->filename, ent->depends[i]->filename);
72         return;
73       }
74
75   ent->u.tmp = 1;
76   for (i = 0; i < ent->ndepends; ++i)
77     ent->depends[i]->u.tmp = 1;
78   for (i = 0; i < ent->ndepends; ++i)
79     {
80       struct prelink_entry *dent = ent->depends[i];
81       for (j = 0; j < dent->ndepends; ++j)
82         if (dent->depends[j]->u.tmp == 0)
83           {
84             ent->done = 0;
85             if (! undo)
86               ent->type = ET_UNPRELINKABLE;
87             if (verbose)
88               error (0, 0, "Could not prelink %s because it doesn't use %s, but one of its dependencies has been prelinked against it",
89                      ent->filename, dent->depends[j]->filename);
90             ent->u.tmp = 0;
91             for (i = 0; i < ent->ndepends; ++i)
92               ent->depends[i]->u.tmp = 0;
93             return;
94           }
95     }
96   ent->u.tmp = 0;
97   for (i = 0; i < ent->ndepends; ++i)
98     ent->depends[i]->u.tmp = 0;
99
100   if (verbose)
101     {
102       if (dry_run)
103         printf ("Would prelink %s\n", ent->canon_filename);
104       else
105         printf ("Prelinking %s\n", ent->canon_filename);
106     }
107
108   dso = open_dso (ent->canon_filename);
109   if (dso == NULL)
110     goto error_out;
111
112   if (fstat64 (dso->fd, &st) < 0)
113     {
114       error (0, errno, "%s changed during prelinking", ent->filename);
115       goto error_out;
116     }
117
118   if (st.st_dev != ent->dev || st.st_ino != ent->ino)
119     {
120       error (0, 0, "%s changed during prelinking", ent->filename);
121       goto error_out;
122     }
123
124   if (dry_run)
125     close_dso (dso);
126   else
127     {
128       if (prelink_prepare (dso))
129         goto make_unprelinkable;
130       if (ent->type == ET_DYN && relocate_dso (dso, ent->base))
131         goto make_unprelinkable;
132       if (prelink (dso, ent))
133         goto make_unprelinkable;
134       if (update_dso (dso, NULL))
135         {
136           dso = NULL;
137           goto error_out;
138         }
139     }
140   ent->done = 2;
141   ent->flags |= PCF_PRELINKED;
142
143   /* Redo hardlinks.  */
144   for (hardlink = ent->hardlink; hardlink; hardlink = hardlink->next)
145     {
146       size_t len;
147
148       if (lstat64 (hardlink->canon_filename, &st) < 0)
149         {
150           error (0, 0, "Could not stat %s (former hardlink to %s)",
151                  hardlink->canon_filename, ent->canon_filename);
152           continue;
153         }
154
155       if (st.st_dev != ent->dev || st.st_ino != ent->ino)
156         {
157           error (0, 0, "%s is no longer hardlink to %s",
158                  hardlink->canon_filename, ent->canon_filename);
159           continue;
160         }
161
162       if (verbose)
163         {
164           if (dry_run)
165             printf ("Would link %s to %s\n", hardlink->canon_filename,
166                     ent->canon_filename);
167           else
168             printf ("Linking %s to %s\n", hardlink->canon_filename,
169                     ent->canon_filename);
170         }
171
172       if (dry_run)
173         continue;
174
175       len = strlen (hardlink->canon_filename);
176       if (len + sizeof (".#prelink#") > movelen)
177         {
178           movelen = len + sizeof (".#prelink#");
179           move = realloc (move, movelen);
180           if (move == NULL)
181             {
182               error (0, ENOMEM, "Could not hardlink %s to %s",
183                      hardlink->canon_filename, ent->canon_filename);
184               movelen = 0;
185               continue;
186             }
187         }
188
189       memcpy (mempcpy (move, hardlink->canon_filename, len), ".#prelink#",
190               sizeof (".#prelink#"));
191       if (rename (hardlink->canon_filename, move) < 0)
192         {
193           error (0, errno, "Could not hardlink %s to %s",
194                  hardlink->canon_filename, ent->canon_filename);
195           continue;
196         }
197
198       if (link (ent->canon_filename, hardlink->canon_filename) < 0)
199         {
200           error (0, errno, "Could not hardlink %s to %s",
201                  hardlink->canon_filename, ent->canon_filename);
202
203           if (rename (move, hardlink->canon_filename) < 0)
204             {
205               error (0, errno, "Could not rename %s back to %s",
206                      move, hardlink->canon_filename);
207             }
208           continue;
209         }
210
211       if (unlink (move) < 0)
212         {
213           error (0, errno, "Could not unlink %s", move);
214           continue;
215         }
216     }
217   free (move);
218
219   if (! dry_run && stat64 (ent->canon_filename, &st) >= 0)
220     {
221       ent->dev = st.st_dev;
222       ent->ino = st.st_ino;
223       ent->ctime = st.st_ctime;
224       ent->mtime = st.st_mtime;
225     }
226   return;
227
228 make_unprelinkable:
229   if (! undo)
230     ent->type = ET_UNPRELINKABLE;
231 error_out:
232   ent->done = 0;
233   if (dso)
234     close_dso (dso);
235   return;
236 }
237
238 void
239 prelink_all (void)
240 {
241   struct collect_ents l;
242   int i;
243
244   l.ents =
245     (struct prelink_entry **) alloca (prelink_entry_count
246                                       * sizeof (struct prelink_entry *));
247   l.nents = 0;
248   htab_traverse (prelink_filename_htab, find_ents, &l);
249
250   for (i = 0; i < l.nents; ++i)
251     if (l.ents[i]->done == 1
252         || (l.ents[i]->done == 0 && l.ents[i]->type == ET_EXEC))
253       prelink_ent (l.ents[i]);
254 }