1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-12 09:18:10 +03:00
samba-mirror/source3/printing/printing_db.c
Gerald Carter df6d2db4ce merge from old APP_HEAD
* remove corrupt tdb and shutdown (only for printing tdbs, connections,
  sessionid & locking)
* decrement smbd counter in connections.tdb in smb_panic()
* various Makefile hack to get things to link

'max smbd processes' looks like it might be broken.  The counter KEY is not
being set.  Will look into that tomorrow.
(This used to be commit 6e22c5da92)
2004-02-12 05:24:02 +00:00

207 lines
5.3 KiB
C

/*
Unix SMB/Netbios implementation.
Version 3.0
printing backend routines
Copyright (C) Andrew Tridgell 1992-2000
Copyright (C) Jeremy Allison 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "printing.h"
static struct tdb_print_db *print_db_head;
/****************************************************************************
Function to find or create the printer specific job tdb given a printername.
Limits the number of tdb's open to MAX_PRINT_DBS_OPEN.
****************************************************************************/
struct tdb_print_db *get_print_db_byname(const char *printername)
{
struct tdb_print_db *p = NULL, *last_entry = NULL;
int num_open = 0;
pstring printdb_path;
BOOL done_become_root = False;
for (p = print_db_head, last_entry = print_db_head; p; p = p->next) {
/* Ensure the list terminates... JRA. */
SMB_ASSERT(p->next != print_db_head);
if (p->tdb && strequal(p->printer_name, printername)) {
DLIST_PROMOTE(print_db_head, p);
p->ref_count++;
return p;
}
num_open++;
last_entry = p;
}
/* Not found. */
if (num_open >= MAX_PRINT_DBS_OPEN) {
/* Try and recycle the last entry. */
DLIST_PROMOTE(print_db_head, last_entry);
for (p = print_db_head; p; p = p->next) {
if (p->ref_count)
continue;
if (p->tdb) {
if (tdb_close(print_db_head->tdb)) {
DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n",
print_db_head->printer_name ));
return NULL;
}
}
p->tdb = NULL;
p->ref_count = 0;
memset(p->printer_name, '\0', sizeof(p->printer_name));
break;
}
if (p) {
DLIST_PROMOTE(print_db_head, p);
p = print_db_head;
}
}
if (!p) {
/* Create one. */
p = (struct tdb_print_db *)malloc(sizeof(struct tdb_print_db));
if (!p) {
DEBUG(0,("get_print_db: malloc fail !\n"));
return NULL;
}
ZERO_STRUCTP(p);
DLIST_ADD(print_db_head, p);
}
pstrcpy(printdb_path, lock_path("printing/"));
pstrcat(printdb_path, printername);
pstrcat(printdb_path, ".tdb");
if (geteuid() != 0) {
become_root();
done_become_root = True;
}
p->tdb = tdb_open_ex(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT,
0600, smbd_tdb_log);
if (done_become_root)
unbecome_root();
if (!p->tdb) {
DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n",
printdb_path ));
DLIST_REMOVE(print_db_head, p);
SAFE_FREE(p);
return NULL;
}
fstrcpy(p->printer_name, printername);
p->ref_count++;
return p;
}
/***************************************************************************
Remove a reference count.
****************************************************************************/
void release_print_db( struct tdb_print_db *pdb)
{
pdb->ref_count--;
SMB_ASSERT(pdb->ref_count >= 0);
}
/***************************************************************************
Close all open print db entries.
****************************************************************************/
void close_all_print_db(void)
{
struct tdb_print_db *p = NULL, *next_p = NULL;
for (p = print_db_head; p; p = next_p) {
next_p = p->next;
if (p->tdb)
tdb_close(p->tdb);
DLIST_REMOVE(print_db_head, p);
ZERO_STRUCTP(p);
SAFE_FREE(p);
}
}
/****************************************************************************
Fetch and clean the pid_t record list for all pids interested in notify
messages. data needs freeing on exit.
****************************************************************************/
TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, BOOL cleanlist)
{
TDB_DATA data;
size_t i;
ZERO_STRUCT(data);
data = tdb_fetch_bystring( tdb, NOTIFY_PID_LIST_KEY );
if (!data.dptr) {
ZERO_STRUCT(data);
return data;
}
if (data.dsize % 8) {
DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name ));
tdb_delete_bystring(tdb, NOTIFY_PID_LIST_KEY );
SAFE_FREE(data.dptr);
ZERO_STRUCT(data);
return data;
}
if (!cleanlist)
return data;
/*
* Weed out all dead entries.
*/
for( i = 0; i < data.dsize; i += 8) {
pid_t pid = (pid_t)IVAL(data.dptr, i);
if (pid == sys_getpid())
continue;
/* Entry is dead if process doesn't exist or refcount is zero. */
while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists(pid))) {
/* Refcount == zero is a logic error and should never happen. */
if (IVAL(data.dptr, i + 4) == 0) {
DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n",
(unsigned int)pid, printer_name ));
}
if (data.dsize - i > 8)
memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8);
data.dsize -= 8;
}
}
return data;
}