예제 #1
0
파일: test.c 프로젝트: albedium/liblist
END_TEST


START_TEST ( llist_07_test_stack )
{
    int retval;
    llist listToTest = NULL;
    llist_node retptr;
    listToTest = llist_create ( NULL, NULL, test_mt ? MT_SUPPORT_FALSE : MT_SUPPORT_TRUE );

    // Push 1000 nodes
    for ( unsigned long i = 0; i < 1000; i ++ )
    {
        retval = llist_push ( listToTest, ( llist_node ) i );
        ck_assert_int_eq ( retval, LLIST_SUCCESS );
    }

    // Peek at the head
    retptr = llist_peek ( listToTest );
    ck_assert_int_eq ( ( unsigned long ) retptr, 999 );
    for ( unsigned long i = 999; i > 0; i-- )
    {
        retptr = llist_pop ( listToTest );
        ck_assert_int_eq ( ( unsigned long ) retptr, i );
    }

    printf ( "Count = %d\n", llist_size ( listToTest ) );
    retptr = llist_pop ( listToTest );
    ck_assert_ptr_eq ( retptr, NULL );

    llist_destroy ( listToTest, false, NULL );
}
예제 #2
0
static void del_line_matching(const char *login, const char *filename)
{
	char *line;
	FILE *passwd;
	int len = strlen(login);
	int found = 0;
	llist_t *plist = NULL;

	passwd = fopen_or_warn(filename, "r");
	if (!passwd) return;

	while ((line = xmalloc_fgets(passwd))) {
		if (!strncmp(line, login, len)
		 && line[len] == ':'
		) {
			found++;
			free(line);
		} else {
			llist_add_to_end(&plist, line);
		}
	}

	if (!ENABLE_FEATURE_CLEAN_UP) {
		if (!found) {
			bb_error_msg("can't find '%s' in '%s'", login, filename);
			return;
		}
		passwd = fopen_or_warn(filename, "w");
		if (passwd)
			while ((line = llist_pop(&plist)))
				fputs(line, passwd);
	} else {
		if (!found) {
			bb_error_msg("can't find '%s' in '%s'", login, filename);
			goto clean_up;
		}
		fclose(passwd);
		passwd = fopen_or_warn(filename, "w");
		if (passwd) {
 clean_up:
			while ((line = llist_pop(&plist))) {
				if (found) fputs(line, passwd);
				free(line);
			}
			fclose(passwd);
		}
	}
}
예제 #3
0
static int write_ar_header(archive_handle_t *handle)
{
    char *fn;
    char fn_h[17]; /* 15 + "/" + NUL */
    struct stat st;
    int fd;

    fn = llist_pop(&handle->accept);
    if (!fn)
        return -1;

    xstat(fn, &st);

    handle->file_header->mtime = st.st_mtime;
    handle->file_header->uid = st.st_uid;
    handle->file_header->gid = st.st_gid;
    handle->file_header->mode = st.st_mode;
    handle->file_header->size = st.st_size;
    handle->file_header->name = fn_h;
//TODO: if ENABLE_FEATURE_AR_LONG_FILENAMES...
    sprintf(fn_h, "%.15s/", bb_basename(fn));

    output_ar_header(handle);

    fd = xopen(fn, O_RDONLY);
    bb_copyfd_exact_size(fd, handle->src_fd, st.st_size);
    close(fd);
    handle->offset += st.st_size;

    return 0;
}
예제 #4
0
status_t
connection_cmd_writer (connection_t * connection)
{
  status_t status = ST_SUCCESS;
  msg_t msg;
  
  memset (&msg, 0, sizeof (msg));
  
  for (;;)
    {
      status = llist_pop (&connection->cmd_out, &msg);
      if (ST_SUCCESS != status)
	break;
      status = msg_send (connection->cmd_fd, &msg);
      MR_FREE_RECURSIVELY (msg_t, &msg);
      
      pthread_mutex_lock (&connection->mutex);
      if (0 == --connection->ref_count)
	pthread_cond_broadcast (&connection->cond);
      pthread_mutex_unlock (&connection->mutex);
      
      if (ST_SUCCESS != status)
	break;
    }

  return (status);
}
예제 #5
0
/* Recursively free all elements in the linked list.  If freeit != NULL
 * call it on each datum in the list */
