Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "common.h"
2
#include <auth.h>
3
#include <ndb.h>
4
 
5
/*
6
 *  number of predefined fd's
7
 */
8
int nsysfile=3;
9
 
10
static char err[Errlen];
11
 
12
/*
13
 *  return the date
14
 */
15
extern char *
16
thedate(void)
17
{
18
	static char now[64];
19
	char *cp;
20
 
21
	strcpy(now, ctime(time(0)));
22
	cp = strchr(now, '\n');
23
	if(cp)
24
		*cp = 0;
25
	return now;
26
}
27
 
28
/*
29
 *  return the user id of the current user
30
 */
31
extern char *
32
getlog(void)
33
{
34
	static char user[64];
35
	int fd;
36
	int n;
37
 
38
	fd = open("/dev/user", 0);
39
	if(fd < 0)
40
		return nil;
41
	if((n=read(fd, user, sizeof(user)-1)) <= 0)
42
		return nil;
43
	close(fd);
44
	user[n] = 0;
45
	return user;
46
}
47
 
48
/*
49
 *  return the lock name (we use one lock per directory)
50
 */
51
static String *
52
lockname(char *path)
53
{
54
	String *lp;
55
	char *cp;
56
 
57
	/*
58
	 *  get the name of the lock file
59
	 */
60
	lp = s_new();
61
	cp = strrchr(path, '/');
62
	if(cp)
63
		s_nappend(lp, path, cp - path + 1);
64
	s_append(lp, "L.mbox");
65
 
66
	return lp;
67
}
68
 
69
int
70
syscreatelocked(char *path, int mode, int perm)
71
{
72
	return create(path, mode, DMEXCL|perm);
73
}
74
 
75
int
76
sysopenlocked(char *path, int mode)
77
{
78
/*	return open(path, OEXCL|mode);/**/
79
	return open(path, mode);		/* until system call is fixed */
80
}
81
 
82
int
83
sysunlockfile(int fd)
84
{
85
	return close(fd);
86
}
87
 
88
/*
89
 *  try opening a lock file.  If it doesn't exist try creating it.
90
 */
91
static int
92
openlockfile(Mlock *l)
93
{
94
	int fd;
95
	Dir *d;
96
	Dir nd;
97
	char *p;
98
 
99
	fd = open(s_to_c(l->name), OREAD);
100
	if(fd >= 0){
101
		l->fd = fd;
102
		return 0;
103
	}
104
 
105
	d = dirstat(s_to_c(l->name));
106
	if(d == nil){
107
		/* file doesn't exist */
108
		/* try creating it */
109
		fd = create(s_to_c(l->name), OREAD, DMEXCL|0666);
110
		if(fd >= 0){
111
			nulldir(&nd);
112
			nd.mode = DMEXCL|0666;
113
			if(dirfwstat(fd, &nd) < 0){
114
				/* if we can't chmod, don't bother */
115
				/* live without the lock but log it */
116
				syslog(0, "mail", "lock error: %s: %r", s_to_c(l->name));
117
				remove(s_to_c(l->name));
118
			}
119
			l->fd = fd;
120
			return 0;
121
		}
122
 
123
		/* couldn't create */
124
		/* do we have write access to the directory? */
125
		p = strrchr(s_to_c(l->name), '/');
126
		if(p != 0){
127
			*p = 0;
128
			fd = access(s_to_c(l->name), 2);
129
			*p = '/';
130
			if(fd < 0){
131
				/* live without the lock but log it */
132
				syslog(0, "mail", "lock error: %s: %r", s_to_c(l->name));
133
				return 0;
134
			}
135
		} else {
136
			fd = access(".", 2);
137
			if(fd < 0){
138
				/* live without the lock but log it */
139
				syslog(0, "mail", "lock error: %s: %r", s_to_c(l->name));
140
				return 0;
141
			}
142
		}
143
	} else
144
		free(d);
145
 
146
	return 1; /* try again later */
147
}
148
 
149
#define LSECS 5*60
150
 
151
/*
152
 *  Set a lock for a particular file.  The lock is a file in the same directory
153
 *  and has L. prepended to the name of the last element of the file name.
154
 */
