source: MondoRescue/branches/3.3/mindi-busybox/coreutils/install.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 6.5 KB
RevLine 
[1765]1/* vi: set sw=4 ts=4: */
[821]2/*
[1765]3 * Copyright (C) 2003 by Glenn McGrath
4 * SELinux support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
[821]5 *
[2725]6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
[821]7 */
8
[3232]9/* -v, -b, -c are ignored */
10//usage:#define install_trivial_usage
[3621]11//usage: "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [-t DIR] [SOURCE]... DEST"
[3232]12//usage:#define install_full_usage "\n\n"
13//usage: "Copy files and set attributes\n"
14//usage: "\n -c Just copy (default)"
15//usage: "\n -d Create directories"
16//usage: "\n -D Create leading target directories"
17//usage: "\n -s Strip symbol table"
18//usage: "\n -p Preserve date"
19//usage: "\n -o USER Set ownership"
20//usage: "\n -g GRP Set group ownership"
21//usage: "\n -m MODE Set permissions"
[3621]22//usage: "\n -t DIR Install to DIR"
[3232]23//usage: IF_SELINUX(
24//usage: "\n -Z Set security context"
25//usage: )
26
[1765]27#include "libbb.h"
[821]28#include "libcoreutils/coreutils.h"
29
30#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
[1765]31static const char install_longopts[] ALIGN1 =
[3621]32 IF_FEATURE_VERBOSE(
33 "verbose\0" No_argument "v"
34 )
[1765]35 "directory\0" No_argument "d"
36 "preserve-timestamps\0" No_argument "p"
37 "strip\0" No_argument "s"
[2725]38 "group\0" Required_argument "g"
39 "mode\0" Required_argument "m"
40 "owner\0" Required_argument "o"
[3621]41 "target-directory\0" Required_argument "t"
[1765]42/* autofs build insists of using -b --suffix=.orig */
43/* TODO? (short option for --suffix is -S) */
44#if ENABLE_SELINUX
45 "context\0" Required_argument "Z"
46 "preserve_context\0" No_argument "\xff"
47 "preserve-context\0" No_argument "\xff"
[821]48#endif
[1765]49 ;
50#endif
[821]51
[1765]52
53#if ENABLE_SELINUX
54static void setdefaultfilecon(const char *path)
55{
56 struct stat s;
57 security_context_t scontext = NULL;
58
59 if (!is_selinux_enabled()) {
60 return;
61 }
62 if (lstat(path, &s) != 0) {
63 return;
64 }
65
66 if (matchpathcon(path, s.st_mode, &scontext) < 0) {
67 goto out;
68 }
69 if (strcmp(scontext, "<<none>>") == 0) {
70 goto out;
71 }
72
73 if (lsetfilecon(path, scontext) < 0) {
74 if (errno != ENOTSUP) {
[2725]75 bb_perror_msg("warning: can't change context"
76 " of %s to %s", path, scontext);
[1765]77 }
78 }
79
80 out:
81 freecon(scontext);
82}
83
84#endif
85
[2725]86int install_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
[821]87int install_main(int argc, char **argv)
88{
[1765]89 struct stat statbuf;
[821]90 mode_t mode;
91 uid_t uid;
92 gid_t gid;
[1765]93 char *arg, *last;
94 const char *gid_str;
95 const char *uid_str;
96 const char *mode_str;
[3621]97 int mkdir_flags = FILEUTILS_RECUR;
[821]98 int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
[2725]99 int opts;
[1765]100 int ret = EXIT_SUCCESS;
[3621]101 int isdir;
[1765]102#if ENABLE_SELINUX
103 security_context_t scontext;
104 bool use_default_selinux_context = 1;
105#endif
106 enum {
107 OPT_c = 1 << 0,
108 OPT_v = 1 << 1,
109 OPT_b = 1 << 2,
[2725]110 OPT_MKDIR_LEADING = 1 << 3,
111 OPT_DIRECTORY = 1 << 4,
112 OPT_PRESERVE_TIME = 1 << 5,
113 OPT_STRIP = 1 << 6,
114 OPT_GROUP = 1 << 7,
115 OPT_MODE = 1 << 8,
116 OPT_OWNER = 1 << 9,
[3621]117 OPT_TARGET = 1 << 10,
[1765]118#if ENABLE_SELINUX
[3621]119 OPT_SET_SECURITY_CONTEXT = 1 << 11,
120 OPT_PRESERVE_SECURITY_CONTEXT = 1 << 12,
[1765]121#endif
122 };
[821]123
124#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
[1765]125 applet_long_options = install_longopts;
[821]126#endif
[3621]127 opt_complementary = "t--d:d--t:s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z"));
[1765]128 /* -c exists for backwards compatibility, it's needed */
129 /* -b is ignored ("make a backup of each existing destination file") */
[3621]130 opts = getopt32(argv, "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:"),
131 &gid_str, &mode_str, &uid_str, &last
132 IF_SELINUX(, &scontext));
[1765]133 argc -= optind;
134 argv += optind;
[821]135
[1765]136#if ENABLE_SELINUX
[2725]137 if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) {
[1765]138 selinux_or_die();
139 use_default_selinux_context = 0;
[2725]140 if (opts & OPT_PRESERVE_SECURITY_CONTEXT) {
[1765]141 copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
142 }
[2725]143 if (opts & OPT_SET_SECURITY_CONTEXT) {
[1765]144 setfscreatecon_or_die(scontext);
145 copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT;
146 }
147 }
148#endif
149
[3621]150 if ((opts & OPT_v) && FILEUTILS_VERBOSE) {
151 mkdir_flags |= FILEUTILS_VERBOSE;
152 copy_flags |= FILEUTILS_VERBOSE;
153 }
154
[2725]155 /* preserve access and modification time, this is GNU behaviour,
156 * BSD only preserves modification time */
157 if (opts & OPT_PRESERVE_TIME) {
[821]158 copy_flags |= FILEUTILS_PRESERVE_STATUS;
159 }
[2725]160 mode = 0755; /* GNU coreutils 6.10 compat */
161 if (opts & OPT_MODE)
[3621]162 mode = bb_parse_mode(mode_str, mode);
[2725]163 uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
164 gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
[821]165
[3621]166 /* If -t DIR is in use, then isdir=true, last="DIR" */
167 isdir = (opts & OPT_TARGET);
168 if (!(opts & (OPT_TARGET|OPT_DIRECTORY))) {
169 /* Neither -t DIR nor -d is in use */
170 argc--;
171 last = argv[argc];
172 argv[argc] = NULL;
[2725]173 /* coreutils install resolves link in this case, don't use lstat */
174 isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
[821]175 }
176
[3621]177 if (argc < 1)
[1765]178 bb_show_usage();
[821]179
[1765]180 while ((arg = *argv++) != NULL) {
[3621]181 char *dest;
182
[2725]183 if (opts & OPT_DIRECTORY) {
184 dest = arg;
185 /* GNU coreutils 6.9 does not set uid:gid
186 * on intermediate created directories
187 * (only on last one) */
[3621]188 if (bb_make_directory(dest, 0755, mkdir_flags)) {
[2725]189 ret = EXIT_FAILURE;
190 goto next;
191 }
192 } else {
[3621]193 dest = last;
[2725]194 if (opts & OPT_MKDIR_LEADING) {
195 char *ddir = xstrdup(dest);
[3621]196 bb_make_directory(dirname(ddir), 0755, mkdir_flags);
[2725]197 /* errors are not checked. copy_file
198 * will fail if dir is not created. */
199 free(ddir);
200 }
201 if (isdir)
202 dest = concat_path_file(last, bb_basename(arg));
203 if (copy_file(arg, dest, copy_flags) != 0) {
204 /* copy is not made */
205 ret = EXIT_FAILURE;
206 goto next;
207 }
208 if (opts & OPT_STRIP) {
209 char *args[4];
210 args[0] = (char*)"strip";
211 args[1] = (char*)"-p"; /* -p --preserve-dates */
212 args[2] = dest;
213 args[3] = NULL;
214 if (spawn_and_wait(args)) {
215 bb_perror_msg("strip");
216 ret = EXIT_FAILURE;
217 }
218 }
[1765]219 }
220
[2725]221 /* Set the file mode (always, not only with -m).
222 * GNU coreutils 6.10 is not affected by umask. */
223 if (chmod(dest, mode) == -1) {
224 bb_perror_msg("can't change %s of %s", "permissions", dest);
[821]225 ret = EXIT_FAILURE;
226 }
[1765]227#if ENABLE_SELINUX
228 if (use_default_selinux_context)
229 setdefaultfilecon(dest);
230#endif
[821]231 /* Set the user and group id */
[2725]232 if ((opts & (OPT_OWNER|OPT_GROUP))
[1765]233 && lchown(dest, uid, gid) == -1
234 ) {
[2725]235 bb_perror_msg("can't change %s of %s", "ownership", dest);
[821]236 ret = EXIT_FAILURE;
237 }
[1765]238 next:
239 if (ENABLE_FEATURE_CLEAN_UP && isdir)
240 free(dest);
[821]241 }
242
[1765]243 return ret;
[821]244}
Note: See TracBrowser for help on using the repository browser.