void FAST_FUNC llist_free(llist_t *elm, void (*freeit)(void *data))
{
	while (elm) {
		void *data = llist_pop(&elm);

		if (freeit)
			freeit(data);
	}
}
예제 #6
0
파일: main.c 프로젝트: jgraef/meinOS
static int cdrom_destroy() {
  struct cdrom_device *dev;
  while ((dev = llist_pop(cdrom_devices))) {
    devfs_removedev(dev->devfs);
    cdrom_device_destroy(dev);
  }
  llist_destroy(cdrom_devices);
  return 0;
}
예제 #7
0
void   clear_pending_recv(socket_t sw)
{
    if((sw)->clear_pending_io)
    {
        lnode *tmp;
        while((tmp = llist_pop(&sw->pending_recv))!=NULL)
            sw->clear_pending_io((st_io*)tmp);
    }
}
예제 #8
0
파일: socket.c 프로젝트: grasswin/KendyNet
void   clear_pending_send(socket_t sw)
{
    if(destroy_stio)
    {
        lnode *tmp;
        while((tmp = llist_pop(&sw->pending_send))!=NULL)
            destroy_stio((st_io*)tmp);
    }
}
예제 #9
0
static void add_user_to_group(char **args,
		const char *path,
		FILE *(*fopen_func)(const char *fileName, const char *mode))
{
	char *line;
	int len = strlen(args[1]);
	llist_t *plist = NULL;
	FILE *group_file;

	group_file = fopen_func(path, "r");

	if (!group_file) return;

	while ((line = xmalloc_fgetline(group_file)) != NULL) {
		/* Find the group */
		if (!strncmp(line, args[1], len)
		 && line[len] == ':'
		) {
			/* Add the new user */
			line = xasprintf("%s%s%s", line,
						last_char_is(line, ':') ? "" : ",",
						args[0]);
		}
		llist_add_to_end(&plist, line);
	}

	if (ENABLE_FEATURE_CLEAN_UP) {
		fclose(group_file);
		group_file = fopen_func(path, "w");
		while ((line = llist_pop(&plist))) {
			if (group_file)
				fprintf(group_file, "%s\n", line);
			free(line);
		}
		if (group_file)
			fclose(group_file);
	} else {
		group_file = fopen_func(path, "w");
		if (group_file)
			while ((line = llist_pop(&plist)))
				fprintf(group_file, "%s\n", line);
	}
}
예제 #10
0
static void flush_append(char *last_puts_char, char last_gets_char)
{
	char *data;

	/* Output appended lines. */
	while ((data = (char *)llist_pop(&G.append_head))) {
		puts_maybe_newline(data, G.nonstdout, last_puts_char, last_gets_char);
		free(data);
	}
}
예제 #11
0
파일: sed.c 프로젝트: pgavin/or1k-busybox
static void flush_append(void)
{
	char *data;

	/* Output appended lines. */
	while ((data = (char *)llist_pop(&G.append_head))) {
		fprintf(G.nonstdout, "%s\n", data);
		free(data);
	}
}
예제 #12
0
int env_main(int argc UNUSED_PARAM, char **argv)
{
	char **ep;
	unsigned opt;
	llist_t *unset_env = NULL;

	opt_complementary = "u::";
#if ENABLE_FEATURE_ENV_LONG_OPTIONS
	applet_long_options = env_longopts;
#endif
	opt = getopt32(argv, "+iu:", &unset_env);
	argv += optind;
	if (*argv && LONE_DASH(argv[0])) {
		opt |= 1;
		++argv;
	}
	if (opt & 1) {
		clearenv();
	}
	while (unset_env) {
		char *var = llist_pop(&unset_env);
		/* This does not handle -uVAR=VAL
		 * (coreutils _sets_ the variable in that case): */
		/*unsetenv(var);*/
		/* This does, but uses somewhan undocumented feature that
		 * putenv("name_without_equal_sign") unsets the variable: */
		putenv(var);
	}

	while (*argv && (strchr(*argv, '=') != NULL)) {
		if (putenv(*argv) < 0) {
			bb_perror_msg_and_die("putenv");
		}
		++argv;
	}

	if (*argv) {
		BB_EXECVP(*argv, argv);
		/* SUSv3-mandated exit codes. */
		xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
		bb_simple_perror_msg_and_die(*argv);
	}

	for (ep = environ; *ep; ep++) {
		puts(*ep);
	}

	fflush_stdout_and_exit(EXIT_SUCCESS);
}
예제 #13
0
파일: main.c 프로젝트: jgraef/meinOS
static int cdrom_init() {
  if (cdrom_buf_init()==-1) return -1;
  devfs_init();
  cdrom_devices = llist_create();

  llist_t list = rpc_list();
  char *name;
  while ((name = llist_pop(list))) {
    if (strncmp(name,"scsi_request_atapi",18)==0) {
      char *dev = name+13; // dev = "atapiXX"
      if (cdrom_device_init(dev)==-1) fprintf(stderr,"Could not initialize ATAPI device %s\n",dev);
    }
    free(name);
  }
  llist_destroy(list);

  return 0;
}
예제 #14
0
파일: sed.c 프로젝트: rehsack/busybox
static void flush_append(char *last_puts_char)
{
	char *data;

	/* Output appended lines. */
	while ((data = (char *)llist_pop(&G.append_head)) != NULL) {
		/* Append command does not respect "nonterminated-ness"
		 * of last line. Try this:
		 * $ echo -n "woot" | sed -e '/woot/a woo' -
		 * woot
		 * woo
		 * (both lines are terminated with \n)
		 * Therefore we do not propagate "last_gets_char" here,
		 * pass '\n' instead:
		 */
		puts_maybe_newline(data, G.nonstdout, last_puts_char, '\n');
		free(data);
	}
}
예제 #15
0
static llist_t *append_file_list_to_list(llist_t *list)
{
	FILE *src_stream;
	char *line;
	llist_t *newlist = NULL;

	while (list) {
		src_stream = xfopen_for_read(llist_pop(&list));
		while ((line = xmalloc_fgetline(src_stream)) != NULL) {
			/* kill trailing '/' unless the string is just "/" */
			char *cp = last_char_is(line, '/');
			if (cp > line)
				*cp = '\0';
			llist_add_to(&newlist, line);
		}
		fclose(src_stream);
	}
	return newlist;
}
예제 #16
0
파일: which.c 프로젝트: 0x6e3078/toybox
static int which_in_path(char *filename)
{
  struct string_list *list;

  // If they gave us a path, don't worry about $PATH or -a

  if (strchr(filename, '/')) {
    // Confirm it has the executable bit set, and it's not a directory.
    if (!access(filename, X_OK)) {
      struct stat st;

      if (!stat(filename, &st) && S_ISREG(st.st_mode)) {
        puts(filename);
        return 0;
      }
      return 1;
    }
  }

  // Search $PATH for matches.
  list = find_in_path(getenv("PATH"), filename);
  if (!list) return 1;

  // Print out matches
  while (list) {
    if (!access(list->str, X_OK)) {
      puts(list->str);
      // If we should stop at one match, do so
      if (!toys.optflags) {
        llist_traverse(list, free);
        break;
      }
    }
    free(llist_pop(&list));
  }

  return 0;
}
예제 #17
0
int sort_main(int argc UNUSED_PARAM, char **argv)
{
	FILE *fp, *outfile = stdout;
	char *line, **lines = NULL;
	char *str_ignored, *str_o, *str_t;
	llist_t *lst_k = NULL;
	int i, flag;
	int linecount = 0;

	xfunc_error_retval = 2;

	/* Parse command line options */
	/* -o and -t can be given at most once */
	opt_complementary = "o--o:t--t:" /* -t, -o: maximum one of each */
			"k::"; /* -k takes list */
	getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
#if ENABLE_FEATURE_SORT_BIG
	if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o);
	if (option_mask32 & FLAG_t) {
		if (!str_t[0] || str_t[1])
			bb_error_msg_and_die("bad -t parameter");
		key_separator = str_t[0];
	}
	/* parse sort key */
	while (lst_k) {
		enum {
			FLAG_allowed_for_k =
				FLAG_n | /* Numeric sort */
				FLAG_g | /* Sort using strtod() */
				FLAG_M | /* Sort date */
				FLAG_b | /* Ignore leading blanks */
				FLAG_r | /* Reverse */
				FLAG_d | /* Ignore !(isalnum()|isspace()) */
				FLAG_f | /* Force uppercase */
				FLAG_i | /* Ignore !isprint() */
			0
		};
		struct sort_key *key = add_key();
		char *str_k = llist_pop(&lst_k);
		const char *temp2;

		i = 0; /* i==0 before comma, 1 after (-k3,6) */
		while (*str_k) {
			/* Start of range */
			/* Cannot use bb_strtou - suffix can be a letter */
			key->range[2*i] = str2u(&str_k);
			if (*str_k == '.') {
				str_k++;
				key->range[2*i+1] = str2u(&str_k);
			}
			while (*str_k) {
				if (*str_k == ',' && !i++) {
					str_k++;
					break;
				} /* no else needed: fall through to syntax error
					 because comma isn't in OPT_STR */
				temp2 = strchr(OPT_STR, *str_k);
				if (!temp2)
					bb_error_msg_and_die("unknown key option");
				flag = 1 << (temp2 - OPT_STR);
				if (flag & ~FLAG_allowed_for_k)
					bb_error_msg_and_die("unknown sort type");
				/* b after ',' means strip _trailing_ space */
				if (i && flag == FLAG_b) flag = FLAG_bb;
				key->flags |= flag;
				str_k++;
			}
		}
	}
#endif
	/* global b strips leading and trailing spaces */
	if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb;

	/* Open input files and read data */
	argv += optind;
	if (!*argv)
		*--argv = (char*)"-";
	do {
		/* coreutils 6.9 compat: abort on first open error,
		 * do not continue to next file: */
		fp = xfopen_stdin(*argv);
		for (;;) {
			line = GET_LINE(fp);
			if (!line) break;
			lines = xrealloc_vector(lines, 6, linecount);
			lines[linecount++] = line;
		}
		fclose_if_not_stdin(fp);
	} while (*++argv);

#if ENABLE_FEATURE_SORT_BIG
	/* if no key, perform alphabetic sort */
	if (!key_list)
		add_key()->range[0] = 1;
	/* handle -c */
	if (option_mask32 & FLAG_c) {
		int j = (option_mask32 & FLAG_u) ? -1 : 0;
		for (i = 1; i < linecount; i++)
			if (compare_keys(&lines[i-1], &lines[i]) > j) {
				fprintf(stderr, "Check line %d\n", i);
				return EXIT_FAILURE;
			}
		return EXIT_SUCCESS;
	}