155
extern Mlock *
156
syslock(char *path)
157
{
158
	Mlock *l;
159
	int tries;
160
 
161
	l = mallocz(sizeof(Mlock), 1);
162
	if(l == 0)
163
		return nil;
164
 
165
	l->name = lockname(path);
166
 
167
	/*
168
	 *  wait LSECS seconds for it to unlock
169
	 */
170
	for(tries = 0; tries < LSECS*2; tries++){
171
		switch(openlockfile(l)){
172
		case 0:
173
			return l;
174
		case 1:
175
			sleep(500);
176
			break;
177
		default:
178
			goto noway;
179
		}
180
	}
181
 
182
noway:
183
	s_free(l->name);
184
	free(l);
185
	return nil;
186
}
187
 
188
/*
189
 *  like lock except don't wait
190
 */
191
extern Mlock *
192
trylock(char *path)
193
{
194
	Mlock *l;
195
	char buf[1];
196
	int fd;
197
 
198
	l = malloc(sizeof(Mlock));
199
	if(l == 0)
200
		return 0;
201
 
202
	l->name = lockname(path);
203
	if(openlockfile(l) != 0){
204
		s_free(l->name);
205
		free(l);
206
		return 0;
207
	}
208
 
209
	/* fork process to keep lock alive */
210
	switch(l->pid = rfork(RFPROC)){
211
	default:
212
		break;
213
	case 0:
214
		fd = l->fd;
215
		for(;;){
216
			sleep(1000*60);
217
			if(pread(fd, buf, 1, 0) < 0)
218
				break;
219
		}
220
		_exits(0);
221
	}
222
	return l;
223
}
224
 
225
extern void
226
syslockrefresh(Mlock *l)
227
{
228
	char buf[1];
229
 
230
	pread(l->fd, buf, 1, 0);
231
}
232
 
233
extern void
234
sysunlock(Mlock *l)
235
{
236
	if(l == 0)
237
		return;
238
	if(l->name){
239
		s_free(l->name);
240
	}
241
	if(l->fd >= 0)
242
		close(l->fd);
243
	if(l->pid > 0)
244
		postnote(PNPROC, l->pid, "time to die");
245
	free(l);
246
}
247
 
248
/*
249
 *  Open a file.  The modes are:
250
 *
251
 *	l	- locked
252
 *	a	- set append permissions
253
 *	r	- readable
254
 *	w	- writable
255
 *	A	- append only (doesn't exist in Bio)
256
 */
257
extern Biobuf *
258
sysopen(char *path, char *mode, ulong perm)
259
{
260
	int sysperm;
261
	int sysmode;
262
	int fd;
263
	int docreate;
264
	int append;
265
	int truncate;
266
	Dir *d, nd;
267
	Biobuf *bp;
268
 
269
	/*
270
	 *  decode the request
271
	 */
272
	sysperm = 0;
273
	sysmode = -1;
274
	docreate = 0;
275
	append = 0;
276
	truncate = 0;
277
 	for(; mode && *mode; mode++)
278
		switch(*mode){
279
		case 'A':
280
			sysmode = OWRITE;
281
			append = 1;
282
			break;
283
		case 'c':
284
			docreate = 1;
285
			break;
286
		case 'l':
287
			sysperm |= DMEXCL;
288
			break;
289
		case 'a':
290
			sysperm |= DMAPPEND;
291
			break;
292
		case 'w':
293
			if(sysmode == -1)
294
				sysmode = OWRITE;
295
			else
296
				sysmode = ORDWR;
297
			break;
298
		case 'r':
299
			if(sysmode == -1)
300
				sysmode = OREAD;
301
			else
302
				sysmode = ORDWR;
303
			break;
304
		case 't':
305
			truncate = 1;
306
			break;
307
		default:
308
			break;
309
		}
310
	switch(sysmode){
311
	case OREAD:
312
	case OWRITE:
313
	case ORDWR:
314
		break;
315
	default:
316
		if(sysperm&DMAPPEND)
317
			sysmode = OWRITE;
318
		else
319
			sysmode = OREAD;
320
		break;
321
	}
322
 
323
	/*
324
	 *  create file if we need to
325
	 */
326
	if(truncate)
327
		sysmode |= OTRUNC;
328
	fd = open(path, sysmode);
329
	if(fd < 0){
330
		d = dirstat(path);
331
		if(d == nil){
332
			if(docreate == 0)
333
				return 0;
334
 
335
			fd = create(path, sysmode, sysperm|perm);
336
			if(fd < 0)
337
				return 0;
338
			nulldir(&nd);
339
			nd.mode = sysperm|perm;
340
			dirfwstat(fd, &nd);
341
		} else {
342
			free(d);
343
			return 0;
344
		}
345
	}
346
 
347
	bp = (Biobuf*)malloc(sizeof(Biobuf));
348
	if(bp == 0){
349
		close(fd);
350
		return 0;
351
	}
352
	memset(bp, 0, sizeof(Biobuf));
353
	Binit(bp, fd, sysmode&~OTRUNC);
354
 
355
	if(append)
356
		Bseek(bp, 0, 2);
357
	return bp;
358
}
359
 
