Beispiel #1
0
/*
 * Perform file copy from source to target
 */
static int
copyfile(char *source, char *target)
{
	int fi, fo;
	int mapsize, munmapsize;
	caddr_t cp;
	off_t filesize;
	off_t offset;
	int nbytes;
	int remains;
	int n;
	struct stat s1, s2;
	fi = open(source, O_RDONLY);
	if (fi == -1) {
		Perror(source);
		return (1);
	}

	DBG_MSG3("Copying file %s to %s", source, target);
	fo = open(target, O_WRONLY|O_CREAT|O_TRUNC);
	if (fo == -1) {
		Perror(target);
		(void) close(fi);
		return (1);
	}

	if (fstat(fi, &s1) < 0) {
		Perror(source);
		(void) close(fi);
		(void) close(fo);
		return (1);
	}

	if (fstat(fo, &s2) < 0) {
		Perror(source);
		(void) close(fi);
		(void) close(fo);
		return (1);
	}

	if (s1.st_size > SMALLFILESIZE) {
		/*
		 * Determine size of initial mapping.  This will determine the
		 * size of the address space chunk we work with.  This initial
		 * mapping size will be used to perform munmap() in the future.
		 */
		mapsize = MAXMAPSIZE;
		if (s1.st_size < mapsize) mapsize = s1.st_size;
		munmapsize = mapsize;

		/*
		 * Mmap time!
		 */
		if ((cp = mmap((caddr_t)NULL, mapsize, PROT_READ,
		    MAP_SHARED, fi, (off_t)0)) == MAP_FAILED)
			mapsize = 0;   /* can't mmap today */
	} else
		mapsize = 0;

	filesize = s1.st_size;

	if (mapsize != 0) {
		offset = 0;

		for (;;) {
			nbytes = write(fo, cp, mapsize);
			/*
			 * if we write less than the mmaped size it's due to a
			 * media error on the input file or out of space on
			 * the output file.  So, try again, and look for errno.
			 */
			if ((nbytes >= 0) && (nbytes != (int)mapsize)) {
				remains = mapsize - nbytes;
				while (remains > 0) {
					nbytes = write(fo,
					    cp + mapsize - remains, remains);
					if (nbytes < 0) {
						if (errno == ENOSPC)
							Perror(target);
						else
							Perror(source);
						(void) close(fi);
						(void) close(fo);
						(void) munmap(cp, munmapsize);
						(void) unlink(target);
						return (1);
					}
					remains -= nbytes;
					if (remains == 0)
						nbytes = mapsize;
				}
			}
			/*
			 * although the write manual page doesn't specify this
			 * as a possible errno, it is set when the nfs read
			 * via the mmap'ed file is accessed, so report the
			 * problem as a source access problem, not a target file
			 * problem
			 */
			if (nbytes < 0) {
				if (errno == EACCES)
					Perror(source);
				else
					Perror(target);
				(void) close(fi);
				(void) close(fo);
				(void) munmap(cp, munmapsize);
				(void) unlink(target);
				return (1);
			}
			filesize -= nbytes;
			if (filesize == 0)
				break;
			offset += nbytes;
			if (filesize < mapsize)
				mapsize = filesize;
			if (mmap(cp, mapsize, PROT_READ, MAP_SHARED | MAP_FIXED,
			    fi, offset) == MAP_FAILED) {
				Perror(source);
				(void) close(fi);
				(void) close(fo);
				(void) munmap(cp, munmapsize);
				(void) unlink(target);
				return (1);
			}
		}
		(void) munmap(cp, munmapsize);
	} else {
		char buf[SMALLFILESIZE];
		for (;;) {
			n = read(fi, buf, sizeof (buf));
			if (n == 0) {
				return (0);
			} else if (n < 0) {
				Perror(source);
				(void) close(fi);
				(void) close(fo);
				(void) unlink(target);
				return (1);
			} else if (write(fo, buf, n) != n) {
				Perror(target);
				(void) close(fi);
				(void) close(fo);
				(void) unlink(target);
				return (1);
			}
		}
	}
	return (0);
}
Beispiel #2
0
/*
 * Main function for doing the copying of bits
 */
