/src/pdsh/pcp_server.c

https://code.google.com/ · C · 464 lines · 325 code · 54 blank · 85 comment · 110 complexity · a3f50f6dcd3302fdcd0852a92680ed74 MD5 · raw file

  1. /*****************************************************************************\
  2. * $Id$
  3. *****************************************************************************
  4. * Copyright (C) 2001-2006 The Regents of the University of California.
  5. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  6. * Written by Jim Garlick <garlick@llnl.gov>.
  7. * UCRL-CODE-2003-005.
  8. *
  9. * This file is part of Pdsh, a parallel remote shell program.
  10. * For details, see <http://www.llnl.gov/linux/pdsh/>.
  11. *
  12. * Pdsh is free software; you can redistribute it and/or modify it under
  13. * the terms of the GNU General Public License as published by the Free
  14. * Software Foundation; either version 2 of the License, or (at your option)
  15. * any later version.
  16. *
  17. * Pdsh is distributed in the hope that it will be useful, but WITHOUT ANY
  18. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  19. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  20. * details.
  21. *
  22. * You should have received a copy of the GNU General Public License along
  23. * with Pdsh; if not, write to the Free Software Foundation, Inc.,
  24. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  25. \*****************************************************************************/
  26. /*
  27. * Copyright (c) 1983, 1990 The Regents of the University of California.
  28. * All rights reserved.
  29. *
  30. * Redistribution and use in source and binary forms, with or without
  31. * modification, are permitted provided that the following conditions
  32. * are met:
  33. * 1. Redistributions of source code must retain the above copyright
  34. * notice, this list of conditions and the following disclaimer.
  35. * 2. Redistributions in binary form must reproduce the above copyright
  36. * notice, this list of conditions and the following disclaimer in the
  37. * documentation and/or other materials provided with the distribution.
  38. * 3. Advertising clause removed per the following letter:
  39. * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
  40. * 4. Neither the name of the University nor the names of its contributors
  41. * may be used to endorse or promote products derived from this software
  42. * without specific prior written permission.
  43. *
  44. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  45. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  46. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  47. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  48. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  49. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  50. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  51. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  52. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  53. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  54. * SUCH DAMAGE.
  55. */
  56. char copyright[] =
  57. "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n"
  58. "All rights reserved.\n";
  59. /*
  60. * From: @(#)rcp.c 5.32 (Berkeley) 2/25/91
  61. */
  62. char rcsid[] = "$Id$";
  63. /* #include "../version.h" */
  64. #if HAVE_CONFIG_H
  65. # include "config.h"
  66. #endif
  67. #include <sys/param.h> /* roundup() */
  68. #if HAVE_SYS_SYSMACROS_H
  69. # include <sys/sysmacros.h>
  70. #endif
  71. #include <sys/stat.h>
  72. #include <sys/time.h>
  73. #include <sys/ioctl.h>
  74. #include <sys/socket.h>
  75. #include <sys/types.h>
  76. #include <sys/wait.h>
  77. #include <netinet/in.h>
  78. #include <dirent.h>
  79. #include <fcntl.h>
  80. #include <signal.h>
  81. #include <pwd.h>
  82. #include <netdb.h>
  83. #include <errno.h>
  84. #include <unistd.h>
  85. #include <stdio.h>
  86. #include <stdarg.h>
  87. #include <stdlib.h>
  88. #include <string.h>
  89. #include <ctype.h>
  90. #include <stdio.h>
  91. #include "src/common/err.h"
  92. #include "pcp_server.h"
  93. #include "opt.h"
  94. #ifndef roundup
  95. # define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
  96. #endif
  97. /* The majority of the code below is unchanged from the original
  98. * rcp code. Changes include:
  99. * - rcp bug fix
  100. * - removal of conditions that are impossible to hit in pdcp
  101. * - update error messages to use pdcp error functions
  102. * - minor changes to enhance readability and fit style to rest
  103. * of pdsh/pdcp code.
  104. * - pass infd/outfd through structure rather than global
  105. * - don't exit on error, just return
  106. */
  107. typedef struct _buf {
  108. int cnt;
  109. char *buf;
  110. } BUF;
  111. static int _verifydir(struct pcp_server *s, const char *cp);
  112. static int _response(struct pcp_server *s);
  113. static BUF *_allocbuf(struct pcp_server *s, BUF *bp, int fd, int blksize);
  114. static void _error(struct pcp_server *s, const char *fmt, ...);
  115. static void _sink(struct pcp_server *s, char *targ, BUF *bufp);
  116. static int
  117. _verifydir(struct pcp_server *s, const char *cp)
  118. {
  119. struct stat stb;
  120. if (stat(cp, &stb) >= 0) {
  121. if ((stb.st_mode & S_IFMT) == S_IFDIR)
  122. return 0;
  123. errno = ENOTDIR;
  124. }
  125. _error(s, "%s not a directory\n", cp);
  126. return -1;
  127. }
  128. static int
  129. _response(struct pcp_server *s)
  130. {
  131. char resp;
  132. if (read(s->infd, &resp, sizeof(resp)) != sizeof(resp)) {
  133. _error(s, "lost connection\n");
  134. return -1;
  135. }
  136. switch(resp) {
  137. case 0: /* ok */
  138. return 0;
  139. default:
  140. _error(s, "invalid response received\n");
  141. return -1;
  142. }
  143. /*NOTREACHED*/
  144. return 0;
  145. }
  146. static BUF *
  147. _allocbuf(struct pcp_server *s, BUF *bp, int fd, int blksize)
  148. {
  149. struct stat stb;
  150. int size;
  151. if (fstat(fd, &stb) < 0) {
  152. _error(s, "fstat: %m\n");
  153. return NULL;
  154. }
  155. size = roundup(stb.st_blksize, blksize);
  156. if (size == 0)
  157. size = blksize;
  158. if (bp->cnt < size) {
  159. if (bp->buf != 0)
  160. free(bp->buf);
  161. bp->buf = malloc(size);
  162. if (!bp->buf) {
  163. _error(s, "malloc: out of memory\n");
  164. bp->cnt = 0;
  165. return NULL;
  166. }
  167. }
  168. bp->cnt = size;
  169. return(bp);
  170. }
  171. static void
  172. _error(struct pcp_server *s, const char *fmt, ...)
  173. {
  174. static FILE *fp = NULL;
  175. char newfmt[1000];
  176. va_list ap;
  177. int save_errno = errno; /* errno could be changed by fopen */
  178. if (!(fp = fdopen(s->outfd, "w")))
  179. return;
  180. va_start(ap, fmt);
  181. /* must put "1" at beginning of the format to indicate an error */
  182. snprintf(newfmt, 1000, "%c%s", 0x01, fmt);
  183. errno = save_errno;
  184. errf(fp, newfmt, ap);
  185. va_end(ap);
  186. fflush(fp);
  187. }
  188. static void
  189. _sink(struct pcp_server *svr, char *targ, BUF *bufp) {
  190. register char *cp;
  191. struct stat stb;
  192. struct timeval tv[2];
  193. enum { YES, NO, DISPLAYED } wrerr;
  194. BUF *bp;
  195. off_t i, j, size;
  196. char ch;
  197. const char *why = "failed to set 'why' string";
  198. int amt, count, exists, mask, mode;
  199. int ofd, setimes, targisdir, cursize = 0;
  200. char *np, *buf = NULL, *namebuf = NULL;
  201. #define atime tv[0]
  202. #define mtime tv[1]
  203. #define SCREWUP(str) { why = str; goto screwup; }
  204. if (!(buf = malloc(BUFSIZ))) {
  205. _error(svr, "out of memory for buf: %m\n");
  206. return;
  207. }
  208. setimes = targisdir = 0;
  209. mask = umask(0);
  210. if (!svr->preserve)
  211. (void)umask(mask);
  212. if (svr->target_is_dir) {
  213. if (_verifydir(svr, svr->outfile) < 0)
  214. return;
  215. }
  216. (void)write(svr->outfd, "", 1);
  217. if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
  218. targisdir = 1;
  219. while (1) {
  220. int rc;
  221. cp = buf;
  222. if ((rc = read(svr->infd, cp, 1)) <= 0)
  223. goto end_server;
  224. if (*cp++ == '\n')
  225. SCREWUP("unexpected <newline>");
  226. do {
  227. if (read(svr->infd, &ch, sizeof(ch)) != sizeof(ch))
  228. SCREWUP("lost connection");
  229. *cp++ = ch;
  230. } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
  231. *cp = 0;
  232. if (buf[0] == '\01' || buf[0] == '\02') {
  233. if (buf[0] == '\02')
  234. goto end_server;
  235. continue;
  236. }
  237. if (buf[0] == 'E') {
  238. (void)write(svr->outfd, "", 1);
  239. goto end_server;
  240. }
  241. if (ch == '\n')
  242. *--cp = 0;
  243. #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
  244. cp = buf;
  245. if (*cp == 'T') {
  246. setimes++;
  247. cp++;
  248. getnum(mtime.tv_sec);
  249. if (*cp++ != ' ')
  250. SCREWUP("mtime.sec not delimited");
  251. getnum(mtime.tv_usec);
  252. if (*cp++ != ' ')
  253. SCREWUP("mtime.usec not delimited");
  254. getnum(atime.tv_sec);
  255. if (*cp++ != ' ')
  256. SCREWUP("atime.sec not delimited");
  257. getnum(atime.tv_usec);
  258. if (*cp++ != '\0')
  259. SCREWUP("atime.usec not delimited");
  260. (void)write(svr->outfd, "", 1);
  261. continue;
  262. }
  263. if (*cp != 'C' && *cp != 'D')
  264. SCREWUP("expected control record");
  265. mode = 0;
  266. for (++cp; cp < buf + 5; cp++) {
  267. if (*cp < '0' || *cp > '7')
  268. SCREWUP("bad mode");
  269. mode = (mode << 3) | (*cp - '0');
  270. }
  271. if (*cp++ != ' ')
  272. SCREWUP("mode not delimited");
  273. size = 0;
  274. while (isdigit(*cp))
  275. size = size * 10 + (*cp++ - '0');
  276. if (*cp++ != ' ')
  277. SCREWUP("size not delimited");
  278. /* filename is "retrieved" in this if/else block */
  279. if (targisdir) {
  280. /* achu: The original rcp code here was completely whack.
  281. * Memory was allocated for every file, memory was never
  282. * freed, cursize was never set to the current buffer
  283. * size, and a code path existed that could write past
  284. * allocated memory boundaries. Lots and lots of fixes
  285. * here. Atleast one person on google-groups concurs with
  286. * my thoughts.
  287. */
  288. int need;
  289. need = strlen(targ) + strlen(cp) + 250;
  290. if (need > cursize) {
  291. if (namebuf)
  292. free(namebuf);
  293. if (!(namebuf = malloc(need))) {
  294. _error(svr, "out of memory\n");
  295. cursize = 0;
  296. /* original rcp may not work with a continue here,
  297. * but it will work with pdcp protocol.
  298. */
  299. continue;
  300. }
  301. cursize = need;
  302. }
  303. (void)snprintf(namebuf, cursize, "%s%s%s", targ,
  304. *targ ? "/" : "", cp);
  305. np = namebuf;
  306. }
  307. else
  308. np = targ;
  309. exists = stat(np, &stb) == 0;
  310. if (buf[0] == 'D') {
  311. if (exists) {
  312. if ((stb.st_mode & S_IFMT) != S_IFDIR) {
  313. errno = ENOTDIR;
  314. goto bad;
  315. }
  316. if (svr->preserve)
  317. (void)chmod(np, mode);
  318. } else if (mkdir(np, mode) < 0)
  319. goto bad;
  320. /* recursively go down a directory */
  321. _sink(svr, np, bufp);
  322. if (setimes) {
  323. setimes = 0;
  324. if (utimes(np, tv) < 0)
  325. _error(svr, "can't set times on %s: %m\n", np);
  326. }
  327. continue;
  328. }
  329. if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
  330. bad:
  331. _error(svr, "%s: %m\n", np);
  332. continue;
  333. }
  334. if (exists && svr->preserve)
  335. (void)fchmod(ofd, mode);
  336. (void)write(svr->outfd, "", 1);
  337. if ((bp = _allocbuf(svr, bufp, ofd, BUFSIZ)) == NULL) {
  338. (void)close(ofd);
  339. continue;
  340. }
  341. cp = bp->buf;
  342. count = 0;
  343. wrerr = NO;
  344. for (i = 0; i < size; i += BUFSIZ) {
  345. amt = BUFSIZ;
  346. if (i + amt > size)
  347. amt = size - i;
  348. count += amt;
  349. do {
  350. j = read(svr->infd, cp, amt);
  351. if (j <= 0) {
  352. _error(svr, "%m\n");
  353. goto end_server;
  354. }
  355. amt -= j;
  356. cp += j;
  357. } while (amt > 0);
  358. if (count == bp->cnt) {
  359. if (wrerr == NO && write(ofd, bp->buf, count) != count)
  360. wrerr = YES;
  361. count = 0;
  362. cp = bp->buf;
  363. }
  364. }
  365. if (count != 0 && wrerr == NO && write(ofd, bp->buf, count) != count)
  366. wrerr = YES;
  367. if (ftruncate(ofd, size)) {
  368. _error(svr, "can't truncate %s: %m\n", np);
  369. wrerr = DISPLAYED;
  370. }
  371. (void)close(ofd);
  372. if (_response(svr) < 0)
  373. goto end_server;
  374. if (setimes && wrerr == NO) {
  375. setimes = 0;
  376. if (utimes(np, tv) < 0) {
  377. _error(svr, "can't set times on %s: %m\n", np);
  378. wrerr = DISPLAYED;
  379. }
  380. }
  381. switch(wrerr) {
  382. case YES:
  383. _error(svr, "%s: %m\n", np);
  384. break;
  385. case NO:
  386. (void)write(svr->outfd, "", 1);
  387. break;
  388. case DISPLAYED:
  389. break;
  390. }
  391. }
  392. screwup:
  393. _error(svr, "protocol screwup: %s\n", why);
  394. end_server:
  395. if (buf)
  396. free(buf);
  397. if (namebuf)
  398. free(namebuf);
  399. return;
  400. }
  401. int pcp_server(struct pcp_server *svr)
  402. {
  403. BUF buffer;
  404. memset (&buffer, 0, sizeof (buffer));
  405. /* If reverse copy, outfile is always a directory. */
  406. _sink (svr, svr->outfile, &buffer);
  407. if (buffer.buf)
  408. free (buffer.buf);
  409. return 0;
  410. }