summaryrefslogtreecommitdiff
path: root/src/lib9
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-03-06 15:48:28 -0500
committerRuss Cox <rsc@golang.org>2013-03-06 15:48:28 -0500
commitf8e5108edb41239505581bf5becfc6003291545a (patch)
treeb54aac721f3272dbcbc2c1af02d3282a3c0c054b /src/lib9
parent716ac8e0c201da7701831bd6333a62becccff283 (diff)
downloadgo-f8e5108edb41239505581bf5becfc6003291545a.tar.gz
lib9: add mktempdir, removeall, runprog
R=golang-dev, bradfitz CC=golang-dev https://codereview.appspot.com/7523043
Diffstat (limited to 'src/lib9')
-rw-r--r--src/lib9/run_plan9.c38
-rw-r--r--src/lib9/run_unix.c43
-rw-r--r--src/lib9/run_windows.c83
-rw-r--r--src/lib9/tempdir_plan9.c54
-rw-r--r--src/lib9/tempdir_unix.c52
-rw-r--r--src/lib9/tempdir_windows.c112
-rw-r--r--src/lib9/win.h8
7 files changed, 390 insertions, 0 deletions
diff --git a/src/lib9/run_plan9.c b/src/lib9/run_plan9.c
new file mode 100644
index 000000000..7feb48d98
--- /dev/null
+++ b/src/lib9/run_plan9.c
@@ -0,0 +1,38 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+int
+runcmd(char **argv)
+{
+ int pid;
+ Waitmsg *w;
+
+ switch(pid = fork()) {
+ case -1:
+ return -1;
+ case 0:
+ execvp(argv[0], argv);
+ fprint(2, "exec %s: %r", argv[0]);
+ _exit(1);
+ }
+
+ w = wait();
+ if(w == nil)
+ return -1;
+ if(w->pid != pid) {
+ werrstr("unexpected pid in wait");
+ free(w);
+ return -1;
+ }
+ if(w->msg[0]) {
+ werrstr("unsuccessful exit status: %s", w->msg);
+ free(w);
+ return -1;
+ }
+ free(w);
+ return 0;
+}
diff --git a/src/lib9/run_unix.c b/src/lib9/run_unix.c
new file mode 100644
index 000000000..1b4c6de1b
--- /dev/null
+++ b/src/lib9/run_unix.c
@@ -0,0 +1,43 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd
+
+#include <u.h>
+#include <errno.h>
+#include <sys/wait.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+int
+runcmd(char **argv)
+{
+ int pid, pid1, status;
+
+ switch(pid = fork()) {
+ case -1:
+ return -1;
+ case 0:
+ execvp(argv[0], argv);
+ fprint(2, "exec %s: %r", argv[0]);
+ _exit(1);
+ }
+
+ while((pid1 = wait(&status)) < 0) {
+ if(errno != EINTR) {
+ werrstr("waitpid: %r");
+ return -1;
+ }
+ }
+ if(pid1 != pid) {
+ werrstr("unexpected pid in wait");
+ return -1;
+ }
+ if(!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ werrstr("unsuccessful exit status %#x", status);
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/src/lib9/run_windows.c b/src/lib9/run_windows.c
new file mode 100644
index 000000000..87875b42d
--- /dev/null
+++ b/src/lib9/run_windows.c
@@ -0,0 +1,83 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <windows.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include "win.h"
+
+int
+runcmd(char **argv)
+{
+ // Mostly copied from ../cmd/dist/windows.c.
+ // If there's a bug here, fix the logic there too.
+ int i, j, nslash;
+ Fmt fmt;
+ char *q;
+ WinRune *r;
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ DWORD code;
+
+ fmtstrinit(&fmt);
+ for(i=0; argv[i]; i++) {
+ if(i > 0)
+ fmtprint(&fmt, " ");
+ q = argv[i];
+ if(strstr(q, " ") || strstr(q, "\t") || strstr(q, "\"") || strstr(q, "\\\\") || (strlen(q) > 0 && q[strlen(q)-1] == '\\')) {
+ fmtprint(&fmt, "\"");
+ nslash = 0;
+ for(; *q; q++) {
+ if(*q == '\\') {
+ nslash++;
+ continue;
+ }
+ if(*q == '"') {
+ for(j=0; j<2*nslash+1; j++)
+ fmtprint(&fmt, "\\");
+ nslash = 0;
+ }
+ for(j=0; j<nslash; j++)
+ fmtprint(&fmt, "\\");
+ nslash = 0;
+ fmtprint(&fmt, "\"");
+ }
+ for(j=0; j<2*nslash; j++)
+ fmtprint(&fmt, "\\");
+ fmtprint(&fmt, "\"");
+ } else {
+ fmtprint(&fmt, "%s", q);
+ }
+ }
+
+ q = fmtstrflush(&fmt);
+ r = torune(q);
+ free(q);
+
+ memset(&si, 0, sizeof si);
+ si.cb = sizeof si;
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+ if(!CreateProcessW(nil, r, nil, nil, TRUE, 0, nil, nil, &si, &pi)) {
+ free(r);
+ return -1;
+ }
+
+ free(r);
+ if(WaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE) != 0)
+ return -1;
+ i = GetExitCodeProcess(pi.hProcess, &code);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ if(!i)
+ return -1;
+ if(code != 0) {
+ werrstr("unsuccessful exit status: %d", (int)code);
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/lib9/tempdir_plan9.c b/src/lib9/tempdir_plan9.c
new file mode 100644
index 000000000..9c14d6dd0
--- /dev/null
+++ b/src/lib9/tempdir_plan9.c
@@ -0,0 +1,54 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+
+char*
+mktempdir(void)
+{
+ char *p;
+ int i;
+
+ p = smprint("/tmp/go-link-XXXXXX");
+ for(i=0; i<1000; i++) {
+ sprint(p, "/tmp/go-link-%06x", nrand((1<<24)-1));
+ fd = create(p, OREAD|OEXCL, 0700|DMDIR);
+ if(fd >= 0) {
+ close(fd);
+ return p;
+ }
+ }
+ free(p);
+ return nil;
+}
+
+void
+removeall(char *p)
+{
+ int fd, n;
+ Dir *d;
+ char *q;
+
+ if(remove(p) >= 0)
+ return;
+ if((d = dirstat(p)) == nil)
+ return;
+ if(!(d->mode & DMDIR)) {
+ free(d);
+ return;
+ }
+ free(d);
+
+ if((fd = open(p, OREAD)) < 0)
+ return;
+ n = dirreadall(fd, &d);
+ close(fd);
+ for(i=0; i<n; i++) {
+ q = smprint("%s/%s", p, d[i].name);
+ removeall(q);
+ free(q);
+ }
+ free(d);
+}
diff --git a/src/lib9/tempdir_unix.c b/src/lib9/tempdir_unix.c
new file mode 100644
index 000000000..7b7e58b4d
--- /dev/null
+++ b/src/lib9/tempdir_unix.c
@@ -0,0 +1,52 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd
+
+#include <u.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+char*
+mktempdir(void)
+{
+ char *tmp, *p;
+
+ tmp = getenv("TMPDIR");
+ if(tmp == nil)
+ tmp = "/var/tmp";
+ p = smprint("%s/go-link-XXXXXX", tmp);
+ if(mkdtemp(p) == nil)
+ return nil;
+ return p;
+}
+
+void
+removeall(char *p)
+{
+ DIR *d;
+ struct dirent *dp;
+ char *q;
+ struct stat st;
+
+ if(stat(p, &st) < 0)
+ return;
+ if(!S_ISDIR(st.st_mode)) {
+ unlink(p);
+ return;
+ }
+
+ d = opendir(p);
+ while((dp = readdir(d)) != nil) {
+ if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+ continue;
+ q = smprint("%s/%s", p, dp->d_name);
+ removeall(q);
+ free(q);
+ }
+ closedir(d);
+ rmdir(p);
+}
diff --git a/src/lib9/tempdir_windows.c b/src/lib9/tempdir_windows.c
new file mode 100644
index 000000000..8e9322dc8
--- /dev/null
+++ b/src/lib9/tempdir_windows.c
@@ -0,0 +1,112 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <windows.h>
+#include <libc.h>
+#include "win.h"
+
+char*
+toutf(WinRune *r)
+{
+ Rune *r1;
+ int i, n;
+ char *p;
+
+ n = 0;
+ while(r[n] != '\0')
+ n++;
+ n++;
+ r1 = malloc(n*sizeof r1[0]);
+ for(i=0; i<n; i++)
+ r1[i] = r[i];
+ p = smprint("%S", r1);
+ free(r1);
+ return p;
+}
+
+WinRune*
+torune(char *p)
+{
+ int i, n;
+ Rune *r1;
+ WinRune *r;
+
+ r1 = runesmprint("%s", p);
+ n = 0;
+ while(r1[n] != '\0')
+ n++;
+ n++;
+ r = malloc(n*sizeof r[0]);
+ for(i=0; i<n; i++)
+ r[i] = r1[i];
+ free(r1);
+ return r;
+}
+
+char*
+mktempdir(void)
+{
+ WinRune buf[1024];
+ WinRune tmp[MAX_PATH];
+ WinRune golink[] = {'g', 'o', 'l', 'i', 'n', 'k', '\0'};
+ int n;
+
+ n = GetTempPathW(nelem(buf), buf);
+ if(n <= 0)
+ return nil;
+ buf[n] = '\0';
+
+ if(GetTempFileNameW(buf, golink, 0, tmp) == 0)
+ return nil;
+ DeleteFileW(tmp);
+ if(!CreateDirectoryW(tmp, nil))
+ return nil;
+
+ return toutf(tmp);
+}
+
+void
+removeall(char *p)
+{
+ WinRune *r, *r1;
+ DWORD attr;
+ char *q, *elem;
+ HANDLE h;
+ WIN32_FIND_DATAW data;
+
+ r = torune(p);
+ attr = GetFileAttributesW(r);
+ if(attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ DeleteFileW(r);
+ free(r);
+ return;
+ }
+
+ q = smprint("%s\\*", p);
+ r1 = torune(q);
+ free(q);
+ h = FindFirstFileW(r1, &data);
+ if(h == INVALID_HANDLE_VALUE)
+ goto done;
+ do{
+ q = toutf(data.cFileName);
+ elem = strrchr(q, '\\');
+ if(elem != nil) {
+ elem++;
+ if(strcmp(elem, ".") == 0 || strcmp(elem, "..") == 0) {
+ free(q);
+ continue;
+ }
+ }
+ removeall(q);
+ free(q);
+ }while(FindNextFileW(h, &data));
+ FindClose(h);
+
+done:
+ free(r1);
+ RemoveDirectoryW(r);
+ free(r);
+}
diff --git a/src/lib9/win.h b/src/lib9/win.h
new file mode 100644
index 000000000..d9df319af
--- /dev/null
+++ b/src/lib9/win.h
@@ -0,0 +1,8 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+typedef unsigned short WinRune;
+
+WinRune* torune(char*);
+char *toutf(WinRune*);