360
/*
361
 *  close the file, etc.
362
 */
363
int
364
sysclose(Biobuf *bp)
365
{
366
	int rv;
367
 
368
	rv = Bterm(bp);
369
	close(Bfildes(bp));
370
	free(bp);
371
	return rv;
372
}
373
 
374
/*
375
 *  create a file
376
 */
377
int
378
syscreate(char *file, int mode, ulong perm)
379
{
380
	return create(file, mode, perm);
381
}
382
 
383
/*
384
 *  make a directory
385
 */
386
int
387
sysmkdir(char *file, ulong perm)
388
{
389
	int fd;
390
 
391
	if((fd = create(file, OREAD, DMDIR|perm)) < 0)
392
		return -1;
393
	close(fd);
394
	return 0;
395
}
396
 
397
/*
398
 *  change the group of a file
399
 */
400
int
401
syschgrp(char *file, char *group)
402
{
403
	Dir nd;
404
 
405
	if(group == 0)
406
		return -1;
407
	nulldir(&nd);
408
	nd.gid = group;
409
	return dirwstat(file, &nd);
410
}
411
 
412
extern int
413
sysdirreadall(int fd, Dir **d)
414
{
415
	return dirreadall(fd, d);
416
}
417
 
418
/*
419
 *  read in the system name
420
 */
421
extern char *
422
sysname_read(void)
423
{
424
	static char name[128];
425
	char *cp;
426
 
427
	cp = getenv("site");
428
	if(cp == 0 || *cp == 0)
429
		cp = alt_sysname_read();
430
	if(cp == 0 || *cp == 0)
431
		cp = "kremvax";
432
	strecpy(name, name+sizeof name, cp);
433
	return name;
434
}
435
extern char *
436
alt_sysname_read(void)
437
{
438
	static char name[128];
439
	int n, fd;
440
 
441
	fd = open("/dev/sysname", OREAD);
442
	if(fd < 0)
443
		return 0;
444
	n = read(fd, name, sizeof(name)-1);
445
	close(fd);
446
	if(n <= 0)
447
		return 0;
448
	name[n] = 0;
449
	return name;
450
}
451
 
452
/*
453
 *  get all names
454
 */
455
extern char**
456
sysnames_read(void)
457
{
458
	static char **namev;
459
	Ndbtuple *t, *nt;
460
	int n;
461
	char *cp;
462
 
463
	if(namev)
464
		return namev;
465
 
466
	free(csgetvalue(0, "sys", alt_sysname_read(), "dom", &t));
467
 
468
	n = 0;
469
	for(nt = t; nt; nt = nt->entry)
470
		if(strcmp(nt->attr, "dom") == 0)
471
			n++;
472
 
473
	namev = (char**)malloc(sizeof(char *)*(n+3));
474
 
475
	if(namev){
476
		n = 0;
477
		namev[n++] = strdup(sysname_read());
478
		cp = alt_sysname_read();
479
		if(cp)
480
			namev[n++] = strdup(cp);
481
		for(nt = t; nt; nt = nt->entry)
482
			if(strcmp(nt->attr, "dom") == 0)
483
				namev[n++] = strdup(nt->val);
484
		namev[n] = 0;
485
	}
486
	if(t)
487
		ndbfree(t);
488
 
489
	return namev;
490
}
491
 