#endif
	/* Perform the actual sort */
	qsort(lines, linecount, sizeof(char *), compare_keys);
	/* handle -u */
	if (option_mask32 & FLAG_u) {
		flag = 0;
		/* coreutils 6.3 drop lines for which only key is the same */
		/* -- disabling last-resort compare... */
		option_mask32 |= FLAG_s;
		for (i = 1; i < linecount; i++) {
			if (!compare_keys(&lines[flag], &lines[i]))
				free(lines[i]);
			else
				lines[++flag] = lines[i];
		}
		if (linecount) linecount = flag+1;
	}
	/* Print it */
	flag = (option_mask32 & FLAG_z) ? '\0' : '\n';
	for (i = 0; i < linecount; i++)
		fprintf(outfile, "%s%c", lines[i], flag);

	fflush_stdout_and_exit(EXIT_SUCCESS);
}
예제 #18
0
int wget_main(int argc UNUSED_PARAM, char **argv)
{
    char buf[512];
    struct host_info server, target;
    len_and_sockaddr *lsa;
    unsigned opt;
    int redir_limit;
    char *proxy = NULL;
    char *dir_prefix = NULL;
#if ENABLE_FEATURE_WGET_LONG_OPTIONS
    char *post_data;
    char *extra_headers = NULL;
    llist_t *headers_llist = NULL;
#endif
    FILE *sfp;                      /* socket to web/ftp server         */
    FILE *dfp;                      /* socket to ftp server (data)      */
    char *fname_out;                /* where to direct output (-O)      */
    int output_fd = -1;
    bool use_proxy;                 /* Use proxies if env vars are set  */
    const char *proxy_flag = "on";  /* Use proxies if env vars are set  */
    const char *user_agent = "Wget";/* "User-Agent" header field        */

    static const char keywords[] ALIGN1 =
        "content-length\0""transfer-encoding\0""chunked\0""location\0";
    enum {
        KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location
    };
#if ENABLE_FEATURE_WGET_LONG_OPTIONS
    static const char wget_longopts[] ALIGN1 =
        /* name, has_arg, val */
        "continue\0"         No_argument       "c"
        "spider\0"           No_argument       "s"
        "quiet\0"            No_argument       "q"
        "output-document\0"  Required_argument "O"
        "directory-prefix\0" Required_argument "P"
        "proxy\0"            Required_argument "Y"
        "user-agent\0"       Required_argument "U"
        /* Ignored: */
        // "tries\0"            Required_argument "t"
        // "timeout\0"          Required_argument "T"
        /* Ignored (we always use PASV): */
        "passive-ftp\0"      No_argument       "\xff"
        "header\0"           Required_argument "\xfe"
        "post-data\0"        Required_argument "\xfd"
        /* Ignored (we don't do ssl) */
        "no-check-certificate\0" No_argument   "\xfc"
        ;
#endif

    INIT_G();

#if ENABLE_FEATURE_WGET_LONG_OPTIONS
    applet_long_options = wget_longopts;
#endif
    /* server.allocated = target.allocated = NULL; */
    opt_complementary = "-1" IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::");
    opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:",
                   &fname_out, &dir_prefix,
                   &proxy_flag, &user_agent,
                   NULL, /* -t RETRIES */
                   NULL /* -T NETWORK_READ_TIMEOUT */
                   IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
                   IF_FEATURE_WGET_LONG_OPTIONS(, &post_data)
                  );
#if ENABLE_FEATURE_WGET_LONG_OPTIONS
    if (headers_llist) {
        int size = 1;
        char *cp;
        llist_t *ll = headers_llist;
        while (ll) {
            size += strlen(ll->data) + 2;
            ll = ll->link;
        }
        extra_headers = cp = xmalloc(size);
        while (headers_llist) {
            cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist));
        }
    }
#endif

    /* TODO: compat issue: should handle "wget URL1 URL2..." */

    target.user = NULL;
    parse_url(argv[optind], &target);

    /* Use the proxy if necessary */
    use_proxy = (strcmp(proxy_flag, "off") != 0);
    if (use_proxy) {
        proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
        if (proxy && proxy[0]) {
            server.user = NULL;
            parse_url(proxy, &server);
        } else {
            use_proxy = 0;
        }
    }
    if (!use_proxy) {
        server.port = target.port;
        if (ENABLE_FEATURE_IPV6) {
            server.host = xstrdup(target.host);
        } else {
            server.host = target.host;
        }
    }

    if (ENABLE_FEATURE_IPV6)
        strip_ipv6_scope_id(target.host);

    /* Guess an output filename, if there was no -O FILE */
    if (!(opt & WGET_OPT_OUTNAME)) {
        fname_out = bb_get_last_path_component_nostrip(target.path);
        /* handle "wget http://kernel.org//" */
        if (fname_out[0] == '/' || !fname_out[0])
            fname_out = (char*)"index.html";
        /* -P DIR is considered only if there was no -O FILE */
        if (dir_prefix)
            fname_out = concat_path_file(dir_prefix, fname_out);
    } else {
        if (LONE_DASH(fname_out)) {
            /* -O - */
            output_fd = 1;
            opt &= ~WGET_OPT_CONTINUE;
        }
    }
#if ENABLE_FEATURE_WGET_STATUSBAR
    G.curfile = bb_get_last_path_component_nostrip(fname_out);
#endif

    /* Impossible?
    if ((opt & WGET_OPT_CONTINUE) && !fname_out)
    	bb_error_msg_and_die("can't specify continue (-c) without a filename (-O)");
    */

    /* Determine where to start transfer */
    if (opt & WGET_OPT_CONTINUE) {
        output_fd = open(fname_out, O_WRONLY);
        if (output_fd >= 0) {
            G.beg_range = xlseek(output_fd, 0, SEEK_END);
        }
        /* File doesn't exist. We do not create file here yet.
         * We are not sure it exists on remove side */
    }

    redir_limit = 5;
resolve_lsa:
    lsa = xhost2sockaddr(server.host, server.port);
    if (!(opt & WGET_OPT_QUIET)) {
        char *s = xmalloc_sockaddr2dotted(&lsa->u.sa);
        fprintf(stderr, "Connecting to %s (%s)\n", server.host, s);
        free(s);
    }
establish_session:
    if (use_proxy || !target.is_ftp) {
        /*
         *  HTTP session
         */
        char *str;
        int status;

        /* Open socket to http server */
        sfp = open_socket(lsa);

        /* Send HTTP request */
        if (use_proxy) {
            fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n",
                    target.is_ftp ? "f" : "ht", target.host,
                    target.path);
        } else {
            if (opt & WGET_OPT_POST_DATA)
                fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path);
            else
                fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
        }

        fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n",
                target.host, user_agent);

#if ENABLE_FEATURE_WGET_AUTHENTICATION
        if (target.user) {
            fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
                    base64enc_512(buf, target.user));
        }
        if (use_proxy && server.user) {
            fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
                    base64enc_512(buf, server.user));
        }
#endif

        if (G.beg_range)
            fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range);
#if ENABLE_FEATURE_WGET_LONG_OPTIONS
        if (extra_headers)
            fputs(extra_headers, sfp);

        if (opt & WGET_OPT_POST_DATA) {
            char *estr = URL_escape(post_data);
            fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n");
            fprintf(sfp, "Content-Length: %u\r\n" "\r\n" "%s",
                    (int) strlen(estr), estr);
            /*fprintf(sfp, "Connection: Keep-Alive\r\n\r\n");*/
            /*fprintf(sfp, "%s\r\n", estr);*/
            free(estr);
        } else
#endif
        {   /* If "Connection:" is needed, document why */
            fprintf(sfp, /* "Connection: close\r\n" */ "\r\n");
        }

        /*
         * Retrieve HTTP response line and check for "200" status code.
         */
