source: MondoRescue/branches/2.2.5/mindi-busybox/coreutils/install.c@ 1765

Last change on this file since 1765 was 1765, checked in by Bruno Cornec, 16 years ago

Update to busybox 1.7.2

File size: 5.7 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2003 by Glenn McGrath
4 * SELinux support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 *
8 * TODO: -d option, need a way of recursively making directories and changing
9 * owner/group, will probably modify bb_make_directory(...)
10 */
11
12#include <libgen.h>
13#include <getopt.h> /* struct option */
14
15#include "libbb.h"
16#include "libcoreutils/coreutils.h"
17
18#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
19static const char install_longopts[] ALIGN1 =
20 "directory\0" No_argument "d"
21 "preserve-timestamps\0" No_argument "p"
22 "strip\0" No_argument "s"
23 "group\0" No_argument "g"
24 "mode\0" No_argument "m"
25 "owner\0" No_argument "o"
26/* autofs build insists of using -b --suffix=.orig */
27/* TODO? (short option for --suffix is -S) */
28#if ENABLE_SELINUX
29 "context\0" Required_argument "Z"
30 "preserve_context\0" No_argument "\xff"
31 "preserve-context\0" No_argument "\xff"
32#endif
33 ;
34#endif
35
36
37#if ENABLE_SELINUX
38static void setdefaultfilecon(const char *path)
39{
40 struct stat s;
41 security_context_t scontext = NULL;
42
43 if (!is_selinux_enabled()) {
44 return;
45 }
46 if (lstat(path, &s) != 0) {
47 return;
48 }
49
50 if (matchpathcon(path, s.st_mode, &scontext) < 0) {
51 goto out;
52 }
53 if (strcmp(scontext, "<<none>>") == 0) {
54 goto out;
55 }
56
57 if (lsetfilecon(path, scontext) < 0) {
58 if (errno != ENOTSUP) {
59 bb_perror_msg("warning: failed to change context of %s to %s", path, scontext);
60 }
61 }
62
63 out:
64 freecon(scontext);
65}
66
67#endif
68
69int install_main(int argc, char **argv);
70int install_main(int argc, char **argv)
71{
72 struct stat statbuf;
73 mode_t mode;
74 uid_t uid;
75 gid_t gid;
76 char *arg, *last;
77 const char *gid_str;
78 const char *uid_str;
79 const char *mode_str;
80 int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
81 int flags;
82 int ret = EXIT_SUCCESS;
83 int isdir;
84#if ENABLE_SELINUX
85 security_context_t scontext;
86 bool use_default_selinux_context = 1;
87#endif
88 enum {
89 OPT_c = 1 << 0,
90 OPT_v = 1 << 1,
91 OPT_b = 1 << 2,
92 OPT_DIRECTORY = 1 << 3,
93 OPT_PRESERVE_TIME = 1 << 4,
94 OPT_STRIP = 1 << 5,
95 OPT_GROUP = 1 << 6,
96 OPT_MODE = 1 << 7,
97 OPT_OWNER = 1 << 8,
98#if ENABLE_SELINUX
99 OPT_SET_SECURITY_CONTEXT = 1 << 9,
100 OPT_PRESERVE_SECURITY_CONTEXT = 1 << 10,
101#endif
102 };
103
104#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
105 applet_long_options = install_longopts;
106#endif
107 opt_complementary = "s--d:d--s" USE_SELINUX(":Z--\xff:\xff--Z");
108 /* -c exists for backwards compatibility, it's needed */
109 /* -v is ignored ("print name of each created directory") */
110 /* -b is ignored ("make a backup of each existing destination file") */
111 flags = getopt32(argv, "cvb" "dpsg:m:o:" USE_SELINUX("Z:"),
112 &gid_str, &mode_str, &uid_str USE_SELINUX(, &scontext));
113 argc -= optind;
114 argv += optind;
115
116#if ENABLE_SELINUX
117 if (flags & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) {
118 selinux_or_die();
119 use_default_selinux_context = 0;
120 if (flags & OPT_PRESERVE_SECURITY_CONTEXT) {
121 copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
122 }
123 if (flags & OPT_SET_SECURITY_CONTEXT) {
124 setfscreatecon_or_die(scontext);
125 copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT;
126 }
127 }
128#endif
129
130 /* preserve access and modification time, this is GNU behaviour, BSD only preserves modification time */
131 if (flags & OPT_PRESERVE_TIME) {
132 copy_flags |= FILEUTILS_PRESERVE_STATUS;
133 }
134 mode = 0666;
135 if (flags & OPT_MODE)
136 bb_parse_mode(mode_str, &mode);
137 uid = (flags & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
138 gid = (flags & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
139 if (flags & (OPT_OWNER|OPT_GROUP))
140 umask(0);
141
142 /* Create directories
143 * don't use bb_make_directory() as it can't change uid or gid
144 * perhaps bb_make_directory() should be improved.
145 */
146 if (flags & OPT_DIRECTORY) {
147 while ((arg = *argv++) != NULL) {
148 char *slash = arg;
149 while (1) {
150 slash = strchr(slash + 1, '/');
151 if (slash)
152 *slash = '\0';
153 if (mkdir(arg, mode | 0111) == -1) {
154 if (errno != EEXIST) {
155 bb_perror_msg("cannot create %s", arg);
156 ret = EXIT_FAILURE;
157 break;
158 }
159 } /* dir was created, chown? */
160 else if ((flags & (OPT_OWNER|OPT_GROUP))
161 && lchown(arg, uid, gid) == -1
162 ) {
163 bb_perror_msg("cannot change ownership of %s", arg);
164 ret = EXIT_FAILURE;
165 break;
166 }
167 if (!slash)
168 break;
169 *slash = '/';
170 }
171 }
172 return ret;
173 }
174
175 if (argc < 2)
176 bb_show_usage();
177
178 last = argv[argc - 1];
179 argv[argc - 1] = NULL;
180 /* coreutils install resolves link in this case, don't use lstat */
181 isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
182
183 while ((arg = *argv++) != NULL) {
184 char *dest = last;
185 if (isdir)
186 dest = concat_path_file(last, basename(arg));
187 if (copy_file(arg, dest, copy_flags)) {
188 /* copy is not made */
189 ret = EXIT_FAILURE;
190 goto next;
191 }
192
193 /* Set the file mode */
194 if ((flags & OPT_MODE) && chmod(dest, mode) == -1) {
195 bb_perror_msg("cannot change permissions of %s", dest);
196 ret = EXIT_FAILURE;
197 }
198#if ENABLE_SELINUX
199 if (use_default_selinux_context)
200 setdefaultfilecon(dest);
201#endif
202 /* Set the user and group id */
203 if ((flags & (OPT_OWNER|OPT_GROUP))
204 && lchown(dest, uid, gid) == -1
205 ) {
206 bb_perror_msg("cannot change ownership of %s", dest);
207 ret = EXIT_FAILURE;
208 }
209 if (flags & OPT_STRIP) {
210 char *args[3];
211 args[0] = (char*)"strip";
212 args[1] = dest;
213 args[2] = NULL;
214 if (spawn_and_wait(args)) {
215 bb_perror_msg("strip");
216 ret = EXIT_FAILURE;
217 }
218 }
219 next:
220 if (ENABLE_FEATURE_CLEAN_UP && isdir)
221 free(dest);
222 }
223
224 return ret;
225}
Note: See TracBrowser for help on using the repository browser.