Whamcloud - gitweb
Ignore generated files.
[fs/lustre-release.git] / libsysio / src / init.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
8  *    The redistribution of this Cplant(TM) source code is subject to the
9  *    terms of the GNU Lesser General Public License
10  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
11  *
12  *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
13  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14  *    license for use of this work by or on behalf of the US Government.
15  *    Export of this program may require a license from the United States
16  *    Government.
17  */
18
19 /*
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  * 
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  * 
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33  *
34  * Questions or comments about this library should be sent to:
35  *
36  * Lee Ward
37  * Sandia National Laboratories, New Mexico
38  * P.O. Box 5800
39  * Albuquerque, NM 87185-1110
40  *
41  * lee@sandia.gov
42  */
43
44 #define _BSD_SOURCE
45
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <limits.h>
51 #include <assert.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <fcntl.h>
55 #include <sys/uio.h>
56 #include <sys/queue.h>
57
58 #include "xtio.h"
59 #include "sysio.h"
60 #include "inode.h"
61 #include "fs.h"
62 #include "mount.h"
63 #include "file.h"
64 #include "dev.h"
65
66 #ifdef STDFD_DEV
67 #include "stdfd.h"
68 #endif
69
70 /*
71  * The namespace assembly buffer passes args with a `name'=`value'
72  * syntax. We use the following to record that in various
73  * routines below.
74  */
75 struct named_argument {
76         const char *name;                               /* arg name */
77         char    *value;                                 /* arg value */
78 };
79
80 /*
81  * White space characters.
82  */
83 #define IGNORE_WHITE            " \t\r\n"
84
85 /*
86  * Sysio library initialization. Must be called before anything else in the
87  * library.
88  */
89 int
90 _sysio_init()
91 {
92         int     err;
93 #ifdef WITH_SOCKETS
94         int     _sysio_sockets_init(void);
95 #endif
96
97         err = _sysio_ioctx_init();
98         if (err)
99                 goto error;
100         err = _sysio_i_init();
101         if (err)
102                 goto error;
103         err = _sysio_mount_init();
104         if (err)
105                 goto error;
106
107         err = _sysio_dev_init();
108         if (err)
109                 goto error;
110 #ifdef STDFD_DEV
111         err = _sysio_stdfd_init();
112         if (err)
113                 goto error;
114 #endif
115 #ifdef WITH_SOCKETS
116         err = _sysio_sockets_init();
117         if (err)
118                 goto error;
119 #endif
120
121         goto out;
122 error:
123         errno = -err;
124 out:
125         /*
126          * Unlike all other _sysio routines, this one returns with errno
127          * set. It also returns the error, as usual.
128          */
129         return err;
130 }
131
132 /*
133  * Sysio library shutdown.
134  */
135 void
136 _sysio_shutdown()
137 {
138
139         if (!(_sysio_fd_close_all() == 0 &&
140               _sysio_unmount_all() == 0))
141                         abort();
142
143 #if ZERO_SUM_MEMORY
144         _sysio_fd_shutdown();
145         _sysio_i_shutdown();
146         _sysio_fssw_shutdown();
147 #endif
148 }
149
150 /* 
151  * (kind of)Duplicates strtok function.
152  *
153  * Given a buffer, returns the longest string
154  * that does not contain any delim characters.  Will
155  * remove ws and any characters in the ignore string.  
156  * Returns the token.  
157  *
158  * The parameter controlling acceptance controls whether a positive
159  * match for some delimiter be made or not. If set, then either a delimiter
160  * or NUL character is success.
161  *
162  */
163 static const char *
164 get_token(const char *buf,
165           int accepts,
166           const char *delim,
167           const char *ignore,
168           char *tbuf)
169 {
170         char    c;
171         int     escape, quote;
172
173         /* 
174          * Find the first occurance of delim, recording how many
175          * characters lead up to it.  Ignore indicated characters.
176          */
177         escape = quote = 0;
178         while ((c = *buf) != '\0') {
179                 buf++;
180                 if (!escape) {
181                         if (c == '\\') {
182                                 escape = 1;
183                                 continue;
184                         }
185                         if (c == '\"') {
186                                 quote ^= 1;
187                                 continue;
188                         }
189                         if (!quote) {
190                                 if (strchr(delim, c) != NULL) {
191                                         accepts = 1;
192                                         break;
193                                 }
194                                 if (strchr(ignore, c) != NULL)
195                                         continue;
196                         }
197                 } else
198                         escape = 0;
199                 *tbuf++ = c;
200         }
201         if (!accepts)
202                 return NULL;
203         *tbuf = '\0';                                           /* NUL term */
204         return buf;
205 }
206
207 /*
208  * Parse and record named arguments given as `name = value', comma-separated
209  * pairs.
210  *
211  * NB: Alters the passed buffer.
212  */
213 static char *
214 get_args(char *buf, struct named_argument *vec)
215 {
216         char    *nxt;
217         char    *name, *value;
218         struct named_argument *v;
219
220         for (;;) {
221                 nxt = (char *)get_token(buf, 1, "=,", IGNORE_WHITE, name = buf);
222                 if (!nxt ||
223                     (nxt != buf && *name == '\0' && buf + strlen(buf) == nxt)) {
224                         buf = NULL;
225                         break;
226                 }
227                 if (*name == '\0')
228                         break;
229                 buf = (char *)get_token(nxt, 1, ",", IGNORE_WHITE, value = nxt);
230                 if (*value == '\0')
231                         value = NULL;
232                 for (v = vec; v->name; v++)
233                         if (strcmp(v->name, name) == 0)
234                                 break;
235                 if (!v->name)
236                         return NULL;
237                 v->value = value;
238         }
239
240         return buf;
241 }
242
243 static int
244 parse_mm(const char *s, dev_t *devp)
245 {
246         unsigned long ul;
247         char    *cp;
248         dev_t   dev;
249
250         ul = strtoul(s, &cp, 0);
251         if (*cp != '+' || ul > USHRT_MAX)
252                 return -EINVAL;
253         dev = ul << 16;
254         s = (const char *)++cp;
255         ul = strtoul(s, &cp, 0);
256         if (*cp != '\0' || ul > USHRT_MAX)
257                 return -EINVAL;
258         dev |= ul & 0xffff;
259         *devp = dev;
260         return 0;
261 }
262
263 /*
264  * Performs the creat command for the namespace assembly
265  *
266  * NB: Alters the passed buffer.
267  */
268 static int 
269 do_creat(char *args) 
270 {
271         size_t  len;
272         struct named_argument v[] = {
273                 { "ft",         NULL },                 /* file type */
274                 { "nm",         NULL },                 /* name */
275                 { "pm",         NULL },                 /* permissions */
276                 { "ow",         NULL },                 /* owner */
277                 { "gr",         NULL },                 /* group */
278                 { "mm",         NULL },                 /* major + minor */
279                 { "str",        NULL },                 /* file data */
280                 { NULL,         NULL }
281         };
282         const char *cp;
283         long    perms;
284         long    owner, group;
285         struct pnode *dir, *pno;
286         mode_t  mode;
287         struct intent intent;
288         dev_t   dev;
289         int     err;
290   
291         len = strlen(args);
292         if (get_args(args, v) - args != (ssize_t )len ||
293             !(v[0].value &&
294               v[1].value &&
295               v[2].value))
296                 return -EINVAL;
297         perms = strtol(v[2].value, (char **)&cp, 0);
298         if (*cp ||
299             perms < 0 ||
300             (perms == LONG_MAX && errno == ERANGE) ||
301             ((unsigned)perms & ~07777))
302                 return -EINVAL;
303         if (v[3].value) {
304                 owner = strtol(v[3].value, (char **)&cp, 0);
305                 if (*cp ||
306                     ((owner == LONG_MIN || owner == LONG_MAX)
307                      && errno == ERANGE))
308                         return -EINVAL;
309         } else
310                 owner = getuid();
311         if (v[4].value) {
312                 group = strtol(v[4].value, (char **)&cp, 0);
313                 if (*cp ||
314                     ((group == LONG_MIN || group == LONG_MAX) &&
315                      errno == ERANGE))
316                         return -EINVAL;
317         } else
318                 group = getegid();
319
320         if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
321                 return -ENOENT;
322         err = 0;
323         mode = perms;
324         if (strcmp(v[0].value, "dir") == 0) {
325                 INTENT_INIT(&intent, INT_CREAT, &mode, 0);
326                 err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno);
327                 if (err)
328                         return err;
329                 if (pno->p_base->pb_ino)
330                         err = -EEXIST;
331                 else if (IS_RDONLY(pno->p_parent,
332                                    pno->p_parent->p_base->pb_ino))
333                         err = -EROFS;
334                 else {
335                         struct inode *ino;
336
337                         ino = pno->p_parent->p_base->pb_ino;
338                         err = (*ino->i_ops.inop_mkdir)(pno, mode);
339                 }
340                 P_RELE(pno);
341         } else if (strcmp(v[0].value, "chr") == 0) {
342                 if (!(v[5].value && parse_mm(v[5].value, &dev) == 0))
343                         return -EINVAL;
344                 mode |= S_IFCHR;
345                 INTENT_INIT(&intent, INT_CREAT, &mode, 0);
346                 err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno);
347                 if (err)
348                         return err;
349                 if (pno->p_base->pb_ino)
350                         err = -EEXIST;
351                 else if (IS_RDONLY(pno->p_parent,
352                                    pno->p_parent->p_base->pb_ino))
353                         err = -EROFS;
354                 else {
355                         struct inode *ino;
356
357                         ino = pno->p_parent->p_base->pb_ino;
358                         err = (*ino->i_ops.inop_mknod)(pno, mode, dev);
359                 }
360                 P_RELE(pno);
361         } else if (strcmp(v[0].value, "blk") == 0) {
362                 /*
363                  * We don't support block special files yet.
364                  */
365                 return -EINVAL;
366         } else if (strcmp(v[0].value, "file") == 0) {
367                 int     i;
368                 struct inode *ino;
369
370                 i = O_CREAT|O_EXCL;
371                 INTENT_INIT(&intent, INT_CREAT, &mode, &i);
372                 err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno);
373                 if (err)
374                         return err;
375                 err = _sysio_open(pno, O_CREAT|O_EXCL, mode);
376                 if (err) {
377                         P_RELE(pno);
378                         return err;
379                 }
380                 ino = pno->p_base->pb_ino;
381                 if (!err && v[6].value) {
382                         struct iovec iovec;
383                         struct intnl_xtvec xtvec;
384                         struct ioctx io_context;
385
386                         /*
387                          * Deposit optional file content.
388                          */
389                         iovec.iov_base = v[6].value;
390                         iovec.iov_len = strlen(v[6].value);
391                         xtvec.xtv_off = 0;
392                         xtvec.xtv_len = iovec.iov_len;
393                         IOCTX_INIT(&io_context,
394                                    1,
395                                    1,
396                                    ino,
397                                    &iovec, 1,
398                                    &xtvec, 1);
399                         _sysio_ioctx_enter(&io_context);
400                         err =
401                             (*ino->i_ops.inop_write)(pno->p_base->pb_ino,
402                                                      &io_context);
403                         if (!err) {
404                                 ssize_t cc;
405
406                                 cc = _sysio_ioctx_wait(&io_context);
407                                 if (cc < 0)
408                                         err = cc;
409                                 else if ((size_t )cc != iovec.iov_len)
410                                         err = -EIO;             /* huh? */
411                         } else
412                                 _sysio_ioctx_complete(&io_context);
413                 }
414                 i = (*ino->i_ops.inop_close)(ino);
415                 if (!err)
416                         err = i;
417                 P_RELE(pno);
418         } else 
419                 err = -EINVAL;
420
421         return err;
422 }
423
424 /*
425  * Do mount.
426  *
427  * NB: The passed buffer is altered.
428  */
429 static int 
430 do_mnt(char *args) 
431 {
432         size_t  len;
433         struct named_argument v[] = {
434                 { "dev",        NULL },                 /* source (type:dev) */
435                 { "dir",        NULL },                 /* target dir */
436                 { "fl",         NULL },                 /* flags */
437                 { "da",         NULL },                 /* mount data */
438                 { NULL,         NULL }
439         };
440         char    *ty, *name;
441         unsigned long flags;
442         struct pnode *dir;
443   
444         len = strlen(args);
445         if (get_args(args, v) - args != (ssize_t )len ||
446             !(v[0].value && v[1].value))
447                 return -EINVAL;
448         ty = (char *)get_token(v[0].value, 1, ":", "", name = v[0].value);
449         flags = 0;
450         if (v[2].value) {
451                 char    *cp;
452
453                 /*
454                  * Optional flags.
455                  */
456                 flags = strtoul(v[2].value, &cp, 0);
457                 if (*cp || (flags == ULONG_MAX && errno == ERANGE))
458                         return -EINVAL;
459         }
460
461         if (strlen(v[1].value) == 1 && v[1].value[0] == PATH_SEPARATOR) {
462                 /*
463                  * Aha! It's root they want. Have to do that special.
464                  */
465                 return _sysio_mount_root(ty, name, flags, v[3].value);
466         }
467
468         if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
469                 return -ENOENT;
470         return _sysio_mount(dir, ty, v[1].value, name, flags, v[3].value);
471 }
472
473
474 /*
475  * Chdir
476  *
477  * NB: Alters the passed buffer.
478  */
479 static int 
480 do_cd(char *args) 
481 {
482         size_t  len;
483         struct named_argument v[] = {
484                 { "dir",        NULL },                 /* directory */
485                 { NULL,         NULL }
486         };
487         int     err;
488         struct pnode *dir, *pno;
489
490         len = strlen(args);
491         if (get_args(args, v) - args != (ssize_t )len || !v[0].value)
492                 return -EINVAL;
493
494         if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
495                 return -ENOENT;
496         err = _sysio_namei(dir, v[0].value, 0, NULL, &pno);
497         if (err)
498                 return err;
499         err = _sysio_p_chdir(pno);
500         if (err)
501                 P_RELE(pno);
502         return err;
503 }
504
505 /*
506  * Does a chmod
507  *
508  * NB: Alters passed buffer.
509  */
510 static int 
511 do_chmd(char *args)
512 {
513         size_t  len;
514         struct named_argument v[] = {
515                 { "src",        NULL },                 /* path */
516                 { "pm",         NULL },                 /* perms */
517                 { NULL,         NULL }
518         };
519         long    perms;
520         char    *cp;
521         struct intnl_stat stbuf;
522         int     err;
523         struct pnode *dir, *pno;
524   
525         len = strlen(args);
526         if (get_args(args, v) - args != (ssize_t )len ||
527             !(v[0].value && v[1].value))
528                 return -EINVAL;
529         perms = strtol(v[1].value, &cp, 0);
530         if (*cp ||
531             perms < 0 ||
532             (perms == LONG_MAX && errno == ERANGE) ||
533             ((unsigned)perms & ~07777))
534                 return -EINVAL;
535         (void )memset(&stbuf, 0, sizeof(stbuf));
536         stbuf.st_mode = (mode_t)perms;
537
538         if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
539                 return -ENOENT;
540         err = _sysio_namei(dir, v[0].value, 0, NULL, &pno);
541         if (err)
542                 return err;
543         err = _sysio_setattr(pno, pno->p_base->pb_ino, SETATTR_MODE, &stbuf);
544         P_RELE(pno);
545
546         return err;
547 }
548
549 static int
550 do_open(char *args)
551 {
552         size_t  len;
553         struct named_argument v[] = {
554                 { "nm", NULL },                 /* path */
555                 { "fd",         NULL },                 /* fildes */
556                 { "m",          NULL },                 /* mode */
557                 { NULL,         NULL }
558         };
559         char    *cp;
560         int     fd;
561         mode_t  m;
562         struct pnode *dir, *pno;
563         struct intent intent;
564         int     err;
565         struct file *fil;
566
567         len = strlen(args);
568         if (get_args(args, v) - args != (ssize_t )len ||
569             !(v[0].value && v[1].value && v[2].value))
570                 return -EINVAL;
571         fd = strtol(v[1].value, (char **)&cp, 0);
572         if (*cp ||
573             (((fd == LONG_MIN || fd == LONG_MAX) && errno == ERANGE)) ||
574              fd < 0)
575                 return -EINVAL;
576         m = strtoul(v[1].value, (char **)&cp, 0);
577         if (*cp ||
578             (m == LONG_MAX && errno == ERANGE))
579                 return -EINVAL;
580         m &= O_RDONLY|O_WRONLY|O_RDWR;
581
582         if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
583                 return -ENOENT;
584         INTENT_INIT(&intent, INT_OPEN, &m, NULL);
585         pno = NULL;
586         err = _sysio_namei(dir, v[0].value, 0, &intent, &pno);
587         if (err)
588                 return err;
589         fil = NULL;
590         do {
591                 err = _sysio_open(pno, m, 0);
592                 if (err)
593                         break;
594                 fil = _sysio_fnew(pno->p_base->pb_ino, m);
595                 if (!fil) {
596                         err = -ENOMEM;
597                         break;
598                 }
599                 err = _sysio_fd_set(fil, fd, 1);
600                 if (err < 0)
601                         break;
602                 P_RELE(pno);
603                 return 0;
604         } while (0);
605         if (fil)
606                 F_RELE(fil);
607         if (pno)
608                 P_RELE(pno);
609         return err;
610 }
611
612 /*
613  * Execute the given cmd.
614  *
615  * NB: Buf is altered.
616  */
617 static int 
618 do_command(char *buf)
619 {
620         size_t  len;
621         char    *args, *cmd;
622
623         len = strlen(buf);
624         args = (char *)get_token(buf, 1, ",", IGNORE_WHITE, cmd = buf);
625         if (args) {
626                 if (strcmp("creat", cmd) == 0)
627                         return do_creat(args);
628                 if (strcmp("mnt", cmd) == 0)
629                         return do_mnt(args);
630                 if (strcmp("cd", cmd) == 0)
631                         return do_cd(args);
632                 if (strcmp("chmd", cmd) == 0)
633                         return do_chmd(args);
634                 if (strcmp("open", cmd) == 0)
635                         return do_open(args);
636         }
637         return -EINVAL;
638 }
639
640 /*
641  * Given a command sequence buffer, parse it and run the given
642  * commands 
643  */
644 int 
645 _sysio_boot(const char *buf) 
646 {
647         char    c, *tok;
648         int     err;
649
650         /*
651          * Allocate token buffer.
652          */
653         tok = malloc(strlen(buf));
654         if (!tok)
655                 return -ENOMEM;
656         err = 0;
657         while (1) {
658                 /*
659                  * Discard leading white space.
660                  */
661                 while ((c = *buf) != '\0' &&
662                        !(c == '{' || strchr(IGNORE_WHITE, c) == NULL))
663                         buf++;
664                 if (c == '\0')
665                         break;
666                 if (c != '{') {
667                         err = -EINVAL;
668                         break;
669                 }
670                 /*
671                  * Get the command.
672                  */
673                 buf = (char *)get_token(buf + 1, 0, "}", IGNORE_WHITE, tok);
674                 if (!buf) {
675                         err = -EINVAL;
676                         break;
677                 }
678                 /*
679                  * Perform.
680                  */
681                 err = do_command(tok);
682                 if (err)
683                         break;
684         }
685         free(tok);
686         return err;
687 }