read_response:
        if (fgets(buf, sizeof(buf), sfp) == NULL)
            bb_error_msg_and_die("no response from server");

        str = buf;
        str = skip_non_whitespace(str);
        str = skip_whitespace(str);
        // FIXME: no error check
        // xatou wouldn't work: "200 OK"
        status = atoi(str);
        switch (status) {
        case 0:
        case 100:
            while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL)
                /* eat all remaining headers */;
            goto read_response;
        case 200:
        /*
        Response 204 doesn't say "null file", it says "metadata
        has changed but data didn't":

        "10.2.5 204 No Content
        The server has fulfilled the request but does not need to return
        an entity-body, and might want to return updated metainformation.
        The response MAY include new or updated metainformation in the form
        of entity-headers, which if present SHOULD be associated with
        the requested variant.

        If the client is a user agent, it SHOULD NOT change its document
        view from that which caused the request to be sent. This response
        is primarily intended to allow input for actions to take place
        without causing a change to the user agent's active document view,
        although any new or updated metainformation SHOULD be applied
        to the document currently in the user agent's active view.

        The 204 response MUST NOT include a message-body, and thus
        is always terminated by the first empty line after the header fields."

        However, in real world it was observed that some web servers
        (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero.
        */
        case 204:
            break;
        case 300:	/* redirection */
        case 301:
        case 302:
        case 303:
            break;
        case 206:
            if (G.beg_range)
                break;
        /* fall through */
        default:
            bb_error_msg_and_die("server returned error: %s", sanitize_string(buf));
        }

        /*
         * Retrieve HTTP headers.
         */
        while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) {
            /* gethdr converted "FOO:" string to lowercase */
            smalluint key;
            /* strip trailing whitespace */
            char *s = strchrnul(str, '\0') - 1;
            while (s >= str && (*s == ' ' || *s == '\t')) {
                *s = '\0';
                s--;
            }
            key = index_in_strings(keywords, buf) + 1;
            if (key == KEY_content_length) {
                G.content_len = BB_STRTOOFF(str, NULL, 10);
                if (G.content_len < 0 || errno) {
                    bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str));
                }
                G.got_clen = 1;
                continue;
            }
            if (key == KEY_transfer_encoding) {
                if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked)
                    bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str));
                G.chunked = G.got_clen = 1;
            }
            if (key == KEY_location && status >= 300) {
                if (--redir_limit == 0)
                    bb_error_msg_and_die("too many redirections");
                fclose(sfp);
                G.got_clen = 0;
                G.chunked = 0;
                if (str[0] == '/')
                    /* free(target.allocated); */
                    target.path = /* target.allocated = */ xstrdup(str+1);
                /* lsa stays the same: it's on the same server */
                else {
                    parse_url(str, &target);
                    if (!use_proxy) {
                        server.host = target.host;
                        /* strip_ipv6_scope_id(target.host); - no! */
                        /* we assume remote never gives us IPv6 addr with scope id */
                        server.port = target.port;
                        free(lsa);
                        goto resolve_lsa;
                    } /* else: lsa stays the same: we use proxy */
                }
                goto establish_session;
            }
        }