492
/*
493
 *  read in the domain name
494
 */
495
extern char *
496
domainname_read(void)
497
{
498
	char **namev;
499
 
500
	for(namev = sysnames_read(); *namev; namev++)
501
		if(strchr(*namev, '.'))
502
			return *namev;
503
	return 0;
504
}
505
 
506
/*
507
 *  return true if the last error message meant file
508
 *  did not exist.
509
 */
510
extern int
511
e_nonexistent(void)
512
{
513
	rerrstr(err, sizeof(err));
514
	return strcmp(err, "file does not exist") == 0;
515
}
516
 
517
/*
518
 *  return true if the last error message meant file
519
 *  was locked.
520
 */
521
extern int
522
e_locked(void)
523
{
524
	rerrstr(err, sizeof(err));
525
	return strcmp(err, "open/create -- file is locked") == 0;
526
}
527
 
528
/*
529
 *  return the length of a file
530
 */
531
extern long
532
sysfilelen(Biobuf *fp)
533
{
534
	Dir *d;
535
	long rv;
536
 
537
	d = dirfstat(Bfildes(fp));
538
	if(d == nil)
539
		return -1;
540
	rv = d->length;
541
	free(d);
542
	return rv;
543
}
544
 
545
/*
546
 *  remove a file
547
 */
548
extern int
549
sysremove(char *path)
550
{
551
	return remove(path);
552
}
553
 
554
/*
555
 *  rename a file, fails unless both are in the same directory
556
 */
557
extern int
558
sysrename(char *old, char *new)
559
{
560
	Dir d;
561
	char *obase;
562
	char *nbase;
563
 
564
	obase = strrchr(old, '/');
565
	nbase = strrchr(new, '/');
566
	if(obase){
567
		if(nbase == 0)
568
			return -1;
569
		if(strncmp(old, new, obase-old) != 0)
570
			return -1;
571
		nbase++;
572
	} else {
573
		if(nbase)
574
			return -1;
575
		nbase = new;
576
	}
577
	nulldir(&d);
578
	d.name = nbase;
579
	return dirwstat(old, &d);
580
}
581
 
582
/*
583
 *  see if a file exists
584
 */
585
extern int
586
sysexist(char *file)
587
{
588
	Dir	*d;
589
 
590
	d = dirstat(file);
591
	if(d == nil)
592
		return 0;
593
	free(d);
594
	return 1;
595
}
596
 
597
/*
598
 *  return nonzero if file is a directory
599
 */
600
extern int
601
sysisdir(char *file)
602
{
603
	Dir	*d;
604
	int	rv;
605
 
606
	d = dirstat(file);
607
	if(d == nil)
608
		return 0;
609
	rv = d->mode & DMDIR;
610
	free(d);
611
	return rv;
612
}
613
 
614
/*
615
 * kill a process or process group
616
 */
617
 
618
static int
619
stomp(int pid, char *file)
620
{
621
	char name[64];
622
	int fd;
623
 
624
	snprint(name, sizeof(name), "/proc/%d/%s", pid, file);
625
	fd = open(name, 1);
626
	if(fd < 0)
627
		return -1;
628
	if(write(fd, "die: yankee pig dog\n", sizeof("die: yankee pig dog\n") - 1) <= 0){
629
		close(fd);
630
		return -1;
631
	}
632
	close(fd);
633
	return 0;
634
 
635
}
636
 
637
/*
638
 *  kill a process
639
 */
640
extern int
641
syskill(int pid)
642
{
643
	return stomp(pid, "note");
644
 
645
}
646
 
647
/*
648
 *  kill a process group
649
 */
650
extern int
651
syskillpg(int pid)
652
{
653
	return stomp(pid, "notepg");
654
}
655
 
656
extern int
657
sysdetach(void)
658
{
659
	if(rfork(RFENVG|RFNAMEG|RFNOTEG) < 0) {
660
		werrstr("rfork failed");
661
		return -1;
662
	}
663
	return 0;
664
}
665
 
666
/*
667
 *  catch a write on a closed pipe
668
 */
