github.com/afumu/libc@v0.0.6/musl/src/misc/wordexp.c (about)

     1  #include <wordexp.h>
     2  #include <unistd.h>
     3  #include <stdio.h>
     4  #include <string.h>
     5  #include <limits.h>
     6  #include <stdint.h>
     7  #include <stdlib.h>
     8  #include <sys/wait.h>
     9  #include <signal.h>
    10  #include <errno.h>
    11  #include <fcntl.h>
    12  #include "pthread_impl.h"
    13  
    14  static void reap(pid_t pid)
    15  {
    16  	int status;
    17  	while (waitpid(pid, &status, 0) < 0 && errno == EINTR);
    18  }
    19  
    20  static char *getword(FILE *f)
    21  {
    22  	char *s = 0;
    23  	return getdelim(&s, (size_t [1]){0}, 0, f) < 0 ? 0 : s;
    24  }
    25  
    26  static int do_wordexp(const char *s, wordexp_t *we, int flags)
    27  {
    28  	size_t i, l;
    29  	int sq=0, dq=0;
    30  	size_t np=0;
    31  	char *w, **tmp;
    32  	char *redir = (flags & WRDE_SHOWERR) ? "" : "2>/dev/null";
    33  	int err = 0;
    34  	FILE *f;
    35  	size_t wc = 0;
    36  	char **wv = 0;
    37  	int p[2];
    38  	pid_t pid;
    39  	sigset_t set;
    40  
    41  	if (flags & WRDE_REUSE) wordfree(we);
    42  
    43  	if (flags & WRDE_NOCMD) for (i=0; s[i]; i++) switch (s[i]) {
    44  	case '\\':
    45  		if (!sq && !s[++i]) return WRDE_SYNTAX;
    46  		break;
    47  	case '\'':
    48  		if (!dq) sq^=1;
    49  		break;
    50  	case '"':
    51  		if (!sq) dq^=1;
    52  		break;
    53  	case '(':
    54  		if (np) {
    55  			np++;
    56  			break;
    57  		}
    58  	case ')':
    59  		if (np) {
    60  			np--;
    61  			break;
    62  		}
    63  	case '\n':
    64  	case '|':
    65  	case '&':
    66  	case ';':
    67  	case '<':
    68  	case '>':
    69  	case '{':
    70  	case '}':
    71  		if (!(sq|dq|np)) return WRDE_BADCHAR;
    72  		break;
    73  	case '$':
    74  		if (sq) break;
    75  		if (s[i+1]=='(' && s[i+2]=='(') {
    76  			i += 2;
    77  			np += 2;
    78  			break;
    79  		} else if (s[i+1] != '(') break;
    80  	case '`':
    81  		if (sq) break;
    82  		return WRDE_CMDSUB;
    83  	}
    84  
    85  	if (flags & WRDE_APPEND) {
    86  		wc = we->we_wordc;
    87  		wv = we->we_wordv;
    88  	}
    89  
    90  	i = wc;
    91  	if (flags & WRDE_DOOFFS) {
    92  		if (we->we_offs > SIZE_MAX/sizeof(void *)/4)
    93  			goto nospace;
    94  		i += we->we_offs;
    95  	} else {
    96  		we->we_offs = 0;
    97  	}
    98  
    99  	if (pipe2(p, O_CLOEXEC) < 0) goto nospace;
   100  	__block_all_sigs(&set);
   101  	pid = fork();
   102  	__restore_sigs(&set);
   103  	if (pid < 0) {
   104  		close(p[0]);
   105  		close(p[1]);
   106  		goto nospace;
   107  	}
   108  	if (!pid) {
   109  		if (p[1] == 1) fcntl(1, F_SETFD, 0);
   110  		else dup2(p[1], 1);
   111  		execl("/bin/sh", "sh", "-c",
   112  			"eval \"printf %s\\\\\\\\0 x $1 $2\"",
   113  			"sh", s, redir, (char *)0);
   114  		_exit(1);
   115  	}
   116  	close(p[1]);
   117  	
   118  	f = fdopen(p[0], "r");
   119  	if (!f) {
   120  		close(p[0]);
   121  		kill(pid, SIGKILL);
   122  		reap(pid);
   123  		goto nospace;
   124  	}
   125  
   126  	l = wv ? i+1 : 0;
   127  
   128  	free(getword(f));
   129  	if (feof(f)) {
   130  		fclose(f);
   131  		reap(pid);
   132  		return WRDE_SYNTAX;
   133  	}
   134  
   135  	while ((w = getword(f))) {
   136  		if (i+1 >= l) {
   137  			l += l/2+10;
   138  			tmp = realloc(wv, l*sizeof(char *));
   139  			if (!tmp) break;
   140  			wv = tmp;
   141  		}
   142  		wv[i++] = w;
   143  		wv[i] = 0;
   144  	}
   145  	if (!feof(f)) err = WRDE_NOSPACE;
   146  
   147  	fclose(f);
   148  	reap(pid);
   149  
   150  	if (!wv) wv = calloc(i+1, sizeof *wv);
   151  
   152  	we->we_wordv = wv;
   153  	we->we_wordc = i;
   154  
   155  	if (flags & WRDE_DOOFFS) {
   156  		if (wv) for (i=we->we_offs; i; i--)
   157  			we->we_wordv[i-1] = 0;
   158  		we->we_wordc -= we->we_offs;
   159  	}
   160  	return err;
   161  
   162  nospace:
   163  	if (!(flags & WRDE_APPEND)) {
   164  		we->we_wordc = 0;
   165  		we->we_wordv = 0;
   166  	}
   167  	return WRDE_NOSPACE;
   168  }
   169  
   170  int wordexp(const char *restrict s, wordexp_t *restrict we, int flags)
   171  {
   172  	int r, cs;
   173  	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
   174  	r = do_wordexp(s, we, flags);
   175  	pthread_setcancelstate(cs, 0);
   176  	return r;
   177  }
   178  
   179  void wordfree(wordexp_t *we)
   180  {
   181  	size_t i;
   182  	if (!we->we_wordv) return;
   183  	for (i=0; i<we->we_wordc; i++) free(we->we_wordv[we->we_offs+i]);
   184  	free(we->we_wordv);
   185  	we->we_wordv = 0;
   186  	we->we_wordc = 0;
   187  }