//		if (status >= 300)
//			bb_error_msg_and_die("bad redirection (no Location: header from server)");

        /* For HTTP, data is pumped over the same connection */
        dfp = sfp;

    } else {
        /*
         *  FTP session
         */
        sfp = prepare_ftp_session(&dfp, &target, lsa);
    }

    if (opt & WGET_OPT_SPIDER) {
        if (ENABLE_FEATURE_CLEAN_UP)
            fclose(sfp);
        return EXIT_SUCCESS;
    }

    if (output_fd < 0) {
        int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL;
        /* compat with wget: -O FILE can overwrite */
        if (opt & WGET_OPT_OUTNAME)
            o_flags = O_WRONLY | O_CREAT | O_TRUNC;
        output_fd = xopen(fname_out, o_flags);
    }

    retrieve_file_data(dfp, output_fd);
    xclose(output_fd);

    if (dfp != sfp) {
        /* It's ftp. Close it properly */
        fclose(dfp);
        if (ftpcmd(NULL, NULL, sfp, buf) != 226)
            bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4));
        /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */
    }

    return EXIT_SUCCESS;
}
예제 #19
0
int sendmail_main(int argc UNUSED_PARAM, char **argv)
{
	char *opt_connect = opt_connect;
	char *opt_from = NULL;
	char *s;
	llist_t *list = NULL;
	char *host = sane_address(safe_gethostname());
	unsigned nheaders = 0;
	int code;
	enum {
		HDR_OTHER = 0,
		HDR_TOCC,
		HDR_BCC,
	} last_hdr = 0;
	int check_hdr;
	int has_to = 0;

	enum {
	//--- standard options
		OPT_t = 1 << 0,         // read message for recipients, append them to those on cmdline
		OPT_f = 1 << 1,         // sender address
		OPT_o = 1 << 2,         // various options. -oi IMPLIED! others are IGNORED!
		OPT_i = 1 << 3,         // IMPLIED!
	//--- BB specific options
		OPT_w = 1 << 4,         // network timeout
		OPT_H = 1 << 5,         // use external connection helper
		OPT_S = 1 << 6,         // specify connection string
		OPT_a = 1 << 7,         // authentication tokens
		OPT_v = 1 << 8,         // verbosity
	};

	// init global variables
	INIT_G();

	// save initial stdin since body is piped!
	xdup2(STDIN_FILENO, 3);
	G.fp0 = xfdopen_for_read(3);

	// parse options
	// -v is a counter, -H and -S are mutually exclusive, -a is a list
	opt_complementary = "vv:w+:H--S:S--H:a::";
	// N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect
	// -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility,
	// it is still under development.
	opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL,
			&timeout, &opt_connect, &opt_connect, &list, &verbose);
	//argc -= optind;
	argv += optind;

	// process -a[upm]<token> options
	if ((opts & OPT_a) && !list)
		bb_show_usage();
	while (list) {
		char *a = (char *) llist_pop(&list);
		if ('u' == a[0])
			G.user = xstrdup(a+1);
		if ('p' == a[0])
			G.pass = xstrdup(a+1);
		// N.B. we support only AUTH LOGIN so far
		//if ('m' == a[0])
		//	G.method = xstrdup(a+1);
	}
	// N.B. list == NULL here
	//bb_info_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv);

	// connect to server

	// connection helper ordered? ->
	if (opts & OPT_H) {
		const char *args[] = { "sh", "-c", opt_connect, NULL };
		// plug it in
		launch_helper(args);
		// Now:
		// our stdout will go to helper's stdin,
		// helper's stdout will be available on our stdin.

		// Wait for initial server message.
		// If helper (such as openssl) invokes STARTTLS, the initial 220
		// is swallowed by helper (and not repeated after TLS is initiated).
		// We will send NOOP cmd to server and check the response.
		// We should get 220+250 on plain connection, 250 on STARTTLSed session.
		//
		// The problem here is some servers delay initial 220 message,
		// and consider client to be a spammer if it starts sending cmds
		// before 220 reached it. The code below is unsafe in this regard:
		// in non-STARTTLSed case, we potentially send NOOP before 220
		// is sent by server.
		// Ideas? (--delay SECS opt? --assume-starttls-helper opt?)
		code = smtp_check("NOOP", -1);
		if (code == 220)
			// we got 220 - this is not STARTTLSed connection,
			// eat 250 response to our NOOP
			smtp_check(NULL, 250);
		else
		if (code != 250)
			bb_error_msg_and_die("SMTP init failed");
	} else {
		// vanilla connection
		int fd;
		// host[:port] not explicitly specified? -> use $SMTPHOST
		// no $SMTPHOST? -> use localhost
		if (!(opts & OPT_S)) {
			opt_connect = getenv("SMTPHOST");
			if (!opt_connect)
				opt_connect = (char *)"127.0.0.1";
		}
		// do connect
		fd = create_and_connect_stream_or_die(opt_connect, 25);
		// and make ourselves a simple IO filter
		xmove_fd(fd, STDIN_FILENO);
		xdup2(STDIN_FILENO, STDOUT_FILENO);

		// Wait for initial server 220 message
		smtp_check(NULL, 220);
	}

	// we should start with modern EHLO
	if (250 != smtp_checkp("EHLO %s", host, -1))
		smtp_checkp("HELO %s", host, 250);

	// perform authentication
	if (opts & OPT_a) {
		smtp_check("AUTH LOGIN", 334);
		// we must read credentials unless they are given via -a[up] options
		if (!G.user || !G.pass)
			get_cred_or_die(4);
		encode_base64(NULL, G.user, NULL);
		smtp_check("", 334);
		encode_base64(NULL, G.pass, NULL);
		smtp_check("", 235);
	}

	// set sender
	// N.B. we have here a very loosely defined algorythm
	// since sendmail historically offers no means to specify secrets on cmdline.
	// 1) server can require no authentication ->
	//	we must just provide a (possibly fake) reply address.
	// 2) server can require AUTH ->
	//	we must provide valid username and password along with a (possibly fake) reply address.
	//	For the sake of security username and password are to be read either from console or from a secured file.
	//	Since reading from console may defeat usability, the solution is either to read from a predefined
	//	file descriptor (e.g. 4), or again from a secured file.

	// got no sender address? use auth name, then UID username as a last resort
	if (!opt_from) {
		opt_from = xasprintf("%s@%s",
		                     G.user ? G.user : xuid2uname(getuid()),
		                     xgethostbyname(host)->h_name);
	}
	free(host);

	smtp_checkp("MAIL FROM:<%s>", opt_from, 250);

	// process message

	// read recipients from message and add them to those given on cmdline.
	// this means we scan stdin for To:, Cc:, Bcc: lines until an empty line
	// and then use the rest of stdin as message body
	code = 0; // set "analyze headers" mode
	while ((s = xmalloc_fgetline(G.fp0)) != NULL) {
 dump:
		// put message lines doubling leading dots
		if (code) {
			// escape leading dots
			// N.B. this feature is implied even if no -i (-oi) switch given
			// N.B. we need to escape the leading dot regardless of
			// whether it is single or not character on the line
			if ('.' == s[0] /*&& '\0' == s[1] */)
				bb_putchar('.');
			// dump read line
			send_r_n(s);
			free(s);
			continue;
		}

		// analyze headers
		// To: or Cc: headers add recipients
		check_hdr = (0 == strncasecmp("To:", s, 3));
		has_to |= check_hdr;
		if (opts & OPT_t) {
			if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
				rcptto_list(s+3);
				last_hdr = HDR_TOCC;
				goto addheader;
			}
			// Bcc: header adds blind copy (hidden) recipient
			if (0 == strncasecmp("Bcc:", s, 4)) {
				rcptto_list(s+4);
				free(s);
				last_hdr = HDR_BCC;
				continue; // N.B. Bcc: vanishes from headers!
			}
		}
		check_hdr = (list && isspace(s[0]));
		if (strchr(s, ':') || check_hdr) {
			// other headers go verbatim
			// N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines.
			// Continuation is denoted by prefixing additional lines with whitespace(s).
			// Thanks (stefan.seyfried at googlemail.com) for pointing this out.
			if (check_hdr && last_hdr != HDR_OTHER) {
				rcptto_list(s+1);
				if (last_hdr == HDR_BCC)
					continue;
					// N.B. Bcc: vanishes from headers!
			} else {
				last_hdr = HDR_OTHER;
			}
 addheader:
			// N.B. we allow MAX_HEADERS generic headers at most to prevent attacks
			if (MAX_HEADERS && ++nheaders >= MAX_HEADERS)
				goto bail;
			llist_add_to_end(&list, s);
		} else {
			// a line without ":" (an empty line too, by definition) doesn't look like a valid header
			// so stop "analyze headers" mode
 reenter:
			// put recipients specified on cmdline
			check_hdr = 1;
			while (*argv) {
				char *t = sane_address(*argv);
				rcptto(t);
				//if (MAX_HEADERS && ++nheaders >= MAX_HEADERS)
				//	goto bail;
				if (!has_to) {
					const char *hdr;

					if (check_hdr && argv[1])
						hdr = "To: %s,";
					else if (check_hdr)
						hdr = "To: %s";
					else if (argv[1])
						hdr = "To: %s," + 3;
					else
						hdr = "To: %s" + 3;
					llist_add_to_end(&list,
							xasprintf(hdr, t));
					check_hdr = 0;
				}
				argv++;
			}
			// enter "put message" mode
			// N.B. DATA fails iff no recipients were accepted (or even provided)
			// in this case just bail out gracefully
			if (354 != smtp_check("DATA", -1))
				goto bail;
			// dump the headers
			while (list) {
				send_r_n((char *) llist_pop(&list));
			}
			// stop analyzing headers
			code++;
			// N.B. !s means: we read nothing, and nothing to be read in the future.
			// just dump empty line and break the loop
			if (!s) {
				send_r_n("");
				break;
			}
			// go dump message body
			// N.B. "s" already contains the first non-header line, so pretend we read it from input
			goto dump;
		}
	}
	// odd case: we didn't stop "analyze headers" mode -> message body is empty. Reenter the loop
	// N.B. after reenter code will be > 0
	if (!code)
		goto reenter;

	// finalize the message
	smtp_check(".", 250);
 bail:
	// ... and say goodbye
	smtp_check("QUIT", 221);
	// cleanup
	if (ENABLE_FEATURE_CLEAN_UP)
		fclose(G.fp0);

	return EXIT_SUCCESS;
}
예제 #20
0
int sed_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
	enum {
		OPT_in_place = 1 << 0,
	};
	unsigned opt;
	llist_t *opt_e, *opt_f;
	int status = EXIT_SUCCESS;

	INIT_G();

	/* destroy command strings on exit */
	if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff);

	/* Lie to autoconf when it starts asking stupid questions. */
	if (argv[1] && !strcmp(argv[1], "--version")) {
		puts("This is not GNU sed version 4.0");
		return 0;
	}

	/* do normal option parsing */
	opt_e = opt_f = NULL;
	opt_complementary = "e::f::" /* can occur multiple times */
	                    "nn"; /* count -n */
	opt = getopt32(argv, "irne:f:", &opt_e, &opt_f,
			    &G.be_quiet); /* counter for -n */
	//argc -= optind;
	argv += optind;
	if (opt & OPT_in_place) { // -i
		atexit(cleanup_outname);
	}
	if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r
	//if (opt & 0x4) G.be_quiet++; // -n
	while (opt_e) { // -e
		add_cmd_block(llist_pop(&opt_e));
	}
	while (opt_f) { // -f
		char *line;
		FILE *cmdfile;
		cmdfile = xfopen(llist_pop(&opt_f), "r");
		while ((line = xmalloc_fgetline(cmdfile)) != NULL) {
			add_cmd(line);
			free(line);
		}
		fclose(cmdfile);
	}
	/* if we didn't get a pattern from -e or -f, use argv[0] */
	if (!(opt & 0x18)) {
		if (!*argv)
			bb_show_usage();
		add_cmd_block(*argv++);
	}
	/* Flush any unfinished commands. */
	add_cmd("");

	/* By default, we write to stdout */
	G.nonstdout = stdout;

	/* argv[0..(argc-1)] should be names of file to process. If no
	 * files were specified or '-' was specified, take input from stdin.
	 * Otherwise, we process all the files specified. */
	if (argv[0] == NULL) {
		if (opt & OPT_in_place)
			bb_error_msg_and_die(bb_msg_requires_arg, "-i");
		add_input_file(stdin);
		process_files();
	} else {
		int i;
		FILE *file;

		for (i = 0; argv[i]; i++) {
			struct stat statbuf;
			int nonstdoutfd;

			if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
				add_input_file(stdin);
				process_files();
				continue;
			}
			file = fopen_or_warn(argv[i], "r");
			if (!file) {
				status = EXIT_FAILURE;
				continue;
			}
			if (!(opt & OPT_in_place)) {
				add_input_file(file);
				continue;
			}

			G.outname = xasprintf("%sXXXXXX", argv[i]);
			nonstdoutfd = mkstemp(G.outname);
			if (-1 == nonstdoutfd)
				bb_perror_msg_and_die("cannot create temp file %s", G.outname);
			G.nonstdout = fdopen(nonstdoutfd, "w");

			/* Set permissions of output file */

			fstat(fileno(file), &statbuf);
			fchmod(nonstdoutfd, statbuf.st_mode);
			add_input_file(file);
			process_files();
			fclose(G.nonstdout);

			G.nonstdout = stdout;
			/* unlink(argv[i]); */
			xrename(G.outname, argv[i]);
			free(G.outname);
			G.outname = NULL;
		}
		if (G.input_file_count > G.current_input_file)
			process_files();
	}

	return status;
}
예제 #21
0
int sendmail_main(int argc UNUSED_PARAM, char **argv)
{
	char *opt_connect = opt_connect;
	char *opt_from;
	char *s;
	llist_t *list = NULL;
	char *domain = sane_address(safe_getdomainname());
	int code;

	enum {
	//--- standard options
		OPT_t = 1 << 0,         // read message for recipients, append them to those on cmdline
		OPT_f = 1 << 1,         // sender address
		OPT_o = 1 << 2,         // various options. -oi IMPLIED! others are IGNORED!
	//--- BB specific options
		OPT_w = 1 << 3,         // network timeout
		OPT_H = 1 << 4,         // use external connection helper
		OPT_S = 1 << 5,         // specify connection string
		OPT_a = 1 << 6,         // authentication tokens
	};

	// init global variables
	INIT_G();

	// save initial stdin since body is piped!
	xdup2(STDIN_FILENO, 3);
	G.fp0 = fdopen(3, "r");

	// parse options
	// -f is required. -H and -S are mutually exclusive
	opt_complementary = "f:w+:H--S:S--H:a::";
	// N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect
	// -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility,
	// it is still under development.
	opts = getopt32(argv, "tf:o:w:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list);
	//argc -= optind;
	argv += optind;

	// process -a[upm]<token> options
	if ((opts & OPT_a) && !list)
		bb_show_usage();
	while (list) {
		char *a = (char *) llist_pop(&list);
		if ('u' == a[0])
			G.user = xstrdup(a+1);
		if ('p' == a[0])
			G.pass = xstrdup(a+1);
		// N.B. we support only AUTH LOGIN so far
		//if ('m' == a[0])
		//	G.method = xstrdup(a+1);
	}
	// N.B. list == NULL here
	//bb_info_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv);

	// connect to server

	// connection helper ordered? ->
	if (opts & OPT_H) {
		const char *args[] = { "sh", "-c", opt_connect, NULL };
		// plug it in
		launch_helper(args);
	// vanilla connection
	} else {
		int fd;
		// host[:port] not explicitly specified? -> use $SMTPHOST
		// no $SMTPHOST ? -> use localhost
		if (!(opts & OPT_S)) {
			opt_connect = getenv("SMTPHOST");
			if (!opt_connect)
				opt_connect = (char *)"127.0.0.1";
		}
		// do connect
		fd = create_and_connect_stream_or_die(opt_connect, 25);
		// and make ourselves a simple IO filter
		xmove_fd(fd, STDIN_FILENO);
		xdup2(STDIN_FILENO, STDOUT_FILENO);
	}
	// N.B. from now we know nothing about network :)

	// wait for initial server OK
	// N.B. if we used openssl the initial 220 answer is already swallowed during openssl TLS init procedure
	// so we need to kick the server to see whether we are ok
	code = smtp_check("NOOP", -1);
	// 220 on plain connection, 250 on openssl-helped TLS session
	if (220 == code)
		smtp_check(NULL, 250); // reread the code to stay in sync
	else if (250 != code)
		bb_error_msg_and_die("INIT failed");

	// we should start with modern EHLO
	if (250 != smtp_checkp("EHLO %s", domain, -1)) {
		smtp_checkp("HELO %s", domain, 250);
	}
	if (ENABLE_FEATURE_CLEAN_UP)
		free(domain);

	// perform authentication
	if (opts & OPT_a) {
		smtp_check("AUTH LOGIN", 334);
		// we must read credentials unless they are given via -a[up] options
		if (!G.user || !G.pass)
			get_cred_or_die(4);
		encode_base64(NULL, G.user, NULL);
		smtp_check("", 334);
		encode_base64(NULL, G.pass, NULL);
		smtp_check("", 235);
	}

	// set sender
	// N.B. we have here a very loosely defined algotythm
	// since sendmail historically offers no means to specify secrets on cmdline.
	// 1) server can require no authentication ->
	//	we must just provide a (possibly fake) reply address.
	// 2) server can require AUTH ->
	//	we must provide valid username and password along with a (possibly fake) reply address.
	//	For the sake of security username and password are to be read either from console or from a secured file.
	//	Since reading from console may defeat usability, the solution is either to read from a predefined
	//	file descriptor (e.g. 4), or again from a secured file.

	// got no sender address? -> use system username as a resort
	// N.B. we marked -f as required option!
	//if (!G.user) {
	//	// N.B. IMHO getenv("USER") can be way easily spoofed!
	//	G.user = xuid2uname(getuid());
	//	opt_from = xasprintf("%s@%s", G.user, domain);
	//}
	//if (ENABLE_FEATURE_CLEAN_UP)
	//	free(domain);
	smtp_checkp("MAIL FROM:<%s>", opt_from, 250);

	// process message

	// read recipients from message and add them to those given on cmdline.
	// this means we scan stdin for To:, Cc:, Bcc: lines until an empty line
	// and then use the rest of stdin as message body
	code = 0; // set "analyze headers" mode
	while ((s = xmalloc_fgetline(G.fp0)) != NULL) {
		// put message lines doubling leading dots
		if (code) {
			// escape leading dots
			// N.B. this feature is implied even if no -i (-oi) switch given
			// N.B. we need to escape the leading dot regardless of
			// whether it is single or not character on the line
			if ('.' == s[0] /*&& '\0' == s[1] */)
				printf(".");
			// dump read line
			printf("%s\r\n", s);
			free(s);
			continue;
		}

		// analyze headers
		// To: or Cc: headers add recipients
		if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Bcc: " + 1, s, 4)) {
			rcptto(sane_address(s+4));
//			goto addh;
			llist_add_to_end(&list, s);
		// Bcc: header adds blind copy (hidden) recipient
		} else if (0 == strncasecmp("Bcc: ", s, 5)) {
			rcptto(sane_address(s+5));
			free(s);
			// N.B. Bcc: vanishes from headers!
		// other headers go verbatim
		} else if (s[0]) {
// addh:
			llist_add_to_end(&list, s);
		// the empty line stops analyzing headers
		} else {
			free(s);
			// put recipients specified on cmdline
			while (*argv) {
				s = sane_address(*argv);
				rcptto(s);
				llist_add_to_end(&list, xasprintf("To: %s", s));
				argv++;
			}
			// enter "put message" mode
			smtp_check("DATA", 354);
			// dump the headers
			while (list) {
				printf("%s\r\n", (char *) llist_pop(&list));
			}
			printf("%s\r\n" + 2); // quirk for format string to be reused
			// stop analyzing headers
			code++;
		}
	}

	// finalize the message
	smtp_check(".", 250);
	// ... and say goodbye
	smtp_check("QUIT", 221);
	// cleanup
	if (ENABLE_FEATURE_CLEAN_UP)
		fclose(G.fp0);

	return EXIT_SUCCESS;
}
예제 #22
0
파일: sed.c 프로젝트: pgavin/or1k-busybox
int sed_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opt;
	llist_t *opt_e, *opt_f;
	char *opt_i;

