blob: f380e2b9d162d3174daab4c602f4eb992a3917c2 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Update data structures for changes and write them out.
2 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 2.
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#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <libelf.h>
23#include <unistd.h>
24#include <sys/mman.h>
Roland McGrath89757442005-09-11 09:05:20 +000025#include <sys/stat.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000026
27#include "libelfP.h"
28
29
30static off_t
31write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
32{
33 int class = elf->class;
34
Roland McGrath89757442005-09-11 09:05:20 +000035 /* Check the mode bits now, before modification might change them. */
36 struct stat st;
37 if (unlikely (fstat (elf->fildes, &st) != 0))
38 {
39 __libelf_seterrno (ELF_E_WRITE_ERROR);
40 return -1;
41 }
42
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000043 /* Adjust the size in any case. We do this even if we use `write'.
44 We cannot do this if this file is in an archive. We also don't
45 do it *now* if we are shortening the file since this would
46 prevent programs to use the data of the file in generating the
47 new file. We truncate the file later in this case. */
48 if (elf->parent == NULL
49 && (elf->maximum_size == ~((size_t) 0)
50 || (size_t) size > elf->maximum_size)
51 && unlikely (ftruncate (elf->fildes, size) != 0))
52 {
53 __libelf_seterrno (ELF_E_WRITE_ERROR);
54 return -1;
55 }
56
57 /* Try to map the file if this isn't done yet. */
58 if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
59 {
60#if _MUDFLAP
61 /* Mudflap doesn't grok that our mmap'd data is ok. */
62#else
63 elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE,
64 MAP_SHARED, elf->fildes, 0);
65 if (unlikely (elf->map_address == MAP_FAILED))
66 elf->map_address = NULL;
67#endif
68 }
69
70 if (elf->map_address != NULL)
71 {
72 /* The file is mmaped. */
73 if ((class == ELFCLASS32
74 ? __elf32_updatemmap (elf, change_bo, shnum)
75 : __elf64_updatemmap (elf, change_bo, shnum)) != 0)
76 /* Some problem while writing. */
77 size = -1;
78 }
79 else
80 {
81 /* The file is not mmaped. */
82 if ((class == ELFCLASS32
83 ? __elf32_updatefile (elf, change_bo, shnum)
84 : __elf64_updatefile (elf, change_bo, shnum)) != 0)
85 /* Some problem while writing. */
86 size = -1;
87 }
88
89 if (size != -1
90 && elf->parent == NULL
91 && elf->maximum_size != ~((size_t) 0)
92 && (size_t) size < elf->maximum_size
93 && unlikely (ftruncate (elf->fildes, size) != 0))
94 {
95 __libelf_seterrno (ELF_E_WRITE_ERROR);
96 size = -1;
97 }
98
Roland McGrath89757442005-09-11 09:05:20 +000099 /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
100 mode bits. So make sure we restore them afterwards if they were set.
101 This is not atomic if someone else chmod's the file while we operate. */
102 if (size != -1
103 && unlikely (st.st_mode & (S_ISUID | S_ISGID))
104 /* fchmod ignores the bits we cannot change. */
105 && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
106 {
107 __libelf_seterrno (ELF_E_WRITE_ERROR);
108 size = -1;
109 }
110
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000111 if (size != -1 && elf->parent == NULL)
112 elf->maximum_size = size;
113
114 return size;
115}
116
117
118off_t
119elf_update (elf, cmd)
120 Elf *elf;
121 Elf_Cmd cmd;
122{
123 size_t shnum;
124 off_t size;
125 int change_bo = 0;
126
127 if (cmd != ELF_C_NULL
128 && cmd != ELF_C_WRITE
129 && unlikely (cmd != ELF_C_WRITE_MMAP))
130 {
131 __libelf_seterrno (ELF_E_INVALID_CMD);
132 return -1;
133 }
134
135 if (elf == NULL)
136 return -1;
137
138 if (elf->kind != ELF_K_ELF)
139 {
140 __libelf_seterrno (ELF_E_INVALID_HANDLE);
141 return -1;
142 }
143
144 rwlock_wrlock (elf->lock);
145
146 /* Make sure we have an ELF header. */
147 if (elf->state.elf.ehdr == NULL)
148 {
149 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
150 size = -1;
151 goto out;
152 }
153
154 /* Determine the number of sections. */
155 shnum = (elf->state.elf.scns_last->cnt == 0
156 ? 0
157 : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index);
158
159 /* Update the ELF descriptor. First, place the program header. It
160 will come right after the ELF header. The count the size of all
161 sections and finally place the section table. */
162 size = (elf->class == ELFCLASS32
163 ? __elf32_updatenull (elf, &change_bo, shnum)
164 : __elf64_updatenull (elf, &change_bo, shnum));
165 if (likely (size != -1)
166 /* See whether we actually have to write out the data. */
167 && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP))
168 {
169 if (elf->cmd != ELF_C_RDWR
170 && elf->cmd != ELF_C_RDWR_MMAP
171 && elf->cmd != ELF_C_WRITE
172 && unlikely (elf->cmd != ELF_C_WRITE_MMAP))
173 {
174 __libelf_seterrno (ELF_E_UPDATE_RO);
175 size = -1;
176 }
177 else if (unlikely (elf->fildes == -1))
178 {
179 /* We closed the file already. */
180 __libelf_seterrno (ELF_E_FD_DISABLED);
181 size = -1;
182 }
183 else
184 {
185 if (elf->parent != NULL)
186 {
187 extern int puts (const char *);
188 puts ("this is an archive member");
189 }
190
191 size = write_file (elf, size, change_bo, shnum);
192 }
193 }
194
195 out:
196 rwlock_unlock (elf->lock);
197
198 return size;
199}