669
static int *closedflag;
670
static int
671
catchpipe(void *a, char *msg)
672
{
673
	static char *foo = "sys: write on closed pipe";
674
 
675
	USED(a);
676
	if(strncmp(msg, foo, strlen(foo)) == 0){
677
		if(closedflag)
678
			*closedflag = 1;
679
		return 1;
680
	}
681
	return 0;
682
}
683
void
684
pipesig(int *flagp)
685
{
686
	closedflag = flagp;
687
	atnotify(catchpipe, 1);
688
}
689
void
690
pipesigoff(void)
691
{
692
	atnotify(catchpipe, 0);
693
}
694
 
695
void
696
exit(int i)
697
{
698
	char buf[32];
699
 
700
	if(i == 0)
701
		exits(0);
702
	snprint(buf, sizeof(buf), "%d", i);
703
	exits(buf);
704
}
705
 
706
static int
707
islikeatty(int fd)
708
{
709
	char buf[64];
710
 
711
	if(fd2path(fd, buf, sizeof buf) != 0)
712
		return 0;
713
 
714
	/* might be /mnt/term/dev/cons */
715
	return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
716
}
717
 
718
extern int
719
holdon(void)
720
{
721
	int fd;
722
 
723
	if(!islikeatty(0))
724
		return -1;
725
 
726
	fd = open("/dev/consctl", OWRITE);
727
	write(fd, "holdon", 6);
728
 
729
	return fd;
730
}
731
 
732
extern int
733
sysopentty(void)
734
{
735
	return open("/dev/cons", ORDWR);
736
}
737
 
738
extern void
739
holdoff(int fd)
740
{
741
	write(fd, "holdoff", 7);
742
	close(fd);
743
}
744
 
745
extern int
746
sysfiles(void)
747
{
748
	return 128;
749
}
750
 
751
/*
752
 *  expand a path relative to the user's mailbox directory
753
 *
754
 *  if the path starts with / or ./, don't change it
755
 *
756
 */
757
extern String *
758
mboxpath(char *path, char *user, String *to, int dot)
759
{
760
	if (dot || *path=='/' || strncmp(path, "./", 2) == 0
761
			      || strncmp(path, "../", 3) == 0) {
762
		to = s_append(to, path);
763
	} else {
764
		to = s_append(to, MAILROOT);
765
		to = s_append(to, "/box/");
766
		to = s_append(to, user);
767
		to = s_append(to, "/");
768
		to = s_append(to, path);
769
	}
770
	return to;
771
}
772
 
773
extern String *
774
mboxname(char *user, String *to)
775
{
776
	return mboxpath("mbox", user, to, 0);
777
}
778
 
779
extern String *
780
deadletter(String *to)		/* pass in sender??? */
781
{
782
	char *cp;
783
 
784
	cp = getlog();
785
	if(cp == 0)
786
		return 0;
787
	return mboxpath("dead.letter", cp, to, 0);
788
}
789
 
790
char *
791
homedir(char *user)
792
{
793
	USED(user);
794
	return getenv("home");
795
}
796
 
797
String *
798
readlock(String *file)
799
{
800
	char *cp;
801
 
802
	cp = getlog();
803
	if(cp == 0)
804
		return 0;
805
	return mboxpath("reading", cp, file, 0);
806
}
807
 
808
String *
809
username(String *from)
810
{
811
	int n;
812
	Biobuf *bp;
813
	char *p, *q;
814
	String *s;
815
 
816
	bp = Bopen("/adm/keys.who", OREAD);
817
	if(bp == 0)
818
		bp = Bopen("/adm/netkeys.who", OREAD);
819
	if(bp == 0)
820
		return 0;
821
 
822
	s = 0;
823
	n = strlen(s_to_c(from));
824
	for(;;) {
825
		p = Brdline(bp, '\n');
826
		if(p == 0)
827
			break;
828
		p[Blinelen(bp)-1] = 0;
829
		if(strncmp(p, s_to_c(from), n))
830
			continue;
831
		p += n;
832
		if(*p != ' ' && *p != '\t')	/* must be full match */
833
			continue;
834
		while(*p && (*p == ' ' || *p == '\t'))
835
				p++;
836
		if(*p == 0)
837
			continue;
838
		for(q = p; *q; q++)
839
			if(('0' <= *q && *q <= '9') || *q == '<')
840
				break;
841
		while(q > p && q[-1] != ' ' && q[-1] != '\t')
842
			q--;
843
		while(q > p && (q[-1] == ' ' || q[-1] == '\t'))
844
			q--;
845
		*q = 0;
846
		s = s_new();
847
		s_append(s, "\"");
848
		s_append(s, p);
849
		s_append(s, "\"");
850
		break;
851
	}
852
	Bterm(bp);
853
	return s;
854
}
855
 
