plan9fox/sys/src/cmd/screenlock.c
Ori Bernstein 319e625be0 screenlock: use initdisplay(2), top the window (thanks stuart morrow)
Screenlock should use libdraw(2) to init the display
and create the window, instead of looking at the screen
file directly. Also, to prevent new windows from popping
up over screenlock, bring it to the top periodically.
2021-01-28 18:07:48 -08:00

224 lines
4.1 KiB
C

/* screenlock - lock a terminal */
#include <u.h>
#include <libc.h>
#include <libsec.h>
#include <draw.h>
#include <thread.h>
#include <auth.h>
char pic[] = "/lib/bunny.bit";
int debug;
long blank;
void
usage(void)
{
fprint(2, "usage: %s [-d]\n", argv0);
exits("usage");
}
/* ^D, Delete, Enter, Backspace, ^U */
void
readline(char *buf, int nbuf)
{
char c;
int i;
i = 0;
while(i < nbuf-1){
if(read(0, &c, 1) != 1 || c == '\04' || c == '\177'){
i = 0;
break;
} else if(c == '\n')
break;
else if(c == '\b' && i > 0)
--i;
else if(c == ('u' & 037))
i = 0;
else
buf[i++] = c;
blank = time(0);
}
buf[i] = '\0';
}
void
checkpassword(void)
{
char buf[256];
AuthInfo *ai;
for(;;){
memset(buf, 0, sizeof buf);
readline(buf, sizeof buf);
border(screen, screen->r, 8, display->white, ZP);
flushimage(display, 1);
/* authenticate */
ai = auth_userpasswd(getuser(), buf);
if(ai != nil && ai->cap != nil)
break;
rerrstr(buf, sizeof buf);
if(strncmp(buf, "needkey ", 8) == 0)
break;
auth_freeAI(ai);
border(screen, screen->r, 8, display->black, ZP);
flushimage(display, 1);
}
auth_freeAI(ai);
memset(buf, 0, sizeof buf);
}
void
blanker(void *)
{
int fd;
if((fd = open("/dev/mousectl", OWRITE)) < 0)
return;
for(;;){
if(blank != 0 && ((ulong)time(0) - (ulong)blank) >= 5){
blank = 0;
write(fd, "blank", 5);
}
sleep(1000);
}
}
void
grabmouse(void*)
{
int fd, x, y;
char ibuf[256], obuf[256];
if((fd = open("/dev/mouse", ORDWR)) < 0)
sysfatal("can't open /dev/mouse: %r");
snprint(obuf, sizeof obuf, "m %d %d",
screen->r.min.x + Dx(screen->r)/2,
screen->r.min.y + Dy(screen->r)/2);
while(read(fd, ibuf, sizeof ibuf) > 0){
ibuf[12] = 0;
ibuf[24] = 0;
x = atoi(ibuf+1);
y = atoi(ibuf+13);
if(x != screen->r.min.x + Dx(screen->r)/2 ||
y != screen->r.min.y + Dy(screen->r)/2){
if(!debug)
fprint(fd, "%s", obuf);
blank = time(0);
}
}
}
void
top(void*)
{
int fd;
if((fd = open("/dev/wctl", OWRITE)) < 0)
return;
for(;;){
write(fd, "current", 7);
sleep(500);
}
}
void
lockscreen(void)
{
enum { Cursorlen = 2*4 + 2*2*16 };
char *s;
char newcmd[128], cbuf[Cursorlen];
int fd, dx, dy;
Image *i;
Point p;
Rectangle r;
Tm *tm;
display = initdisplay(nil, nil, nil);
if(display == nil)
sysfatal("can't open /dev/draw: %r");
r = display->image->r;
snprint(newcmd, sizeof newcmd, "-r %d %d %d %d",
r.min.x, r.min.y, r.max.x, r.max.y);
closedisplay(display);
newwindow(newcmd);
if((fd = open("/dev/consctl", OWRITE)) >= 0)
write(fd, "rawon", 5);
if((fd = open("/dev/cons", OREAD)) < 0)
sysfatal("can't open cons: %r");
dup(fd, 0);
if((fd = open("/dev/cons", OWRITE)) < 0)
sysfatal("can't open cons: %r");
dup(fd, 1);
dup(fd, 2);
if(initdraw(nil, nil, "screenlock") < 0)
sysfatal("initdraw failed");
screen = _screen->image; /* fullscreen */
if((fd = open(pic, OREAD)) >= 0){
if((i = readimage(display, fd, 0)) != nil){
r = screen->r;
p = Pt(r.max.x / 2, r.max.y * 2 / 3);
dx = (Dx(screen->r) - Dx(i->r)) / 2;
r.min.x += dx;
r.max.x -= dx;
dy = (Dy(screen->r) - Dy(i->r)) / 2;
r.min.y += dy;
r.max.y -= dy;
draw(screen, screen->r, display->black, nil, ZP);
draw(screen, r, i, nil, i->r.min);
}
close(fd);
/* identify the user on screen, centered */
tm = localtime(time(&blank));
s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min);
p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0));
string(screen, p, screen->display->white, ZP, font, s);
}
flushimage(display, 1);
/* screen is now open and covered. grab mouse and hold on tight */
procrfork(top, nil, 8*1024, RFFDG);
procrfork(grabmouse, nil, 8*1024, RFFDG);
procrfork(blanker, nil, 8*1024, RFFDG);
/* clear the cursor */
if((fd = open("/dev/cursor", OWRITE)) >= 0){
memset(cbuf, 0, sizeof cbuf);
write(fd, cbuf, sizeof cbuf);
/* leave it open */
}
}
void
threadmain(int argc, char *argv[])
{
ARGBEGIN{
case 'd':
debug++;
break;
default:
usage();
}ARGEND
if(argc != 0)
usage();
lockscreen();
checkpassword();
threadexitsall(nil);
}