コード例 #1
0
ファイル: copyfd.c プロジェクト: Nusince/TWRP2
void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size)
{
	off_t sz = bb_copyfd_size(fd1, fd2, size);
	if (sz == size)
		return;
	if (sz != -1)
		bb_error_msg_and_die("short read");
	/* if sz == -1, bb_copyfd_XX already complained */
	xfunc_die();
}
コード例 #2
0
static int ftp_recieve(ftp_host_info_t *server, FILE *control_stream,
		const char *local_path, char *server_path)
{
	char buf[512];
	off_t filesize = 0;
	int fd_data;
	int fd_local = -1;
	off_t beg_range = 0;

	/* Connect to the data socket */
	if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
		bb_error_msg_and_die("PASV error: %s", buf + 4);
	}
	fd_data = xconnect_ftpdata(server, buf);

	if (ftpcmd("SIZE ", server_path, control_stream, buf) == 213) {
		unsigned long value=filesize;
		if (safe_strtoul(buf + 4, &value))
			bb_error_msg_and_die("SIZE error: %s", buf + 4);
		filesize = value;
	}

	if ((local_path[0] == '-') && (local_path[1] == '\0')) {
		fd_local = STDOUT_FILENO;
		do_continue = 0;
	}

	if (do_continue) {
		struct stat sbuf;
		if (lstat(local_path, &sbuf) < 0) {
			bb_perror_msg_and_die("fstat()");
		}
		if (sbuf.st_size > 0) {
			beg_range = sbuf.st_size;
		} else {
			do_continue = 0;
		}
	}

	if (do_continue) {
		sprintf(buf, "REST %ld", (long)beg_range);
		if (ftpcmd(buf, NULL, control_stream, buf) != 350) {
			do_continue = 0;
		} else {
			filesize -= beg_range;
		}
	}

	if (ftpcmd("RETR ", server_path, control_stream, buf) > 150) {
		bb_error_msg_and_die("RETR error: %s", buf + 4);
	}

	/* only make a local file if we know that one exists on the remote server */
	if (fd_local == -1) {
		if (do_continue) {
			fd_local = bb_xopen(local_path, O_APPEND | O_WRONLY);
		} else {
			fd_local = bb_xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY);
		}
	}

	/* Copy the file */
	if (bb_copyfd_size(fd_data, fd_local, filesize) == -1) {
		exit(EXIT_FAILURE);
	}

	/* close it all down */
	close(fd_data);
	if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
		bb_error_msg_and_die("ftp error: %s", buf + 4);
	}
	ftpcmd("QUIT", NULL, control_stream, buf);

	return(EXIT_SUCCESS);
}
コード例 #3
0
void data_extract_all(archive_handle_t *archive_handle)
{
	file_header_t *file_header = archive_handle->file_header;
	int dst_fd;
	int res;

	if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) {
		char *name = bb_xstrdup(file_header->name);
		bb_make_directory (dirname(name), -1, FILEUTILS_RECUR);
		free(name);
	}

	/* Check if the file already exists */
	if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
		/* Remove the existing entry if it exists */
		if (((file_header->mode & S_IFMT) != S_IFDIR) && (unlink(file_header->name) == -1) && (errno != ENOENT)) {
			bb_perror_msg_and_die("Couldnt remove old file");
		}
	}
	else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) {
		/* Remove the existing entry if its older than the extracted entry */
		struct stat statbuf;
		if (lstat(file_header->name, &statbuf) == -1) {
			if (errno != ENOENT) {
				bb_perror_msg_and_die("Couldnt stat old file");
			}
		}
		else if (statbuf.st_mtime <= file_header->mtime) {
			if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
				bb_error_msg("%s not created: newer or same age file exists", file_header->name);
			}
			data_skip(archive_handle);
			return;
		}
		else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
			bb_perror_msg_and_die("Couldnt remove old file %s", file_header->name);
		}
	}

	/* Handle hard links separately
	 * We identified hard links as regular files of size 0 with a symlink */
	if (S_ISREG(file_header->mode) && (file_header->link_name) && (file_header->size == 0)) {
		/* hard link */
		res = link(file_header->link_name, file_header->name);
		if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
			bb_perror_msg("Couldnt create hard link");
		}
	} else {
		/* Create the filesystem entry */
		switch(file_header->mode & S_IFMT) {
			case S_IFREG: {
				/* Regular file */
				dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL);
				bb_copyfd_size(archive_handle->src_fd, dst_fd, file_header->size);
				close(dst_fd);
				break;
				}
			case S_IFDIR:
				res = mkdir(file_header->name, file_header->mode);
				if ((errno != EISDIR) && (res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
					bb_perror_msg("extract_archive: %s", file_header->name);
				}
				break;
			case S_IFLNK:
				/* Symlink */
				res = symlink(file_header->link_name, file_header->name);
				if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
					bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name);
				}
				break;
			case S_IFSOCK:
			case S_IFBLK:
			case S_IFCHR:
			case S_IFIFO:
				res = mknod(file_header->name, file_header->mode, file_header->device);
				if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
					bb_perror_msg("Cannot create node %s", file_header->name);
				}
				break;
			default:
				bb_error_msg_and_die("Unrecognised file type");
		}
	}

	if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) {
		lchown(file_header->name, file_header->uid, file_header->gid);
	}
	if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM) &&
		 (file_header->mode & S_IFMT) != S_IFLNK)
	{
		chmod(file_header->name, file_header->mode);
	}

	if (archive_handle->flags & ARCHIVE_PRESERVE_DATE && !S_ISLNK(file_header->mode)) {
		struct utimbuf t;
		t.actime = t.modtime = file_header->mtime;
		utime(file_header->name, &t);
	}
}
コード例 #4
0
ファイル: lpd.c プロジェクト: 0xD34D/android_external_busybox
int lpd_main(int argc UNUSED_PARAM, char *argv[])
{
	int spooling = spooling; // for compiler
	char *s, *queue;
	char *filenames[2];

	// goto spool directory
	if (*++argv)
		xchdir(*argv++);

	// error messages of xfuncs will be sent over network
	xdup2(STDOUT_FILENO, STDERR_FILENO);

	// nullify ctrl/data filenames
	memset(filenames, 0, sizeof(filenames));

	// read command
	s = queue = xmalloc_read_stdin();
	// we understand only "receive job" command
	if (2 != *queue) {
 unsupported_cmd:
		printf("Command %02x %s\n",
			(unsigned char)s[0], "is not supported");
		goto err_exit;
	}

	// parse command: "2 | QUEUE_NAME | '\n'"
	queue++;
	// protect against "/../" attacks
	// *strchrnul(queue, '\n') = '\0'; - redundant, sane() will do
	if (!*sane(queue))
		return EXIT_FAILURE;

	// queue is a directory -> chdir to it and enter spooling mode
	spooling = chdir(queue) + 1; // 0: cannot chdir, 1: done
	// we don't free(s), we might need "queue" var later

	while (1) {
		char *fname;
		int fd;
		// int is easier than ssize_t: can use xatoi_u,
		// and can correctly display error returns (-1)
		int expected_len, real_len;

		// signal OK
		safe_write(STDOUT_FILENO, "", 1);

		// get subcommand
		// valid s must be of form: "SUBCMD | LEN | space | FNAME"
		// N.B. we bail out on any error
		s = xmalloc_read_stdin();
		if (!s) { // (probably) EOF
			char *p, *q, var[2];

			// non-spooling mode or no spool helper specified
			if (!spooling || !*argv)
				return EXIT_SUCCESS; // the only non-error exit
			// spooling mode but we didn't see both ctrlfile & datafile
			if (spooling != 7)
				goto err_exit; // reject job

			// spooling mode and spool helper specified -> exec spool helper
			// (we exit 127 if helper cannot be executed)
			var[1] = '\0';
			// read and delete ctrlfile
			q = xmalloc_xopen_read_close(filenames[0], NULL);
			unlink(filenames[0]);
			// provide datafile name
			// we can use leaky setenv since we are about to exec or exit
			xsetenv("DATAFILE", filenames[1]);
			// parse control file by "\n"
			while ((p = strchr(q, '\n')) != NULL && isalpha(*q)) {
				*p++ = '\0';
				// q is a line of <SYM><VALUE>,
				// we are setting environment string <SYM>=<VALUE>.
				// Ignoring "l<datafile>", exporting others:
				if (*q != 'l') {
					var[0] = *q++;
					xsetenv(var, q);
				}
				q = p; // next line
			}
			// helper should not talk over network.
			// this call reopens stdio fds to "/dev/null"
			// (no daemonization is done)
			bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL);
			BB_EXECVP(*argv, argv);
			exit(127);
		}

		// validate input.
		// we understand only "control file" or "data file" cmds
		if (2 != s[0] && 3 != s[0])
			goto unsupported_cmd;
		if (spooling & (1 << (s[0]-1))) {
			printf("Duplicated subcommand\n");
			goto err_exit;
		}
		// get filename
		*strchrnul(s, '\n') = '\0';
		fname = strchr(s, ' ');
		if (!fname) {
// bad_fname:
			printf("No or bad filename\n");
			goto err_exit;
		}
		*fname++ = '\0';
//		// s[0]==2: ctrlfile, must start with 'c'
//		// s[0]==3: datafile, must start with 'd'
//		if (fname[0] != s[0] + ('c'-2))
//			goto bad_fname;
		// get length
		expected_len = bb_strtou(s + 1, NULL, 10);
		if (errno || expected_len < 0) {
			printf("Bad length\n");
			goto err_exit;
		}
		if (2 == s[0] && expected_len > 16 * 1024) {
			// SECURITY:
			// ctrlfile can't be big (we want to read it back later!)
			printf("File is too big\n");
			goto err_exit;
		}

		// open the file
		if (spooling) {
			// spooling mode: dump both files
			// job in flight has mode 0200 "only writable"
			sane(fname);
			fd = open3_or_warn(fname, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0200);
			if (fd < 0)
				goto err_exit;
			filenames[s[0] - 2] = xstrdup(fname);
		} else {
			// non-spooling mode:
			// 2: control file (ignoring), 3: data file
			fd = -1;
			if (3 == s[0])
				fd = xopen(queue, O_RDWR | O_APPEND);
		}

		// signal OK
		safe_write(STDOUT_FILENO, "", 1);

		// copy the file
		real_len = bb_copyfd_size(STDIN_FILENO, fd, expected_len);
		if (real_len != expected_len) {
			printf("Expected %d but got %d bytes\n",
				expected_len, real_len);
			goto err_exit;
		}
		// get EOF indicator, see whether it is NUL (ok)
		// (and don't trash s[0]!)
		if (safe_read(STDIN_FILENO, &s[1], 1) != 1 || s[1] != 0) {
			// don't send error msg to peer - it obviously
			// doesn't follow the protocol, so probably
			// it can't understand us either
			goto err_exit;
		}

		if (spooling) {
			// chmod completely downloaded file as "readable+writable"
			fchmod(fd, 0600);
			// accumulate dump state
			// N.B. after all files are dumped spooling should be 1+2+4==7
			spooling |= (1 << (s[0]-1)); // bit 1: ctrlfile; bit 2: datafile
		}

		free(s);
		close(fd); // NB: can do close(-1). Who cares?

		// NB: don't do "signal OK" write here, it will be done
		// at the top of the loop
	} // while (1)

 err_exit:
	// don't keep corrupted files
	if (spooling) {
#define i spooling
		for (i = 2; --i >= 0; )
			if (filenames[i])
				unlink(filenames[i]);
	}
	return EXIT_FAILURE;
}
コード例 #5
0
ファイル: ftpclient.c プロジェクト: github188/SimpleCode
static int ftp_receive(ftp_host_info_t *server, FILE *control_stream, const char *local_path, char *server_path)
{
    char buf[512];
    /* I think 'filesize' usage here is bogus. Let's see... */
    //off_t filesize = -1;
#define filesize ((off_t)-1)
    int fd_data;
    int fd_local = -1;
    off_t beg_range = 0;
    /* Connect to the data socket */
    if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
        ftp_die("PASV", buf);
    }

    fd_data = xconnect_ftpdata(server, buf);
    if (ftpcmd("SIZE", server_path, control_stream, buf) == 213) {
        //filesize = BB_STRTOOFF(buf + 4, NULL, 10);
        //if (errno || filesize < 0)
        //  ftp_die("SIZE", buf);
    } else {
        do_continue = 0;
    }

    if (LONE_DASH(local_path)) {
        fd_local = STDOUT_FILENO;
        do_continue = 0;
    }

    if (do_continue) {
        struct stat sbuf;
        if (lstat(local_path, &sbuf) < 0) {
            //bb_error_msg_and_die("lstat");
            printf("lstat error.");
            exit - 1;
        }
        if (sbuf.st_size > 0) {
            beg_range = sbuf.st_size;
        } else {
            do_continue = 0;
        }
    }

    if (do_continue) {
        sprintf(buf, "REST %""1""d", (int)beg_range);
        if (ftpcmd(buf, NULL, control_stream, buf) != 350) {
            do_continue = 0;
        } else {
            //if (filesize != -1)
            //  filesize -= beg_range;
        }
    }

    if (ftpcmd("RETR", server_path, control_stream, buf) > 150) {
        ftp_die("RETR", buf);
    }

    /* only make a local file if we know that one exists on the remote server */
    if (fd_local == -1) {
        if (do_continue) {
            fd_local = xopen(local_path, O_APPEND | O_WRONLY, 0666);
        } else {
            fd_local = xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY, 0666);
        }
    }

    /* Copy the file */
    if (filesize != -1) {
        if (bb_copyfd_size(fd_data, fd_local, filesize) == -1)
            return EXIT_FAILURE;
    } else {
        if (bb_copyfd_eof(fd_data, fd_local) == -1)
            return EXIT_FAILURE;
    }

    /* close it all down */
    close(fd_data);
    if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
        ftp_die(NULL, buf);
    }
    ftpcmd("QUIT", NULL, control_stream, buf);

    return EXIT_SUCCESS;
}
コード例 #6
0
int lpqr_main(int argc UNUSED_PARAM, char *argv[])
{
	enum {
		OPT_P           = 1 << 0, // -P queue[@host[:port]]. If no -P is given use $PRINTER, then "lp@localhost:515"
		OPT_U           = 1 << 1, // -U username

		LPR_V           = 1 << 2, // -V: be verbose
		LPR_h           = 1 << 3, // -h: want banner printed
		LPR_C           = 1 << 4, // -C class: job "class" (? supposedly printed on banner)
		LPR_J           = 1 << 5, // -J title: the job title for the banner page
		LPR_m           = 1 << 6, // -m: send mail back to user

		LPQ_SHORT_FMT   = 1 << 2, // -s: short listing format
		LPQ_DELETE      = 1 << 3, // -d: delete job(s)
		LPQ_FORCE       = 1 << 4, // -f: force waiting job(s) to be printed
	};
	char tempfile[sizeof("/tmp/lprXXXXXX")];
	const char *job_title;
	const char *printer_class = "";   // printer class, max 32 char
	const char *queue;                // name of printer queue
	const char *server = "localhost"; // server[:port] of printer queue
	char *hostname;
	// N.B. IMHO getenv("USER") can be way easily spoofed!
	const char *user = xuid2uname(getuid());
	unsigned job;
	unsigned opts;
	int fd;

	queue = getenv("PRINTER");
	if (!queue)
		queue = "lp";

	// parse options
	// TODO: set opt_complementary: s,d,f are mutually exclusive
	opts = getopt32(argv,
		(/*lp*/'r' == applet_name[2]) ? "P:U:VhC:J:m" : "P:U:sdf"
		, &queue, &user
		, &printer_class, &job_title
	);
	argv += optind;

	{
		// queue name is to the left of '@'
		char *s = strchr(queue, '@');
		if (s) {
			// server name is to the right of '@'
			*s = '\0';
			server = s + 1;
		}
	}

	// do connect
	fd = create_and_connect_stream_or_die(server, 515);

	//
	// LPQ ------------------------
	//
	if (/*lp*/'q' == applet_name[2]) {
		char cmd;
		// force printing of every job still in queue
		if (opts & LPQ_FORCE) {
			cmd = 1;
			goto command;
		// delete job(s)
		} else if (opts & LPQ_DELETE) {
			fdprintf(fd, "\x5" "%s %s", queue, user);
			while (*argv) {
				fdprintf(fd, " %s", *argv++);
			}
			bb_putchar('\n');
		// dump current jobs status
		// N.B. periodical polling should be achieved
		// via "watch -n delay lpq"
		// They say it's the UNIX-way :)
		} else {
			cmd = (opts & LPQ_SHORT_FMT) ? 3 : 4;
 command:
			fdprintf(fd, "%c" "%s\n", cmd, queue);
			bb_copyfd_eof(fd, STDOUT_FILENO);
		}

		return EXIT_SUCCESS;
	}

	//
	// LPR ------------------------
	//
	if (opts & LPR_V)
		bb_error_msg("connected to server");

	job = getpid() % 1000;
	hostname = safe_gethostname();

	// no files given on command line? -> use stdin
	if (!*argv)
		*--argv = (char *)"-";

	fdprintf(fd, "\x2" "%s\n", queue);
	get_response_or_say_and_die(fd, "setting queue");

	// process files
	do {
		unsigned cflen;
		int dfd;
		struct stat st;
		char *c;
		char *remote_filename;
		char *controlfile;

		// if data file is stdin, we need to dump it first
		if (LONE_DASH(*argv)) {
			strcpy(tempfile, "/tmp/lprXXXXXX");
			dfd = xmkstemp(tempfile);
			bb_copyfd_eof(STDIN_FILENO, dfd);
			xlseek(dfd, 0, SEEK_SET);
			*argv = (char*)bb_msg_standard_input;
		} else {
			dfd = xopen(*argv, O_RDONLY);
		}

		st.st_size = 0; /* paranoia: fstat may theoretically fail */
		fstat(dfd, &st);

		/* Apparently, some servers are buggy and won't accept 0-sized jobs.
		 * Standard lpr works around it by refusing to send such jobs:
		 */
		if (st.st_size == 0) {
			bb_error_msg("nothing to print");
			continue;
		}

		/* "The name ... should start with ASCII "cfA",
		 * followed by a three digit job number, followed
		 * by the host name which has constructed the file."
		 * We supply 'c' or 'd' as needed for control/data file. */
		remote_filename = xasprintf("fA%03u%s", job, hostname);

		// create control file
		// TODO: all lines but 2 last are constants! How we can use this fact?
		controlfile = xasprintf(
			"H" "%.32s\n" "P" "%.32s\n" /* H HOST, P USER */
			"C" "%.32s\n" /* C CLASS - printed on banner page (if L cmd is also given) */
			"J" "%.99s\n" /* J JOBNAME */
			/* "class name for banner page and job name
			 * for banner page commands must precede L command" */
			"L" "%.32s\n" /* L USER - print banner page, with given user's name */
			"M" "%.32s\n" /* M WHOM_TO_MAIL */
			"l" "d%.31s\n" /* l DATA_FILE_NAME ("dfAxxx") */
			, hostname, user
			, printer_class /* can be "" */
			, ((opts & LPR_J) ? job_title : *argv)
			, (opts & LPR_h) ? user : ""
			, (opts & LPR_m) ? user : ""
			, remote_filename
		);
		// delete possible "\nX\n" (that is, one-char) patterns
		c = controlfile;
		while ((c = strchr(c, '\n')) != NULL) {
			if (c[1] && c[2] == '\n') {
				overlapping_strcpy(c, c+2);
			} else {
				c++;
			}
		}

		// send control file
		if (opts & LPR_V)
			bb_error_msg("sending control file");
		/* "Acknowledgement processing must occur as usual
		 * after the command is sent." */
		cflen = (unsigned)strlen(controlfile);
		fdprintf(fd, "\x2" "%u c%s\n", cflen, remote_filename);
		get_response_or_say_and_die(fd, "sending control file");
		/* "Once all of the contents have
		 * been delivered, an octet of zero bits is sent as
		 * an indication that the file being sent is complete.
		 * A second level of acknowledgement processing
		 * must occur at this point." */
		full_write(fd, controlfile, cflen + 1); /* writes NUL byte too */
		get_response_or_say_and_die(fd, "sending control file");

		// send data file, with name "dfaXXX"
		if (opts & LPR_V)
			bb_error_msg("sending data file");
		fdprintf(fd, "\x3" "%"FILESIZE_FMT"u d%s\n", st.st_size, remote_filename);
		get_response_or_say_and_die(fd, "sending data file");
		if (bb_copyfd_size(dfd, fd, st.st_size) != st.st_size) {
			// We're screwed. We sent less bytes than we advertised.
			bb_error_msg_and_die("local file changed size?!");
		}
		write(fd, "", 1); // send ACK
		get_response_or_say_and_die(fd, "sending data file");

		// delete temporary file if we dumped stdin
		if (*argv == (char*)bb_msg_standard_input)
			unlink(tempfile);

		// cleanup
		close(fd);
		free(remote_filename);
		free(controlfile);

		// say job accepted
		if (opts & LPR_V)
			bb_error_msg("job accepted");

		// next, please!
		job = (job + 1) % 1000;
	} while (*++argv);

	return EXIT_SUCCESS;
}