856
char *
857
remoteaddr(int fd, char *dir)
858
{
859
	char buf[128], *p;
860
	int n;
861
 
862
	if(dir == 0){
863
		if(fd2path(fd, buf, sizeof(buf)) != 0)
864
			return "";
865
 
866
		/* parse something of the form /net/tcp/nnnn/data */
867
		p = strrchr(buf, '/');
868
		if(p == 0)
869
			return "";
870
		strncpy(p+1, "remote", sizeof(buf)-(p-buf)-2);
871
	} else
872
		snprint(buf, sizeof buf, "%s/remote", dir);
873
	buf[sizeof(buf)-1] = 0;
874
 
875
	fd = open(buf, OREAD);
876
	if(fd < 0)
877
		return "";
878
	n = read(fd, buf, sizeof(buf)-1);
879
	close(fd);
880
	if(n > 0){
881
		buf[n] = 0;
882
		p = strchr(buf, '!');
883
		if(p)
884
			*p = 0;
885
		return strdup(buf);
886
	}
887
	return "";
888
}
889
 
890
//  create a file and 
891
//	1) ensure the modes we asked for
892
//	2) make gid == uid
893
static int
894
docreate(char *file, int perm)
895
{
896
	int fd;
897
	Dir ndir;
898
	Dir *d;
899
 
900
	//  create the mbox
901
	fd = create(file, OREAD, perm);
902
	if(fd < 0){
903
		fprint(2, "couldn't create %s\n", file);
904
		return -1;
905
	}
906
	d = dirfstat(fd);
907
	if(d == nil){
908
		fprint(2, "couldn't stat %s\n", file);
909
		return -1;
910
	}
911
	nulldir(&ndir);
912
	ndir.mode = perm;
913
	ndir.gid = d->uid;
914
	if(dirfwstat(fd, &ndir) < 0)
915
		fprint(2, "couldn't chmod %s: %r\n", file);
916
	close(fd);
917
	return 0;
918
}
919
 
920
//  create a mailbox
921
int
922
creatembox(char *user, char *folder)
923
{
924
	char *p;
925
	String *mailfile;
926
	char buf[512];
927
	Mlock *ml;
928
 
929
	mailfile = s_new();
930
	if(folder == 0)
931
		mboxname(user, mailfile);
932
	else {
933
		snprint(buf, sizeof(buf), "%s/mbox", folder);
934
		mboxpath(buf, user, mailfile, 0);
935
	}
936
 
937
	// don't destroy existing mailbox
938
	if(access(s_to_c(mailfile), 0) == 0){
939
		fprint(2, "mailbox already exists\n");
940
		return -1;
941
	}
942
	fprint(2, "creating new mbox: %s\n", s_to_c(mailfile));
943
 
944
	//  make sure preceding levels exist
945
	for(p = s_to_c(mailfile); p; p++) {
946
		if(*p == '/')	/* skip leading or consecutive slashes */
947
			continue;
948
		p = strchr(p, '/');
949
		if(p == 0)
950
			break;
951
		*p = 0;
952
		if(access(s_to_c(mailfile), 0) != 0){
953
			if(docreate(s_to_c(mailfile), DMDIR|0711) < 0)
954
				return -1;
955
		}
956
		*p = '/';
957
	}
958
 
959
	//  create the mbox
960
	if(docreate(s_to_c(mailfile), 0622|DMAPPEND|DMEXCL) < 0)
961
		return -1;
962
 
963
	/*
964
	 *  create the lock file if it doesn't exist
965
	 */
966
	ml = trylock(s_to_c(mailfile));
967
	if(ml != nil)
968
		sysunlock(ml);
969
 
970
	return 0;
971
}