#if ENABLE_LONG_OPTS
	static const char sed_longopts[] ALIGN1 =
		/* name             has_arg             short */
		"in-place\0"        Optional_argument   "i"
		"regexp-extended\0" No_argument         "r"
		"quiet\0"           No_argument         "n"
		"silent\0"          No_argument         "n"
		"expression\0"      Required_argument   "e"
		"file\0"            Required_argument   "f";
#endif

	int status = EXIT_SUCCESS;

	INIT_G();

	/* destroy command strings on exit */
	if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff);

	/* Lie to autoconf when it starts asking stupid questions. */
	if (argv[1] && strcmp(argv[1], "--version") == 0) {
		puts("This is not GNU sed version 4.0");
		return 0;
	}

	/* do normal option parsing */
	opt_e = opt_f = NULL;
	opt_i = NULL;
	opt_complementary = "e::f::" /* can occur multiple times */
	                    "nn"; /* count -n */

	IF_LONG_OPTS(applet_long_options = sed_longopts);

	/* -i must be first, to match OPT_in_place definition */
	opt = getopt32(argv, "i::rne:f:", &opt_i, &opt_e, &opt_f,
			    &G.be_quiet); /* counter for -n */
	//argc -= optind;
	argv += optind;
	if (opt & OPT_in_place) { // -i
		atexit(cleanup_outname);
	}
	if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r
	//if (opt & 0x4) G.be_quiet++; // -n
	while (opt_e) { // -e
		add_cmd_block(llist_pop(&opt_e));
	}
	while (opt_f) { // -f
		char *line;
		FILE *cmdfile;
		cmdfile = xfopen_for_read(llist_pop(&opt_f));
		while ((line = xmalloc_fgetline(cmdfile)) != NULL) {
			add_cmd(line);
			free(line);
		}
		fclose(cmdfile);
	}
	/* if we didn't get a pattern from -e or -f, use argv[0] */
	if (!(opt & 0x18)) {
		if (!*argv)
			bb_show_usage();
		add_cmd_block(*argv++);
	}
	/* Flush any unfinished commands. */
	add_cmd("");

	/* By default, we write to stdout */
	G.nonstdout = stdout;

	/* argv[0..(argc-1)] should be names of file to process. If no
	 * files were specified or '-' was specified, take input from stdin.
	 * Otherwise, we process all the files specified. */
	if (argv[0] == NULL) {
		if (opt & OPT_in_place)
			bb_error_msg_and_die(bb_msg_requires_arg, "-i");
		add_input_file(stdin);
	} else {
		int i;

		for (i = 0; argv[i]; i++) {
			struct stat statbuf;
			int nonstdoutfd;
			FILE *file;
			sed_cmd_t *sed_cmd;

			if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
				add_input_file(stdin);
				process_files();
				continue;
			}
			file = fopen_or_warn(argv[i], "r");
			if (!file) {
				status = EXIT_FAILURE;
				continue;
			}
			add_input_file(file);
			if (!(opt & OPT_in_place)) {
				continue;
			}

			/* -i: process each FILE separately: */

			G.outname = xasprintf("%sXXXXXX", argv[i]);
			nonstdoutfd = xmkstemp(G.outname);
			G.nonstdout = xfdopen_for_write(nonstdoutfd);

			/* Set permissions/owner of output file */
			fstat(fileno(file), &statbuf);
			/* chmod'ing AFTER chown would preserve suid/sgid bits,
			 * but GNU sed 4.2.1 does not preserve them either */
			fchmod(nonstdoutfd, statbuf.st_mode);
			fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);

			process_files();
			fclose(G.nonstdout);
			G.nonstdout = stdout;

			if (opt_i) {
				char *backupname = xasprintf("%s%s", argv[i], opt_i);
				xrename(argv[i], backupname);
				free(backupname);
			}
			/* else unlink(argv[i]); - rename below does this */
			xrename(G.outname, argv[i]); //TODO: rollback backup on error?
			free(G.outname);
			G.outname = NULL;

			/* Re-enable disabled range matches */
			for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
				sed_cmd->beg_line = sed_cmd->beg_line_orig;
			}
		}
		/* Here, to handle "sed 'cmds' nonexistent_file" case we did:
		 * if (G.current_input_file >= G.input_file_count)
		 *	return status;
		 * but it's not needed since process_files() works correctly
		 * in this case too. */
	}
	process_files();

	return status;
}
예제 #23
0
파일: sed.c 프로젝트: rehsack/busybox
int sed_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opt;
	llist_t *opt_e, *opt_f;
	char *opt_i;

