2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Assign CLI command
10 #include <aros/debug.h>
11 #include <aros/config.h>
13 #include <exec/types.h>
14 #include <exec/memory.h>
15 #include <exec/execbase.h>
17 #include <dos/dosextens.h>
18 #include <proto/dos.h>
19 #include <proto/exec.h>
20 #include <utility/tagitem.h>
25 #include <aros/shcommands.h>
27 /******************************************************************************
32 Assign [(name):] [{(target)}] [LIST] [EXISTS] [DISMOUNT] [DEFER]
33 [PATH] [ADD] [REMOVE] [VOLS] [DIRS] [DEVICES]
37 NAME, TARGET/M, LIST/S, EXISTS/S, DISMOUNT/S, DEFER/S, PATH/S, ADD/S,
38 REMOVE/S, VOLS/S, DIRS/S, DEVICES/S
46 ASSIGN creates a reference to a file or directory. The reference
47 is a logical device name which makes it very convenient to specify
48 assigned objects using the reference instead of their paths.
50 If the NAME and TARGET arguments are given, ASSIGN assigns the
51 given logical name to the specified target. If the NAME given is
52 already assigned to a file or directory the new target replaces the
53 previous target. A colon must be included after the NAME argument.
55 If only the NAME argument is given, any assigns to that NAME are
56 removed. If no arguments whatsoever are given, all logical
61 NAME -- the name that should be assigned to a file or directory
62 TARGET -- one or more files or directories to assign the NAME to
63 LIST -- list all assigns made
64 EXISTS -- if NAME is already assigned, set the condition flag to
66 DISMOUNT -- remove the volume or device NAME from the dos list
67 DEFER -- make an ASSIGN to a path or directory that not need to
68 exist at the time of assignment. The first time the
69 NAME is referenced the NAME is bound to the object
70 PATH -- path to assign with a non-binding assign. This means
71 that the assign is re-evaluated each time a reference
72 to NAME is done. Like for DEFER, the path doesn't have
73 to exist when the ASSIGN command is executed
74 ADD -- don't replace an assign but add another object for a
76 REMOVE -- remove an ASSIGN
77 VOLS -- show assigned volumes if in LIST mode
78 DIRS -- show assigned directories if in LIST mode
79 DEVICES -- show assigned devices if in LIST mode
94 The assign command has many switches. This together with the somewhat
95 messy handling of DosList:s by dos.library makes the operation rather
98 There are some fundamental building blocks that defines the semantics
99 of the Assign command.
101 Only one of the switches ADD, REMOVE, PATH and DEFER may be specified.
103 If EXISTS is specified, only the name parameter is important.
105 The implementation is split up in two fundamental procedures.
107 doAssign() -- make [a number of] assigns
108 showAssigns() -- show the available assigns
109 checkAssign() -- check if a particular assign exists
113 ******************************************************************************/
116 static int checkAssign(struct ExecBase
*SysBase
, struct DosLibrary
*DOSBase
, STRPTR name
);
117 static int doAssign(struct DosLibrary
*DOSBase
, STRPTR name
, STRPTR
*target
,
118 BOOL dismount
, BOOL defer
, BOOL path
,
119 BOOL add
, BOOL remove
);
120 static void showAssigns(struct ExecBase
*SysBase
, struct DosLibrary
*DOSBase
,
121 BOOL vols
, BOOL dirs
, BOOL devices
);
122 static int removeAssign(struct DosLibrary
*DOSBase
, STRPTR name
);
123 static STRPTR
GetFullPath(struct ExecBase
*SysBase
, struct DosLibrary
*DOSBase
,
126 AROS_SH12(Assign
, 41.5,
127 AROS_SHA(STRPTR
, ,NAME
, ,NULL
),
128 AROS_SHA(STRPTR
*, ,TARGET
,/M
,NULL
),
129 AROS_SHA(BOOL
, ,LIST
,/S
,FALSE
),
130 AROS_SHA(BOOL
, ,EXISTS
,/S
,FALSE
),
131 AROS_SHA(BOOL
, ,DISMOUNT
,/S
,FALSE
),
132 AROS_SHA(BOOL
, ,DEFER
,/S
,FALSE
),
133 AROS_SHA(BOOL
, ,PATH
,/S
,FALSE
),
134 AROS_SHA(BOOL
, ,ADD
,/S
,FALSE
),
135 AROS_SHA(BOOL
, ,REMOVE
,/S
,FALSE
),
136 AROS_SHA(BOOL
, ,VOLS
,/S
,FALSE
),
137 AROS_SHA(BOOL
, ,DIRS
,/S
,FALSE
),
138 AROS_SHA(BOOL
, ,DEVICES
,/S
,FALSE
))
141 int error
= RETURN_OK
;
143 if (SHArg(ADD
) + SHArg(REMOVE
) + SHArg(PATH
) + SHArg(DEFER
) > 1)
145 PutStr("Only one of ADD, REMOVE, PATH or DEFER is allowed\n");
156 /* Correct assign name construction? The rule is that the device name
157 * should end with a colon at the same time as no other colon may be
160 pos
= strchr(SHArg(NAME
), ':');
163 VPrintf("Invalid device name %s\n", &SHArg(NAME
));
167 /* If the EXISTS keyword is specified, we only care about NAME */
170 error
= checkAssign(SysBase
, DOSBase
, SHArg(NAME
));
172 else if (SHArg(NAME
) != NULL
)
174 /* If a NAME is specified, our primary task is to add or
177 error
= doAssign(DOSBase
, SHArg(NAME
), SHArg(TARGET
), SHArg(DISMOUNT
),
178 SHArg(DEFER
), SHArg(PATH
), SHArg(ADD
), SHArg(REMOVE
));
182 /* With the LIST keyword, the current assigns will be
183 displayed also when (after) making an assign */
185 showAssigns(SysBase
, DOSBase
, SHArg(VOLS
), SHArg(DIRS
),
191 /* If no NAME was given, we just show the current assigns
192 as specified by the user (VOLS, DIRS, DEVICES) */
194 showAssigns(SysBase
, DOSBase
, SHArg(VOLS
), SHArg(DIRS
),
204 static void showAssigns(struct ExecBase
*SysBase
, struct DosLibrary
*DOSBase
,
205 BOOL vols
, BOOL dirs
, BOOL devices
)
207 ULONG lockBits
= LDF_READ
;
210 /* If none of the parameters are specified, everything should be
212 if (!(vols
|| dirs
|| devices
))
219 lockBits
|= vols
? LDF_VOLUMES
: 0;
220 lockBits
|= dirs
? LDF_ASSIGNS
: 0;
221 lockBits
|= devices
? LDF_DEVICES
: 0;
223 dl
= LockDosList(lockBits
);
227 struct DosList
*tdl
= dl
; /* Loop variable */
229 PutStr("Volumes:\n");
231 /* Print all mounted volumes */
232 while ((tdl
= NextDosEntry(tdl
, LDF_VOLUMES
)) != NULL
)
234 VPrintf("%s [Mounted]\n", (IPTR
*)&tdl
->dol_DevName
);
240 struct DosList
*tdl
= dl
; /* Loop variable */
241 int count
; /* Loop variable */
243 PutStr("Directories:\n");
245 /* Print all assigned directories */
246 while ((tdl
= NextDosEntry(tdl
, LDF_ASSIGNS
)) != NULL
)
248 PutStr(tdl
->dol_DevName
);
250 for(count
= 14 - strlen(tdl
->dol_DevName
); count
> 0; count
--)
255 switch (tdl
->dol_Type
)
259 (IPTR
*)&tdl
->dol_misc
.dol_assign
.dol_AssignName
);
264 (IPTR
*)&tdl
->dol_misc
.dol_assign
.dol_AssignName
);
269 STRPTR dirName
; /* For NameFromLock() */
270 struct AssignList
*nextAssign
; /* For multiassigns */
272 dirName
= GetFullPath(SysBase
, DOSBase
, tdl
->dol_Lock
);
276 VPrintf("%s\n", (IPTR
*)&dirName
);
284 nextAssign
= tdl
->dol_misc
.dol_assign
.dol_List
;
286 while (nextAssign
!= NULL
)
288 dirName
= GetFullPath(SysBase
, DOSBase
,
289 nextAssign
->al_Lock
);
293 VPrintf(" + %s\n", (IPTR
*)&dirName
);
297 nextAssign
= nextAssign
->al_Next
;
303 } /* while(NextDosEntry() != NULL) */
308 struct DosList
*tdl
= dl
; /* Loop variable */
309 int count
= 0; /* Used to make sure that as most 5
310 entries are printed per line */
312 PutStr("Devices:\n");
314 /* Print all assigned devices */
315 while ((tdl
= NextDosEntry(tdl
, LDF_DEVICES
)) != NULL
)
317 VPrintf("%s ", (IPTR
*)&tdl
->dol_DevName
);
333 UnLockDosList(lockBits
);
337 static STRPTR
GetFullPath(struct ExecBase
*SysBase
, struct DosLibrary
*DOSBase
,
340 UBYTE
*buf
; /* Pointer to the memory allocated for the string */
341 ULONG size
; /* Holder of the (growing) size of the string */
343 for (size
= 512; ; size
+= 512)
345 buf
= AllocVec(size
, MEMF_ANY
);
352 if (NameFromLock(lock
, buf
, size
))
359 if (IoErr() != ERROR_LINE_TOO_LONG
)
369 static int doAssign(struct DosLibrary
*DOSBase
, STRPTR name
, STRPTR
*target
,
370 BOOL dismount
, BOOL defer
, BOOL path
, BOOL add
,
375 int i
; /* Loop variable */
377 int error
= RETURN_OK
;
382 colon
= strchr(name
, ':');
383 *colon
= 0; /* Remove trailing colon; name[] is changed! */
385 /* This is a little bit messy... We first remove the 'name' assign
386 and later in the loop the target assigns. */
393 dl
= LockDosList(LDF_VOLUMES
| LDF_DEVICES
| LDF_WRITE
);
395 fdl
= FindDosEntry(dl
, name
, LDF_VOLUMES
| LDF_DEVICES
);
397 /* Note the ! for conversion to boolean value */
399 success
= RemDosEntry(fdl
);
401 UnLockDosList(LDF_VOLUMES
| LDF_DEVICES
| LDF_WRITE
);
405 if(target
== NULL
|| *target
== NULL
|| remove
)
407 error
= removeAssign(DOSBase
, name
);
415 /* AmigaDOS doesn't use RETURN_WARN here... but it should? */
416 error
= success
? error
: RETURN_WARN
;
418 // The Loop over multiple targets starts here
422 for (i
= 0; target
[i
] != NULL
; i
++)
425 if (!(path
|| defer
|| dismount
))
427 lock
= Lock(target
[i
], SHARED_LOCK
);
431 VPrintf("Can't find %s\n", (IPTR
*)&target
[i
]);
439 AssignLock(target
[i
], NULL
);
444 if (!AssignPath(name
, target
[i
]))
452 if (AssignAdd(name
, lock
) == DOSFALSE
)
458 /* Check if the assign doesn't exist at all. If so, create it.
459 * This fix bug id 145. - Piru
461 dl
= LockDosList(LDF_ASSIGNS
| LDF_READ
);
462 dl
= FindDosEntry(dl
, name
, LDF_ASSIGNS
);
463 UnLockDosList(LDF_ASSIGNS
| LDF_READ
);
467 if (AssignLock(name
, lock
))
481 if (error
&& ioerr
!= ERROR_OBJECT_EXISTS
)
483 STRPTR Args
[] = {target
[i
], name
};
484 VPrintf("Can't add %s to %s\n", Args
);
490 if (AssignLate(name
, target
[i
]) == DOSFALSE
)
499 /* If no extra parameters are specified we just do a regular
500 assign (replacing any possible previous assign with that
501 name. The case of target being NULL is taken care of above. */
502 if (AssignLock(name
, lock
) == DOSFALSE
)
510 /* If there are several targets, the next ones have to be added. */
514 /* We break as soon as we get a serious error */
515 if (error
>= RETURN_FAIL
)
520 } /* loop through all targets */
524 if (ioerr
== ERROR_OBJECT_EXISTS
)
526 STRPTR Args
[] = {cancel
? "cancel" : "assign", name
};
527 VPrintf("Can't %s %s\n", Args
);
531 PrintFault(ioerr
, NULL
);
537 static int removeAssign(struct DosLibrary
*DOSBase
, STRPTR name
)
539 /* In case no target is given, the 'name' assign should be removed.
540 * The AmigaDOS semantics for this is apparently that the error
541 * code is never set even if the assign didn't exist.
544 if (!AssignLock(name
, NULL
))
551 static int checkAssign(struct ExecBase
*SysBase
, struct DosLibrary
*DOSBase
, STRPTR name
)
555 int error
= RETURN_OK
;
560 colon
= strchr(name
, ':');
566 dl
= LockDosList(LDF_DEVICES
| LDF_ASSIGNS
| LDF_VOLUMES
| LDF_READ
);
567 dl
= FindDosEntry(dl
, name
, LDF_DEVICES
| LDF_ASSIGNS
| LDF_VOLUMES
);
570 struct DosList
*tdl
= dl
;
573 switch (dl
->dol_Type
)
576 VPrintf("%s\n", &tdl
->dol_OldName
);
580 VPrintf("%s [Mounted]\n", &tdl
->dol_OldName
);
587 VPrintf("%s ", &tdl
->dol_OldName
);
589 for (count
= 14 - *((UBYTE
*)tdl
->dol_OldName
); count
> 0; count
--)
594 switch (tdl
->dol_Type
)
597 VPrintf("<%s>\n", (IPTR
) &tdl
->dol_misc
.dol_assign
.dol_AssignName
);
601 VPrintf("[%s]\n", (IPTR
) &tdl
->dol_misc
.dol_assign
.dol_AssignName
);
606 STRPTR dirName
; /* For NameFromLock() */
607 struct AssignList
*nextAssign
; /* For multiassigns */
609 dirName
= GetFullPath(SysBase
, DOSBase
, tdl
->dol_Lock
);
618 nextAssign
= tdl
->dol_misc
.dol_assign
.dol_List
;
622 dirName
= GetFullPath(SysBase
, DOSBase
, nextAssign
->al_Lock
);
626 VPrintf(" + %s\n", (IPTR
) &dirName
);
630 nextAssign
= nextAssign
->al_Next
;
639 VPrintf("%s: not assigned\n", &name
);
643 UnLockDosList(LDF_DEVICES
| LDF_ASSIGNS
| LDF_VOLUMES
| LDF_READ
);