1From 0f88ba02c7bbcb91b428bfb294831769e521a81b Mon Sep 17 00:00:00 2001
2From: Michael Forney <mforney@mforney.org>
3Date: Sun, 19 Apr 2026 14:11:15 -0700
4Subject: [PATCH] implement umask builtin on unix
5
6---
7 exec.h | 2 +-
8 fns.h | 1 +
9 simple.c | 2 +-
10 unix.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
11 4 files changed, 49 insertions(+), 2 deletions(-)
12
13diff --git a/exec.h b/exec.h
14index 69b1004..ee8edab 100644
15--- a/exec.h
16+++ b/exec.h
17@@ -77,7 +77,7 @@ extern void (*builtinfunc(char *name))(void);
18 void execcd(void), execwhatis(void), execeval(void), execexec(void);
19 int execforkexec(void);
20 void execexit(void), execshift(void);
21-void execwait(void), execumask(void), execdot(void), execflag(void);
22+void execwait(void), execdot(void), execflag(void);
23 void execfunc(var*), execcmds(io*, char*, var*, redir*);
24 void startfunc(var*, word*, var*, redir*);
25
26diff --git a/fns.h b/fns.h
27index 339f08b..1644d1e 100644
28--- a/fns.h
29+++ b/fns.h
30@@ -45,6 +45,7 @@ int havewaitpid(int);
31 int idchr(int);
32 void inttoascii(char*, int);
33 void kinit(void);
34+int mapfd(int);
35 int match(char*, char*, int);
36 char* makepath(char*, char*);
37 void panic(char*, int);
38diff --git a/simple.c b/simple.c
39index 362b77b..1a9d27d 100644
40--- a/simple.c
41+++ b/simple.c
42@@ -287,7 +287,7 @@ execshift(void)
43 poplist();
44 }
45
46-static int
47+int
48 mapfd(int fd)
49 {
50 redir *rp;
51diff --git a/unix.c b/unix.c
52index 05d883c..cbb2054 100644
53--- a/unix.c
54+++ b/unix.c
55@@ -12,9 +12,12 @@
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <dirent.h>
59+#include <limits.h>
60+#include <sys/stat.h>
61 #include <sys/wait.h>
62
63 static void execfinit(void);
64+static void execumask(void);
65
66 builtin Builtin[] = {
67 "cd", execcd,
68@@ -24,6 +27,7 @@ builtin Builtin[] = {
69 "exit", execexit,
70 "shift", execshift,
71 "wait", execwait,
72+ "umask", execumask,
73 ".", execdot,
74 "flag", execflag,
75 "finit", execfinit,
76@@ -81,6 +85,48 @@ execfinit(void)
77 start(rdfns, 2, runq->local, runq->redir);
78 }
79
80+static int
81+octal(char *s)
82+{
83+ int n = 0;
84+
85+ while(n<INT_MAX/8 && '0'<=*s && *s<='7')
86+ n = n*8+*s++-'0';
87+ return *s=='\0' ? n : -1;
88+}
89+
90+static void
91+execumask(void)
92+{
93+ int m;
94+ struct io *out;
95+ char *e;
96+
97+ switch(count(runq->argv->words)){
98+ case 2:
99+ m = octal(runq->argv->words->next->word);
100+ if(m>=0 && m<=07777) {
101+ umask(m);
102+ break;
103+ }
104+ /* fallthrough */
105+ default:
106+ pfmt(err, "Usage: umask [umask]\n");
107+ setstatus("umask usage");
108+ poplist();
109+ return;
110+ case 1:
111+ umask(m = umask(0));
112+ out = openiofd(mapfd(1));
113+ pfmt(out, "%o\n", m);
114+ flushio(out);
115+ free(closeiostr(out));
116+ break;
117+ }
118+ setstatus("");
119+ poplist();
120+}
121+
122 static int
123 cmpenv(const void *aa, const void *ab)
124 {
125--
1262.49.0
127