1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * 	Copyright (c) 1999 by Sun Microsystems, Inc.
24 * 	All rights reserved.
25 */
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27/*	  All Rights Reserved  	*/
28
29
30#ident	"%Z%%M%	%I%	%E% SMI"	/* from SVR4 bnu:cpmv.c	2.13 */
31
32#include "uucp.h"
33
34/*
35 * copy f1 to f2 locally
36 *	f1	-> source file name
37 *	f2	-> destination file name
38 * return:
39 *	0	-> ok
40 *	FAIL	-> failed
41 */
42
43static int
44xcp(f1, f2)
45char *f1, *f2;
46{
47	register int	fd1, fd2;
48	register int	nr, nw;
49	char buf[BUFSIZ];
50	char *temp_p, temp[MAXFULLNAME];
51
52	if ((fd1 = open(f1, O_RDONLY)) == -1)
53		return (FAIL);
54
55	if (DIRECTORY(f2)) {
56		(void) strcat(f2, "/");
57		(void) strcat(f2, BASENAME(f1, '/'));
58	}
59	DEBUG(4, "file name is %s\n", f2);
60
61	(void) strcpy(temp, f2);
62	if ((temp_p = strrchr(temp, '/')) == NULL)
63	    temp_p = temp;
64	else
65	    temp_p++;
66	(void) strcpy(temp_p, ".TM.XXXXXX");
67	temp_p = temp;
68	DEBUG(4, "temp name is %s\n", temp_p);
69
70	if ((fd2 = mkstemp(temp_p)) == -1) {
71		/* open of temp may fail if called from uidxcp() */
72		/* in this case, try f2 since it is pre-created */
73		temp_p = f2;
74		if ((fd2 = open(temp_p, O_CREAT | O_TRUNC | O_WRONLY,
75		    PUB_FILEMODE)) == -1) {
76			DEBUG(5, "open of file returned errno %d\n", errno);
77			(void) close(fd1);
78			return (FAIL);
79		}
80		DEBUG(4, "using file name directly.%s\n", "");
81	}
82	(void) chmod(temp_p, PUB_FILEMODE);
83
84	/*	copy, looking for read or write failures */
85	while ((nr = read(fd1, buf, sizeof (buf))) > 0 &&
86		(nw = write(fd2, buf, nr)) == nr)
87		;
88
89	close(fd1);
90	close(fd2);
91
92	if (nr != 0 || nw == -1) {
93		(void) unlink(temp_p);
94		return (FAIL);
95	}
96	if (temp_p != f2) {
97	    if (rename(temp_p, f2) != 0) {
98		DEBUG(5, "rename failed: errno %d\n", errno);
99		(void) unlink(temp_p);
100		return (FAIL);
101	    }
102	}
103	return (0);
104}
105
106
107/*
108 * move f1 to f2 locally
109 * returns:
110 *	0	-> ok
111 *	FAIL	-> failed
112 */
113
114int
115xmv(f1, f2)
116register char *f1, *f2;
117{
118	register int do_unlink, ret;
119	struct stat sbuf;
120
121	if (stat(f2, &sbuf) == 0)
122		do_unlink = ((sbuf.st_mode & S_IFMT) == S_IFREG);
123	else
124		do_unlink = 1;
125
126	if (do_unlink)
127		(void) unlink(f2);	/* i'm convinced this is the right */
128					/* thing to do */
129	if ((ret = link(f1, f2)) < 0) {
130	    /* copy file */
131	    ret = xcp(f1, f2);
132	}
133
134	if (ret == 0)
135	    (void) unlink(f1);
136	return (ret);
137}
138
139/*
140 * toCorrupt - move file to CORRUPTDIR
141 * return - none
142 */
143
144void
145toCorrupt(file)
146char *file;
147{
148	char corrupt[MAXFULLNAME];
149
150	(void) sprintf(corrupt, "%s/%s", CORRUPTDIR, BASENAME(file, '/'));
151	(void) link(file, corrupt);
152	ASSERT(unlink(file) == 0, Ct_UNLINK, file, errno);
153}
154
155/*
156 * append f1 to f2
157 *	f1	-> source FILE pointer
158 *	f2	-> destination FILE pointer
159 * return:
160 *	SUCCESS	-> ok
161 *	FAIL	-> failed
162 *
163 * to avoid confusing mail, turn lines with just "." into "..".
164 */
165int
166xfappend(fp1, fp2)
167register FILE	*fp1, *fp2;
168{
169	char	buf[BUFSIZ];
170
171	while (fgets(buf, sizeof (buf), fp1) != NULL) {
172		if (buf[0] == '.' && buf[1] == '\n')
173			strcpy(buf, "..\n");
174		fputs(buf, fp2);
175	}
176
177	return (ferror(fp1) || ferror(fp2) ? FAIL : SUCCESS);
178}
179
180
181/*
182 * copy f1 to f2 locally under uid of uid argument
183 *	f1	-> source file name
184 *	f2	-> destination file name
185 *	Uid and Euid are global
186 * return:
187 *	0	-> ok
188 *	FAIL	-> failed
189 * NOTES:
190 *  for V7 systems, flip-flop between real and effective uid is
191 *  not allowed, so fork must be done.  This code will not
192 *  work correctly when realuid is root on System 5 because of
193 *  a bug in setuid.
194 */
195
196int
197uidxcp(f1, f2)
198char *f1, *f2;
199{
200	int status;
201	char full[MAXFULLNAME];
202
203	(void) strcpy(full, f2);
204	if (DIRECTORY(f2)) {
205	    (void) strcat(full, "/");
206	    (void) strcat(full, BASENAME(f1, '/'));
207	}
208
209	/* create full owned by uucp */
210	(void) close(creat(full, PUB_FILEMODE));
211	(void) chmod(full, PUB_FILEMODE);
212
213	/* do file copy as read uid */
214#ifndef V7
215	(void) setuid(Uid);
216	status = xcp(f1, full);
217	(void) setuid(Euid);
218	return (status);
219
220#else /* V7 */
221
222	if (vfork() == 0) {
223	    setuid(Uid);
224	    _exit(xcp(f1, full));
225	}
226	wait(&status);
227	return (status);
228#endif
229}
230
231/*
232 * put file in public place
233 * if successful, filename is modified
234 * returns:
235 *	0	-> success
236 *	FAIL	-> failure
237 */
238int
239putinpub(file, tmp, user)
240char *file, *user, *tmp;
241{
242	int status;
243	char fullname[MAXFULLNAME];
244
245	(void) sprintf(fullname, "%s/%s/", Pubdir, user);
246	if (mkdirs(fullname, PUBMASK) != 0) {
247		/* cannot make directories */
248		return (FAIL);
249	}
250	(void) strcat(fullname, BASENAME(file, '/'));
251	status = xmv(tmp, fullname);
252	if (status == 0) {
253		(void) strcpy(file, fullname);
254		(void) chmod(fullname, PUB_FILEMODE);
255	}
256	return (status);
257}
258