]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/screenlock.c
screenlock: don't poll to top window (thanks Stuart Morrow)
[plan9front.git] / sys / src / cmd / screenlock.c
1 /* screenlock - lock a terminal */
2 #include <u.h>
3 #include <libc.h>
4 #include <libsec.h>
5 #include <draw.h>
6 #include <thread.h>
7 #include <auth.h>
8
9 char pic[] = "/lib/bunny.bit";
10 int debug;
11 long blank;
12
13 void
14 usage(void)
15 {
16         fprint(2, "usage: %s [-d]\n", argv0);
17         exits("usage");
18 }
19
20 /* ^D, Delete, Enter, Backspace, ^U */
21 void
22 readline(char *buf, int nbuf)
23 {
24         char c;
25         int i;
26
27         i = 0;
28         while(i < nbuf-1){
29                 if(read(0, &c, 1) != 1 || c == '\04' || c == '\177'){
30                         i = 0;
31                         break;
32                 } else if(c == '\n')
33                         break;
34                 else if(c == '\b' && i > 0)
35                         --i;
36                 else if(c == ('u' & 037))
37                         i = 0;
38                 else
39                         buf[i++] = c;
40                 blank = time(0);
41         }
42         buf[i] = '\0';
43 }
44
45 void
46 checkpassword(void)
47 {
48         char buf[256];
49         AuthInfo *ai;
50
51         for(;;){
52                 memset(buf, 0, sizeof buf);
53                 readline(buf, sizeof buf);
54
55                 border(screen, screen->r, 8, display->white, ZP);
56                 flushimage(display, 1);
57
58                 /* authenticate */
59                 ai = auth_userpasswd(getuser(), buf);
60                 if(ai != nil && ai->cap != nil)
61                         break;
62
63                 rerrstr(buf, sizeof buf);
64                 if(strncmp(buf, "needkey ", 8) == 0)
65                         break;
66
67                 auth_freeAI(ai);
68                 border(screen, screen->r, 8, display->black, ZP);
69                 flushimage(display, 1);
70         }
71         auth_freeAI(ai);
72         memset(buf, 0, sizeof buf);
73 }
74
75 void
76 blanker(void *)
77 {
78         int fd;
79
80         if((fd = open("/dev/mousectl", OWRITE)) < 0)
81                 return;
82
83         for(;;){
84                 if(blank != 0 && ((ulong)time(0) - (ulong)blank) >= 5){
85                         blank = 0;
86                         write(fd, "blank", 5);
87                 }
88                 sleep(1000);
89         }
90 }
91
92 void
93 grabmouse(void*)
94 {
95         int fd, x, y;
96         char ibuf[256], obuf[256];
97
98         if((fd = open("/dev/mouse", ORDWR)) < 0)
99                 sysfatal("can't open /dev/mouse: %r");
100
101         snprint(obuf, sizeof obuf, "m %d %d",
102                 screen->r.min.x + Dx(screen->r)/2,
103                 screen->r.min.y + Dy(screen->r)/2);
104
105         while(read(fd, ibuf, sizeof ibuf) > 0){
106                 ibuf[12] = 0;
107                 ibuf[24] = 0;
108                 x = atoi(ibuf+1);
109                 y = atoi(ibuf+13);
110                 if(x != screen->r.min.x + Dx(screen->r)/2 ||
111                    y != screen->r.min.y + Dy(screen->r)/2){
112                         if(!debug)
113                                 fprint(fd, "%s", obuf);
114                         blank = time(0);
115                 }
116         }
117 }
118
119 void
120 top(void*)
121 {
122         int fd, n;
123         char buf[128];
124
125         if((fd = open("/dev/wctl", ORDWR)) < 0)
126                 return;
127
128         for(;;){
129                 n = read(fd, buf, sizeof buf-1);
130                 if(n > 48){
131                         buf[n] = '\0';
132                         if(strstr(buf+48, "notcurrent"))
133                                 write(fd, "current", 7);
134                 }
135         }
136 }
137
138 void
139 lockscreen(void)
140 {
141         enum { Cursorlen = 2*4 + 2*2*16 };
142         char *s;
143         char newcmd[128], cbuf[Cursorlen];
144         int fd, dx, dy;
145         Image *i;
146         Point p;
147         Rectangle r;
148         Tm *tm;
149
150         display = initdisplay(nil, nil, nil);
151         if(display == nil)
152                 sysfatal("can't open /dev/draw: %r");
153         r = display->image->r;
154         snprint(newcmd, sizeof newcmd, "-r %d %d %d %d",
155                 r.min.x, r.min.y, r.max.x, r.max.y);
156         closedisplay(display);
157
158         newwindow(newcmd);
159         if((fd = open("/dev/consctl", OWRITE)) >= 0)
160                 write(fd, "rawon", 5);
161
162         if((fd = open("/dev/cons", OREAD)) < 0)
163                 sysfatal("can't open cons: %r");
164         dup(fd, 0);
165
166         if((fd = open("/dev/cons", OWRITE)) < 0)
167                 sysfatal("can't open cons: %r");
168         dup(fd, 1);
169         dup(fd, 2);
170
171         if(initdraw(nil, nil, "screenlock") < 0)
172                 sysfatal("initdraw failed");
173         screen = _screen->image;        /* fullscreen */
174
175         if((fd = open(pic, OREAD)) >= 0){
176                 if((i = readimage(display, fd, 0)) != nil){
177                         r = screen->r;
178                         p = Pt(r.max.x / 2, r.max.y * 2 / 3); 
179                         dx = (Dx(screen->r) - Dx(i->r)) / 2;
180                         r.min.x += dx;
181                         r.max.x -= dx;
182                         dy = (Dy(screen->r) - Dy(i->r)) / 2;
183                         r.min.y += dy;
184                         r.max.y -= dy;
185                         draw(screen, screen->r, display->black, nil, ZP);
186                         draw(screen, r, i, nil, i->r.min);
187                 }
188                 close(fd);
189
190                 /* identify the user on screen, centered */
191                 tm = localtime(time(&blank));
192                 s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min);
193                 p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0));
194                 stringbg(screen, p, display->white, ZP, font, s, display->black, ZP);
195         }
196         flushimage(display, 1);
197
198         /* screen is now open and covered.  grab mouse and hold on tight */
199         procrfork(top, nil, 8*1024, RFFDG);
200         procrfork(grabmouse, nil, 8*1024, RFFDG);
201         procrfork(blanker, nil, 8*1024, RFFDG);
202
203         /* clear the cursor */
204         if((fd = open("/dev/cursor", OWRITE)) >= 0){
205                 memset(cbuf, 0, sizeof cbuf);
206                 write(fd, cbuf, sizeof cbuf);
207                 /* leave it open */
208         }
209 }
210
211 void
212 threadmain(int argc, char *argv[])
213 {
214         ARGBEGIN{
215         case 'd':
216                 debug++;
217                 break;
218         default:
219                 usage();
220         }ARGEND
221
222         if(argc != 0)
223                 usage();
224
225         lockscreen();
226         checkpassword();
227         threadexitsall(nil);
228 }