1*cf5a6c84SAndroid Build Coastguard Worker /* Copyright 2008 Rob Landley <[email protected]>
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * See http://opengroup.org/onlinepubs/9699919799/utilities/cp.html
4*cf5a6c84SAndroid Build Coastguard Worker * And http://opengroup.org/onlinepubs/9699919799/utilities/mv.html
5*cf5a6c84SAndroid Build Coastguard Worker * And http://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic.html#INSTALL
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * Posix says "cp -Rf dir file" shouldn't delete file, but our -f does.
8*cf5a6c84SAndroid Build Coastguard Worker *
9*cf5a6c84SAndroid Build Coastguard Worker * Deviations from posix: -adlnrsvF, --preserve... about half the
10*cf5a6c84SAndroid Build Coastguard Worker * functionality in this cp isn't in posix. Posix is stuck in the 1970's.
11*cf5a6c84SAndroid Build Coastguard Worker *
12*cf5a6c84SAndroid Build Coastguard Worker * TODO: --preserve=links
13*cf5a6c84SAndroid Build Coastguard Worker * TODO: what's this _CP_mode system.posix_acl_ business? We chmod()?
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker // options shared between mv/cp must be in same order (right to left)
16*cf5a6c84SAndroid Build Coastguard Worker // for FLAG macros to work out right in shared infrastructure.
17*cf5a6c84SAndroid Build Coastguard Worker
18*cf5a6c84SAndroid Build Coastguard Worker USE_CP(NEWTOY(cp, "<1(preserve):;D(parents)RHLPprudaslv(verbose)nF(remove-destination)fit:T[-HLPd][-niu][+Rr]", TOYFLAG_BIN))
19*cf5a6c84SAndroid Build Coastguard Worker USE_MV(NEWTOY(mv, "<1x(swap)v(verbose)nF(remove-destination)fit:T[-ni]", TOYFLAG_BIN))
20*cf5a6c84SAndroid Build Coastguard Worker USE_INSTALL(NEWTOY(install, "<1cdDp(preserve-timestamps)svt:m:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
21*cf5a6c84SAndroid Build Coastguard Worker
22*cf5a6c84SAndroid Build Coastguard Worker config CP
23*cf5a6c84SAndroid Build Coastguard Worker bool "cp"
24*cf5a6c84SAndroid Build Coastguard Worker default y
25*cf5a6c84SAndroid Build Coastguard Worker help
26*cf5a6c84SAndroid Build Coastguard Worker usage: cp [-aDdFfHiLlnPpRrsTuv] [--preserve=motcxa] [-t TARGET] SOURCE... [DEST]
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker Copy files from SOURCE to DEST. If more than one SOURCE, DEST must
29*cf5a6c84SAndroid Build Coastguard Worker be a directory.
30*cf5a6c84SAndroid Build Coastguard Worker
31*cf5a6c84SAndroid Build Coastguard Worker -a Same as -dpr
32*cf5a6c84SAndroid Build Coastguard Worker -D Create leading dirs under DEST (--parents)
33*cf5a6c84SAndroid Build Coastguard Worker -d Don't dereference symlinks
34*cf5a6c84SAndroid Build Coastguard Worker -F Delete any existing DEST first (--remove-destination)
35*cf5a6c84SAndroid Build Coastguard Worker -f Delete destination files we can't write to
36*cf5a6c84SAndroid Build Coastguard Worker -H Follow symlinks listed on command line
37*cf5a6c84SAndroid Build Coastguard Worker -i Interactive, prompt before overwriting existing DEST
38*cf5a6c84SAndroid Build Coastguard Worker -L Follow all symlinks
39*cf5a6c84SAndroid Build Coastguard Worker -l Hard link instead of copy
40*cf5a6c84SAndroid Build Coastguard Worker -n No clobber (don't overwrite DEST)
41*cf5a6c84SAndroid Build Coastguard Worker -P Do not follow symlinks
42*cf5a6c84SAndroid Build Coastguard Worker -p Preserve timestamps, ownership, and mode
43*cf5a6c84SAndroid Build Coastguard Worker -R Recurse into subdirectories (DEST must be a directory)
44*cf5a6c84SAndroid Build Coastguard Worker -r Synonym for -R
45*cf5a6c84SAndroid Build Coastguard Worker -s Symlink instead of copy
46*cf5a6c84SAndroid Build Coastguard Worker -T DEST always treated as file, max 2 arguments
47*cf5a6c84SAndroid Build Coastguard Worker -t Copy to TARGET dir (no DEST)
48*cf5a6c84SAndroid Build Coastguard Worker -u Update (keep newest mtime)
49*cf5a6c84SAndroid Build Coastguard Worker -v Verbose
50*cf5a6c84SAndroid Build Coastguard Worker
51*cf5a6c84SAndroid Build Coastguard Worker Arguments to --preserve are the first letter(s) of:
52*cf5a6c84SAndroid Build Coastguard Worker
53*cf5a6c84SAndroid Build Coastguard Worker mode - permissions (ignore umask for rwx, copy suid and sticky bit)
54*cf5a6c84SAndroid Build Coastguard Worker ownership - user and group
55*cf5a6c84SAndroid Build Coastguard Worker timestamps - file creation, modification, and access times.
56*cf5a6c84SAndroid Build Coastguard Worker context - security context
57*cf5a6c84SAndroid Build Coastguard Worker xattr - extended attributes
58*cf5a6c84SAndroid Build Coastguard Worker all - all of the above
59*cf5a6c84SAndroid Build Coastguard Worker
60*cf5a6c84SAndroid Build Coastguard Worker config MV
61*cf5a6c84SAndroid Build Coastguard Worker bool "mv"
62*cf5a6c84SAndroid Build Coastguard Worker default y
63*cf5a6c84SAndroid Build Coastguard Worker help
64*cf5a6c84SAndroid Build Coastguard Worker usage: mv [-FfinTvx] [-t TARGET] SOURCE... [DEST]
65*cf5a6c84SAndroid Build Coastguard Worker
66*cf5a6c84SAndroid Build Coastguard Worker -F Delete any existing DEST first (--remove-destination)
67*cf5a6c84SAndroid Build Coastguard Worker -f Force copy by deleting destination file
68*cf5a6c84SAndroid Build Coastguard Worker -i Interactive, prompt before overwriting existing DEST
69*cf5a6c84SAndroid Build Coastguard Worker -n No clobber (don't overwrite DEST)
70*cf5a6c84SAndroid Build Coastguard Worker -t Move to TARGET dir (no DEST)
71*cf5a6c84SAndroid Build Coastguard Worker -T DEST always treated as file, max 2 arguments
72*cf5a6c84SAndroid Build Coastguard Worker -v Verbose
73*cf5a6c84SAndroid Build Coastguard Worker -x Atomically exchange source/dest (--swap)
74*cf5a6c84SAndroid Build Coastguard Worker
75*cf5a6c84SAndroid Build Coastguard Worker config INSTALL
76*cf5a6c84SAndroid Build Coastguard Worker bool "install"
77*cf5a6c84SAndroid Build Coastguard Worker default y
78*cf5a6c84SAndroid Build Coastguard Worker help
79*cf5a6c84SAndroid Build Coastguard Worker usage: install [-dDpsv] [-o USER] [-g GROUP] [-m MODE] [-t TARGET] [SOURCE...] [DEST]
80*cf5a6c84SAndroid Build Coastguard Worker
81*cf5a6c84SAndroid Build Coastguard Worker Copy files and set attributes.
82*cf5a6c84SAndroid Build Coastguard Worker
83*cf5a6c84SAndroid Build Coastguard Worker -d Act like mkdir -p
84*cf5a6c84SAndroid Build Coastguard Worker -D Create leading directories for DEST
85*cf5a6c84SAndroid Build Coastguard Worker -g Make copy belong to GROUP
86*cf5a6c84SAndroid Build Coastguard Worker -m Set permissions to MODE
87*cf5a6c84SAndroid Build Coastguard Worker -o Make copy belong to USER
88*cf5a6c84SAndroid Build Coastguard Worker -p Preserve timestamps
89*cf5a6c84SAndroid Build Coastguard Worker -s Call "strip -p"
90*cf5a6c84SAndroid Build Coastguard Worker -t Copy files to TARGET dir (no DEST)
91*cf5a6c84SAndroid Build Coastguard Worker -v Verbose
92*cf5a6c84SAndroid Build Coastguard Worker */
93*cf5a6c84SAndroid Build Coastguard Worker
94*cf5a6c84SAndroid Build Coastguard Worker #define FORCE_FLAGS
95*cf5a6c84SAndroid Build Coastguard Worker #define FOR_cp
96*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
97*cf5a6c84SAndroid Build Coastguard Worker
98*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
99*cf5a6c84SAndroid Build Coastguard Worker union {
100*cf5a6c84SAndroid Build Coastguard Worker // install's options
101*cf5a6c84SAndroid Build Coastguard Worker struct {
102*cf5a6c84SAndroid Build Coastguard Worker char *g, *o, *m, *t;
103*cf5a6c84SAndroid Build Coastguard Worker } i;
104*cf5a6c84SAndroid Build Coastguard Worker // cp's options
105*cf5a6c84SAndroid Build Coastguard Worker struct {
106*cf5a6c84SAndroid Build Coastguard Worker char *t, *preserve;
107*cf5a6c84SAndroid Build Coastguard Worker } c;
108*cf5a6c84SAndroid Build Coastguard Worker };
109*cf5a6c84SAndroid Build Coastguard Worker
110*cf5a6c84SAndroid Build Coastguard Worker char *destname;
111*cf5a6c84SAndroid Build Coastguard Worker struct stat top;
112*cf5a6c84SAndroid Build Coastguard Worker int (*callback)(struct dirtree *try);
113*cf5a6c84SAndroid Build Coastguard Worker uid_t uid;
114*cf5a6c84SAndroid Build Coastguard Worker gid_t gid;
115*cf5a6c84SAndroid Build Coastguard Worker int pflags;
116*cf5a6c84SAndroid Build Coastguard Worker )
117*cf5a6c84SAndroid Build Coastguard Worker
118*cf5a6c84SAndroid Build Coastguard Worker struct cp_preserve {
119*cf5a6c84SAndroid Build Coastguard Worker char *name;
120*cf5a6c84SAndroid Build Coastguard Worker } static const cp_preserve[] = TAGGED_ARRAY(CP,
121*cf5a6c84SAndroid Build Coastguard Worker {"mode"}, {"ownership"}, {"timestamps"}, {"context"}, {"xattr"},
122*cf5a6c84SAndroid Build Coastguard Worker );
123*cf5a6c84SAndroid Build Coastguard Worker
cp_xattr(int fdin,int fdout,char * file)124*cf5a6c84SAndroid Build Coastguard Worker void cp_xattr(int fdin, int fdout, char *file)
125*cf5a6c84SAndroid Build Coastguard Worker {
126*cf5a6c84SAndroid Build Coastguard Worker ssize_t listlen, len;
127*cf5a6c84SAndroid Build Coastguard Worker char *name, *value, *list;
128*cf5a6c84SAndroid Build Coastguard Worker
129*cf5a6c84SAndroid Build Coastguard Worker if (!(TT.pflags&(_CP_xattr|_CP_context))) return;
130*cf5a6c84SAndroid Build Coastguard Worker if ((listlen = xattr_flist(fdin, 0, 0))<1) return;
131*cf5a6c84SAndroid Build Coastguard Worker
132*cf5a6c84SAndroid Build Coastguard Worker list = xmalloc(listlen);
133*cf5a6c84SAndroid Build Coastguard Worker xattr_flist(fdin, list, listlen);
134*cf5a6c84SAndroid Build Coastguard Worker for (name = list; name-list < listlen; name += strlen(name)+1) {
135*cf5a6c84SAndroid Build Coastguard Worker // context copies security, xattr copies everything else
136*cf5a6c84SAndroid Build Coastguard Worker len = strncmp(name, "security.", 9) ? _CP_xattr : _CP_context;
137*cf5a6c84SAndroid Build Coastguard Worker if (!(TT.pflags&len)) continue;
138*cf5a6c84SAndroid Build Coastguard Worker if ((len = xattr_fget(fdin, name, 0, 0))>0) {
139*cf5a6c84SAndroid Build Coastguard Worker value = xmalloc(len);
140*cf5a6c84SAndroid Build Coastguard Worker if (len == xattr_fget(fdin, name, value, len))
141*cf5a6c84SAndroid Build Coastguard Worker if (xattr_fset(fdout, name, value, len, 0))
142*cf5a6c84SAndroid Build Coastguard Worker perror_msg("%s setxattr(%s=%s)", file, name, value);
143*cf5a6c84SAndroid Build Coastguard Worker free(value);
144*cf5a6c84SAndroid Build Coastguard Worker }
145*cf5a6c84SAndroid Build Coastguard Worker }
146*cf5a6c84SAndroid Build Coastguard Worker free(list);
147*cf5a6c84SAndroid Build Coastguard Worker }
148*cf5a6c84SAndroid Build Coastguard Worker
149*cf5a6c84SAndroid Build Coastguard Worker // Callback from dirtree_read() for each file/directory under a source dir.
150*cf5a6c84SAndroid Build Coastguard Worker
151*cf5a6c84SAndroid Build Coastguard Worker // traverses two directories in parallel: try->dirfd is source dir,
152*cf5a6c84SAndroid Build Coastguard Worker // try->extra is dest dir. TODO: filehandle exhaustion?
153*cf5a6c84SAndroid Build Coastguard Worker
cp_node(struct dirtree * try)154*cf5a6c84SAndroid Build Coastguard Worker static int cp_node(struct dirtree *try)
155*cf5a6c84SAndroid Build Coastguard Worker {
156*cf5a6c84SAndroid Build Coastguard Worker int fdout = -1, cfd = try->parent ? try->parent->extra : AT_FDCWD,
157*cf5a6c84SAndroid Build Coastguard Worker save = DIRTREE_SAVE*(CFG_MV && *toys.which->name == 'm'), rc = 0, rr = 0,
158*cf5a6c84SAndroid Build Coastguard Worker tfd = dirtree_parentfd(try);
159*cf5a6c84SAndroid Build Coastguard Worker char *s = 0, *catch = try->parent ? try->name : TT.destname, *err = "%s";
160*cf5a6c84SAndroid Build Coastguard Worker struct stat cst;
161*cf5a6c84SAndroid Build Coastguard Worker
162*cf5a6c84SAndroid Build Coastguard Worker if (!dirtree_notdotdot(try)) return 0;
163*cf5a6c84SAndroid Build Coastguard Worker
164*cf5a6c84SAndroid Build Coastguard Worker // If returning from COMEAGAIN, jump straight to -p logic at end.
165*cf5a6c84SAndroid Build Coastguard Worker if (S_ISDIR(try->st.st_mode) && (try->again&DIRTREE_COMEAGAIN)) {
166*cf5a6c84SAndroid Build Coastguard Worker fdout = try->extra;
167*cf5a6c84SAndroid Build Coastguard Worker err = 0;
168*cf5a6c84SAndroid Build Coastguard Worker
169*cf5a6c84SAndroid Build Coastguard Worker // If mv child had a problem, free data and don't try to delete parent dir.
170*cf5a6c84SAndroid Build Coastguard Worker if (try->child) {
171*cf5a6c84SAndroid Build Coastguard Worker save = 0;
172*cf5a6c84SAndroid Build Coastguard Worker llist_traverse(try->child, free);
173*cf5a6c84SAndroid Build Coastguard Worker }
174*cf5a6c84SAndroid Build Coastguard Worker
175*cf5a6c84SAndroid Build Coastguard Worker cp_xattr(try->dirfd, try->extra, catch);
176*cf5a6c84SAndroid Build Coastguard Worker } else {
177*cf5a6c84SAndroid Build Coastguard Worker // -d is only the same as -r for symlinks, not for directories
178*cf5a6c84SAndroid Build Coastguard Worker if (S_ISLNK(try->st.st_mode) && FLAG(d)) rr++;
179*cf5a6c84SAndroid Build Coastguard Worker
180*cf5a6c84SAndroid Build Coastguard Worker // Detect recursive copies via repeated top node (cp -R .. .) or
181*cf5a6c84SAndroid Build Coastguard Worker // identical source/target (fun with hardlinks).
182*cf5a6c84SAndroid Build Coastguard Worker if ((same_file(&TT.top, &try->st) && (catch = TT.destname))
183*cf5a6c84SAndroid Build Coastguard Worker || (!fstatat(cfd, catch, &cst, 0) && same_file(&cst, &try->st)))
184*cf5a6c84SAndroid Build Coastguard Worker {
185*cf5a6c84SAndroid Build Coastguard Worker error_msg("'%s' is '%s'", catch, err = dirtree_path(try, 0));
186*cf5a6c84SAndroid Build Coastguard Worker free(err);
187*cf5a6c84SAndroid Build Coastguard Worker
188*cf5a6c84SAndroid Build Coastguard Worker return save;
189*cf5a6c84SAndroid Build Coastguard Worker }
190*cf5a6c84SAndroid Build Coastguard Worker
191*cf5a6c84SAndroid Build Coastguard Worker // Handle -inuvF
192*cf5a6c84SAndroid Build Coastguard Worker if (!faccessat(cfd, catch, F_OK, 0) && !S_ISDIR(cst.st_mode)) {
193*cf5a6c84SAndroid Build Coastguard Worker if (S_ISDIR(try->st.st_mode))
194*cf5a6c84SAndroid Build Coastguard Worker error_msg("dir at '%s'", s = dirtree_path(try, 0));
195*cf5a6c84SAndroid Build Coastguard Worker else if (FLAG(F) && unlinkat(cfd, catch, 0))
196*cf5a6c84SAndroid Build Coastguard Worker error_msg("unlink '%s'", catch);
197*cf5a6c84SAndroid Build Coastguard Worker else if (FLAG(i)) {
198*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "%s: overwrite '%s'", toys.which->name, catch);
199*cf5a6c84SAndroid Build Coastguard Worker if (yesno(0)) rc++;
200*cf5a6c84SAndroid Build Coastguard Worker } else if (!(FLAG(u) && nanodiff(&try->st.st_mtim, &cst.st_mtim)>0)
201*cf5a6c84SAndroid Build Coastguard Worker && !FLAG(n)) rc++;
202*cf5a6c84SAndroid Build Coastguard Worker free(s);
203*cf5a6c84SAndroid Build Coastguard Worker if (!rc) return save;
204*cf5a6c84SAndroid Build Coastguard Worker }
205*cf5a6c84SAndroid Build Coastguard Worker
206*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) {
207*cf5a6c84SAndroid Build Coastguard Worker printf("%s '%s' -> '%s'\n", toys.which->name, s = dirtree_path(try, 0),
208*cf5a6c84SAndroid Build Coastguard Worker catch);
209*cf5a6c84SAndroid Build Coastguard Worker free(s);
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker // Loop for -f retry after unlink
213*cf5a6c84SAndroid Build Coastguard Worker do {
214*cf5a6c84SAndroid Build Coastguard Worker int ii, fdin = -1;
215*cf5a6c84SAndroid Build Coastguard Worker
216*cf5a6c84SAndroid Build Coastguard Worker // directory, hardlink, symlink, mknod (char, block, fifo, socket), file
217*cf5a6c84SAndroid Build Coastguard Worker
218*cf5a6c84SAndroid Build Coastguard Worker // Copy directory
219*cf5a6c84SAndroid Build Coastguard Worker
220*cf5a6c84SAndroid Build Coastguard Worker if (S_ISDIR(try->st.st_mode)) {
221*cf5a6c84SAndroid Build Coastguard Worker struct stat st2;
222*cf5a6c84SAndroid Build Coastguard Worker
223*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(a) && !FLAG(r) && !rr) {
224*cf5a6c84SAndroid Build Coastguard Worker err = "Skipped dir '%s'";
225*cf5a6c84SAndroid Build Coastguard Worker catch = try->name;
226*cf5a6c84SAndroid Build Coastguard Worker break;
227*cf5a6c84SAndroid Build Coastguard Worker }
228*cf5a6c84SAndroid Build Coastguard Worker
229*cf5a6c84SAndroid Build Coastguard Worker // Always make directory writeable to us, so we can create files in it.
230*cf5a6c84SAndroid Build Coastguard Worker //
231*cf5a6c84SAndroid Build Coastguard Worker // Yes, there's a race window between mkdir() and open() so it's
232*cf5a6c84SAndroid Build Coastguard Worker // possible that -p can be made to chown a directory other than the one
233*cf5a6c84SAndroid Build Coastguard Worker // we created. The closest we can do to closing this is make sure
234*cf5a6c84SAndroid Build Coastguard Worker // that what we open _is_ a directory rather than something else.
235*cf5a6c84SAndroid Build Coastguard Worker
236*cf5a6c84SAndroid Build Coastguard Worker if (!mkdirat(cfd, catch, try->st.st_mode | 0200) || errno == EEXIST)
237*cf5a6c84SAndroid Build Coastguard Worker if (-1 != (try->extra = openat(cfd, catch, O_NOFOLLOW)))
238*cf5a6c84SAndroid Build Coastguard Worker if (!fstat(try->extra, &st2) && S_ISDIR(st2.st_mode))
239*cf5a6c84SAndroid Build Coastguard Worker return DIRTREE_COMEAGAIN | DIRTREE_SYMFOLLOW*FLAG(L);
240*cf5a6c84SAndroid Build Coastguard Worker
241*cf5a6c84SAndroid Build Coastguard Worker // Hardlink
242*cf5a6c84SAndroid Build Coastguard Worker
243*cf5a6c84SAndroid Build Coastguard Worker } else if (FLAG(l)) {
244*cf5a6c84SAndroid Build Coastguard Worker if (!linkat(tfd, try->name, cfd, catch, 0)) err = 0;
245*cf5a6c84SAndroid Build Coastguard Worker
246*cf5a6c84SAndroid Build Coastguard Worker // Copy tree as symlinks. For non-absolute paths this involves
247*cf5a6c84SAndroid Build Coastguard Worker // appending the right number of .. entries as you go down the tree.
248*cf5a6c84SAndroid Build Coastguard Worker
249*cf5a6c84SAndroid Build Coastguard Worker } else if (FLAG(s)) {
250*cf5a6c84SAndroid Build Coastguard Worker char *s, *s2;
251*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *or;
252*cf5a6c84SAndroid Build Coastguard Worker
253*cf5a6c84SAndroid Build Coastguard Worker s = dirtree_path(try, 0);
254*cf5a6c84SAndroid Build Coastguard Worker for (ii = 0, or = try; or->parent; or = or->parent) ii++;
255*cf5a6c84SAndroid Build Coastguard Worker if (*or->name == '/') ii = 0;
256*cf5a6c84SAndroid Build Coastguard Worker if (ii) {
257*cf5a6c84SAndroid Build Coastguard Worker s2 = xmprintf("%*c%s", 3*ii, ' ', s);
258*cf5a6c84SAndroid Build Coastguard Worker free(s);
259*cf5a6c84SAndroid Build Coastguard Worker s = s2;
260*cf5a6c84SAndroid Build Coastguard Worker while(ii--) {
261*cf5a6c84SAndroid Build Coastguard Worker memcpy(s2, "../", 3);
262*cf5a6c84SAndroid Build Coastguard Worker s2 += 3;
263*cf5a6c84SAndroid Build Coastguard Worker }
264*cf5a6c84SAndroid Build Coastguard Worker }
265*cf5a6c84SAndroid Build Coastguard Worker if (!symlinkat(s, cfd, catch)) {
266*cf5a6c84SAndroid Build Coastguard Worker err = 0;
267*cf5a6c84SAndroid Build Coastguard Worker fdout = AT_FDCWD;
268*cf5a6c84SAndroid Build Coastguard Worker }
269*cf5a6c84SAndroid Build Coastguard Worker free(s);
270*cf5a6c84SAndroid Build Coastguard Worker
271*cf5a6c84SAndroid Build Coastguard Worker // Do something _other_ than copy contents of a file?
272*cf5a6c84SAndroid Build Coastguard Worker } else if (!S_ISREG(try->st.st_mode)
273*cf5a6c84SAndroid Build Coastguard Worker && (try->parent||FLAG(a)||FLAG(P)||FLAG(r)||rr))
274*cf5a6c84SAndroid Build Coastguard Worker {
275*cf5a6c84SAndroid Build Coastguard Worker // make symlink, or make block/char/fifo/socket
276*cf5a6c84SAndroid Build Coastguard Worker if (S_ISLNK(try->st.st_mode)
277*cf5a6c84SAndroid Build Coastguard Worker ? readlinkat0(tfd, try->name, toybuf, sizeof(toybuf)) &&
278*cf5a6c84SAndroid Build Coastguard Worker (!unlinkat(cfd, catch, 0) || ENOENT == errno) &&
279*cf5a6c84SAndroid Build Coastguard Worker !symlinkat(toybuf, cfd, catch)
280*cf5a6c84SAndroid Build Coastguard Worker : !mknodat(cfd, catch, try->st.st_mode, try->st.st_rdev))
281*cf5a6c84SAndroid Build Coastguard Worker {
282*cf5a6c84SAndroid Build Coastguard Worker err = 0;
283*cf5a6c84SAndroid Build Coastguard Worker fdout = AT_FDCWD;
284*cf5a6c84SAndroid Build Coastguard Worker }
285*cf5a6c84SAndroid Build Coastguard Worker
286*cf5a6c84SAndroid Build Coastguard Worker // Copy contents of file.
287*cf5a6c84SAndroid Build Coastguard Worker } else {
288*cf5a6c84SAndroid Build Coastguard Worker fdin = openat(tfd, try->name, O_RDONLY);
289*cf5a6c84SAndroid Build Coastguard Worker if (fdin < 0) {
290*cf5a6c84SAndroid Build Coastguard Worker catch = try->name;
291*cf5a6c84SAndroid Build Coastguard Worker break;
292*cf5a6c84SAndroid Build Coastguard Worker }
293*cf5a6c84SAndroid Build Coastguard Worker
294*cf5a6c84SAndroid Build Coastguard Worker // When copying contents use symlink target's attributes
295*cf5a6c84SAndroid Build Coastguard Worker if (S_ISLNK(try->st.st_mode)) fstat(fdin, &try->st);
296*cf5a6c84SAndroid Build Coastguard Worker fdout = openat(cfd, catch, O_RDWR|O_CREAT|O_TRUNC, try->st.st_mode);
297*cf5a6c84SAndroid Build Coastguard Worker if (fdout >= 0) {
298*cf5a6c84SAndroid Build Coastguard Worker xsendfile(fdin, fdout);
299*cf5a6c84SAndroid Build Coastguard Worker err = 0;
300*cf5a6c84SAndroid Build Coastguard Worker }
301*cf5a6c84SAndroid Build Coastguard Worker
302*cf5a6c84SAndroid Build Coastguard Worker cp_xattr(fdin, fdout, catch);
303*cf5a6c84SAndroid Build Coastguard Worker }
304*cf5a6c84SAndroid Build Coastguard Worker if (fdin != -1) close(fdin);
305*cf5a6c84SAndroid Build Coastguard Worker } while (err && (FLAG(f)||FLAG(n)) && !unlinkat(cfd, catch, 0));
306*cf5a6c84SAndroid Build Coastguard Worker }
307*cf5a6c84SAndroid Build Coastguard Worker
308*cf5a6c84SAndroid Build Coastguard Worker // Did we make a thing?
309*cf5a6c84SAndroid Build Coastguard Worker if (fdout != -1) {
310*cf5a6c84SAndroid Build Coastguard Worker // Inability to set --preserve isn't fatal, some require root access.
311*cf5a6c84SAndroid Build Coastguard Worker
312*cf5a6c84SAndroid Build Coastguard Worker // ownership
313*cf5a6c84SAndroid Build Coastguard Worker if (TT.pflags & _CP_ownership) {
314*cf5a6c84SAndroid Build Coastguard Worker
315*cf5a6c84SAndroid Build Coastguard Worker // permission bits already correct for mknod and don't apply to symlink
316*cf5a6c84SAndroid Build Coastguard Worker // If we can't get a filehandle to the actual object, use racy functions
317*cf5a6c84SAndroid Build Coastguard Worker if (fdout == AT_FDCWD)
318*cf5a6c84SAndroid Build Coastguard Worker rc = fchownat(cfd, catch, try->st.st_uid, try->st.st_gid,
319*cf5a6c84SAndroid Build Coastguard Worker AT_SYMLINK_NOFOLLOW);
320*cf5a6c84SAndroid Build Coastguard Worker else rc = fchown(fdout, try->st.st_uid, try->st.st_gid);
321*cf5a6c84SAndroid Build Coastguard Worker if (rc && !geteuid()) {
322*cf5a6c84SAndroid Build Coastguard Worker char *pp;
323*cf5a6c84SAndroid Build Coastguard Worker
324*cf5a6c84SAndroid Build Coastguard Worker perror_msg("chown '%s'", pp = dirtree_path(try, 0));
325*cf5a6c84SAndroid Build Coastguard Worker free(pp);
326*cf5a6c84SAndroid Build Coastguard Worker }
327*cf5a6c84SAndroid Build Coastguard Worker }
328*cf5a6c84SAndroid Build Coastguard Worker
329*cf5a6c84SAndroid Build Coastguard Worker // timestamp
330*cf5a6c84SAndroid Build Coastguard Worker if (TT.pflags & _CP_timestamps) {
331*cf5a6c84SAndroid Build Coastguard Worker struct timespec times[] = {try->st.st_atim, try->st.st_mtim};
332*cf5a6c84SAndroid Build Coastguard Worker
333*cf5a6c84SAndroid Build Coastguard Worker if (fdout == AT_FDCWD) utimensat(cfd, catch, times, AT_SYMLINK_NOFOLLOW);
334*cf5a6c84SAndroid Build Coastguard Worker else futimens(fdout, times);
335*cf5a6c84SAndroid Build Coastguard Worker }
336*cf5a6c84SAndroid Build Coastguard Worker
337*cf5a6c84SAndroid Build Coastguard Worker // mode comes last because other syscalls can strip suid bit
338*cf5a6c84SAndroid Build Coastguard Worker if (fdout != AT_FDCWD) {
339*cf5a6c84SAndroid Build Coastguard Worker if (TT.pflags & _CP_mode) fchmod(fdout, try->st.st_mode);
340*cf5a6c84SAndroid Build Coastguard Worker xclose(fdout);
341*cf5a6c84SAndroid Build Coastguard Worker }
342*cf5a6c84SAndroid Build Coastguard Worker
343*cf5a6c84SAndroid Build Coastguard Worker if (save)
344*cf5a6c84SAndroid Build Coastguard Worker if (unlinkat(tfd, try->name, S_ISDIR(try->st.st_mode) ? AT_REMOVEDIR :0))
345*cf5a6c84SAndroid Build Coastguard Worker err = "%s";
346*cf5a6c84SAndroid Build Coastguard Worker }
347*cf5a6c84SAndroid Build Coastguard Worker
348*cf5a6c84SAndroid Build Coastguard Worker if (err) {
349*cf5a6c84SAndroid Build Coastguard Worker if (catch == try->name) {
350*cf5a6c84SAndroid Build Coastguard Worker s = dirtree_path(try, 0);
351*cf5a6c84SAndroid Build Coastguard Worker while (try->parent) try = try->parent;
352*cf5a6c84SAndroid Build Coastguard Worker catch = xmprintf("%s%s", TT.destname, s+strlen(try->name));
353*cf5a6c84SAndroid Build Coastguard Worker free(s);
354*cf5a6c84SAndroid Build Coastguard Worker s = catch;
355*cf5a6c84SAndroid Build Coastguard Worker } else s = 0;
356*cf5a6c84SAndroid Build Coastguard Worker perror_msg(err, catch);
357*cf5a6c84SAndroid Build Coastguard Worker free(s);
358*cf5a6c84SAndroid Build Coastguard Worker }
359*cf5a6c84SAndroid Build Coastguard Worker
360*cf5a6c84SAndroid Build Coastguard Worker return 0;
361*cf5a6c84SAndroid Build Coastguard Worker }
362*cf5a6c84SAndroid Build Coastguard Worker
cp_main(void)363*cf5a6c84SAndroid Build Coastguard Worker void cp_main(void)
364*cf5a6c84SAndroid Build Coastguard Worker {
365*cf5a6c84SAndroid Build Coastguard Worker char *tt = *toys.which->name == 'i' ? TT.i.t : TT.c.t,
366*cf5a6c84SAndroid Build Coastguard Worker *destname = tt ? : toys.optargs[--toys.optc];
367*cf5a6c84SAndroid Build Coastguard Worker int i, destdir = !stat(destname, &TT.top);
368*cf5a6c84SAndroid Build Coastguard Worker
369*cf5a6c84SAndroid Build Coastguard Worker if (!toys.optc) error_exit("Needs 2 arguments");
370*cf5a6c84SAndroid Build Coastguard Worker if (!destdir && errno==ENOENT && FLAG(D)) {
371*cf5a6c84SAndroid Build Coastguard Worker if (tt && mkpathat(AT_FDCWD, tt, 0777, MKPATHAT_MAKE|MKPATHAT_MKLAST))
372*cf5a6c84SAndroid Build Coastguard Worker perror_exit("-t '%s'", tt);
373*cf5a6c84SAndroid Build Coastguard Worker destdir = 1;
374*cf5a6c84SAndroid Build Coastguard Worker } else {
375*cf5a6c84SAndroid Build Coastguard Worker destdir = destdir && S_ISDIR(TT.top.st_mode);
376*cf5a6c84SAndroid Build Coastguard Worker if (!destdir && (toys.optc>1 || FLAG(D) || tt))
377*cf5a6c84SAndroid Build Coastguard Worker error_exit("'%s' not directory", destname);
378*cf5a6c84SAndroid Build Coastguard Worker }
379*cf5a6c84SAndroid Build Coastguard Worker
380*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(T)) {
381*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc>1) help_exit("Max 2 arguments");
382*cf5a6c84SAndroid Build Coastguard Worker if (destdir) error_exit("'%s' is a directory", destname);
383*cf5a6c84SAndroid Build Coastguard Worker }
384*cf5a6c84SAndroid Build Coastguard Worker
385*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(a)||FLAG(p)) TT.pflags = _CP_mode|_CP_ownership|_CP_timestamps;
386*cf5a6c84SAndroid Build Coastguard Worker
387*cf5a6c84SAndroid Build Coastguard Worker // Not using comma_args() (yet?) because interpeting as letters.
388*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(preserve)) {
389*cf5a6c84SAndroid Build Coastguard Worker char *pre = xstrdup(TT.c.preserve ? TT.c.preserve : "mot"), *s;
390*cf5a6c84SAndroid Build Coastguard Worker
391*cf5a6c84SAndroid Build Coastguard Worker if (comma_remove(pre, "all")) TT.pflags = ~0;
392*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<ARRAY_LEN(cp_preserve); i++)
393*cf5a6c84SAndroid Build Coastguard Worker while (comma_remove(pre, cp_preserve[i].name)) TT.pflags |= 1<<i;
394*cf5a6c84SAndroid Build Coastguard Worker if (*pre) {
395*cf5a6c84SAndroid Build Coastguard Worker
396*cf5a6c84SAndroid Build Coastguard Worker // Try to interpret as letters, commas won't set anything this doesn't.
397*cf5a6c84SAndroid Build Coastguard Worker for (s = pre; *s; s++) {
398*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<ARRAY_LEN(cp_preserve); i++)
399*cf5a6c84SAndroid Build Coastguard Worker if (*s == *cp_preserve[i].name) break;
400*cf5a6c84SAndroid Build Coastguard Worker if (i == ARRAY_LEN(cp_preserve)) {
401*cf5a6c84SAndroid Build Coastguard Worker if (*s == 'a') TT.pflags = ~0;
402*cf5a6c84SAndroid Build Coastguard Worker else break;
403*cf5a6c84SAndroid Build Coastguard Worker } else TT.pflags |= 1<<i;
404*cf5a6c84SAndroid Build Coastguard Worker }
405*cf5a6c84SAndroid Build Coastguard Worker
406*cf5a6c84SAndroid Build Coastguard Worker if (*s) error_exit("bad --preserve=%s", pre);
407*cf5a6c84SAndroid Build Coastguard Worker }
408*cf5a6c84SAndroid Build Coastguard Worker free(pre);
409*cf5a6c84SAndroid Build Coastguard Worker }
410*cf5a6c84SAndroid Build Coastguard Worker if (TT.pflags & _CP_mode) umask(0);
411*cf5a6c84SAndroid Build Coastguard Worker if (!TT.callback) TT.callback = cp_node;
412*cf5a6c84SAndroid Build Coastguard Worker
413*cf5a6c84SAndroid Build Coastguard Worker // Loop through sources
414*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<toys.optc; i++) {
415*cf5a6c84SAndroid Build Coastguard Worker char *src = toys.optargs[i], *trail;
416*cf5a6c84SAndroid Build Coastguard Worker int send = 1;
417*cf5a6c84SAndroid Build Coastguard Worker
418*cf5a6c84SAndroid Build Coastguard Worker if (!(trail = strrchr(src, '/')) || trail[1]) trail = 0;
419*cf5a6c84SAndroid Build Coastguard Worker else while (trail>src && *trail=='/') *trail-- = 0;
420*cf5a6c84SAndroid Build Coastguard Worker
421*cf5a6c84SAndroid Build Coastguard Worker if (destdir) {
422*cf5a6c84SAndroid Build Coastguard Worker char *s = FLAG(D) ? src : getbasename(src);
423*cf5a6c84SAndroid Build Coastguard Worker
424*cf5a6c84SAndroid Build Coastguard Worker TT.destname = xmprintf("%s/%s", destname, s);
425*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(D)) {
426*cf5a6c84SAndroid Build Coastguard Worker if (!(s = fileunderdir(TT.destname, destname))) {
427*cf5a6c84SAndroid Build Coastguard Worker error_msg("%s not under %s", TT.destname, destname);
428*cf5a6c84SAndroid Build Coastguard Worker continue;
429*cf5a6c84SAndroid Build Coastguard Worker }
430*cf5a6c84SAndroid Build Coastguard Worker // TODO: .. follows abspath, not links...
431*cf5a6c84SAndroid Build Coastguard Worker free(s);
432*cf5a6c84SAndroid Build Coastguard Worker mkpath(TT.destname);
433*cf5a6c84SAndroid Build Coastguard Worker }
434*cf5a6c84SAndroid Build Coastguard Worker } else TT.destname = destname;
435*cf5a6c84SAndroid Build Coastguard Worker
436*cf5a6c84SAndroid Build Coastguard Worker // "mv across devices" triggers cp fallback path, so set that as default
437*cf5a6c84SAndroid Build Coastguard Worker errno = EXDEV;
438*cf5a6c84SAndroid Build Coastguard Worker if (CFG_MV && *toys.which->name == 'm') {
439*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(f) || FLAG(n)) {
440*cf5a6c84SAndroid Build Coastguard Worker struct stat st;
441*cf5a6c84SAndroid Build Coastguard Worker int exists = !stat(TT.destname, &st);
442*cf5a6c84SAndroid Build Coastguard Worker
443*cf5a6c84SAndroid Build Coastguard Worker // Prompt if -i or file isn't writable. Technically "is writable" is
444*cf5a6c84SAndroid Build Coastguard Worker // more complicated (022 is not writeable by the owner, just everybody
445*cf5a6c84SAndroid Build Coastguard Worker // _else_) but I don't care.
446*cf5a6c84SAndroid Build Coastguard Worker if (exists && (FLAG(i) || (!(st.st_mode & 0222) && isatty(0)))) {
447*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "%s: overwrite '%s'", toys.which->name, TT.destname);
448*cf5a6c84SAndroid Build Coastguard Worker if (!yesno(0)) send = 0;
449*cf5a6c84SAndroid Build Coastguard Worker else unlink(TT.destname);
450*cf5a6c84SAndroid Build Coastguard Worker }
451*cf5a6c84SAndroid Build Coastguard Worker // if -n and dest exists, don't try to rename() or copy
452*cf5a6c84SAndroid Build Coastguard Worker if (exists && FLAG(n)) send = 0;
453*cf5a6c84SAndroid Build Coastguard Worker }
454*cf5a6c84SAndroid Build Coastguard Worker if (send) send = rename(src, TT.destname);
455*cf5a6c84SAndroid Build Coastguard Worker if (trail) trail[1] = '/';
456*cf5a6c84SAndroid Build Coastguard Worker }
457*cf5a6c84SAndroid Build Coastguard Worker
458*cf5a6c84SAndroid Build Coastguard Worker // Copy if we didn't mv or hit an error, skipping nonexistent sources
459*cf5a6c84SAndroid Build Coastguard Worker if (send) {
460*cf5a6c84SAndroid Build Coastguard Worker if (errno!=EXDEV || dirtree_flagread(src, DIRTREE_SHUTUP+
461*cf5a6c84SAndroid Build Coastguard Worker DIRTREE_SYMFOLLOW*(FLAG(H)|FLAG(L)), TT.callback))
462*cf5a6c84SAndroid Build Coastguard Worker perror_msg("bad '%s'", src);
463*cf5a6c84SAndroid Build Coastguard Worker }
464*cf5a6c84SAndroid Build Coastguard Worker if (destdir) free(TT.destname);
465*cf5a6c84SAndroid Build Coastguard Worker }
466*cf5a6c84SAndroid Build Coastguard Worker }
467*cf5a6c84SAndroid Build Coastguard Worker
468*cf5a6c84SAndroid Build Coastguard Worker // Export cp's flags into mv and install flag context.
469*cf5a6c84SAndroid Build Coastguard Worker
cp_flag_F(void)470*cf5a6c84SAndroid Build Coastguard Worker static inline int cp_flag_F(void) { return FLAG_F; }
cp_flag_p(void)471*cf5a6c84SAndroid Build Coastguard Worker static inline int cp_flag_p(void) { return FLAG_p; }
cp_flag_v(void)472*cf5a6c84SAndroid Build Coastguard Worker static inline int cp_flag_v(void) { return FLAG_v; }
cp_flag_dpr(void)473*cf5a6c84SAndroid Build Coastguard Worker static inline int cp_flag_dpr(void) { return FLAG_d|FLAG_p|FLAG_r; }
474*cf5a6c84SAndroid Build Coastguard Worker
475*cf5a6c84SAndroid Build Coastguard Worker #define FOR_mv
476*cf5a6c84SAndroid Build Coastguard Worker #include <generated/flags.h>
477*cf5a6c84SAndroid Build Coastguard Worker
mv_main(void)478*cf5a6c84SAndroid Build Coastguard Worker void mv_main(void)
479*cf5a6c84SAndroid Build Coastguard Worker {
480*cf5a6c84SAndroid Build Coastguard Worker toys.optflags |= cp_flag_dpr();
481*cf5a6c84SAndroid Build Coastguard Worker TT.pflags =~0;
482*cf5a6c84SAndroid Build Coastguard Worker
483*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(x)) {
484*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc != 2) error_exit("-x needs 2 args");
485*cf5a6c84SAndroid Build Coastguard Worker if (rename_exchange(toys.optargs[0], toys.optargs[1]))
486*cf5a6c84SAndroid Build Coastguard Worker perror_exit("-x %s %s", toys.optargs[0], toys.optargs[1]);
487*cf5a6c84SAndroid Build Coastguard Worker } else cp_main();
488*cf5a6c84SAndroid Build Coastguard Worker }
489*cf5a6c84SAndroid Build Coastguard Worker
490*cf5a6c84SAndroid Build Coastguard Worker #define FOR_install
491*cf5a6c84SAndroid Build Coastguard Worker #include <generated/flags.h>
492*cf5a6c84SAndroid Build Coastguard Worker
install_node(struct dirtree * try)493*cf5a6c84SAndroid Build Coastguard Worker static int install_node(struct dirtree *try)
494*cf5a6c84SAndroid Build Coastguard Worker {
495*cf5a6c84SAndroid Build Coastguard Worker try->st.st_mode = TT.i.m ? string_to_mode(TT.i.m, try->st.st_mode) : 0755;
496*cf5a6c84SAndroid Build Coastguard Worker if (TT.i.g) try->st.st_gid = TT.gid;
497*cf5a6c84SAndroid Build Coastguard Worker if (TT.i.o) try->st.st_uid = TT.uid;
498*cf5a6c84SAndroid Build Coastguard Worker
499*cf5a6c84SAndroid Build Coastguard Worker // Always returns 0 because no -r
500*cf5a6c84SAndroid Build Coastguard Worker cp_node(try);
501*cf5a6c84SAndroid Build Coastguard Worker
502*cf5a6c84SAndroid Build Coastguard Worker // No -r so always one level deep, so destname as set by cp_node() is correct
503*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(s) && xrun((char *[]){"strip", "-p", TT.destname, 0}))
504*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = 1;
505*cf5a6c84SAndroid Build Coastguard Worker
506*cf5a6c84SAndroid Build Coastguard Worker return 0;
507*cf5a6c84SAndroid Build Coastguard Worker }
508*cf5a6c84SAndroid Build Coastguard Worker
install_main(void)509*cf5a6c84SAndroid Build Coastguard Worker void install_main(void)
510*cf5a6c84SAndroid Build Coastguard Worker {
511*cf5a6c84SAndroid Build Coastguard Worker char **ss;
512*cf5a6c84SAndroid Build Coastguard Worker
513*cf5a6c84SAndroid Build Coastguard Worker TT.uid = TT.i.o ? xgetuid(TT.i.o) : -1;
514*cf5a6c84SAndroid Build Coastguard Worker TT.gid = TT.i.g ? xgetgid(TT.i.g) : -1;
515*cf5a6c84SAndroid Build Coastguard Worker
516*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(d)) {
517*cf5a6c84SAndroid Build Coastguard Worker int mode = TT.i.m ? string_to_mode(TT.i.m, 0) : 0755;
518*cf5a6c84SAndroid Build Coastguard Worker
519*cf5a6c84SAndroid Build Coastguard Worker for (ss = toys.optargs; *ss; ss++) {
520*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(v)) printf("%s\n", *ss);
521*cf5a6c84SAndroid Build Coastguard Worker if (mkpathat(AT_FDCWD, *ss, mode, MKPATHAT_MKLAST | MKPATHAT_MAKE))
522*cf5a6c84SAndroid Build Coastguard Worker perror_msg_raw(*ss);
523*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(g)||FLAG(o))
524*cf5a6c84SAndroid Build Coastguard Worker if (lchown(*ss, TT.uid, TT.gid)) perror_msg("chown '%s'", *ss);
525*cf5a6c84SAndroid Build Coastguard Worker if ((mode&~01777) && chmod(*ss, mode)) perror_msg("chmod '%s'", *ss);
526*cf5a6c84SAndroid Build Coastguard Worker }
527*cf5a6c84SAndroid Build Coastguard Worker
528*cf5a6c84SAndroid Build Coastguard Worker return;
529*cf5a6c84SAndroid Build Coastguard Worker }
530*cf5a6c84SAndroid Build Coastguard Worker
531*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(D)) {
532*cf5a6c84SAndroid Build Coastguard Worker char *destname = TT.i.t ? : (TT.destname = toys.optargs[toys.optc-1]);
533*cf5a6c84SAndroid Build Coastguard Worker if (mkpathat(AT_FDCWD, destname, 0777, MKPATHAT_MAKE|MKPATHAT_MKLAST*FLAG(t)))
534*cf5a6c84SAndroid Build Coastguard Worker perror_exit("-D '%s'", destname);
535*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc == !FLAG(t)) return;
536*cf5a6c84SAndroid Build Coastguard Worker }
537*cf5a6c84SAndroid Build Coastguard Worker
538*cf5a6c84SAndroid Build Coastguard Worker // Translate flags from install to cp
539*cf5a6c84SAndroid Build Coastguard Worker toys.optflags = cp_flag_F() + cp_flag_v()*FLAG(v)
540*cf5a6c84SAndroid Build Coastguard Worker + cp_flag_p()*(FLAG(p)|FLAG(o)|FLAG(g));
541*cf5a6c84SAndroid Build Coastguard Worker
542*cf5a6c84SAndroid Build Coastguard Worker TT.callback = install_node;
543*cf5a6c84SAndroid Build Coastguard Worker cp_main();
544*cf5a6c84SAndroid Build Coastguard Worker }
545