]> git.saurik.com Git - apple/xnu.git/blame - SETUP/installfile/installfile.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / SETUP / installfile / installfile.c
CommitLineData
39236c6e
A
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
39void usage(void);
40
0a7de745
A
41int
42main(int argc, char * argv[])
39236c6e
A
43{
44 struct stat sb;
45 void *mset;
46 mode_t mode;
47 bool gotmode = false;
48 int ch;
49 int ret;
50 int srcfd, dstfd;
51 const char *src = NULL;
52 const char *dst = NULL;
53 char dsttmpname[MAXPATHLEN];
54
55 while ((ch = getopt(argc, argv, "cSm:")) != -1) {
0a7de745
A
56 switch (ch) {
57 case 'c':
58 case 'S':
59 /* ignored for compatibility */
60 break;
61 case 'm':
62 gotmode = true;
63 mset = setmode(optarg);
64 if (!mset) {
65 errx(EX_USAGE, "Unrecognized mode %s", optarg);
66 }
67
68 mode = getmode(mset, 0);
69 free(mset);
70 break;
71 case '?':
72 default:
73 usage();
39236c6e
A
74 }
75 }
76
77 argc -= optind;
78 argv += optind;
79
80 if (argc < 2) {
81 usage();
82 }
83
84 src = argv[0];
85 dst = argv[1];
86
87 srcfd = open(src, O_RDONLY | O_SYMLINK, 0);
0a7de745 88 if (srcfd < 0) {
39236c6e 89 err(EX_NOINPUT, "open(%s)", src);
0a7de745 90 }
39236c6e
A
91
92 ret = fstat(srcfd, &sb);
0a7de745 93 if (ret < 0) {
39236c6e 94 err(EX_NOINPUT, "fstat(%s)", src);
0a7de745 95 }
39236c6e 96
0a7de745 97 if (!S_ISREG(sb.st_mode)) {
39236c6e 98 err(EX_USAGE, "%s is not a regular file", src);
0a7de745 99 }
39236c6e
A
100
101 snprintf(dsttmpname, sizeof(dsttmpname), "%s.XXXXXX", dst);
102
103 dstfd = mkstemp(dsttmpname);
0a7de745 104 if (dstfd < 0) {
39236c6e 105 err(EX_UNAVAILABLE, "mkstemp(%s)", dsttmpname);
0a7de745 106 }
39236c6e
A
107
108 ret = fcopyfile(srcfd, dstfd, NULL,
0a7de745
A
109 COPYFILE_DATA);
110 if (ret < 0) {
39236c6e 111 err(EX_UNAVAILABLE, "fcopyfile(%s, %s)", src, dsttmpname);
0a7de745 112 }
39236c6e
A
113
114 ret = futimes(dstfd, NULL);
0a7de745 115 if (ret < 0) {
39236c6e 116 err(EX_UNAVAILABLE, "futimes(%s)", dsttmpname);
0a7de745 117 }
39236c6e
A
118
119 if (gotmode) {
120 ret = fchmod(dstfd, mode);
0a7de745 121 if (ret < 0) {
39236c6e 122 err(EX_NOINPUT, "fchmod(%s, %ho)", dsttmpname, mode);
0a7de745 123 }
39236c6e
A
124 }
125
126 ret = rename(dsttmpname, dst);
0a7de745 127 if (ret < 0) {
39236c6e 128 err(EX_NOINPUT, "rename(%s, %s)", dsttmpname, dst);
0a7de745 129 }
39236c6e
A
130
131 ret = close(dstfd);
0a7de745 132 if (ret < 0) {
39236c6e 133 err(EX_NOINPUT, "close(dst)");
0a7de745 134 }
39236c6e
A
135
136 ret = close(srcfd);
0a7de745 137 if (ret < 0) {
39236c6e 138 err(EX_NOINPUT, "close(src)");
0a7de745 139 }
39236c6e
A
140
141 return 0;
142}
143
0a7de745
A
144void
145usage(void)
39236c6e
A
146{
147 fprintf(stderr, "Usage: %s [-c] [-S] [-m <mode>] <src> <dst>\n",
0a7de745 148 getprogname());
39236c6e
A
149 exit(EX_USAGE);
150}