blob: e9682990ddb9cbe889cbf7e2a57c0ac84893e505 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGratheebcc1d2003-09-24 03:22:57 +00002/*
Denis Vlasenko0beaff82007-09-21 13:16:32 +00003 * Copyright (C) 2003 by Glenn McGrath
Denis Vlasenko1203c9b2007-03-11 22:16:02 +00004 * SELinux support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
Glenn L McGratheebcc1d2003-09-24 03:22:57 +00005 *
"Robert P. J. Day"801ab142006-07-12 07:56:04 +00006 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGratheebcc1d2003-09-24 03:22:57 +00007 */
8
Denis Vlasenkob6adbf12007-05-26 19:00:18 +00009#include "libbb.h"
10#include "libcoreutils/coreutils.h"
11
Bernhard Reutner-Fischer01d23ad2006-05-26 20:19:22 +000012#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013static const char install_longopts[] ALIGN1 =
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +000014 "directory\0" No_argument "d"
15 "preserve-timestamps\0" No_argument "p"
16 "strip\0" No_argument "s"
Denis Vlasenkoc80191c2008-08-15 19:56:24 +000017 "group\0" Required_argument "g"
18 "mode\0" Required_argument "m"
19 "owner\0" Required_argument "o"
Denis Vlasenko4dd4e6d2007-09-26 10:34:54 +000020/* autofs build insists of using -b --suffix=.orig */
21/* TODO? (short option for --suffix is -S) */
Denis Vlasenko49622d72007-03-10 16:58:49 +000022#if ENABLE_SELINUX
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +000023 "context\0" Required_argument "Z"
24 "preserve_context\0" No_argument "\xff"
25 "preserve-context\0" No_argument "\xff"
Denis Vlasenko49622d72007-03-10 16:58:49 +000026#endif
Denis Vlasenko990d0f62007-07-24 15:54:42 +000027 ;
Bernhard Reutner-Fischer01d23ad2006-05-26 20:19:22 +000028#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +000029
Denis Vlasenko49622d72007-03-10 16:58:49 +000030
31#if ENABLE_SELINUX
Denis Vlasenkoac678ec2007-04-16 22:32:04 +000032static void setdefaultfilecon(const char *path)
33{
Denis Vlasenko49622d72007-03-10 16:58:49 +000034 struct stat s;
35 security_context_t scontext = NULL;
36
37 if (!is_selinux_enabled()) {
38 return;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000039 }
Denis Vlasenko49622d72007-03-10 16:58:49 +000040 if (lstat(path, &s) != 0) {
41 return;
42 }
43
44 if (matchpathcon(path, s.st_mode, &scontext) < 0) {
45 goto out;
46 }
47 if (strcmp(scontext, "<<none>>") == 0) {
48 goto out;
49 }
50
51 if (lsetfilecon(path, scontext) < 0) {
52 if (errno != ENOTSUP) {
Denis Vlasenkod4b71982008-09-03 21:54:46 +000053 bb_perror_msg("warning: failed to change context"
54 " of %s to %s", path, scontext);
Denis Vlasenko49622d72007-03-10 16:58:49 +000055 }
56 }
57
58 out:
59 freecon(scontext);
60}
61
62#endif
63
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000064int install_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +000065int install_main(int argc, char **argv)
Glenn L McGratheebcc1d2003-09-24 03:22:57 +000066{
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000067 struct stat statbuf;
Glenn L McGrath578eff52004-01-23 10:57:00 +000068 mode_t mode;
69 uid_t uid;
70 gid_t gid;
Denis Vlasenko614aca62007-08-26 14:21:55 +000071 char *arg, *last;
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000072 const char *gid_str;
73 const char *uid_str;
74 const char *mode_str;
Glenn L McGrath11e69472003-11-27 22:40:08 +000075 int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
Denis Vlasenkod4b71982008-09-03 21:54:46 +000076 int opts;
Denis Vlasenkod6817f52008-07-16 21:49:02 +000077 int min_args = 1;
Denis Vlasenko614aca62007-08-26 14:21:55 +000078 int ret = EXIT_SUCCESS;
Denis Vlasenkod6817f52008-07-16 21:49:02 +000079 int isdir = 0;
Denis Vlasenko49622d72007-03-10 16:58:49 +000080#if ENABLE_SELINUX
81 security_context_t scontext;
Denis Vlasenko4dd4e6d2007-09-26 10:34:54 +000082 bool use_default_selinux_context = 1;
Denis Vlasenko49622d72007-03-10 16:58:49 +000083#endif
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000084 enum {
Denis Vlasenko4dd4e6d2007-09-26 10:34:54 +000085 OPT_c = 1 << 0,
86 OPT_v = 1 << 1,
87 OPT_b = 1 << 2,
Denis Vlasenkod4b71982008-09-03 21:54:46 +000088 OPT_MKDIR_LEADING = 1 << 3,
89 OPT_DIRECTORY = 1 << 4,
90 OPT_PRESERVE_TIME = 1 << 5,
91 OPT_STRIP = 1 << 6,
92 OPT_GROUP = 1 << 7,
93 OPT_MODE = 1 << 8,
94 OPT_OWNER = 1 << 9,
Denis Vlasenko49622d72007-03-10 16:58:49 +000095#if ENABLE_SELINUX
Denis Vlasenkod4b71982008-09-03 21:54:46 +000096 OPT_SET_SECURITY_CONTEXT = 1 << 10,
97 OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11,
Denis Vlasenko49622d72007-03-10 16:58:49 +000098#endif
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000099 };
100
Bernhard Reutner-Fischer01d23ad2006-05-26 20:19:22 +0000101#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +0000102 applet_long_options = install_longopts;
Bernhard Reutner-Fischer01d23ad2006-05-26 20:19:22 +0000103#endif
Denys Vlasenkoa40f0622010-01-15 22:05:07 +0100104 opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z"));
Denis Vlasenko49622d72007-03-10 16:58:49 +0000105 /* -c exists for backwards compatibility, it's needed */
Denis Vlasenko4dd4e6d2007-09-26 10:34:54 +0000106 /* -v is ignored ("print name of each created directory") */
107 /* -b is ignored ("make a backup of each existing destination file") */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000108 opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"),
109 &gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext));
Denis Vlasenko614aca62007-08-26 14:21:55 +0000110 argc -= optind;
111 argv += optind;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +0000112
Denis Vlasenko49622d72007-03-10 16:58:49 +0000113#if ENABLE_SELINUX
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000114 if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) {
Denis Vlasenko49622d72007-03-10 16:58:49 +0000115 selinux_or_die();
Denis Vlasenko49622d72007-03-10 16:58:49 +0000116 use_default_selinux_context = 0;
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000117 if (opts & OPT_PRESERVE_SECURITY_CONTEXT) {
Denis Vlasenko4dd4e6d2007-09-26 10:34:54 +0000118 copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
119 }
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000120 if (opts & OPT_SET_SECURITY_CONTEXT) {
Denis Vlasenko4dd4e6d2007-09-26 10:34:54 +0000121 setfscreatecon_or_die(scontext);
122 copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT;
123 }
Denis Vlasenko49622d72007-03-10 16:58:49 +0000124 }
125#endif
Glenn L McGrath11e69472003-11-27 22:40:08 +0000126
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000127 /* preserve access and modification time, this is GNU behaviour,
128 * BSD only preserves modification time */
129 if (opts & OPT_PRESERVE_TIME) {
Glenn L McGrath11e69472003-11-27 22:40:08 +0000130 copy_flags |= FILEUTILS_PRESERVE_STATUS;
131 }
Denys Vlasenko1f363a02009-06-15 18:13:51 +0200132 mode = 0755; /* GNU coreutils 6.10 compat */
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000133 if (opts & OPT_MODE)
Denis Vlasenko6666ac42007-08-24 21:46:24 +0000134 bb_parse_mode(mode_str, &mode);
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000135 uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
136 gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
Denis Vlasenko614aca62007-08-26 14:21:55 +0000137
138 last = argv[argc - 1];
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000139 if (!(opts & OPT_DIRECTORY)) {
Denis Vlasenkod6817f52008-07-16 21:49:02 +0000140 argv[argc - 1] = NULL;
141 min_args++;
142
143 /* coreutils install resolves link in this case, don't use lstat */
144 isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
145 }
146
147 if (argc < min_args)
148 bb_show_usage();
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +0000149
Denis Vlasenko614aca62007-08-26 14:21:55 +0000150 while ((arg = *argv++) != NULL) {
151 char *dest = last;
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000152 if (opts & OPT_DIRECTORY) {
Denis Vlasenkod6817f52008-07-16 21:49:02 +0000153 dest = arg;
154 /* GNU coreutils 6.9 does not set uid:gid
155 * on intermediate created directories
156 * (only on last one) */
157 if (bb_make_directory(dest, 0755, FILEUTILS_RECUR)) {
158 ret = EXIT_FAILURE;
159 goto next;
160 }
161 } else {
Denis Vlasenko9f9c1932008-09-06 14:35:08 +0000162 if (opts & OPT_MKDIR_LEADING) {
163 char *ddir = xstrdup(dest);
164 bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR);
165 /* errors are not checked. copy_file
166 * will fail if dir is not created. */
167 free(ddir);
168 }
Denis Vlasenkod6817f52008-07-16 21:49:02 +0000169 if (isdir)
170 dest = concat_path_file(last, basename(arg));
171 if (copy_file(arg, dest, copy_flags)) {
172 /* copy is not made */
173 ret = EXIT_FAILURE;
174 goto next;
175 }
Denis Vlasenko614aca62007-08-26 14:21:55 +0000176 }
Glenn L McGratheebcc1d2003-09-24 03:22:57 +0000177
Denys Vlasenko1f363a02009-06-15 18:13:51 +0200178 /* Set the file mode (always, not only with -m).
179 * GNU coreutils 6.10 is not affected by umask. */
180 if (chmod(dest, mode) == -1) {
Bernhard Reutner-Fischerd73cbd32008-07-21 14:41:33 +0000181 bb_perror_msg("can't change %s of %s", "permissions", dest);
Glenn L McGrath578eff52004-01-23 10:57:00 +0000182 ret = EXIT_FAILURE;
Glenn L McGratheebcc1d2003-09-24 03:22:57 +0000183 }
Denis Vlasenko49622d72007-03-10 16:58:49 +0000184#if ENABLE_SELINUX
185 if (use_default_selinux_context)
186 setdefaultfilecon(dest);
187#endif
Glenn L McGratheebcc1d2003-09-24 03:22:57 +0000188 /* Set the user and group id */
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000189 if ((opts & (OPT_OWNER|OPT_GROUP))
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +0000190 && lchown(dest, uid, gid) == -1
191 ) {
Bernhard Reutner-Fischerd73cbd32008-07-21 14:41:33 +0000192 bb_perror_msg("can't change %s of %s", "ownership", dest);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000193 ret = EXIT_FAILURE;
Glenn L McGratheebcc1d2003-09-24 03:22:57 +0000194 }
Denis Vlasenkod4b71982008-09-03 21:54:46 +0000195 if (opts & OPT_STRIP) {
Denis Vlasenkoa6163ca2007-06-17 00:35:15 +0000196 char *args[3];
197 args[0] = (char*)"strip";
198 args[1] = dest;
199 args[2] = NULL;
200 if (spawn_and_wait(args)) {
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +0000201 bb_perror_msg("strip");
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000202 ret = EXIT_FAILURE;
Glenn L McGratheebcc1d2003-09-24 03:22:57 +0000203 }
204 }
Denis Vlasenko614aca62007-08-26 14:21:55 +0000205 next:
206 if (ENABLE_FEATURE_CLEAN_UP && isdir)
207 free(dest);
Glenn L McGratheebcc1d2003-09-24 03:22:57 +0000208 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000209
Denis Vlasenko079f8af2006-11-27 16:49:31 +0000210 return ret;
Glenn L McGratheebcc1d2003-09-24 03:22:57 +0000211}