]> git.saurik.com Git - apple/xnu.git/blob - SETUP/installfile/installfile.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / SETUP / installfile / installfile.c
1 /*
2 * Copyright (c) 2012 Apple, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdbool.h>
28 #include <errno.h>
29 #include <err.h>
30 #include <sysexits.h>
31
32 #include <sys/stat.h>
33 #include <sys/fcntl.h>
34 #include <sys/param.h>
35 #include <sys/time.h>
36
37 #include <copyfile.h>
38
39 void usage(void);
40
41 int main(int argc, char * argv[])
42 {
43 struct stat sb;
44 void *mset;
45 mode_t mode;
46 bool gotmode = false;
47 int ch;
48 int ret;
49 int srcfd, dstfd;
50 const char *src = NULL;
51 const char *dst = NULL;
52 char dsttmpname[MAXPATHLEN];
53
54 while ((ch = getopt(argc, argv, "cSm:")) != -1) {
55 switch(ch) {
56 case 'c':
57 case 'S':
58 /* ignored for compatibility */
59 break;
60 case 'm':
61 gotmode = true;
62 mset = setmode(optarg);
63 if (!mset)
64 errx(EX_USAGE, "Unrecognized mode %s", optarg);
65
66 mode = getmode(mset, 0);
67 free(mset);
68 break;
69 case '?':
70 default:
71 usage();
72 }
73 }
74
75 argc -= optind;
76 argv += optind;
77
78 if (argc < 2) {
79 usage();
80 }
81
82 src = argv[0];
83 dst = argv[1];
84
85 srcfd = open(src, O_RDONLY | O_SYMLINK, 0);
86 if (srcfd < 0)
87 err(EX_NOINPUT, "open(%s)", src);
88
89 ret = fstat(srcfd, &sb);
90 if (ret < 0)
91 err(EX_NOINPUT, "fstat(%s)", src);
92
93 if (!S_ISREG(sb.st_mode))
94 err(EX_USAGE, "%s is not a regular file", src);
95
96 snprintf(dsttmpname, sizeof(dsttmpname), "%s.XXXXXX", dst);
97
98 dstfd = mkstemp(dsttmpname);
99 if (dstfd < 0)
100 err(EX_UNAVAILABLE, "mkstemp(%s)", dsttmpname);
101
102 ret = fcopyfile(srcfd, dstfd, NULL,
103 COPYFILE_DATA);
104 if (ret < 0)
105 err(EX_UNAVAILABLE, "fcopyfile(%s, %s)", src, dsttmpname);
106
107 ret = futimes(dstfd, NULL);
108 if (ret < 0)
109 err(EX_UNAVAILABLE, "futimes(%s)", dsttmpname);
110
111 if (gotmode) {
112 ret = fchmod(dstfd, mode);
113 if (ret < 0)
114 err(EX_NOINPUT, "fchmod(%s, %ho)", dsttmpname, mode);
115 }
116
117 ret = rename(dsttmpname, dst);
118 if (ret < 0)
119 err(EX_NOINPUT, "rename(%s, %s)", dsttmpname, dst);
120
121 ret = close(dstfd);
122 if (ret < 0)
123 err(EX_NOINPUT, "close(dst)");
124
125 ret = close(srcfd);
126 if (ret < 0)
127 err(EX_NOINPUT, "close(src)");
128
129 return 0;
130 }
131
132 void usage(void)
133 {
134 fprintf(stderr, "Usage: %s [-c] [-S] [-m <mode>] <src> <dst>\n",
135 getprogname());
136 exit(EX_USAGE);
137 }