#if ENABLE_LONG_OPTS
	static const char sed_longopts[] ALIGN1 =
		/* name             has_arg             short */
		"in-place\0"        Optional_argument   "i"
		"regexp-extended\0" No_argument         "r"
		"quiet\0"           No_argument         "n"
		"silent\0"          No_argument         "n"
		"expression\0"      Required_argument   "e"
		"file\0"            Required_argument   "f";
#endif

	INIT_G();

	/* destroy command strings on exit */
	if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff);

	/* Lie to autoconf when it starts asking stupid questions. */
	if (argv[1] && strcmp(argv[1], "--version") == 0) {
		puts("This is not GNU sed version 4.0");
		return 0;
	}

	/* do normal option parsing */
	opt_e = opt_f = NULL;
	opt_i = NULL;
	/* -i must be first, to match OPT_in_place definition */
	/* -E is a synonym of -r:
	 * GNU sed 4.2.1 mentions it in neither --help
	 * nor manpage, but does recognize it.
	 */
	opt = getopt32long(argv, "^"
			"i::rEne:*f:*"
			"\0" "nn"/*count -n*/,
			sed_longopts,
			&opt_i, &opt_e, &opt_f,
			&G.be_quiet); /* counter for -n */
	//argc -= optind;
	argv += optind;
	if (opt & OPT_in_place) { // -i
		die_func = cleanup_outname;
	}
	if (opt & (2|4))
		G.regex_type |= REG_EXTENDED; // -r or -E
	//if (opt & 8)
	//	G.be_quiet++; // -n (implemented with a counter instead)
	while (opt_e) { // -e
		add_cmd_block(llist_pop(&opt_e));
	}
	while (opt_f) { // -f
		char *line;
		FILE *cmdfile;
		cmdfile = xfopen_stdin(llist_pop(&opt_f));
		while ((line = xmalloc_fgetline(cmdfile)) != NULL) {
			add_cmd(line);
			free(line);
		}
		fclose_if_not_stdin(cmdfile);
	}
	/* if we didn't get a pattern from -e or -f, use argv[0] */
	if (!(opt & 0x30)) {
		if (!*argv)
			bb_show_usage();
		add_cmd_block(*argv++);
	}
	/* Flush any unfinished commands. */
	add_cmd("");

	/* By default, we write to stdout */
	G.nonstdout = stdout;

	/* argv[0..(argc-1)] should be names of file to process. If no
	 * files were specified or '-' was specified, take input from stdin.
	 * Otherwise, we process all the files specified. */
	G.input_file_list = argv;
	if (!argv[0]) {
		if (opt & OPT_in_place)
			bb_error_msg_and_die(bb_msg_requires_arg, "-i");
		argv[0] = (char*)bb_msg_standard_input;
		/* G.last_input_file = 0; - already is */
	} else {
		goto start;

		for (; *argv; argv++) {
			struct stat statbuf;
			int nonstdoutfd;
			sed_cmd_t *sed_cmd;

			G.last_input_file++;
 start:
			if (!(opt & OPT_in_place)) {
				if (LONE_DASH(*argv)) {
					*argv = (char*)bb_msg_standard_input;
					process_files();
				}
				continue;
			}

			/* -i: process each FILE separately: */

			if (stat(*argv, &statbuf) != 0) {
				bb_simple_perror_msg(*argv);
				G.exitcode = EXIT_FAILURE;
				G.current_input_file++;
				continue;
			}
			G.outname = xasprintf("%sXXXXXX", *argv);
			nonstdoutfd = xmkstemp(G.outname);
			G.nonstdout = xfdopen_for_write(nonstdoutfd);
			/* Set permissions/owner of output file */
			/* chmod'ing AFTER chown would preserve suid/sgid bits,
			 * but GNU sed 4.2.1 does not preserve them either */
			fchmod(nonstdoutfd, statbuf.st_mode);
			fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);

			process_files();
			fclose(G.nonstdout);
			G.nonstdout = stdout;

			if (opt_i) {
				char *backupname = xasprintf("%s%s", *argv, opt_i);
				xrename(*argv, backupname);
				free(backupname);
			}
			/* else unlink(*argv); - rename below does this */
			xrename(G.outname, *argv); //TODO: rollback backup on error?
			free(G.outname);
			G.outname = NULL;

			/* Fix disabled range matches and mangled ",+N" ranges */
			for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
				sed_cmd->beg_line = sed_cmd->beg_line_orig;
				sed_cmd->end_line = sed_cmd->end_line_orig;
			}
		}
		/* Here, to handle "sed 'cmds' nonexistent_file" case we did:
		 * if (G.current_input_file[G.current_input_file] == NULL)
		 *	return G.exitcode;
		 * but it's not needed since process_files() works correctly
		 * in this case too. */
	}

	process_files();

	return G.exitcode;
}
예제 #24
0
int getopt_main(int argc, char **argv)
{
    int n;
    char *optstr = NULL;
    char *name = NULL;
    unsigned opt;
    const char *compatible;
    char *s_arg;
#if ENABLE_FEATURE_GETOPT_LONG
    struct option *long_options = NULL;
    llist_t *l_arg = NULL;
#endif

    compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */

    if (!argv[1]) {
        if (compatible) {
            /* For some reason, the original getopt gave no error
               when there were no arguments. */
            printf(" --\n");
            return 0;
        }
        bb_error_msg_and_die("missing optstring argument");
    }

    if (argv[1][0] != '-' || compatible) {
        char *s = argv[1];

        option_mask32 |= OPT_u; /* quoting off */
        s = xstrdup(s + strspn(s, "-+"));
        argv[1] = argv[0];
        return generate_output(argv+1, argc-1, s, long_options);
    }

#if !ENABLE_FEATURE_GETOPT_LONG
    opt = getopt32(argv, "+o:n:qQs:Tu", &optstr, &name, &s_arg);
#else
    applet_long_options = getopt_longopts;
    opt_complementary = "l::";
    opt = getopt32(argv, "+o:n:qQs:Tual:",
                   &optstr, &name, &s_arg, &l_arg);
    /* Effectuate the read options for the applet itself */
    while (l_arg) {
        long_options = add_long_options(long_options, llist_pop(&l_arg));
    }
#endif

    if (opt & OPT_s) {
        set_shell(s_arg);
    }

    if (opt & OPT_T) {
        return 4;
    }

    /* All options controlling the applet have now been parsed */
    n = optind - 1;
    if (!optstr) {
        optstr = argv[++n];
        if (!optstr)
            bb_error_msg_and_die("missing optstring argument");
    }

    argv[n] = name ? name : argv[0];
    return generate_output(argv + n, argc - n, optstr, long_options);
}
예제 #25
0
파일: sort.c 프로젝트: chrisfair/busybox
int sort_main(int argc UNUSED_PARAM, char **argv)
{
	char *line, **lines;
	char *str_ignored, *str_o, *str_t;
	llist_t *lst_k = NULL;
	int i;
	int linecount;
	unsigned opts;

	xfunc_error_retval = 2;

	/* Parse command line options */
	/* -o and -t can be given at most once */
	opt_complementary = "o--o:t--t"; /* -t, -o: at most one of each */
	opts = getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
	/* global b strips leading and trailing spaces */
	if (opts & FLAG_b)
		option_mask32 |= FLAG_bb;
#if ENABLE_FEATURE_SORT_BIG
	if (opts & FLAG_t) {
		if (!str_t[0] || str_t[1])
			bb_error_msg_and_die("bad -t parameter");
		key_separator = str_t[0];
	}
	/* note: below this point we use option_mask32, not opts,
	 * since that reduces register pressure and makes code smaller */

	/* Parse sort key */
	while (lst_k) {
		enum {
			FLAG_allowed_for_k =
				FLAG_n | /* Numeric sort */
				FLAG_g | /* Sort using strtod() */
				FLAG_M | /* Sort date */
				FLAG_b | /* Ignore leading blanks */
				FLAG_r | /* Reverse */
				FLAG_d | /* Ignore !(isalnum()|isspace()) */
				FLAG_f | /* Force uppercase */
				FLAG_i | /* Ignore !isprint() */
			0
		};
		struct sort_key *key = add_key();
		char *str_k = llist_pop(&lst_k);

		i = 0; /* i==0 before comma, 1 after (-k3,6) */
		while (*str_k) {
			/* Start of range */
			/* Cannot use bb_strtou - suffix can be a letter */
			key->range[2*i] = str2u(&str_k);
			if (*str_k == '.') {
				str_k++;
				key->range[2*i+1] = str2u(&str_k);
			}
			while (*str_k) {
				int flag;
				const char *idx;

				if (*str_k == ',' && !i++) {
					str_k++;
					break;
				} /* no else needed: fall through to syntax error
					because comma isn't in OPT_STR */
				idx = strchr(OPT_STR, *str_k);
				if (!idx)
					bb_error_msg_and_die("unknown key option");
				flag = 1 << (idx - OPT_STR);
				if (flag & ~FLAG_allowed_for_k)
					bb_error_msg_and_die("unknown sort type");
				/* b after ',' means strip _trailing_ space */
				if (i && flag == FLAG_b)
					flag = FLAG_bb;
				key->flags |= flag;
				str_k++;
			}
		}
	}
#endif

	/* Open input files and read data */
	argv += optind;
	if (!*argv)
		*--argv = (char*)"-";
	linecount = 0;
	lines = NULL;
	do {
		/* coreutils 6.9 compat: abort on first open error,
		 * do not continue to next file: */
		FILE *fp = xfopen_stdin(*argv);
		for (;;) {
			line = GET_LINE(fp);
			if (!line)
				break;
			lines = xrealloc_vector(lines, 6, linecount);
			lines[linecount++] = line;
		}
		fclose_if_not_stdin(fp);
	} while (*++argv);

#if ENABLE_FEATURE_SORT_BIG
	/* If no key, perform alphabetic sort */
	if (!key_list)
		add_key()->range[0] = 1;
	/* Handle -c */
	if (option_mask32 & FLAG_c) {
		int j = (option_mask32 & FLAG_u) ? -1 : 0;
		for (i = 1; i < linecount; i++) {
			if (compare_keys(&lines[i-1], &lines[i]) > j) {
				fprintf(stderr, "Check line %u\n", i);
				return EXIT_FAILURE;
			}
		}
		return EXIT_SUCCESS;
	}
#endif
	/* Perform the actual sort */
	qsort(lines, linecount, sizeof(lines[0]), compare_keys);

	/* Handle -u */
	if (option_mask32 & FLAG_u) {
		int j = 0;
		/* coreutils 6.3 drop lines for which only key is the same */
		/* -- disabling last-resort compare... */
		option_mask32 |= FLAG_s;
		for (i = 1; i < linecount; i++) {
			if (compare_keys(&lines[j], &lines[i]) == 0)
				free(lines[i]);
			else
				lines[++j] = lines[i];
		}
		if (linecount)
			linecount = j+1;
	}

	/* Print it */
#if ENABLE_FEATURE_SORT_BIG
	/* Open output file _after_ we read all input ones */
	if (option_mask32 & FLAG_o)
		xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO);
#endif
	{
		int ch = (option_mask32 & FLAG_z) ? '\0' : '\n';
		for (i = 0; i < linecount; i++)
			printf("%s%c", lines[i], ch);
	}

	fflush_stdout_and_exit(EXIT_SUCCESS);
}