1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1996-1997, by Sun Microsystems, Inc.
24 * All Rights reserved.
25 */
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
31 /* LINTLIBRARY */
32
33 /*
34 * putdev.c
35 *
36 * Global Definitions:
37 * _adddevtabrec() Add a record to the device table
38 * _putdevtabrec() Write a record to the device table
39 * _moddevtabrec() Modify a device-table record
40 * _rmdevtabrec() Remove a device-table record
41 * _rmdevtabattrs() Remove attributes from a device-table record
42 * oam_devtab File descriptor of the open device table
43 */
44
45 /*
46 * G L O B A L R E F E R E N C E S
47 *
48 * Header Files
49 * Externals Referenced
50 */
51
52 /*
53 * Header Files
54 * <sys/types.h> UNIX(r) Data Types
55 * <sys/stat.h>
56 * <stdio.h> Standard I/O definitions
57 * <fcntl.h> Definitions for file control
58 * <errno.h> Error handling definitions
59 * <string.h> String Handling Definitions
60 * <devmgmt.h> Device Management Definitions
61 * <unistd.h> Get UNIX(r) Standard Definitions
62 * "devtab.h" Local Device Management Definitions
63 */
64
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <stdio.h>
68 #include <fcntl.h>
69 #include <errno.h>
70 #include <string.h>
71 #include <devmgmt.h>
72 #include <unistd.h>
73 #include <stdlib.h>
74 #include "devtab.h"
75
76 /*
77 * L O C A L D E F I N I T I O N S
78 *
79 * TDTABNM Name of the temporary device table (in the
80 * directory of the existing table)
81 * TDTABNMLN Number of characters added to the directory
82 * name -- the length of the device table temp name
83 */
84
85 #define TDTABNM "%sdevtab.%6.6d"
86 #define TDTABNMLN 13
87
88
89 /*
90 * Static functions
91 * strcatesc Copies a character-string from one place to another
92 * escaping the appropriate characters
93 * lkdevtab Locks the device table
94 * unlkdevtab Unlocks the device table
95 * mkdevtabent Builds a device-table entry from the alias and the
96 * list of attr=val pairs given
97 * opennewdevtab Opens a new device table (as a temp file)
98 * mknewdevtab Makes the temp device table the new devtab
99 * rmnewdevtab Remove the temporary device table and free space
100 * allocated to the filename of that file.
101 */
102
103 static char *strcatesc(char *, char *);
104 static int lkdevtab(char *, short);
105 static int unlkdevtab(void);
106 static struct devtabent *mkdevtabent(char *, char **);
107 static FILE *opennewdevtab(char **);
108 static int mknewdevtab(char *);
109 static int rmnewdevtab(char *);
110
111 /*
112 * char *strcatesc(p, q)
113 * char *p
114 * char *q
115 *
116 * Write the character-string pointed to by "q" to the place
117 * pointed to by "p", escaping those characters in "q" found in the
118 * string "DTAB_ESCS" by preceding them with '\\'. Return a pointer to
119 * the byte beyond the last character written to "p".
120 *
121 * Arguments:
122 * p The place to begin writing to
123 * q The string to write
124 *
125 * Returns: char *
126 * The address of the byte beyond the last character written into "p"
127 */
128
129 static char *
strcatesc(char * p,char * q)130 strcatesc(
131 char *p, /* Place to write to */
132 char *q) /* Thing to write */
133 {
134 while (*q) {
135 if (strchr(DTAB_ESCS, *q)) *p++ = '\\';
136 *p++ = *q++;
137 }
138 return (p);
139 }
140
141 /*
142 * FILE *opennewdevtab(pname)
143 * char **pname
144 *
145 * Generates a temporary device-table name from the existing
146 * device table name (in the same directory) and opens that
147 * file for writing. It puts a pointer to the malloc()ed space
148 * containing the temp device table's name at the place referenced
149 * by <pname>.
150 *
151 * Arguments:
152 * pname Pointer to the char * to contain the address of the name
153 * of the temporary file
154 *
155 * Returns: FILE *
156 * A pointer to the opened stream or (FILE *) NULL if an error occurred.
157 * If an error occurred, "errno" will be set to reflect the problem.
158 */
159
160 static FILE *
opennewdevtab(char ** pname)161 opennewdevtab(char **pname) /* A(ptr to temp filename's path) */
162 {
163 char *oldname; /* Ptr to the device-table's name */
164 char *buf; /* Ptr to the temp file's name */
165 char *dirname; /* Directory containing devtab */
166 char *p; /* Ptr to last '/' in devtab name */
167 int fd; /* Opened file descriptor */
168 FILE *fp; /* Opened file pointer */
169 struct stat64 sbuf; /* stat buf for old devtab file */
170
171 fp = NULL;
172 if (oldname = _devtabpath()) {
173 /*
174 * It is possible for us to have sufficient permissions to create
175 * the new file without having sufficient permissions to write the
176 * original devtab file. For consistency with the operations which
177 * modify the original file by writing it directly we require write
178 * permissions for the original file in order to make a new one.
179 */
180 if ((fd = open(oldname, O_WRONLY)) == -1)
181 return (NULL);
182
183 if (fstat64(fd, &sbuf) == -1) {
184 (void) close(fd);
185 return (NULL);
186 }
187 (void) close(fd);
188
189 if (p = strrchr(oldname, '/')) {
190 *(p+1) = '\0';
191 dirname = oldname;
192 } else dirname = "./";
193 if (buf = malloc(TDTABNMLN + strlen(dirname) + 1)) {
194
195 /*
196 * Build the name of the temp device table and open the
197 * file. We must reset the owner, group and perms to those
198 * of the original devtab file.
199 */
200 (void) sprintf(buf, TDTABNM, dirname, getpid());
201 if (fp = fopen(buf, "w")) {
202 *pname = buf;
203 (void) fchmod(fileno(fp), sbuf.st_mode & 0777);
204 (void) fchown(fileno(fp), sbuf.st_uid, sbuf.st_gid);
205 } else {
206 free(buf);
207 }
208 }
209
210 /*
211 *
212 * Free the space containing the device table's name.
213 */
214 free(oldname);
215 }
216
217 /* Finished. Return what we've got */
218 return (fp);
219 }
220
221 /*
222 * int rmnewdevtab(tempname)
223 * char *tempname
224 *
225 * Unlink the temp device table and free the memory allocated to
226 * contain the name of that file
227 *
228 * Arguments:
229 * tempname Name of the temporary file
230 *
231 * Returns: int
232 * TRUE if successful, FALSE otherwise
233 */
234
235 static int
rmnewdevtab(char * tempname)236 rmnewdevtab(char *tempname) /* Filename of new device table */
237 {
238 int noerr; /* Flag, TRUE if no error, FALSE otherwise */
239
240 /* Unlink the file */
241 noerr = (unlink(tempname) == 0);
242
243 /* Free the space allocated to the filename */
244 free(tempname);
245
246 /* Return success indicator */
247 return (noerr);
248 }
249
250 /*
251 * int mknewdevtab(tempname)
252 * char *tempname
253 *
254 * Make the temporary device-table the new system device table
255 *
256 * Arguments:
257 * tempname Name of the temporary file
258 *
259 * Returns: int
260 * TRUE if successful, FALSE otherwise
261 *
262 * Notes:
263 * - Need to use rename() someday instead of link()/unlink()
264 * - This code is somewhat ineffecient in that asks for the name
265 * of the device-table more than once. Done so that we don't
266 * have to manage that space, but this may be somewhat lazy.
267 */
268
269 static int
mknewdevtab(char * tempname)270 mknewdevtab(char *tempname) /* Ptr to name of temp dev tab */
271 {
272 char *devtabname; /* Ptr to the device table's name */
273 int noerr; /* FLAG, TRUE if all's well */
274
275 /* Get the device table's pathname */
276 if (devtabname = _devtabpath()) {
277
278 /* Unlink the existing file */
279 if (unlink(devtabname) == 0) {
280
281 /* Make the temp file the real device table */
282 noerr = (link(tempname, devtabname) == 0) ? TRUE : FALSE;
283
284 /* Remove the temp file (and resources) */
285 if (noerr) (void) rmnewdevtab(tempname);
286
287 } else noerr = FALSE; /* unlink() failed */
288
289 /* Free the device table's name */
290 free(devtabname);
291
292 } else noerr = FALSE; /* devtabpath() failed */
293
294 /* Finished. Return success indicator */
295 return (noerr);
296 }
297
298 /*
299 * static int lkdevtab(o_mode, lktype)
300 * char *o_mode
301 * short lktype
302 *
303 * Lock the device table for writing. If it isn't available, it waits
304 * until it is.
305 *
306 * Arguments:
307 * o_mode The open() mode to use when opening the device table
308 * lktype The type of lock to apply
309 *
310 * Returns: int
311 * TRUE if successful, FALSE with errno set otherwise
312 */
313
314 static int
lkdevtab(char * o_mode,short lktype)315 lkdevtab(
316 char *o_mode, /* Open mode */
317 short lktype) /* Lock type */
318 {
319 /* Automatic data */
320 struct flock lockinfo; /* File locking structure */
321 int noerr; /* FLAG, TRUE if no error */
322 int olderrno; /* Old value of "errno" */
323
324
325 /* Close the device table (if it's open) */
326 _enddevtab();
327
328 /* Open the device table for read/append */
329 noerr = TRUE;
330 if (_opendevtab(o_mode)) {
331
332 /*
333 * Lock the device table (for writing). If it's not
334 * available, wait until it is, then close and open the
335 * table (modify and delete change the table!) and try
336 * to lock it again
337 */
338
339 /* Build the locking structure */
340 lockinfo.l_type = lktype;
341 lockinfo.l_whence = 0;
342 lockinfo.l_start = 0L;
343 lockinfo.l_len = 0L;
344 olderrno = errno;
345
346 /* Keep on going until we lock the file or an error happens */
347 while ((fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) == -1) &&
348 !noerr) {
349 if (errno == EACCES) {
350 if (fcntl(fileno(oam_devtab), F_SETLKW, &lockinfo) == -1)
351 noerr = FALSE;
352 else {
353 /* Reopen the file (maybe it's moved?) */
354 _enddevtab();
355 if (!_opendevtab(o_mode)) noerr = FALSE;
356 else errno = olderrno;
357 }
358 } else noerr = FALSE;
359 }
360
361 if (!noerr) _enddevtab(); /* Don't keep open if in error */
362
363 } else noerr = FALSE;
364
365 /* Done */
366 return (noerr);
367 }
368
369 /*
370 * int unlkdevtab()
371 *
372 * Unlock the locked device table.
373 *
374 * Arguments: None
375 *
376 * Returns: int
377 * Whatever fcntl() returns...
378 */
379
380 static int
unlkdevtab(void)381 unlkdevtab(void)
382 {
383 /* Automatic data */
384 struct flock lockinfo; /* Locking structure */
385 int noerr; /* FLAG, TRUE if all's well */
386
387 /* Build the locking structure */
388 lockinfo.l_type = F_UNLCK; /* Lock type */
389 lockinfo.l_whence = 0; /* Count from top of file */
390 lockinfo.l_start = 0L; /* From beginning */
391 lockinfo.l_len = 0L; /* Length of locked data */
392
393 /* Unlock it */
394 noerr = (fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) != -1);
395 _enddevtab();
396
397 /* Finished */
398 return (noerr);
399 }
400
401 /*
402 * struct devtabent *mkdevtabent(alias, attrlist)
403 * char *alias
404 * char **attrlist
405 *
406 * This function builds a struct devtabent structure describing the
407 * alias <alias> using the information in the attribute list <attrlist>.
408 * The <attrlist> contains data of the form attr=value where attr is
409 * the name of an attribute and value is the value of that attribute.
410 *
411 * Arguments:
412 * alias The alias being added to the device table
413 * attrlist The attributes and values for that alias
414 *
415 * Returns: struct devtabent *
416 * A completed struct devtabent structure containing the description
417 * of the alias. The structure, and all of the data in the structure
418 * are each in space allocated using the malloc() function and should
419 * be freed using the free() function (or the _freedevtabent() function).
420 *
421 * Errors:
422 * EINVAL If "alias" is used as an attribute in an attr=val pair
423 * EAGAIN If an attribute is specified more than once
424 */
425
426 static struct devtabent *
mkdevtabent(char * alias,char ** attrlist)427 mkdevtabent(
428 char *alias, /* Alias of entry */
429 char **attrlist) /* Attributes of new entry */
430 {
431 /* Automatic data */
432 struct devtabent *devtabent; /* * to struct we're making */
433 struct attrval *prevattrval; /* * to prev attr/val struct */
434 struct attrval *attrval; /* * to current struct */
435 char **pp; /* Ptr into list of ptrs */
436 char *peq; /* Ptr to '=' in string */
437 char *val; /* Ptr to space for value */
438 char *name; /* Ptr to space for name */
439 ssize_t len; /* Length of name */
440 int noerr; /* TRUE if all's well */
441 int found; /* TRUE the attr is found */
442
443
444 /* No problems (yet) */
445 noerr = TRUE;
446
447 /* Get space for the structure */
448 if (devtabent = malloc(sizeof (struct devtabent))) {
449
450 /* Fill in default values */
451 if (devtabent->alias = malloc(strlen(alias)+1)) {
452
453 (void) strcpy(devtabent->alias, alias); /* alias */
454 devtabent->comment = FALSE; /* data rec */
455 devtabent->cdevice = NULL; /* cdevice */
456 devtabent->bdevice = NULL; /* bdevice */
457 devtabent->pathname = NULL; /* pathname */
458 devtabent->attrstr = NULL; /* string */
459 devtabent->attrlist = NULL; /* attr list */
460
461 /* Add attributes to the structure */
462 prevattrval = NULL;
463 if ((pp = attrlist) != NULL)
464 while (*pp && noerr) {
465
466 /* Valid attr=value pair? */
467 if (((peq = strchr(*pp, '=')) != NULL) &&
468 ((len = peq - *pp) > 0)) {
469
470 /* Get space for the value */
471 if (val = malloc(strlen(peq))) {
472 (void) strcpy(val, peq+1); /* Copy it */
473
474 /* Get space for attribute name */
475 if (name = malloc((size_t)(len + 1))) {
476 (void) strncpy(name, *pp, (size_t)len);
477 *(name+len) = '\0';
478
479 /* Specifying the alias? If so, ERROR */
480 if (strcmp(name, DTAB_ALIAS) == 0) {
481 noerr = FALSE;
482 free(name);
483 free(val);
484 errno = EINVAL;
485 }
486
487 /* Specifying the char device path? */
488 else if (strcmp(name, DTAB_CDEVICE) == 0) {
489 if (!devtabent->cdevice) {
490 if (val[0] != '/') {
491 noerr = FALSE;
492 free(name);
493 free(val);
494 errno = ENXIO;
495 } else {
496 devtabent->cdevice = val;
497 free(name);
498 }
499 } else {
500 noerr = FALSE;
501 free(name);
502 free(val);
503 errno = EAGAIN;
504 }
505 }
506
507 /* Specifying the block device path? */
508 else if (strcmp(name, DTAB_BDEVICE) == 0) {
509 if (!devtabent->bdevice) {
510 if (val[0] != '/') {
511 noerr = FALSE;
512 free(name);
513 free(val);
514 errno = ENXIO;
515 } else {
516 devtabent->bdevice = val;
517 free(name);
518 }
519 } else {
520 noerr = FALSE;
521 free(name);
522 free(val);
523 errno = EAGAIN;
524 }
525 }
526
527 /* Specifying the pathname (generic)? */
528 else if (strcmp(name, DTAB_PATHNAME) == 0) {
529 if (!devtabent->pathname) {
530 if (val[0] != '/') {
531 noerr = FALSE;
532 free(name);
533 free(val);
534 errno = ENXIO;
535 } else {
536 devtabent->pathname = val;
537 free(name);
538 }
539 } else {
540 noerr = FALSE;
541 free(name);
542 free(val);
543 errno = EAGAIN;
544 }
545 }
546
547 /* Some other attribute */
548 else {
549 found = FALSE;
550 if ((attrval = devtabent->attrlist) != NULL)
551 do {
552 if (strcmp(attrval->attr,
553 name) == 0) {
554
555 noerr = FALSE;
556 free(name);
557 free(val);
558 errno = EAGAIN;
559 }
560 } while (!found && noerr &&
561 (attrval = attrval->next));
562
563 if (!found && noerr) {
564
565 /* Get space for attr/val structure */
566 if (attrval =
567 malloc(sizeof (struct attrval))) {
568
569 /* Fill attr/val structure */
570 attrval->attr = name;
571 attrval->val = val;
572 attrval->next = NULL;
573
574 /*
575 * Link into the list of attributes
576 */
577 if (prevattrval)
578 prevattrval->next = attrval;
579 else devtabent->attrlist = attrval;
580 prevattrval = attrval;
581
582 } else {
583 /* malloc() for attrval failed */
584 noerr = FALSE;
585 free(name);
586 free(val);
587 }
588 }
589 } /* End else (some other attribute) */
590
591 } else { /* malloc() for attribute name failed */
592 noerr = FALSE;
593 free(val);
594 }
595
596 } else noerr = FALSE; /* Malloc() for "val" failed */
597
598 /* If we saw an error, free structure, returning NULL */
599 if (!noerr) {
600 _freedevtabent(devtabent);
601 devtabent = NULL;
602 }
603
604 } /* Ignore invalid attr=val pair */
605
606 if (noerr) pp++;
607
608 } /* End attribute processing loop */
609
610 } else { /* malloc() failed */
611 free(devtabent);
612 devtabent = NULL;
613 }
614 }
615
616 /* Finished */
617 return (devtabent);
618 }
619
620 /*
621 * int _putdevtabrec(stream, rec)
622 * FILE *stream
623 * struct devtabent *rec
624 *
625 * Write a device table record containing the information in the struct
626 * devtab structure <rec> to the current position of the standard I/O
627 * stream <stream>.
628 *
629 * Arguments:
630 * stream The stream to write to
631 * rec The structure containing the information to write
632 *
633 * Returns: int
634 * The number of characters written or EOF if there was some error.
635 */
636
637 int
_putdevtabrec(FILE * stream,struct devtabent * rec)638 _putdevtabrec(
639 FILE *stream, /* Stream to which to write */
640 struct devtabent *rec) /* Record to write */
641 {
642 /* Automatic Data */
643 struct attrval *attrval; /* Ptr to attr/val pair */
644 char *buf; /* Allocated buffer */
645 char *p; /* Temp char pointer */
646 int count; /* Number of chars written */
647 size_t size = 0; /* Size of needed buffer */
648
649
650 /* Comment or data record? */
651 if (rec->comment) {
652
653 /*
654 * Record is a comment
655 */
656
657 /* Copy (escaping chars) record into temp buffer */
658 size = (strlen(rec->attrstr)*2)+1; /* Max rec size */
659 if (buf = malloc(size+1)) {
660 /* Alloc space */
661 p = strcatesc(buf, rec->attrstr); /* Copy "escaped" */
662 *(p-2) = '\n'; /* Unescape last \n */
663 *(p-1) = '\0'; /* Terminate string */
664
665 /* Write the record */
666 count = fputs(buf, stream);
667 free(buf);
668
669 } else count = EOF; /* malloc() failed */
670 }
671
672 else {
673
674 /*
675 * Record is a data record
676 */
677
678 /*
679 * Figure out maximum amount of space you're going to need.
680 * (Assume every escapable character is escaped to determine the
681 * maximum size needed)
682 */
683
684 if (rec->cdevice)
685 size += (strlen(rec->cdevice)*2) + 1; /* cdevice: */
686 if (rec->bdevice)
687 size += (strlen(rec->bdevice)*2) + 1; /* bdevice: */
688 if (rec->pathname)
689 size += (strlen(rec->pathname)*2) + 1; /* pathname: */
690 if ((attrval = rec->attrlist) != NULL) do { /* Attributes */
691 if (attrval->attr)
692 size += (strlen(attrval->attr)*2); /* attr */
693 if (attrval->val) {
694 /* val & '="" ' or val & '=""\n' */
695 size += (strlen(attrval->val)*2) +4;
696 }
697 } while ((attrval = attrval->next) != NULL); /* Next attr/val */
698 else size++; /* Else make room for trailing '\n' */
699
700 /* Alloc space for "escaped" record */
701 if (buf = malloc(size+1)) {
702
703 /* Initializations */
704 p = buf;
705
706 /* Write the alias ("alias" attribute) */
707 p = strcatesc(p, rec->alias);
708 *p++ = ':';
709
710 /* Write the character device ("cdevice" attribute) */
711 if (rec->cdevice) p = strcatesc(p, rec->cdevice);
712 *p++ = ':';
713
714 /* Write the block device ("bdevice" attribute) */
715 if (rec->bdevice) p = strcatesc(p, rec->bdevice);
716 *p++ = ':';
717
718 /* Write the pathname ("pathname" attribute) */
719 if (rec->pathname) p = strcatesc(p, rec->pathname);
720 *p++ = ':';
721
722 /* Write the rest of the attributes */
723 if ((attrval = rec->attrlist) != NULL)
724 do {
725 p = strcatesc(p, attrval->attr);
726 *p++ = '=';
727 *p++ = '"';
728 p = strcatesc(p, attrval->val);
729 *p++ = '"';
730 if ((attrval = attrval->next) != NULL)
731 *p++ = ' ';
732 } while (attrval);
733
734 /* Terminate the record */
735 *p++ = '\n';
736 *p = '\0';
737
738 /* Write the record */
739 count = fputs(buf, stream);
740 free(buf);
741 } else count = EOF; /* malloc() failed */
742 }
743
744 /* Finished */
745 return (count);
746 }
747
748 /*
749 * int _adddevtabrec(alias, attrval)
750 * char *alias
751 * char **attrval
752 *
753 * This function adds a record to the device table. That record will
754 * have the alias <alias> and will have the attributes described in
755 * the list referenced by <attrval>.
756 *
757 * It always adds the record to the end of the table.
758 *
759 * Arguments:
760 * alias The alias of the device whose description is being
761 * added to the device table.
762 * attrval The pointer to the first item of a list of attributes
763 * defining the device whose description is being added.
764 * (This value may be (char **) NULL).
765 *
766 * Returns: int
767 * TRUE if successful, FALSE with errno set otherwise.
768 */
769
770 int
_adddevtabrec(char * alias,char ** attrval)771 _adddevtabrec(
772 char *alias, /* Alias to add to the device table */
773 char **attrval) /* Attributes for that device */
774 {
775 /* Automatic data */
776 struct devtabent *devtabent; /* Ptr to dev tab entry */
777 int olderrno; /* Errno on entry */
778 int noerr; /* FLAG, TRUE if all's well */
779
780 /* Validate the device alias. Error (EINVAL) if it's not valid */
781 if (!_validalias(alias)) {
782 errno = EINVAL;
783 return (FALSE);
784 }
785
786 /*
787 * Lock the device table. This only returns if the table is locked or
788 * some error occurred. It waits until the table is available.
789 */
790 if (!lkdevtab("a+", F_WRLCK))
791 return (FALSE);
792
793 /* Make sure that the alias isn't already in the table */
794 noerr = TRUE;
795 olderrno = errno;
796 if (devtabent = _getdevrec(alias)) {
797
798 /* The alias is already in the table */
799 _freedevtabent(devtabent); /* Free device table info */
800 errno = EEXIST; /* Set errno, entry exists */
801 noerr = FALSE; /* All's not well */
802 } else if ((errno == ENOENT) || (errno == ENODEV)) {
803
804 /* The alias wasn't in the table or there wasn't a table. */
805
806 errno = olderrno; /* Reset errno */
807
808 /* Build a struct devtabent that describes the new alias */
809 if (devtabent = mkdevtabent(alias, attrval)) {
810
811 /* Position to the end of the existing table */
812 if (fseek(oam_devtab, 0, SEEK_END) == 0)
813
814 /* Write the new entry */
815 noerr = (_putdevtabrec(oam_devtab, devtabent) != EOF);
816
817 /* Free the info we just wrote */
818 _freedevtabent(devtabent);
819
820 } else noerr = FALSE; /* mkdevtabent() failed */
821 } else noerr = FALSE; /* Some odd error, _devtab */
822
823 /* Unlock and close the device table */
824 (void) unlkdevtab();
825
826 /* Fini */
827 return (noerr);
828 }
829
830 /*
831 * int _moddevtabrec(device, attrval)
832 * char *device
833 * char **attrval
834 *
835 * This function modifies the description for the specified device
836 * so that it has the attributes and values as specified in the
837 * given list.
838 *
839 * Arguments:
840 * device The name of the device whose description
841 * is being modified
842 * attrval The first attr/val value in the list (attr=val) of
843 * the attributes that are to change
844 *
845 * Returns: int
846 * TRUE if all went well, FALSE with errno set otherwise
847 */
848
849 int
_moddevtabrec(char * device,char ** attrval)850 _moddevtabrec(
851 char *device, /* Device to modify */
852 char **attrval) /* Attributes to add or change */
853 {
854 /* Automatic data */
855 FILE *fd; /* File ptr, new device table */
856 struct devtabent *ent; /* Device's current description */
857 struct devtabent *chg; /* Changes to make to description */
858 struct attrval *new; /* New attribute/value desc */
859 struct attrval *old; /* Old attribute/value desc */
860 struct attrval *newnew; /* Next "new" value to look at */
861 struct attrval *prevnew; /* Previous item in the 'new' list */
862 char *tname; /* name of temp devtab file */
863 int noerr; /* FLAG, TRUE if all's well */
864 int found; /* FLAG, TRUE if attr found for dev */
865
866 /* Lock the device table */
867 if (!lkdevtab("r", F_WRLCK))
868 return (FALSE);
869
870 /* No problems (so far) */
871 noerr = TRUE;
872
873 /* Get the entry to modify */
874 if (ent = _getdevrec(device)) {
875
876 /* Build a structure describing the changes */
877 if (chg = mkdevtabent(device, attrval)) {
878
879 /* If the "cdevice" field is specified, change it */
880 if (chg->cdevice) {
881 if (ent->cdevice) free(ent->cdevice);
882 ent->cdevice = chg->cdevice;
883 chg->cdevice = NULL;
884 }
885
886 /* If the "bdevice" field is specified, change it */
887 if (chg->bdevice) {
888 if (ent->bdevice) free(ent->bdevice);
889 ent->bdevice = chg->bdevice;
890 chg->bdevice = NULL;
891 }
892
893 /* If the "pathname" field is specified, change it */
894 if (chg->pathname) {
895 if (ent->pathname) free(ent->pathname);
896 ent->pathname = chg->pathname;
897 chg->pathname = NULL;
898 }
899
900 /* Change the other attributes (if any) */
901 if (ent->attrlist) {
902 prevnew = NULL;
903 if ((new = chg->attrlist) != NULL) do {
904
905 found = FALSE;
906 for (old = ent->attrlist; !found && old;
907 old = old->next) {
908 if (strcmp(old->attr, new->attr) == 0) {
909 found = TRUE;
910 free(old->val);
911 old->val = new->val;
912 new->val = NULL;
913 }
914 } /* Loop through the existing attribute list */
915
916 /*
917 * If the attribute wasn't found, add it to the list
918 * of attributes for the device. If it was found, just
919 * bump to the next one and look for it
920 */
921
922 if (!found) {
923
924 /*
925 * Not found. Move attr/val description to the
926 * device's list of attributes
927 */
928
929 if (prevnew) prevnew->next = new->next;
930 else chg->attrlist = new->next;
931 newnew = new->next;
932 new->next = ent->attrlist;
933 ent->attrlist = new;
934 new = newnew;
935 } else {
936
937 /* Attribute changed, bump to the next one */
938 prevnew = new;
939 new = new->next;
940 }
941 } while (new); /* Loop for each attr to add or modify */
942
943 } else {
944
945 /* Device had no attributes -- add entire list */
946 ent->attrlist = chg->attrlist;
947 chg->attrlist = NULL;
948 }
949
950 /* Free the structure containing the changes */
951 _freedevtabent(chg);
952
953 } else noerr = FALSE; /* Couldn't build changes struct */
954
955 /* If there hasn't been an error (so far), write the new record */
956 if (noerr) {
957
958 /* Open the new device table */
959 if (fd = opennewdevtab(&tname)) {
960
961 /*
962 * For each entry in the existing table, write that entry
963 * to the new table. If the entry is the one being
964 * modified, write the modified entry instead of the
965 * original entry.
966 */
967
968 _setdevtab(); /* Rewind existing table */
969 chg = ent; /* Remember new record */
970 while (((ent = _getdevtabent()) != NULL) && noerr) {
971 if (ent->entryno != chg->entryno)
972 noerr = _putdevtabrec(fd, ent) != EOF;
973 else noerr = _putdevtabrec(fd, chg) != EOF;
974 _freedevtabent(ent);
975 }
976
977 /*
978 * If we successfully generated the new table, make it the
979 * new system device table. Otherwise, just remove the
980 * temporary file we've created.
981 */
982
983 if (noerr) {
984 (void) fclose(fd);
985 noerr = mknewdevtab(tname);
986 } else {
987 (void) fclose(fd);
988 (void) rmnewdevtab(tname);
989 }
990
991 /* Free the changed device structure */
992 _freedevtabent(chg);
993
994 } /* if (_opennewdevtab()) */
995 else noerr = FALSE;
996
997 } else _freedevtabent(ent); /* if (noerr) */
998
999 } else noerr = FALSE; /* Device not found? */
1000
1001 /* Finished. Unlock the device table and quit */
1002 (void) unlkdevtab();
1003 return (noerr);
1004 }
1005
1006 /*
1007 * int _rmdevtabrec(device)
1008 * char *device
1009 *
1010 * This function removes the record in the device table for the specified
1011 * device.
1012 *
1013 * Arguments:
1014 * device The device (alias, cdevice, bdevice, pathname, or link to one)
1015 * whose entry is to be removed
1016 *
1017 * Returns: int
1018 * Success indicator: TRUE if successful, FALSE with errno set otherwise.
1019 */
1020
1021 int
_rmdevtabrec(char * device)1022 _rmdevtabrec(char *device) /* Device to remove */
1023 {
1024 struct devtabent *rment;
1025 struct devtabent *devtabent;
1026 char *tempname;
1027 FILE *fd;
1028 int noerr;
1029
1030 if (!lkdevtab("r", F_WRLCK))
1031 return (FALSE);
1032 noerr = TRUE;
1033 if (rment = _getdevrec(device)) {
1034 if (fd = opennewdevtab(&tempname)) {
1035 _setdevtab();
1036 while (((devtabent = _getdevtabent()) != NULL) && noerr) {
1037 if (devtabent->entryno != rment->entryno)
1038 noerr = _putdevtabrec(fd, devtabent) != EOF;
1039 _freedevtabent(devtabent);
1040 }
1041 if (noerr) {
1042 (void) fclose(fd);
1043 noerr = mknewdevtab(tempname);
1044 } else {
1045 (void) fclose(fd);
1046 (void) rmnewdevtab(tempname);
1047 }
1048 } else noerr = FALSE;
1049 _freedevtabent(rment);
1050 } else noerr = FALSE;
1051 (void) unlkdevtab();
1052 return (noerr);
1053 }
1054
1055 /*
1056 * int _rmdevtabattrs(device, attributes, notfounds)
1057 * char *device
1058 * char **attributes
1059 * char ***notfounds
1060 *
1061 * Remove the specified attributes from the specified device. The
1062 * device is specified by <device>, <attributes> is the address of
1063 * the first char * in the list of char * pointing to the attributes
1064 * to remove from the device, and <notfounds> is the address of a
1065 * char ** to put the address of the first element in the malloc()ed
1066 * list of (char *) pointing to requested attributes that were not
1067 * defined for the device <device>.
1068 *
1069 * Arguments:
1070 * device The device from which attributes are to be removed
1071 * attributes The address of the first element in the list of
1072 * attributes to remove. This list is terminated by
1073 * (char *) NULL.
1074 * notfounds The place to put the address of the list of addresses
1075 * referencing the requested attributes that are not
1076 * defined for the specified device.
1077 *
1078 * Returns: int
1079 * TRUE if successful, FALSE with errno set otherwise.
1080 *
1081 * Notes:
1082 * - "alias" may not be undefined
1083 * - "cdevice", "bdevice", and "pathname" are made "null", not really
1084 * undefined
1085 */
1086
1087 int
_rmdevtabattrs(char * device,char ** attributes,char *** notfounds)1088 _rmdevtabattrs(
1089 char *device, /* Device to modify */
1090 char **attributes, /* Attributes to remove */
1091 char ***notfounds) /* Attributes req'd but not found */
1092 {
1093 /* Automatics */
1094 char **pnxt; /* Ptr to next attribute */
1095 char **pp; /* Ptr to current attr name */
1096 struct devtabent *modent; /* Entry being modified */
1097 struct devtabent *devtabent; /* Entry being copied */
1098 struct attrval *attrval; /* Ptr to attr/val desc */
1099 struct attrval *prevattrval; /* Ptr to prev attr/val */
1100 FILE *fd; /* File desc, temp file */
1101 char *tempname; /* Name of temp file */
1102 int nattrs; /* Number of attrs to remove */
1103 int nobaderr; /* TRUE if no fatal error */
1104 int noerr; /* TRUE if no non-fatal error */
1105 int found; /* TRUE if attribute found */
1106 int nonotfounds; /* TRUE if no attrs not fount */
1107
1108
1109 /* Initializations */
1110 nobaderr = TRUE;
1111 noerr = TRUE;
1112
1113 /* Count attributes to remove -- make sure "alias" isn't specified */
1114 for (pp = attributes, nattrs = 0; *pp; pp++, nattrs++)
1115 if (strcmp(*pp, DTAB_ALIAS) == 0) {
1116 *notfounds = NULL;
1117 errno = EINVAL;
1118 return (FALSE);
1119 }
1120
1121 /* Lock the device table */
1122 if (!lkdevtab("r", F_WRLCK))
1123 return (FALSE);
1124
1125 /* Is there a record for the requested device? */
1126 if (modent = _getdevrec(device)) {
1127
1128 /* Record found. Try to modify it */
1129 nonotfounds = TRUE;
1130
1131 /* For each of the attributes in the attribute list ... */
1132 for (pp = attributes; nobaderr && *pp; pp++) {
1133
1134 /*
1135 * Modify the device description, removing the requested
1136 * attributes from the structure
1137 */
1138
1139 found = FALSE; /* Not found yet */
1140
1141 /* If it's the "cdevice" attribute, make it a null-string */
1142 if (strcmp(*pp, DTAB_CDEVICE) == 0) {
1143 if (modent->cdevice) {
1144 free(modent->cdevice);
1145 modent->cdevice = NULL;
1146 }
1147 found = TRUE;
1148 }
1149
1150 /* If it's the "bdevice" attribute, make it a null-string */
1151 else if (strcmp(*pp, DTAB_BDEVICE) == 0) {
1152 if (modent->bdevice) {
1153 free(modent->bdevice);
1154 modent->bdevice = NULL;
1155 }
1156 found = TRUE;
1157 }
1158
1159 /* If it's the "pathname" attribute, make it a null-string */
1160 else if (strcmp(*pp, DTAB_PATHNAME) == 0) {
1161 if (modent->pathname) {
1162 free(modent->pathname);
1163 modent->pathname = NULL;
1164 }
1165 found = TRUE;
1166 }
1167
1168 /* Must be one of the other "auxilliary" attributes */
1169 else {
1170
1171 /* Search the attribute list for the attribute */
1172 prevattrval = NULL;
1173 if ((attrval = modent->attrlist) != NULL) do {
1174 if (strcmp(*pp, attrval->attr) == 0) {
1175
1176 /* Found. Remove from attribute list */
1177 found = TRUE;
1178 free(attrval->attr);
1179 free(attrval->val);
1180 if (prevattrval) {
1181 prevattrval->next = attrval->next;
1182 free(attrval);
1183 attrval = prevattrval->next;
1184 } else {
1185 modent->attrlist = attrval->next;
1186 free(attrval);
1187 attrval = modent->attrlist;
1188 }
1189 } else {
1190 prevattrval = attrval; /* Advance to next */
1191 attrval = attrval->next;
1192 }
1193 } while (!found && attrval);
1194
1195 } /* End attribute search loop */
1196
1197 /*
1198 * If the requested attribute wasn't defined for the device,
1199 * put it in the list of attributes not found
1200 */
1201
1202 if (!found) {
1203
1204 /*
1205 * If there's no list (yet), alloc enough space for
1206 * the list
1207 */
1208
1209 if (nonotfounds)
1210 if (*notfounds = malloc(sizeof (char **)*(nattrs+1))) {
1211
1212 /* List allocated -- put in the first entry */
1213 nonotfounds = FALSE;
1214 pnxt = *notfounds;
1215 if (*pnxt = malloc(strlen(*pp)+1)) {
1216 errno = EINVAL;
1217 noerr = FALSE;
1218 (void) strcpy(*pnxt++, *pp);
1219 } else {
1220 /* malloc() failed, free list */
1221 free(*notfounds);
1222 *notfounds = NULL;
1223 nonotfounds = TRUE;
1224 nobaderr = FALSE;
1225 }
1226
1227 } else nobaderr = FALSE; /* malloc() failed */
1228
1229 else {
1230 /* Already a list, add this attribute to it */
1231 if (*pnxt = malloc(strlen(*pp)+1))
1232 (void) strcpy(*pnxt++, *pp);
1233 else {
1234 /* Out of memory, clean up */
1235 for (pnxt = *notfounds; *pnxt; pnxt++)
1236 free(*pnxt);
1237 free(*notfounds);
1238 *notfounds = NULL;
1239 nonotfounds = TRUE;
1240 nobaderr = FALSE;
1241 }
1242 }
1243
1244 } /* end if (!found) */
1245
1246 /* Terminate the not-found list */
1247 if (!nonotfounds) *pnxt = NULL;
1248
1249 } /* end (for each attribute in attribute list) loop */
1250
1251
1252 /*
1253 * If we haven't seen any problems so far,
1254 * write the new device table
1255 */
1256
1257 if (nobaderr) {
1258
1259 /* Open the new device table */
1260 if (fd = opennewdevtab(&tempname)) {
1261
1262 /*
1263 * For each entry in the existing table, write that entry
1264 * to the new table. If the entry is the one being
1265 * modified, write the modified entry instead of the
1266 * original entry.
1267 */
1268
1269 _setdevtab(); /* Rewind existing table */
1270 while (((devtabent = _getdevtabent()) != NULL) &&
1271 nobaderr) {
1272
1273 if (devtabent->entryno != modent->entryno)
1274 nobaderr = _putdevtabrec(fd, devtabent) != EOF;
1275 else nobaderr = _putdevtabrec(fd, modent) != EOF;
1276 _freedevtabent(devtabent);
1277 }
1278
1279 /*
1280 * If we successfully generated the new table, make it the
1281 * new system device table. Otherwise, just remove the
1282 * temporary file we've created.
1283 */
1284
1285 if (nobaderr) {
1286 (void) fclose(fd);
1287 nobaderr = mknewdevtab(tempname);
1288 } else {
1289 (void) fclose(fd);
1290 (void) rmnewdevtab(tempname);
1291 }
1292
1293 } /* if (_opennewdevtab()) */
1294 else nobaderr = FALSE;
1295
1296 /*
1297 * If there was some error, we need to clean up
1298 * allocated resources
1299 */
1300 if (!nobaderr && !nonotfounds) {
1301 for (pnxt = *notfounds; *pnxt; pnxt++)
1302 free(*pnxt);
1303 free(*notfounds);
1304 *notfounds = NULL;
1305 nonotfounds = TRUE;
1306 }
1307
1308 } /* if (nobaderr) */
1309
1310 /* Free the resources alloc'ed for <device>'s entry */
1311 _freedevtabent(modent);
1312
1313 } else {
1314 /* _getdevrec(device) failed */
1315 nobaderr = FALSE;
1316 *notfounds = NULL;
1317 }
1318
1319 /* Unlock the device table */
1320 (void) unlkdevtab();
1321
1322 /* We're finished */
1323 return (noerr && nobaderr);
1324 }
1325