libsys.c 14 KB

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