int
TM_perform_transfer(nvlist_t *targs, void(*prog)(int))
{
	char *logfile = NULL, *buf = NULL, *cprefix;
	char *buf1 = NULL, *layout = NULL, *dbg;
	FILE *cpipe = NULL, *kbd_file;
	float ipercent, rem_percent, cpfiles;
	float calc_factor;
	int kbd = -1, kbd_layout;
	int rv = 0, i;
	struct file_list flist, *cflist;
	clock_t tm;
	struct stat st;
	char zerolist[PATH_MAX];

	if (pthread_mutex_lock(&tran_mutex) != 0) {
		Perror("Unable to acquire Transfer lock ");
		return (1);
	}

	if (nvlist_lookup_string(targs, "mountpoint", &mntpt) != 0) {
		Perror("Alternate root mountpoint not provided. Bailing. ");
		return (1);
	}

	if (prog == NULL) {
		progress = log_progress;
	} else {
		progress = prog;
	}

	logfile = malloc(PATH_MAX);
	if (logfile == NULL) {
		Perror("Malloc failed ");
		return (1);
	}

	(void) snprintf(logfile, PATH_MAX, "%s/%s", mntpt,
	    TM_LOGFILE_NAME);

	lof = fopen(logfile, "w+");
	if (lof == NULL) {
		Perror("Unable to open logfile ");
		goto error_done;
	}

	buf = malloc(BUF_SIZE);
	if (buf == NULL) {
		Perror("Malloc failed ");
		goto error_done;
	}

	buf1 = malloc(BUF_SIZE);
	if (buf1 == NULL) {
		Perror("Malloc failed ");
		goto error_done;
	}

	dbg = getenv("TM_DEBUG");
	if (dbg != NULL && strcmp(dbg, "1") == 0) {
		TM_enable_debug();
	}

	/*
	 * Set TMPDIR to avoid cpio depleting ramdisk space
	 */
	if (putenv(tmpenv) != 0) {
		Perror(tmpenv);
		goto error_done;
	}

	/*
	 * Zero length file list.
	 */
	(void) strlcpy(zerolist, mntpt, PATH_MAX);
	(void) strlcat(zerolist, "/flist.0length", PATH_MAX);
	if ((zerolength = fopen(zerolist, "w+")) == NULL) {
		Perror(zerolist);
		goto error_done;
	}

	tm = time(NULL);
	(void) strftime(buf, PATH_MAX, (char *)0, localtime(&tm));
	INFO_MSG2("-- Starting transfer process, %s --", buf);
	(void) chdir("/");
	CHECK_ABORT;

	(*progress)(0);
	percent = 0;
	opercent = 0;
	total_find_percent = (NUM_PREFIXES - 1) * FIND_PERCENT;

	/*
	 * Get the optimized libc overlay out of the way.
	 */
	if (umount("/lib/libc.so.1") != 0) {
		if (errno != EINVAL) {
			Perror("Can't unmount /lib/libc.so.1 ");
			goto error_done;
		}
	}
	CHECK_ABORT;
	INFO_MSG1("Building file lists for cpio");

	/*
	 * Do a file tree walk of all the mountpoints provided and
	 * build up pathname lists. Pathname lists of all mountpoints
	 * under the same prefix are aggregated in the same file to
	 * reduce the number of cpio invocations.
	 *
	 * This loop builds a linked list where each entry points to
	 * a file containing a pathname list and mentions other info
	 * like the mountpoint from which to copy etc.
	 */
	cprefix = "";
	flist.next = NULL;
	cflist = &flist;
	for (i = 0; cpio_prefixes[i].chdir_prefix != NULL; i++) {
		char *patt;
		regex_t re;

		CHECK_ABORT;
		DBG_MSG3("Cpio dir: %s, Chdir to: %s",
		    cpio_prefixes[i].cpio_dir,
		    cpio_prefixes[i].chdir_prefix);
		patt = cpio_prefixes[i].match_pattern;
		if (strcmp(cprefix,
		    cpio_prefixes[i].chdir_prefix) != 0 ||
		    patt != NULL ||
		    cpio_prefixes[i].clobber_files == 1 ||
		    cpio_prefixes[i].cpio_args != NULL) {

			cprefix = cpio_prefixes[i].chdir_prefix;
			cflist->next = (struct file_list *)
			    malloc(sizeof (struct file_list));
			cflist = cflist->next;
			cflist->next = NULL;
			(void) snprintf(cflist->name, PATH_MAX, "%s/flist%d",
			    mntpt, i);
			DBG_MSG2(" File list tempfile: %s", cflist->name);

			cflist->handle = fopen(cflist->name, "w+");
			if (cflist->handle == NULL) {
				Perror("Unable to open file list ");
				goto error_done;
			}

			cflist->chdir_prefix =
			    cpio_prefixes[i].chdir_prefix;
			if (patt != NULL) {
				DBG_MSG2(" Compiling regexp: %s", patt);
				if (patt[0] == '!') {
					negate = 1;
					patt++;
				} else {
					negate = 0;
				}
				if (regcomp(&re, patt,
				    REG_EXTENDED|REG_NOSUB) != 0) {
					Perror("Regexp error ");
					goto error_done;
				}
				mre = &re;
			} else {
				mre = NULL;
			}

			listfile = cflist->handle;
			cflist->clobber_files =
			    cpio_prefixes[i].clobber_files;
			if (cpio_prefixes[i].cpio_args != NULL) {
				cflist->cpio_args =
				    cpio_prefixes[i].cpio_args;
			} else {
				cflist->cpio_args = DEFAULT_CPIO_ARGS;
			}
		}

		INFO_MSG3("Scanning %s/%s", cflist->chdir_prefix,
		    cpio_prefixes[i].cpio_dir);
		(void) chdir(cflist->chdir_prefix);
		if (nftw(cpio_prefixes[i].cpio_dir, add_files, 10,
		    FTW_MOUNT|FTW_PHYS) < 0) {
			Perror("Nftw failed ");
			goto error_done;
		}
		(void) fflush(cflist->handle);
	}
	(void) fflush(zerolength);

	/*
	 * Now process each entry in the list. cpio is executed with the
	 * -V option where it prints a dot for each pathname processed.
	 * Since we already know the number of files we can show accurate
	 * percentage completion.
	 */
	INFO_MSG1("Beginning cpio actions ...");

	rem_percent = 95 - percent;
	ipercent = percent;
	cflist = flist.next;
	cpfiles = 0;
	opercent = 0;
	percent = 0;
	calc_factor = rem_percent / nfiles;
	while (cflist != NULL) {
		(void) fclose(cflist->handle);
		cflist->handle = NULL;
		CHECK_ABORT;
		if (cflist->clobber_files) {
			if (do_clobber_files(cflist->name) != 0) {
				goto error_done;
			}
		}

		(void) chdir(cflist->chdir_prefix);
		(void) snprintf(buf, PATH_MAX, "%s -%sV %s < %s",
		    CPIO, cflist->cpio_args, mntpt, cflist->name);
		DBG_MSG3("Executing: %s, CWD: %s", buf,
		    cflist->chdir_prefix);

		cpipe = popen(buf, "r");
		if (cpipe == NULL) {
			Perror("Unable to cpio files ");
			goto error_done;
		}

		while (!feof(cpipe)) {
			int ch = fgetc(cpipe);
			if (ch == '.') {
				cpfiles++;
				percent = (int)(cpfiles * calc_factor +
				    ipercent);
				if (percent - opercent >= 1) {
					if (progress != NULL) {
						(*progress)(percent);
					}
					opercent = percent;
				}
			}
			CHECK_ABORT;
		}
		if (ferror(cpipe)) {
			Perror(CPIO);
			goto error_done;
		}

		(void) fclose(cpipe);
		cpipe = NULL;

		(void) unlink(cflist->name);
		cflist->name[0] = '\0';
		cflist = cflist->next;
	}
	(*progress)(percent);
	cpipe = NULL;

	/*
	 * Process zero-length files if any.
	 */
	INFO_MSG1("Creating zero-length files");
	rewind(zerolength);
	while (fgets(buf, BUF_SIZE, zerolength) != NULL) {
		int fd;
		mode_t mod;
		uid_t st_uid, st_gid;
		char *token, *lasts;

		/* Get the newline out of the way */
		buf[strlen(buf) - 1] = '\0';

		/* Parse out ownership and perms */
		GET_TOKEN(token, lasts, buf, ",");
		mod = atoi(token);
		GET_TOKEN(token, lasts, NULL, ",");
		st_uid = atoi(token);
		GET_TOKEN(token, lasts, NULL, ",");
		st_gid = atoi(token);

		GET_TOKEN(token, lasts, NULL, ",");
		(void) snprintf(buf1, PATH_MAX, "%s/%s", mntpt, token);

		fd = open(buf1, O_WRONLY | O_CREAT | O_TRUNC, mod);
		if (fd != -1) {
			(void) fchown(fd, st_uid, st_gid);
			(void) close(fd);
			DBG_MSG2("Created file %s", buf1);
		} else {
			INFO_MSG1("Unable to create file:");
			Perror(buf1);
		}
	}
	(*progress)(97);

	CHECK_ABORT;
	INFO_MSG1("Extracting archive");
	(void) chdir(mntpt);
	(void) snprintf(buf, PATH_MAX, "%s e -so %s | %s -idum",
	    SZIP, ARCHIVE, CPIO);
	DBG_MSG3("Executing: %s, CWD: %s", buf, mntpt);
	if (system(buf) != 0) {
		Perror("Extracting archive failed ");
		goto error_done;
	}
	(*progress)(98);
	CHECK_ABORT;

	/*
	 * Check for the presence of skeleton.cpio before extracting it.
	 * This file may not be present in a Distro Constructor image.
	 */
	if (lstat(SKELETON, &st) == 0 && (S_ISREG(st.st_mode) ||
	    S_ISLNK(st.st_mode))) {
		INFO_MSG1("Extracting skeleton archive");
		(void) snprintf(buf, PATH_MAX, "%s -imu < %s", CPIO,
		    SKELETON, mntpt);
		DBG_MSG3("Executing: %s, CWD: %s", buf, mntpt);
		if (system(buf) != 0) {
			Perror("Skeleton cpio failed ");
			goto error_done;
		}
	}
	(*progress)(99);

	CHECK_ABORT;
	INFO_MSG1("Performing file operations");
	for (i = 0; i < NUM_FILEOPS_LIST; i++) {
		int rv;

		CHECK_ABORT;
		expand_symbols(fileops_list[i].src, buf, PATH_MAX);

		switch (fileops_list[i].op) {
			int op;

		case FILE_OP_UNLINK:
			DBG_MSG2("Unlink: %s", buf);
			(void) unlink(buf);
			rv = 0; /* unlink errors are non-fatal */
			break;

		case FILE_OP_RMDIR:
			DBG_MSG2("Rmdir: %s", buf);
			(void) rmdir(buf);
			rv = 0; /* Ignore rmdir errors for now */
			break;

		case FILE_OP_MKDIR:

			DBG_MSG2("Mkdir: %s", buf);
			rv = 0;
			if (lstat(buf, &st) == 0) {
				op = 0;
				if ((st.st_mode & S_IFMT)
				    != S_IFDIR) {
					rv = unlink(buf);
					op = 1;
				}
				if (rv == 0 && op) {
					rv = mkdir(buf,
					    fileops_list[i].perms);
				}
			} else {
				rv = mkdir(buf,
				    fileops_list[i].perms);
			}
			break;

		case FILE_OP_COPY:
			expand_symbols(fileops_list[i].dst, buf1,
			    PATH_MAX);
			rv = copyfile(buf, buf1);
			break;
		case FILE_OP_CHMOD:
			expand_symbols(fileops_list[i].dst, buf1,
			    PATH_MAX);
			rv = chmod(buf, fileops_list[i].perms);
			break;
		default:
			Perror("Unsupported file operation ");
			rv = 1;
			break;
		}
		if (rv != 0) {
			Perror("File ops error ");
			Perror(buf);
			goto error_done;
		}
	}

	CHECK_ABORT;
	INFO_MSG1("Fetching and updating keyboard layout");
	(void) chdir(mntpt);

	DBG_MSG2("Opening keyboard device: %s", KBD_DEVICE);
	kbd = open(KBD_DEVICE, O_RDWR);
	if (kbd < 0) {
		Perror("Error opening keyboard");
		goto error_done;
	}

	if (ioctl(kbd, KIOCLAYOUT, &kbd_layout)) {
		Perror("ioctl keyboard layout");
		goto error_done;
	}

	CHECK_ABORT;
	if ((layout = get_layout_name(kbd_layout)) == NULL) {
		goto error_done;
	}

	kbd_file = fopen(KBD_DEFAULTS_FILE, "a+");
	if (kbd_file == NULL) {
		Perror("Unable to open kbd defaults file ");
		goto error_done;
	}

	(void) fprintf(kbd_file, "LAYOUT=%s\n", layout);
	(void) fclose(kbd_file);
	DBG_MSG3("Updated keyboard defaults file: %s/%s", mntpt,
	    KBD_DEFAULTS_FILE);

	INFO_MSG2("Detected %s keyboard layout", layout);
	tm = time(NULL);
	(void) strftime(buf, PATH_MAX, (char *)0, localtime(&tm));
	INFO_MSG2("-- Completed transfer process, %s --", buf);

	(*progress)(100);

	goto done;
error_done:
	rv = 1;

done:
	if (lof != NULL)
		(void) fclose(lof);

	if (cpipe != NULL)
		(void) fclose(cpipe);

	free_flist(flist.next);

	if (logfile != NULL)
		free(logfile);

	if (kbd > 0)
		(void) close(kbd);

	if (buf != NULL)
		free(buf);

	if (buf1 != NULL)
		free(buf1);

	if (layout != NULL)
		free(layout);

	if (zerolength != NULL) {
		(void) fclose(zerolength);
		(void) unlink(zerolist);
	}

	do_abort = 0;
	(void) pthread_mutex_unlock(&tran_mutex);

	return (rv);
}
Beispiel #3
0
/* Main routine for the server threads */
thr_startfunc_t serve_pipe(void *data)
{
	char sio_buf[BUFSIZ], sock_buf[BUFSIZ];
	int fd_max, sio_fd, sock_fd;
	int sio_count, sock_count;
	int res, port;
	fd_set rfds, wfds;
	pipe_s *pipe = (pipe_s *)data;
#if defined(__UNIX__)
	struct timeval tv = {pipe->timeout, 0};
	struct timeval *ptv = &tv;
#elif defined(__WIN32__)
	struct timeval tv = {0,10000};
	struct timeval *ptv = &tv;
	DWORD msecs = 0, timeout = pipe->timeout * 1000;
#endif

	port = pipe->sio.info.port;

	/* Only proceed if we can lock the mutex */
	if (thr_mutex_trylock(pipe->mutex))
	{
		error("server(%d) - resource is locked", port);
	}
	else
	{

		sio_count = 0;
		sock_count = 0;
		sio_fd = pipe->sio.fd;
		sock_fd = pipe->sock.fd;
#if defined(__UNIX__)
		fd_max = sio_fd > sock_fd ? sio_fd : sock_fd;	
#elif defined(__WIN32__)
		fd_max = sock_fd;
		msecs = GetTickCount();
#endif
		fprintf(stderr, "server(%d) - thread started\n", port);
		
		while (1)
		{
			FD_ZERO(&rfds);
			FD_ZERO(&wfds);

#if defined(__UNIX__)
			/* Always ask for read notification to check for EOF */			
			FD_SET(sio_fd, &rfds);
			/* Only ask for write notification if we have something to write */
			if (sock_count > 0)
				FD_SET(sio_fd, &wfds);

			/* Reset timeout values */
			tv.tv_sec = pipe->timeout;
			tv.tv_usec = 0;

#endif
			/* Always ask for read notification to check for EOF */
			FD_SET(sock_fd, &rfds);
			/* Only ask for write notification if we have something to write */
			if (sio_count > 0)
				FD_SET(sock_fd, &wfds);

			//DBG_MSG2("server(%d) waiting for events", port);
			
			/* Wait for read/write events */
			res = select(fd_max + 1, &rfds, &wfds, NULL, ptv);
			if (res == -1)
			{
				perror2("server(%d) - select()", port);
				break;
			}
#if defined(__UNIX__)

			/* Use the select result for timeout detection */
			if (res == 0)
			{
				fprintf(stderr, "server(%d) - timed out\n", port);
				break;
			}

			/* Input from serial port? */
			if (FD_ISSET(sio_fd, &rfds))
#elif defined(__WIN32__)
				
			if (1)
#endif
			{
				/* Only read input if buffer is empty */
				if (sio_count == 0)
				{
					sio_count = sio_read(&pipe->sio, sio_buf, sizeof(sio_buf));
					if (sio_count <= 0)
					{
						if (sio_count == 0)
						{
#if defined(__UNIX__)
							fprintf(stderr, "server(%d) - EOF from sio\n", port);
							break;
#endif
						}
						else
						{
							perror2("server(%d) - read(sio)", port);
							break;
						}
					}
					else 
					{
						DBG_MSG3("server(%d) - read %d bytes from sio", port, sio_count);
					}
				}
			}

			/* Write to socket possible? */
			if (FD_ISSET(sock_fd, &wfds))
			{
				if (sio_count > 0)
				{
					if ((res = tcp_write(&pipe->sock, sio_buf, sio_count)) < 0)
					{
						perror2("server(%d) - write(sock)", port);
						break;
					}
					DBG_MSG3("server(%d) - Wrote %d bytes to sock", port, res);
					sio_count -= res;
				}
			}


			/* Input from socket? */
			if (FD_ISSET(sock_fd, &rfds))
			{
				/* Only read input if buffer is empty */
				if (sock_count == 0)
				{
					sock_count = tcp_read(&pipe->sock, sock_buf, sizeof(sock_buf));
					if (sock_count <= 0)
					{
						if (sock_count == 0)
						{
							fprintf(stderr, "server(%d) - EOF from sock\n", port);
							break;
						}
						else
						{
							perror2("server(%d) - read(sock)", port);
							break;
						}
					}
					DBG_MSG3("server(%d) - read %d bytes from sock", port, sock_count);
				}
			}

#if defined(__UNIX__)
			/* Write to serial port possible? */
			if (FD_ISSET(sio_fd, &wfds))
#elif defined(__WIN32__)
			
			/* No socket IO performed? */
			if ((!FD_ISSET(sock_fd, &rfds)) && (!FD_ISSET(sock_fd, &wfds)))
			{
				/* Break on a time out */
				if (GetTickCount() - msecs > timeout)
				{
					fprintf(stderr, "server(%d) - timed out\n", port);
					break;					
				}
			}
			else
			{
				msecs = GetTickCount();
			}

			if (1)
#endif
			{
				if (sock_count > 0)
				{
					if ((res = sio_write(&pipe->sio, sock_buf, sock_count)) < 0)
					{
						perror2("server(%d) - write(sio)", port);
						break;
					}
					DBG_MSG3("server(%d) - wrote %d bytes to sio", port, res);
					sock_count -= res;
				}
			}

		}
		
		/* Unlock our mutex */
		thr_mutex_unlock(pipe->mutex);		
	}

   	fprintf(stderr, "server(%d) exiting\n", port);

	/* Clean up - don't call pipe_cleanup() as that would nuke our mutex */
	sio_cleanup(&pipe->sio);
	tcp_cleanup(&pipe->sock);


	free(pipe);
	
	thr_exit((thr_exitcode_t)0);

	return (thr_exitcode_t)0;
}